Add edition registration
This commit is contained in:
parent
b4a7e33fa4
commit
2f0c0a38f2
@ -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;
|
||||
}
|
||||
|
@ -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 => {
|
||||
|
@ -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();
|
||||
|
||||
|
22
src/components/section.tsx
Normal file
22
src/components/section.tsx
Normal 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>
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import { Moment } from "moment";
|
||||
import { Course } from "@/data/course";
|
||||
|
||||
export type Edition = {
|
||||
course: Course;
|
||||
startDate: Moment;
|
||||
endDate: Moment;
|
||||
proposalDeadline: Moment;
|
||||
|
@ -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>
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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ę
|
||||
|
@ -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/"),
|
||||
|
Loading…
Reference in New Issue
Block a user