Add more steps

This commit is contained in:
Kacper Donat 2020-07-21 22:19:52 +02:00
parent 16d2ef4315
commit a3db797a06
12 changed files with 129 additions and 64 deletions

View File

@ -7,6 +7,7 @@
"@babel/preset-typescript": "^7.10.1",
"@date-io/moment": "^1.3.13",
"@material-ui/core": "^4.10.1",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.55",
"@material-ui/pickers": "^3.2.10",
"@types/classnames": "^2.2.10",

View File

@ -12,18 +12,12 @@ import { AppState } from "@/state/reducer";
import { StudentAction, StudentActions } from "@/state/actions/student";
import { sampleStudent } from "@/provider/dummy/student";
import { Trans, useTranslation } from "react-i18next";
import { StudentState } from "@/state/reducer/student";
import { Student } from "@/data";
import "moment/locale/pl"
import '@/styles/overrides.scss'
import '@/styles/header.scss'
import classNames from "classnames";
import { Button } from "@material-ui/core";
import { PersistGate } from 'redux-persist/integration/react';
moment.locale("pl")
class LocalizedMomentUtils extends MomentUtils {
getDatePickerHeaderText(date: Moment): string {
return this.format(date, "d MMM yyyy");
@ -65,6 +59,7 @@ const LanguageSwitcher = ({ className, ...props }: HTMLProps<HTMLUListElement>)
const handleLanguageChange = (language: string) => () => {
i18n.changeLanguage(language);
document.documentElement.lang = language;
moment.locale(language)
}
const isActive = (language: string) => language.toLowerCase() === i18n.language.toLowerCase();

View File

@ -1,6 +1,5 @@
import { Moment } from "moment";
import { Identifiable } from "./common";
import { countWorkingWeeksInRange } from "@/utils/date";
import { Student } from "@/data/student";
import { Company } from "@/data/company";

View File

@ -2,6 +2,11 @@ import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
import moment from "moment";
import "moment/locale/pl"
import "moment/locale/en-gb"
const resources = {
en: {
translation: require('../translations/en.yaml'),
@ -23,5 +28,6 @@ i18n
})
document.documentElement.lang = i18n.language;
moment.locale(i18n.language)
export default i18n;

View File

@ -0,0 +1,22 @@
import { Page } from "@/pages/base";
import { Box, Button, Container, Divider, Typography } from "@material-ui/core";
import { route } from "@/routing";
import { Link as RouterLink } from "react-router-dom";
import React from "react";
export const NotFoundPage = () => {
return <Page title="Strona nie została znaleziona">
<Container>
<Typography variant="h1">404</Typography>
<Typography variant="h2">Strona nie została znaleziona</Typography>
<Box my={ 4 }>
<Divider variant="fullWidth"/>
</Box>
<Button to={ route("home") } color="primary" component={ RouterLink }>strona główna</Button>
</Container>
</Page>
}
export default NotFoundPage;

3
src/pages/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from "./internship/proposal";
export * from "./errors/not-found"
export * from "./main"

View File

@ -0,0 +1,23 @@
import { Page } from "@/pages/base";
import { Container, Link, Typography } from "@material-ui/core";
import { Link as RouterLink } from "react-router-dom";
import { route } from "@/routing";
import { InternshipForm } from "@/forms/Internship";
import React from "react";
export const InternshipProposalPage = () => {
return <Page title="Zgłoszenie praktyki">
<Page.Header maxWidth="md">
<Page.Breadcrumbs>
<Link component={ RouterLink } to={ route("home") }>Moja praktyka</Link>
<Typography color="textPrimary">Zgłoszenie praktyki</Typography>
</Page.Breadcrumbs>
<Page.Title>Zgłoszenie praktyki</Page.Title>
</Page.Header>
<Container maxWidth={ "md" }>
<InternshipForm/>
</Container>
</Page>
}
export default InternshipProposalPage;

View File

@ -1,65 +1,58 @@
import React from "react";
import React, { useMemo } from "react";
import { Page } from "@/pages/base";
import { Container, Typography, Button, Divider, Box, Stepper, Step, StepLabel, StepContent, Link } from "@material-ui/core";
import { InternshipForm } from "@/forms/Internship";
import { Box, Button, Container, Step as StepperStep, StepContent, StepLabel, Stepper, StepProps as StepperStepProps, Typography } from "@material-ui/core";
import { Link as RouterLink } from "react-router-dom";
import { route } from "@/routing";
import { useTranslation } from "react-i18next";
import moment, { Moment } from "moment";
type StepProps = StepperStepProps & {
until?: Moment;
completedOn?: Moment;
label: string;
}
const now = moment();
const Step = ({ until, label, completedOn, children, completed, ...props }: StepProps) => {
const { t } = useTranslation();
const isLate = useMemo(() => until?.isBefore(completedOn || now), [completedOn, until]);
const left = useMemo(() => moment.duration(now.diff(until)), [until]);
return <StepperStep { ...props } completed={ completed || !!completedOn }>
<StepLabel>
{ label }
{ until && <Box>
<Typography variant="subtitle2" color="textSecondary">
{ t('until', { date: until.format("DD MMMM YYYY") }) }
{ isLate && <Typography color="error" display="inline" variant="body2"> - { t('late', { by: moment.duration(now.diff(until)).humanize() }) }</Typography> }
{ !isLate && !completed && <Typography display="inline" variant="body2"> - { t('left', { left: left.humanize() }) }</Typography> }
</Typography>
</Box> }
</StepLabel>
{ children && <StepContent>{ children }</StepContent> }
</StepperStep>
}
export const MainPage = () => {
const { t } = useTranslation();
return <Page my={6}>
return <Page my={ 6 }>
<Container>
<Typography variant="h2">{ t("sections.my-internship.header") }</Typography>
<Stepper orientation="vertical" nonLinear>
<Step completed active={false}>
<StepLabel>
{ t('steps.personal-data.header') }
<Box>
<Typography variant="subtitle2" color="textSecondary">{ t('until', { date: '05.07.2020' }) }</Typography>
</Box>
</StepLabel>
</Step>
<Step active>
<StepLabel>{ t('steps.internship-proposal.header')}</StepLabel>
<StepContent>
<Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink }>
{ t('steps.internship-proposal.form') }
</Button>
</StepContent>
<Step label={ t('steps.personal-data.header') } until={ moment("2020-07-01") }/>
<Step label={ t('steps.internship-proposal.header') }>
<Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink }>
{ t('steps.internship-proposal.form') }
</Button>
</Step>
<Step label={ t('steps.plan.header') } until={ moment("2020-07-22") }/>
<Step label={ t('steps.insurance.header') }/>
<Step label={ t('steps.report.header') }/>
<Step label={ t('steps.grade.header') }/>
</Stepper>
</Container>
</Page>
}
export const InternshipFormPage = () => {
return <Page title="Zgłoszenie praktyki">
<Page.Header maxWidth="md">
<Page.Breadcrumbs>
<Link component={ RouterLink } to={ route("home") }>Moja praktyka</Link>
<Typography color="textPrimary">Zgłoszenie praktyki</Typography>
</Page.Breadcrumbs>
<Page.Title>Zgłoszenie praktyki</Page.Title>
</Page.Header>
<Container maxWidth={"md"}>
<InternshipForm />
</Container>
</Page>
}
export const NotFoundPage = () => {
return <Page title="Strona nie została znaleziona">
<Container>
<Typography variant="h1">404</Typography>
<Typography variant="h2">Strona nie została znaleziona</Typography>
<Box my={ 4 }>
<Divider variant="fullWidth" />
</Box>
<Button to={ route("home") } color="primary" component={ RouterLink }>strona główna</Button>
</Container>
</Page>
}

