Add edition registration

This commit is contained in:
Kacper Donat 2020-09-07 23:13:46 +02:00 committed by Gitea
parent b4a7e33fa4
commit 2f0c0a38f2
10 changed files with 97 additions and 32 deletions

View File

@ -1,6 +1,9 @@
import { axios } from "@/api/index";
import { Edition } from "@/data/edition";
import { sampleEdition } from "@/provider/dummy";
const EDITIONS_ENDPOINT = "/editions";
const EDITION_INFO_ENDPOINT = "/editions/:key";
const REGISTER_ENDPOINT = "/register";
export async function editions() {
@ -18,3 +21,12 @@ export async function join(key: string): Promise<boolean> {
return false;
}
}
// MOCK
export async function get(key: string): Promise<Edition | null> {
if (key == "inf2020") {
return sampleEdition;
}
return null;
}

View File

@ -3,12 +3,11 @@ import store from "@/state/store"
import { AppState } from "@/state/reducer";
import { UserState } from "@/state/reducer/user";
import * as user from "./user";
import * as edition from "./edition";
export const axios = Axios.create({
baseURL: "http://system-praktyk-front.localhost:3000/api/",
baseURL: process.env.API_BASE_URL || "https://system-praktyk-front.stg.kadet.net/api/",
})
axios.interceptors.request.use(config => {

View File

@ -1,34 +1,16 @@
import { Internship, internshipTypeLabels } from "@/data";
import React from "react";
import { Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core";
import { Typography } from "@material-ui/core";
import { useTranslation } from "react-i18next";
import { createStyles, makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import { useVerticalSpacing } from "@/styles";
import moment from "moment";
import { Label, Section } from "@/components/section";
export type ProposalPreviewProps = {
proposal: Internship;
}
const Label = ({ children }: TypographyProps) => {
return <Typography variant="subtitle2" className="proposal__header">{ children }</Typography>
}
const useSectionStyles = makeStyles(theme => createStyles({
root: {
padding: theme.spacing(2),
}
}))
const Section = ({ children, ...props }: PaperProps) => {
const classes = useSectionStyles();
return <Paper {...props} className={ classNames(classes.root, props.className ) }>
{ children }
</Paper>
}
export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
const { t } = useTranslation();

View File

@ -0,0 +1,22 @@
import { createStyles, makeStyles } from "@material-ui/core/styles";
import { Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core";
import classNames from "classnames";
import React from "react";
const useSectionStyles = makeStyles(theme => createStyles({
root: {
padding: theme.spacing(2),
}
}))
export const Section = ({ children, ...props }: PaperProps) => {
const classes = useSectionStyles();
return <Paper { ...props } className={ classNames(classes.root, props.className) }>
{ children }
</Paper>
}
export const Label = ({ children }: TypographyProps) => {
return <Typography variant="subtitle2" className="proposal__header">{ children }</Typography>
}

View File

@ -1,6 +1,8 @@
import { Moment } from "moment";
import { Course } from "@/data/course";
export type Edition = {
course: Course;
startDate: Moment;
endDate: Moment;
proposalDeadline: Moment;

View File

@ -1,29 +1,59 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { Page } from "@/pages/base";
import { useTranslation } from "react-i18next";
import { Button, Container, TextField } from "@material-ui/core";
import { Button, Container, TextField, Typography } from "@material-ui/core";
import api from "@/api";
import { useVerticalSpacing } from "@/styles";
import { Edition } from "@/data/edition";
import { Label, Section } from "@/components/section";
import { Alert } from "@material-ui/lab";
export const RegisterEditionPage = () => {
const { t } = useTranslation();
const [key, setKey] = useState<string>("");
const [edition, setEdition] = useState<Edition | null>(null);
const classes = useVerticalSpacing(3);
useEffect(() => {
(async () => setEdition(await api.edition.get(key)))();
}, [ key ])
const handleRegister = () => {
api.edition.join(key);
try {
api.edition.join(key);
} catch (error) {
}
}
const handleKeyChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
setKey(ev.currentTarget.value);
}
return <Page>
<Page.Header maxWidth="md">
<Page.Title>{ t("edition.register") }</Page.Title>
<Page.Title>{ t("pages.edition.header") }</Page.Title>
</Page.Header>
<Container maxWidth="md">
<TextField label={ t("edition.key") } fullWidth
onChange={ (ev: React.ChangeEvent<HTMLInputElement>) => setKey(ev.currentTarget.value) }
<Container maxWidth="md" className={ classes.root }>
<TextField label={ t("forms.edition-register.fields.key") } fullWidth
onChange={ handleKeyChange }
value={ key } />
<Button onClick={ handleRegister }>{ t("edition.register") }</Button>
{ edition
? <Section>
<Label>{ t("forms.edition-register.edition" ) }</Label>
<Typography className="proposal__primary">{ edition.course.name }</Typography>
<Typography className="proposal__secondary">
{ t('internship.date-range', { start: edition.startDate, end: edition.endDate }) }
</Typography>
</Section>
: <Alert severity="warning">{ t("forms.edition-register.edition-not-found") }</Alert>
}
<Button onClick={ handleRegister } variant="contained" color="primary" disabled={ !edition }>{ t("forms.edition-register.register") }</Button>
</Container>
</Page>
}

View File

@ -1,9 +1,11 @@
import { Edition } from "@/data/edition";
import moment from "moment";
import { sampleCourse } from "@/provider/dummy/student";
export const sampleEdition: Edition = {
startDate: moment("2020-07-01"),
endDate: moment("2020-09-30"),
proposalDeadline: moment("2020-07-31"),
minimumInternshipHours: 40,
course: sampleCourse,
}

View File

@ -33,8 +33,14 @@ export const routes: Route[] = [
const routeNameMap = new Map(routes.filter(({ name }) => !!name).map(({ name, path }) => [name, path instanceof Array ? path[0] : path])) as Map<string, string>
export function route(name: string, params: { [param: string]: string } = {}) {
export type URLParams = { [param: string]: string };
export const prepare = (url: string, params: URLParams) => Object
.entries(params)
.reduce((url, [name, value]) => url.replace(`:${ name }`, value), url)
export function route(name: string, params: URLParams = {}) {
const url = routeNameMap.get(name) || "";
return Object.entries(params).reduce((url, [name, value]) => url.replace(`:${ name }`, value), url);
return prepare(url, params)
}

View File

@ -32,6 +32,8 @@ pages:
header: "Moja praktyka"
proposal-form:
header: "Zgłoszenie praktyki"
edition:
header: "Zapisz się do edycji"
forms:
internship:
@ -67,6 +69,12 @@ forms:
instructions: >
Wypełnij i zeskanuj Indywidualny program Praktyk a następnie wyślij go z pomocą tego formularza. <więcej informacji>
dropzone-help: Skan dokumentu w formacie PDF
edition-register:
register: Zapisz się do edycji
edition: Znaleziona edycja
edition-not-found: "Edycja o takim kluczu nie została znaleziona - sprawdź poprawność klucza."
fields:
key: Klucz dostępu do edycji
student:
name: imię

View File

@ -3,6 +3,7 @@ const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { GenerateSW } = require('workbox-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin")
const Webpack = require('webpack');
const config = {
entry: {
@ -46,6 +47,7 @@ const config = {
filename: 'index.html',
template: 'public/index.html'
}),
new Webpack.EnvironmentPlugin(['API_BASE_URL'])
],
devServer: {
contentBase: path.resolve("./public/"),