From e7831cf1e5ea764eddf2b1294df46c830b42fbf9 Mon Sep 17 00:00:00 2001
From: Kacper Donat <kadet1090@gmail.com>
Date: Wed, 5 Aug 2020 22:50:57 +0200
Subject: [PATCH] Add insurance step

---
 src/data/edition.ts            |  1 +
 src/pages/main.tsx             |  5 ++++-
 src/pages/steps/common.tsx     |  9 ++++++++-
 src/pages/steps/insurance.tsx  | 27 +++++++++++++++++++++++++++
 src/pages/steps/plan.tsx       |  7 ++-----
 src/pages/steps/proposal.tsx   |  9 +++------
 src/state/actions/index.ts     |  5 +++--
 src/state/actions/insurance.ts | 12 ++++++++++++
 src/state/reducer/index.ts     |  2 ++
 src/state/reducer/insurance.ts | 26 ++++++++++++++++++++++++++
 translations/pl.yaml           |  2 ++
 11 files changed, 90 insertions(+), 15 deletions(-)
 create mode 100644 src/pages/steps/insurance.tsx
 create mode 100644 src/state/actions/insurance.ts
 create mode 100644 src/state/reducer/insurance.ts

diff --git a/src/data/edition.ts b/src/data/edition.ts
index 8a29c94..7fc5438 100644
--- a/src/data/edition.ts
+++ b/src/data/edition.ts
@@ -11,6 +11,7 @@ export type Deadlines = {
     proposal?: Moment;
     personalPlan?: Moment;
     report?: Moment;
+    insurance?: Moment;
 }
 
 export function getEditionDeadlines(edition: Edition): Deadlines {
diff --git a/src/pages/main.tsx b/src/pages/main.tsx
index 3ddcfef..5d2da88 100644
--- a/src/pages/main.tsx
+++ b/src/pages/main.tsx
@@ -11,12 +11,15 @@ 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";
 
 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]);
 