View File

@ -1,6 +1,8 @@
import React, { ReactComponentElement } from "react";
import { InternshipFormPage, MainPage, NotFoundPage } from "@/pages/main";
import { MainPage } from "@/pages/main";
import { RouteProps } from "react-router-dom";
import { InternshipProposalPage } from "@/pages/internship/proposal";
import { NotFoundPage } from "@/pages/errors/not-found";
type Route = {
name?: string;
@ -8,18 +10,18 @@ type Route = {
} & RouteProps;
export const routes: Route[] = [
{ name: "home", path: "/", exact: true, content: () => <MainPage /> },
{ name: "home", path: "/", exact: true, content: () => <MainPage/> },
{ name: "internship_proposal", path: "/internship/proposal", exact: true, content: () => <InternshipFormPage /> },
{ name: "internship_proposal", path: "/internship/proposal", exact: true, content: () => <InternshipProposalPage/> },
// fallback route for 404 pages
{ path: "*", content: () => <NotFoundPage /> }
{ name: "fallback", path: "*", content: () => <NotFoundPage/> }
]
const routeNameMap = new Map(routes.filter(({name}) => !!name).map(({ name, path }) => [ name, path instanceof Array ? path[0] : path ])) as Map<string, string>
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 function route(name: string, params: { [param: string]: string } = {}) {
const url = routeNameMap.get(name) || "";
return Object.entries(params).reduce((url, [name, value]) => url.replace(`:${name}`, value), url);
return Object.entries(params).reduce((url, [name, value]) => url.replace(`:${ name }`, value), url);
}

View File

@ -4,6 +4,8 @@ logout: logout
logged-in-as: logged in as <1>{{ name }}</1>
until: until {{ date }}
late: late by {{ by }}
left: '{{ left }} left'
sections:
my-internship:
@ -11,7 +13,9 @@ sections:
steps:
personal-data:
header: "Personal data"
header: "Fill personal data"
internship-proposal:
header: "Internship proposal"
form: "Internship proposal form"
plan:
header: "Individual Internship Plan"

View File

@ -4,6 +4,8 @@ logout: wyloguj się
logged-in-as: zalogowany jako <1>{{ name }}</1>
until: do {{ date }}
late: '{{ by }} spóźnienia'
left: jeszcze {{ left }}
sections:
my-internship:
@ -15,3 +17,11 @@ steps:
internship-proposal:
header: "Zgłoszenie praktyki"
form: "Formularz zgłaszania praktyki"
plan:
header: "Indywidualny Program Praktyki"
report:
header: "Raport z praktyki"
grade:
header: "Ocena z praktyki"
insurance:
header: "Ubezpieczenie NWW"

View File

@ -1043,6 +1043,13 @@
react-is "^16.8.0"
react-transition-group "^4.4.0"
"@material-ui/icons@^4.9.1":
version "4.9.1"
resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665"
integrity sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/lab@^4.0.0-alpha.55":
version "4.0.0-alpha.55"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.55.tgz#82a850dc59654e04ee3a31be1b34eb3bf64d5585"