Add fake login page until CAS access is granted #11

Manually merged
kadet merged 1 commits from feature_validation into master 2020-08-18 20:59:06 +02:00
8 changed files with 95 additions and 39 deletions

View File

@ -4,7 +4,6 @@ import { route, routes } from "@/routing";
import { useSelector } from "react-redux";
import { AppState, isReady } from "@/state/reducer";
import { StudentActions } from "@/state/actions/student";
import { sampleStudent } from "@/provider/dummy/student";
import { Trans, useTranslation } from "react-i18next";
import { Student } from "@/data";
import '@/styles/overrides.scss'
@ -26,13 +25,6 @@ const UserMenu = (props: HTMLProps<HTMLUListElement>) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const handleUserLogin = () => {
dispatch({
type: StudentActions.Login,
student: sampleStudent,
})
}
const handleUserLogout = () => {
dispatch({ type: StudentActions.Logout })
}
@ -44,7 +36,7 @@ const UserMenu = (props: HTMLProps<HTMLUListElement>) => {
{ ' ' }
(<Link to={ '#' } onClick={ handleUserLogout }>{ t('logout') }</Link>)
</> : <>
<Link to={ '#' } onClick={ handleUserLogin }>{ t('login') }</Link>
<Link to={ route('user_login') }>{ t('login') }</Link>
</>
}
</ul>;

View File

@ -284,7 +284,7 @@ export const InternshipForm: React.FunctionComponent = () => {
postalCode: Yup.string().required(t("validation.required")),
building: Yup.string().required(t("validation.required")),
kindOther: Yup.string().when("kind", {
is: (values: InternshipFormValues) => values?.kind !== InternshipType.Other,
is: (values: InternshipFormValues) => values?.kind === InternshipType.Other,
then: Yup.string().required(t("validation.required"))
})
})
@ -312,6 +312,8 @@ export const InternshipForm: React.FunctionComponent = () => {
if (Object.keys(errors).length == 0) {
setConfirmDialogOpen(true);
} else {
console.warn(errors);
}
}

View File

@ -1,7 +1,7 @@
import React, { useMemo } from "react";
import { Page } from "@/pages/base";
import { Button, Container, Stepper, Typography } from "@material-ui/core";
import { Link as RouterLink } from "react-router-dom";
import { Link as RouterLink, Redirect } from "react-router-dom";
import { route } from "@/routing";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
@ -11,40 +11,53 @@ import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
import { Step } from "@/components";
import { ProposalStep } from "@/pages/steps/proposal";
import { PlanStep } from "@/pages/steps/plan";
import { InsuranceStep } from "@/pages/steps/insurance";
import { InsuranceState } from "@/state/reducer/insurance";
import { InsuranceStep } from "@/pages/steps/insurance";
export const MainPage = () => {
const { t } = useTranslation();
const student = useSelector<AppState, Student | null>(state => state.student);
const deadlines = useSelector<AppState, Deadlines>(state => getEditionDeadlines(state.edition as Edition)); // edition cannot be null at this point
const insurance = useSelector<AppState, InsuranceState>(root => root.insurance);
const missingStudentData = useMemo(() => student ? getMissingStudentData(student) : [], [student]);
if (!student) {
return <Redirect to={ route("user_login") }/>;
}
function *getSteps() {
yield <Step label={ t('steps.personal-data.header') } completed={ missingStudentData.length === 0 } until={ deadlines.personalData } key="personal-data">
{ missingStudentData.length > 0 && <>
<p>{ t('steps.personal-data.info') }</p>
<ul>
{ missingStudentData.map(field => <li key={ field }>{ t(`student.${ field }`) }</li>) }
</ul>
<Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink }>
{ t('steps.personal-data.form') }
</Button>
</> }
</Step>;
yield <ProposalStep key="proposal"/>;
yield <PlanStep key="plan"/>;
if (insurance.required)
yield <InsuranceStep key="insurance"/>;
yield <Step label={ t('steps.report.header') } until={ deadlines.report } key="report"/>
yield <Step label={ t('steps.grade.header') } key="grade"/>
}
return <Page my={ 6 }>
<Container>
<Typography variant="h2">{ t("pages.my-internship.header") }</Typography>
<Stepper orientation="vertical" nonLinear>
<Step label={ t('steps.personal-data.header') } completed={ missingStudentData.length === 0 } until={ deadlines.personalData }>
{ missingStudentData.length > 0 && <>
<p>{ t('steps.personal-data.info') }</p>
<ul>
{ missingStudentData.map(field => <li key={ field }>{ t(`student.${ field }`) }</li>) }
</ul>
<Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink }>
{ t('steps.personal-data.form') }
</Button>
</> }
</Step>
<ProposalStep />
<PlanStep />
{ insurance.required && <InsuranceStep /> }
<Step label={ t('steps.report.header') } until={ deadlines.report }/>
<Step label={ t('steps.grade.header') }/>
{ Array.from(getSteps()) }
</Stepper>
</Container>
</Page>

View File