@@ -39,7 +42,7 @@ export const MainPage = () => {
                 </Step>
                 <ProposalStep />
                 <PlanStep />
-                <Step label={ t('steps.insurance.header') }/>
+                { insurance.required && <InsuranceStep /> }
                 <Step label={ t('steps.report.header') } until={ deadlines.report }/>
                 <Step label={ t('steps.grade.header') }/>
             </Stepper>
diff --git a/src/pages/steps/common.tsx b/src/pages/steps/common.tsx
index 261ba52..58fdb8e 100644
--- a/src/pages/steps/common.tsx
+++ b/src/pages/steps/common.tsx
@@ -1,8 +1,9 @@
 import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
-import { Theme } from "@material-ui/core";
+import { Button, ButtonProps, Theme } from "@material-ui/core";
 import { createStyles, makeStyles } from "@material-ui/core/styles";
 import { useTranslation } from "react-i18next";
 import React from "react";
+import { CommentQuestion } from "mdi-material-ui/index";
 
 export const getColorByStatus = (status: SubmissionStatus, theme: Theme) => {
     switch (status) {
@@ -44,3 +45,9 @@ export const Status = ({ submission } : SubmissionStatusProps) => {
 
     return <span className={ classes.foreground }>{ t(`submission.status.${ status }`) }</span>;
 }
+
+export const ContactAction = (props: ButtonProps) => {
+    const { t } = useTranslation();
+
+    return <Button startIcon={ <CommentQuestion/> } variant="outlined" color="primary" { ...props }>{ t('contact') }</Button>
+}
diff --git a/src/pages/steps/insurance.tsx b/src/pages/steps/insurance.tsx
new file mode 100644
index 0000000..2245c53
--- /dev/null
+++ b/src/pages/steps/insurance.tsx
@@ -0,0 +1,27 @@
+import { useSelector } from "react-redux";
+import { AppState } from "@/state/reducer";
+import { InsuranceState } from "@/state/reducer/insurance";
+import { Actions, Step } from "@/components";
+import { useTranslation } from "react-i18next";
+import React from "react";
+import { Edition, getEditionDeadlines } from "@/data/edition";
+import { Moment } from "moment";
+import { ContactAction } from "@/pages/steps/common";
+
+export const InsuranceStep = () => {
+    const insurance = useSelector<AppState, InsuranceState>(root => root.insurance);
+    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>
+            <ContactAction />
+        </Actions>
+    </Step>
+}
diff --git a/src/pages/steps/plan.tsx b/src/pages/steps/plan.tsx
index e92169d..7a94c7f 100644
--- a/src/pages/steps/plan.tsx
+++ b/src/pages/steps/plan.tsx
@@ -3,14 +3,14 @@ import { AppState } from "@/state/reducer";
 import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
 import { useTranslation } from "react-i18next";
 import { Box, Button, ButtonProps, StepProps } from "@material-ui/core";
-import { CommentQuestion, FileDownloadOutline, FileUploadOutline } from "mdi-material-ui/index";
+import { FileDownloadOutline, FileUploadOutline } from "mdi-material-ui/index";
 import { route } from "@/routing";
 import { Link as RouterLink } from "react-router-dom";
 import { Actions, Step } from "@/components";
 import React, { HTMLProps } from "react";
 import { Alert, AlertTitle } from "@material-ui/lab";
 import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
-import { Status } from "@/pages/steps/common";
+import { ContactAction, Status } from "@/pages/steps/common";
 import { Description as DescriptionIcon } from "@material-ui/icons";
 
 const PlanActions = () => {
@@ -30,9 +30,6 @@ const PlanActions = () => {
             { t('steps.plan.template') }
         </Button>
 
-    const ContactAction = (props: ButtonProps) =>
-        <Button startIcon={ <CommentQuestion/> } variant="outlined" color="primary" { ...props }>{ t('contact') }</Button>
-
     switch (status) {
         case "awaiting":
             return <Actions>
diff --git a/src/pages/steps/proposal.tsx b/src/pages/steps/proposal.tsx
index 5565cdc..b6f6cd1 100644
--- a/src/pages/steps/proposal.tsx
+++ b/src/pages/steps/proposal.tsx
@@ -10,8 +10,8 @@ import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
 import { Actions, Step } from "@/components";
 import { route } from "@/routing";
 import { Link as RouterLink } from "react-router-dom";
-import { ClipboardEditOutline, CommentQuestion, FileFind } from "mdi-material-ui/index";
-import { Status } from "@/pages/steps/common";
+import { ClipboardEditOutline, FileFind } from "mdi-material-ui/index";
+import { ContactAction, Status } from "@/pages/steps/common";
 
 const ProposalActions = () => {
     const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.proposal));
@@ -26,9 +26,6 @@ const ProposalActions = () => {
             { children }
         </Button>
 
-    const ContactAction = (props: ButtonProps) =>
-        <Button startIcon={ <CommentQuestion/> } variant="outlined" color="primary" { ...props }>{ t('contact') }</Button>
-
     switch (status) {
         case "awaiting":
             return <Actions>
@@ -42,7 +39,7 @@ const ProposalActions = () => {
         case "declined":
             return <Actions>
                 <FormAction>{ t('fix-errors') }</FormAction>
-                <ContactAction/>
+                <ContactAction />
             </Actions>
         case "draft":
             return <Actions>
diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts
index f5bcdfb..54ac996 100644
--- a/src/state/actions/index.ts
+++ b/src/state/actions/index.ts
@@ -6,6 +6,7 @@ import { Dispatch } from "react";
 
 import { useDispatch as useReduxDispatch } from "react-redux";
 import { InternshipPlanAction, InternshipPlanActions } from "@/state/actions/plan";
+import { InsuranceAction, InsuranceActions } from "@/state/actions/insurance";
 
 export * from "./base"
 export * from "./edition"
@@ -14,9 +15,9 @@ export * from "./student"
 export * from "./proposal"
 export * from "./plan"
 
-export type Action = StudentAction | EditionAction | SettingsAction | InternshipProposalAction | InternshipPlanAction;
+export type Action = StudentAction | EditionAction | SettingsAction | InternshipProposalAction | InternshipPlanAction | InsuranceAction;
 
-export const Actions = { ...StudentActions, ...EditionActions, ...SettingActions, ...InternshipProposalActions, ...InternshipPlanActions }
+export const Actions = { ...StudentActions, ...EditionActions, ...SettingActions, ...InternshipProposalActions, ...InternshipPlanActions, ...InsuranceActions }
 export type Actions = typeof Actions;
 
 export const useDispatch = () => useReduxDispatch<Dispatch<Action>>()
diff --git a/src/state/actions/insurance.ts b/src/state/actions/insurance.ts
new file mode 100644
index 0000000..721d7d6
--- /dev/null
+++ b/src/state/actions/insurance.ts
@@ -0,0 +1,12 @@
+import { Action } from "@/state/actions/base";
+import { InsuranceState } from "@/state/reducer/insurance";
+
+export enum InsuranceActions {
+    Signed = "RECEIVE_INSURANCE_SIGN",
+    Update = "RECEIVE_INSURANCE_UPDATE",
+}
+
+export type InsuranceSigned = Action<InsuranceActions.Signed>;
+export type InsuranceUpdate = Action<InsuranceActions.Update> & Partial<InsuranceState>;
+
+export type InsuranceAction = InsuranceSigned | InsuranceUpdate;
diff --git a/src/state/reducer/index.ts b/src/state/reducer/index.ts
index 3d139e2..ca5d238 100644
--- a/src/state/reducer/index.ts
+++ b/src/state/reducer/index.ts
@@ -5,6 +5,7 @@ import editionReducer from "@/state/reducer/edition";
 import settingsReducer from "@/state/reducer/settings";
 import internshipProposalReducer from "@/state/reducer/proposal";
 import internshipPlanReducer from "@/state/reducer/plan";
+import { insuranceReducer } from "@/state/reducer/insurance";
 
 const rootReducer = combineReducers({
     student: studentReducer,
@@ -12,6 +13,7 @@ const rootReducer = combineReducers({
     settings: settingsReducer,
     proposal: internshipProposalReducer,
     plan: internshipPlanReducer,
+    insurance: insuranceReducer,
 })
 
 export type AppState = ReturnType<typeof rootReducer>;
diff --git a/src/state/reducer/insurance.ts b/src/state/reducer/insurance.ts
new file mode 100644
index 0000000..d5aaa4f
--- /dev/null
+++ b/src/state/reducer/insurance.ts
@@ -0,0 +1,26 @@
+import { Reducer } from "react";
+import { InsuranceAction, InsuranceActions } from "@/state/actions/insurance";
+
+export type InsuranceState = {
+    required: boolean;
+    signed: boolean;
+    /// other data?
+}
+
+const initialInsuranceState: InsuranceState = {
+    required: false,
+    signed: false,
+}
+
+export const insuranceReducer: Reducer<InsuranceState, InsuranceAction> = (state = initialInsuranceState, action) => {
+    const { type, ...payload } = action;
+
+    switch (action.type) {
+        case InsuranceActions.Signed:
+            return { ...state, signed: true }
+        case InsuranceActions.Update:
+            return { ...state, ...payload }
+        default:
+            return state;
+    }
+}
diff --git a/translations/pl.yaml b/translations/pl.yaml
index 07be4d1..2cfd0fa 100644
--- a/translations/pl.yaml
+++ b/translations/pl.yaml
@@ -95,5 +95,7 @@ steps:
     header: "Ocena z praktyki"
   insurance:
     header: "Ubezpieczenie NNW"
+    instructions: >
+      papierki do podpisania...
 
 contact-coordinator: "Skontaktuj siÄ™ z koordynatorem"