Refactor submission state management so it is reusable
This commit is contained in:
		
							parent
							
								
									a3475c5f30
								
							
						
					
					
						commit
						886153afb5
					
				@ -67,6 +67,10 @@ export interface Internship extends Identifiable {
 | 
				
			|||||||
    office: BranchOffice;
 | 
					    office: BranchOffice;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface Plan extends Identifiable {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Mentor {
 | 
					export interface Mentor {
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    surname: string;
 | 
					    surname: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,10 +15,11 @@ import { InternshipProposalActions, useDispatch } from "@/state/actions";
 | 
				
			|||||||
import { useTranslation } from "react-i18next";
 | 
					import { useTranslation } from "react-i18next";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { AppState } from "@/state/reducer";
 | 
					import { AppState } from "@/state/reducer";
 | 
				
			||||||
import { useHistory } from "react-router-dom";
 | 
					import { Link as RouterLink, useHistory } from "react-router-dom";
 | 
				
			||||||
import { route } from "@/routing";
 | 
					import { route } from "@/routing";
 | 
				
			||||||
import { useProxyState } from "@/hooks";
 | 
					import { useProxyState } from "@/hooks";
 | 
				
			||||||
import { getInternshipProposal } from "@/state/reducer/proposal";
 | 
					import { getInternshipProposal } from "@/state/reducer/proposal";
 | 
				
			||||||
 | 
					import { Actions } from "@/components";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type InternshipFormProps = {}
 | 
					export type InternshipFormProps = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -161,7 +162,13 @@ export const InternshipForm: React.FunctionComponent<InternshipFormProps> = prop
 | 
				
			|||||||
            <InternshipDurationForm internship={ internship } onChange={ setInternship }/>
 | 
					            <InternshipDurationForm internship={ internship } onChange={ setInternship }/>
 | 
				
			||||||
            <Typography variant="h3" className="section-header">Miejsce odbywania praktyki</Typography>
 | 
					            <Typography variant="h3" className="section-header">Miejsce odbywania praktyki</Typography>
 | 
				
			||||||
            <CompanyForm internship={ internship } onChange={ setInternship }/>
 | 
					            <CompanyForm internship={ internship } onChange={ setInternship }/>
 | 
				
			||||||
            <Button variant="contained" color="primary" onClick={ handleSubmit }>{ t("confirm") }</Button>
 | 
					            <Actions>
 | 
				
			||||||
 | 
					                <Button variant="contained" color="primary" onClick={ handleSubmit }>{ t("confirm") }</Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <Button component={ RouterLink } to={ route("home") }>
 | 
				
			||||||
 | 
					                    { t('go-back') }
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </Actions>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,13 +10,14 @@ import { getMissingStudentData, Student } from "@/data";
 | 
				
			|||||||
import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
 | 
					import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
 | 
				
			||||||
import { Description as DescriptionIcon } from "@material-ui/icons"
 | 
					import { Description as DescriptionIcon } from "@material-ui/icons"
 | 
				
			||||||
import { Actions, Step } from "@/components";
 | 
					import { Actions, Step } from "@/components";
 | 
				
			||||||
import { getInternshipProposalStatus, InternshipProposalState, InternshipProposalStatus } from "@/state/reducer/proposal";
 | 
					import { InternshipProposalState } from "@/state/reducer/proposal";
 | 
				
			||||||
import { createStyles, makeStyles } from "@material-ui/core/styles";
 | 
					import { createStyles, makeStyles } from "@material-ui/core/styles";
 | 
				
			||||||
import { ClipboardEditOutline, CommentQuestion, FileFind } from "mdi-material-ui";
 | 
					import { ClipboardEditOutline, CommentQuestion, FileFind } from "mdi-material-ui";
 | 
				
			||||||
import { Alert, AlertTitle } from "@material-ui/lab";
 | 
					import { Alert, AlertTitle } from "@material-ui/lab";
 | 
				
			||||||
 | 
					import { getSubmissionStatus, SubmissionStatus } from "@/state/reducer/submission";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getColorByStatus = (status: InternshipProposalStatus, theme: Theme) => {
 | 
					const getColorByStatus = (status: SubmissionStatus, theme: Theme) => {
 | 
				
			||||||
    switch (status) {
 | 
					    switch (status) {
 | 
				
			||||||
        case "awaiting":
 | 
					        case "awaiting":
 | 
				
			||||||
            return theme.palette.info.dark;
 | 
					            return theme.palette.info.dark;
 | 
				
			||||||
@ -45,7 +46,7 @@ const useStatusStyles = makeStyles((theme: Theme) => {
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProposalStatus = () => {
 | 
					const ProposalStatus = () => {
 | 
				
			||||||
    const status = useSelector<AppState, InternshipProposalStatus>(state => getInternshipProposalStatus(state.proposal))
 | 
					    const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.proposal))
 | 
				
			||||||
    const classes = useStatusStyles({ status });
 | 
					    const classes = useStatusStyles({ status });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
@ -54,7 +55,7 @@ const ProposalStatus = () => {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProposalActions = () => {
 | 
					const ProposalActions = () => {
 | 
				
			||||||
    const status = useSelector<AppState, InternshipProposalStatus>(state => getInternshipProposalStatus(state.proposal));
 | 
					    const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.proposal));
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const ReviewAction = (props: ButtonProps) =>
 | 
					    const ReviewAction = (props: ButtonProps) =>
 | 
				
			||||||
@ -96,17 +97,17 @@ export const ProposalComment = (props: HTMLProps<HTMLDivElement>) => {
 | 
				
			|||||||
    const { comment, declined } = useSelector<AppState, InternshipProposalState>(state => state.proposal);
 | 
					    const { comment, declined } = useSelector<AppState, InternshipProposalState>(state => state.proposal);
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return <Alert severity={declined ? "error" : "warning"} {...props as any}>
 | 
					    return comment ? <Alert severity={declined ? "error" : "warning"} {...props as any}>
 | 
				
			||||||
        <AlertTitle>{ t('comments') }</AlertTitle>
 | 
					        <AlertTitle>{ t('comments') }</AlertTitle>
 | 
				
			||||||
        { comment }
 | 
					        { comment }
 | 
				
			||||||
    </Alert>
 | 
					    </Alert> : null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProposalStep = (props: StepProps) => {
 | 
					const ProposalStep = (props: StepProps) => {
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { sent, comment, declined } = useSelector<AppState, InternshipProposalState>(state => state.proposal);
 | 
					    const { sent, comment, declined } = useSelector<AppState, InternshipProposalState>(state => state.proposal);
 | 
				
			||||||
    const status = useSelector<AppState, InternshipProposalStatus>(state => getInternshipProposalStatus(state.proposal));
 | 
					    const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.proposal));
 | 
				
			||||||
    const deadlines = useSelector<AppState, Deadlines>(state => getEditionDeadlines(state.edition as Edition)); // edition cannot be null at this point
 | 
					    const deadlines = useSelector<AppState, Deadlines>(state => getEditionDeadlines(state.edition as Edition)); // edition cannot be null at this point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return <Step { ...props }
 | 
					    return <Step { ...props }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { SerializationTransformer } from "@/serialization/types";
 | 
					import { SerializationTransformer } from "@/serialization/types";
 | 
				
			||||||
import moment, { Moment } from "moment";
 | 
					import moment, { Moment } from "moment";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const momentSerializationTransformer: SerializationTransformer<Moment, string> = {
 | 
					export const momentSerializationTransformer: SerializationTransformer<Moment | null, string> = {
 | 
				
			||||||
    transform: (subject: Moment) => subject.toISOString(),
 | 
					    transform: (subject: Moment) => subject && subject.toISOString(),
 | 
				
			||||||
    reverseTransform: (subject: string) => moment(subject),
 | 
					    reverseTransform: (subject: string) => subject ? moment(subject) : null,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,11 @@
 | 
				
			|||||||
import { Action } from "@/state/actions/base";
 | 
					 | 
				
			||||||
import { Internship } from "@/data";
 | 
					import { Internship } from "@/data";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    ReceiveSubmissionApproveAction,
 | 
				
			||||||
 | 
					    ReceiveSubmissionDeclineAction,
 | 
				
			||||||
 | 
					    ReceiveSubmissionUpdateAction,
 | 
				
			||||||
 | 
					    SaveSubmissionAction,
 | 
				
			||||||
 | 
					    SendSubmissionAction
 | 
				
			||||||
 | 
					} from "@/state/actions/submission";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum InternshipProposalActions {
 | 
					export enum InternshipProposalActions {
 | 
				
			||||||
    Send = "SEND_PROPOSAL",
 | 
					    Send = "SEND_PROPOSAL",
 | 
				
			||||||
@ -9,23 +15,23 @@ export enum InternshipProposalActions {
 | 
				
			|||||||
    Receive = "RECEIVE_PROPOSAL_STATE",
 | 
					    Receive = "RECEIVE_PROPOSAL_STATE",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface SendProposalAction extends Action<InternshipProposalActions.Send> {
 | 
					export interface SendProposalAction extends SendSubmissionAction<InternshipProposalActions.Send> {
 | 
				
			||||||
    internship: Internship;
 | 
					    internship: Internship;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ReceiveProposalApproveAction extends Action<InternshipProposalActions.Approve> {
 | 
					export interface ReceiveProposalApproveAction extends ReceiveSubmissionApproveAction<InternshipProposalActions.Approve> {
 | 
				
			||||||
    comment: string | null;
 | 
					    comment: string | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ReceiveProposalDeclineAction extends Action<InternshipProposalActions.Decline> {
 | 
					export interface ReceiveProposalDeclineAction extends ReceiveSubmissionDeclineAction<InternshipProposalActions.Decline> {
 | 
				
			||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ReceiveProposalUpdateAction extends Action<InternshipProposalActions.Receive> {
 | 
					export interface ReceiveProposalUpdateAction extends ReceiveSubmissionUpdateAction<InternshipProposalActions.Receive> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface SaveProposalAction extends Action<InternshipProposalActions.Save> {
 | 
					export interface SaveProposalAction extends SaveSubmissionAction<InternshipProposalActions.Save> {
 | 
				
			||||||
    internship: Internship;
 | 
					    internship: Internship;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/state/actions/submission.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/state/actions/submission.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { Action } from "@/state/actions/base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum SubmissionAction {
 | 
				
			||||||
 | 
					    Send = "SEND",
 | 
				
			||||||
 | 
					    Save = "SAVE",
 | 
				
			||||||
 | 
					    Approve = "RECEIVE_APPROVE",
 | 
				
			||||||
 | 
					    Decline = "RECEIVE_DECLINE",
 | 
				
			||||||
 | 
					    Receive = "RECEIVE_STATE",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SendSubmissionAction<T extends string> extends Action<T> {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ReceiveSubmissionApproveAction<T extends string> extends Action<T> {
 | 
				
			||||||
 | 
					    comment: string | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ReceiveSubmissionDeclineAction<T extends string> extends Action<T> {
 | 
				
			||||||
 | 
					    comment: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ReceiveSubmissionUpdateAction<T extends string> extends Action<T> {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SaveSubmissionAction<T extends string> extends Action<T> {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,80 +1,47 @@
 | 
				
			|||||||
import { DeanApproval } from "@/data/deanApproval";
 | 
					 | 
				
			||||||
import { InternshipProposalAction, InternshipProposalActions } from "@/state/actions";
 | 
					import { InternshipProposalAction, InternshipProposalActions } from "@/state/actions";
 | 
				
			||||||
import { Internship } from "@/data";
 | 
					import { Internship } from "@/data";
 | 
				
			||||||
import moment from "moment";
 | 
					 | 
				
			||||||
import { Serializable } from "@/serialization/types";
 | 
					import { Serializable } from "@/serialization/types";
 | 
				
			||||||
import { internshipSerializationTransformer, momentSerializationTransformer } from "@/serialization";
 | 
					import { internshipSerializationTransformer } from "@/serialization";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    createSubmissionReducer,
 | 
				
			||||||
 | 
					    defaultDeanApprovalsState,
 | 
				
			||||||
 | 
					    defaultSubmissionState,
 | 
				
			||||||
 | 
					    MayRequireDeanApproval,
 | 
				
			||||||
 | 
					    SubmissionState
 | 
				
			||||||
 | 
					} from "@/state/reducer/submission";
 | 
				
			||||||
 | 
					import { Reducer } from "react";
 | 
				
			||||||
 | 
					import { SubmissionAction } from "@/state/actions/submission";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type InternshipProposalStatus = "draft" | "awaiting" | "accepted" | "declined";
 | 
					export type InternshipProposalState = SubmissionState & MayRequireDeanApproval & {
 | 
				
			||||||
 | 
					 | 
				
			||||||
export type InternshipProposalState = {
 | 
					 | 
				
			||||||
    accepted: boolean;
 | 
					 | 
				
			||||||
    sent: boolean;
 | 
					 | 
				
			||||||
    sentOn: string | null;
 | 
					 | 
				
			||||||
    declined: boolean;
 | 
					 | 
				
			||||||
    requiredDeanApprovals: DeanApproval[];
 | 
					 | 
				
			||||||
    proposal: Serializable<Internship> | null;
 | 
					    proposal: Serializable<Internship> | null;
 | 
				
			||||||
    comment: string | null;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const defaultInternshipProposalState: InternshipProposalState = {
 | 
					const defaultInternshipProposalState: InternshipProposalState = {
 | 
				
			||||||
    accepted: false,
 | 
					    ...defaultDeanApprovalsState,
 | 
				
			||||||
    declined: false,
 | 
					    ...defaultSubmissionState,
 | 
				
			||||||
    sentOn: null,
 | 
					 | 
				
			||||||
    proposal: null,
 | 
					    proposal: null,
 | 
				
			||||||
    requiredDeanApprovals: [],
 | 
					 | 
				
			||||||
    sent: false,
 | 
					 | 
				
			||||||
    comment: null
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getInternshipProposalStatus = ({ accepted, declined, sent }: InternshipProposalState): InternshipProposalStatus => {
 | 
					 | 
				
			||||||
    switch (true) {
 | 
					 | 
				
			||||||
        case !sent:
 | 
					 | 
				
			||||||
            return "draft";
 | 
					 | 
				
			||||||
        case sent && accepted:
 | 
					 | 
				
			||||||
            return "accepted"
 | 
					 | 
				
			||||||
        case sent && declined:
 | 
					 | 
				
			||||||
            return "declined"
 | 
					 | 
				
			||||||
        case sent && (!accepted && !declined):
 | 
					 | 
				
			||||||
            return "awaiting"
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            throw new Error("Invalid proposal state " + JSON.stringify({ accepted, declined, sent }));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getInternshipProposal = ({ proposal }: InternshipProposalState): Internship | null =>
 | 
					export const getInternshipProposal = ({ proposal }: InternshipProposalState): Internship | null =>
 | 
				
			||||||
    proposal && internshipSerializationTransformer.reverseTransform(proposal);
 | 
					    proposal && internshipSerializationTransformer.reverseTransform(proposal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const internshipProposalSubmissionReducer: Reducer<InternshipProposalState, InternshipProposalAction> = createSubmissionReducer({
 | 
				
			||||||
 | 
					    [InternshipProposalActions.Approve]: SubmissionAction.Approve,
 | 
				
			||||||
 | 
					    [InternshipProposalActions.Decline]: SubmissionAction.Decline,
 | 
				
			||||||
 | 
					    [InternshipProposalActions.Receive]: SubmissionAction.Receive,
 | 
				
			||||||
 | 
					    [InternshipProposalActions.Save]: SubmissionAction.Save,
 | 
				
			||||||
 | 
					    [InternshipProposalActions.Send]: SubmissionAction.Send,
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const internshipProposalReducer = (state: InternshipProposalState = defaultInternshipProposalState, action: InternshipProposalAction): InternshipProposalState => {
 | 
					const internshipProposalReducer = (state: InternshipProposalState = defaultInternshipProposalState, action: InternshipProposalAction): InternshipProposalState => {
 | 
				
			||||||
 | 
					    state = internshipProposalSubmissionReducer(state, action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (action.type) {
 | 
					    switch (action.type) {
 | 
				
			||||||
        case InternshipProposalActions.Approve:
 | 
					 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
                ...state,
 | 
					 | 
				
			||||||
                accepted: true,
 | 
					 | 
				
			||||||
                declined: false,
 | 
					 | 
				
			||||||
                comment: action.comment,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        case InternshipProposalActions.Decline:
 | 
					 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
                ...state,
 | 
					 | 
				
			||||||
                accepted: false,
 | 
					 | 
				
			||||||
                declined: true,
 | 
					 | 
				
			||||||
                comment: action.comment
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        case InternshipProposalActions.Save:
 | 
					        case InternshipProposalActions.Save:
 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
                ...state,
 | 
					 | 
				
			||||||
                proposal: internshipSerializationTransformer.transform(action.internship),
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        case InternshipProposalActions.Send:
 | 
					        case InternshipProposalActions.Send:
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                ...state,
 | 
					                ...state,
 | 
				
			||||||
                proposal: internshipSerializationTransformer.transform(action.internship),
 | 
					                proposal: internshipSerializationTransformer.transform(action.internship),
 | 
				
			||||||
                sent: true,
 | 
					 | 
				
			||||||
                sentOn: momentSerializationTransformer.transform(moment()),
 | 
					 | 
				
			||||||
                accepted: false,
 | 
					 | 
				
			||||||
                declined: false,
 | 
					 | 
				
			||||||
                comment: null,
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return state;
 | 
					            return state;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										80
									
								
								src/state/reducer/submission.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/state/reducer/submission.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import { DeanApproval } from "@/data/deanApproval";
 | 
				
			||||||
 | 
					import { Action } from "@/state/actions";
 | 
				
			||||||
 | 
					import { momentSerializationTransformer } from "@/serialization";
 | 
				
			||||||
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					import { ReceiveSubmissionApproveAction, ReceiveSubmissionDeclineAction, SubmissionAction } from "@/state/actions/submission";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type SubmissionStatus = "draft" | "awaiting" | "accepted" | "declined";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type SubmissionState = {
 | 
				
			||||||
 | 
					    accepted: boolean;
 | 
				
			||||||
 | 
					    sent: boolean;
 | 
				
			||||||
 | 
					    sentOn: string | null;
 | 
				
			||||||
 | 
					    declined: boolean;
 | 
				
			||||||
 | 
					    comment: string | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type MayRequireDeanApproval = {
 | 
				
			||||||
 | 
					    requiredDeanApprovals: DeanApproval[],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const defaultSubmissionState: SubmissionState = {
 | 
				
			||||||
 | 
					    accepted: false,
 | 
				
			||||||
 | 
					    sent: false,
 | 
				
			||||||
 | 
					    sentOn: null,
 | 
				
			||||||
 | 
					    declined: false,
 | 
				
			||||||
 | 
					    comment: null,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const defaultDeanApprovalsState: MayRequireDeanApproval = {
 | 
				
			||||||
 | 
					    requiredDeanApprovals: [],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getSubmissionStatus = ({ accepted, declined, sent }: SubmissionState): SubmissionStatus => {
 | 
				
			||||||
 | 
					    switch (true) {
 | 
				
			||||||
 | 
					        case !sent:
 | 
				
			||||||
 | 
					            return "draft";
 | 
				
			||||||
 | 
					        case sent && accepted:
 | 
				
			||||||
 | 
					            return "accepted"
 | 
				
			||||||
 | 
					        case sent && declined:
 | 
				
			||||||
 | 
					            return "declined"
 | 
				
			||||||
 | 
					        case sent && (!accepted && !declined):
 | 
				
			||||||
 | 
					            return "awaiting"
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            throw new Error("Invalid submission state " + JSON.stringify({ accepted, declined, sent }));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function createSubmissionReducer<TState, TActionType, TAction extends Action>(mapping: { [TAction in keyof TActionType]: SubmissionAction }) {
 | 
				
			||||||
 | 
					    return (state: TState, action: TAction) => {
 | 
				
			||||||
 | 
					        const mappedAction = mapping[action.type as keyof TActionType];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (mappedAction) {
 | 
				
			||||||
 | 
					            case SubmissionAction.Approve:
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    ...state,
 | 
				
			||||||
 | 
					                    accepted: true,
 | 
				
			||||||
 | 
					                    declined: false,
 | 
				
			||||||
 | 
					                    comment: (action as ReceiveSubmissionApproveAction<any>).comment,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case SubmissionAction.Decline:
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    ...state,
 | 
				
			||||||
 | 
					                    accepted: false,
 | 
				
			||||||
 | 
					                    declined: true,
 | 
				
			||||||
 | 
					                    comment: (action as ReceiveSubmissionDeclineAction<any>).comment,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case SubmissionAction.Send:
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    ...state,
 | 
				
			||||||
 | 
					                    sent: true,
 | 
				
			||||||
 | 
					                    sentOn: momentSerializationTransformer.transform(moment()),
 | 
				
			||||||
 | 
					                    accepted: false,
 | 
				
			||||||
 | 
					                    declined: false,
 | 
				
			||||||
 | 
					                    comment: null,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return state;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user