@ -13,11 +13,6 @@ export const InsuranceStep = () => {
const deadline = useSelector<AppState, Moment | undefined>(state => getEditionDeadlines(state.edition as Edition).insurance); // edition cannot be null at this point
const { t } = useTranslation();
// we don't want to show this step unless it's required
if (!insurance.required) {
return null;
}
return <Step label={ t("steps.insurance.header") } until={ deadline } completed={ insurance.signed } active={ !insurance.signed }>
<p>{ t(`steps.insurance.instructions`) }</p>
<Actions>

35
src/pages/user/login.tsx Normal file
View File

@ -0,0 +1,35 @@
import React from "react";
import { Page } from "@/pages/base";
import { Button, Container, Typography } from "@material-ui/core";
import { StudentActions, useDispatch } from "@/state/actions";
import { sampleStudent } from "@/provider/dummy";
import { useHistory } from "react-router-dom";
import { route } from "@/routing";
import { useVerticalSpacing } from "@/styles";
export const UserLoginPage = () => {
const dispatch = useDispatch();
const history = useHistory();
const handleSampleLogin = () => {
dispatch({
type: StudentActions.Login,
student: sampleStudent,
})
history.push(route("home"));
}
const classes = useVerticalSpacing(3);
return <Page>
<Page.Header maxWidth="md">
<Page.Title>Tu miało być przekierowanie do logowania PG...</Page.Title>
</Page.Header>
<Container maxWidth="md" className={ classes.root }>
<Typography variant="h3">... ale wciąż czekamy na dostęp :(</Typography>
<Button fullWidth onClick={ handleSampleLogin } variant="contained" color="primary">Zaloguj jako przykładowy student</Button>
</Container>
</Page>;
}

View File

@ -4,10 +4,12 @@ import { RouteProps } from "react-router-dom";
import { InternshipProposalFormPage, InternshipProposalPreviewPage } from "@/pages/internship/proposal";
import { NotFoundPage } from "@/pages/errors/not-found";
import SubmitPlanPage from "@/pages/internship/plan";
import { UserLoginPage } from "@/pages/user/login";
type Route = {
name?: string;
content: () => ReactComponentElement<any>,
condition?: () => boolean,
} & RouteProps;
export const routes: Route[] = [
@ -17,6 +19,9 @@ export const routes: Route[] = [
{ name: "internship_proposal_preview", path: "/internship/preview/proposal", exact: true, content: () => <InternshipProposalPreviewPage/> },
{ name: "internship_plan", path: "/internship/plan", exact: true, content: () => <SubmitPlanPage/> },
// user
{ name: "user_login", path: "/user/login", exact: true, content: () => <UserLoginPage /> },
// fallback route for 404 pages
{ name: "fallback", path: "*", content: () => <NotFoundPage/> }
]

View File

@ -1,5 +1,7 @@
import { Reducer } from "react";
import { InsuranceAction, InsuranceActions } from "@/state/actions/insurance";
import { InternshipProposalAction, InternshipProposalActions } from "@/state/actions";
import { InternshipType } from "@/data";
export type InsuranceState = {
required: boolean;
@ -12,10 +14,21 @@ const initialInsuranceState: InsuranceState = {
signed: false,
}
export const insuranceReducer: Reducer<InsuranceState, InsuranceAction> = (state = initialInsuranceState, action) => {
export const insuranceReducer: Reducer<InsuranceState, InsuranceAction | InternshipProposalAction> = (state = initialInsuranceState, action) => {
const { type, ...payload } = action;
switch (action.type) {
case InternshipProposalActions.Send:
return {
...state,
required: [
InternshipType.FreeApprenticeship,
InternshipType.FreeInternship,
InternshipType.PaidApprenticeship,
InternshipType.GraduateInternship,
].includes(action.internship.type)
}
case InsuranceActions.Signed:
return { ...state, signed: true }
case InsuranceActions.Update:

View File

@ -31,7 +31,7 @@ pages:
my-internship:
header: "Moja praktyka"
proposal-form:
header: "Propose internship"
header: "Zgłoszenie praktyki"
forms:
internship:
@ -138,7 +138,8 @@ steps:
header: "Indywidualny Program Praktyki"
info:
draft: >
TODO
W porozumieniu z firmą w której odbywają się praktyki należy sporządzić Indywidualny Plan Praktyk zgodnie z
załączonym szablonem a następnie wysłać go do weryfikacji. (TODO)
awaiting: >
Twój indywidualny program praktyki został poprawnie zapisany w systemie. Musi on jeszcze zostać zweryfikowany i
zatwierdzony. Po weryfikacji zostaniesz poinformowany o akceptacji bądź konieczności wprowadzenia zmian.
@ -157,7 +158,7 @@ steps:
insurance:
header: "Ubezpieczenie NNW"
instructions: >
papierki do podpisania...
Należy zgłosić się do pełnomocnika ds. praktyk Twojego kierunku i podpisać umowę ubezpieczenia. (TODO)
validation:
required: "To pole jest wymagane"