master #7
@ -17,6 +17,15 @@ const plugins = [
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    'core'
 | 
					    'core'
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
					  [
 | 
				
			||||||
 | 
					    'babel-plugin-import',
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      'libraryName': 'mdi-material-ui',
 | 
				
			||||||
 | 
					      'libraryDirectory': '.',
 | 
				
			||||||
 | 
					      'camel2DashComponentName': false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    'mdi-material-ui'
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  [
 | 
					  [
 | 
				
			||||||
    'babel-plugin-import',
 | 
					    'babel-plugin-import',
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import moment, { Moment } from "moment";
 | 
				
			|||||||
import { Box, Step as StepperStep, StepContent, StepLabel, StepProps as StepperStepProps, Typography } from "@material-ui/core";
 | 
					import { Box, Step as StepperStep, StepContent, StepLabel, StepProps as StepperStepProps, Typography } from "@material-ui/core";
 | 
				
			||||||
import { useTranslation } from "react-i18next";
 | 
					import { useTranslation } from "react-i18next";
 | 
				
			||||||
import React, { ReactChild, useMemo } from "react";
 | 
					import React, { ReactChild, useMemo } from "react";
 | 
				
			||||||
 | 
					import { StepIcon } from "@/components/stepIcon";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type StepProps = StepperStepProps & {
 | 
					type StepProps = StepperStepProps & {
 | 
				
			||||||
    until?: Moment;
 | 
					    until?: Moment;
 | 
				
			||||||
@ -9,24 +10,21 @@ type StepProps = StepperStepProps & {
 | 
				
			|||||||
    label: string;
 | 
					    label: string;
 | 
				
			||||||
    state?: ReactChild | null;
 | 
					    state?: ReactChild | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** this roughly translates into completed */
 | 
					    waiting?: boolean;
 | 
				
			||||||
    accepted?: boolean;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** this roughly translates into error */
 | 
					 | 
				
			||||||
    declined?: boolean;
 | 
					    declined?: boolean;
 | 
				
			||||||
    sent?: boolean;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const now = moment();
 | 
					const now = moment();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Step = ({ until, label, completedOn, children, accepted = false, declined = false, completed = false, state = null, ...props }: StepProps) => {
 | 
					export const Step = (props: StepProps) => {
 | 
				
			||||||
 | 
					    const { until, label, completedOn, children, completed = false, declined = false, waiting = false, state = null, ...rest } = props;
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isLate = useMemo(() => until?.isBefore(completedOn || now), [completedOn, until]);
 | 
					    const isLate = useMemo(() => until?.isBefore(completedOn || now), [completedOn, until]);
 | 
				
			||||||
    const left = useMemo(() => moment.duration(now.diff(until)), [until]);
 | 
					    const left = useMemo(() => moment.duration(now.diff(until)), [until]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return <StepperStep { ...props } completed={ completed }>
 | 
					    return <StepperStep { ...rest } completed={ completed }>
 | 
				
			||||||
        <StepLabel error={ declined }>
 | 
					        <StepLabel error={ declined } StepIconComponent={ StepIcon } StepIconProps={{ ...props, waiting } as any}>
 | 
				
			||||||
            { label }
 | 
					            { label }
 | 
				
			||||||
            { until && <Box>
 | 
					            { until && <Box>
 | 
				
			||||||
                { state && <>
 | 
					                { state && <>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/components/stepIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/components/stepIcon.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import { StepIcon as MuiStepIcon, StepIconProps as MuiStepIconProps, Theme } from "@material-ui/core";
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { TimerSand } from "mdi-material-ui";
 | 
				
			||||||
 | 
					import { createStyles, makeStyles } from "@material-ui/core/styles";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type StepIconProps = MuiStepIconProps & {
 | 
				
			||||||
 | 
					    waiting: boolean
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useStyles = makeStyles((theme: Theme) => createStyles({
 | 
				
			||||||
 | 
					    root: {
 | 
				
			||||||
 | 
					        color: theme.palette.primary.main
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const StepIcon = ({ waiting, ...props }: StepIconProps) => {
 | 
				
			||||||
 | 
					    const classes = useStyles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return waiting
 | 
				
			||||||
 | 
					        ? <TimerSand className={ classes.root }/>
 | 
				
			||||||
 | 
					        : <MuiStepIcon { ...props } />;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4,6 +4,7 @@ import { Link as RouterLink } from "react-router-dom";
 | 
				
			|||||||
import { route } from "@/routing";
 | 
					import { route } from "@/routing";
 | 
				
			||||||
import { InternshipForm } from "@/forms/internship";
 | 
					import { InternshipForm } from "@/forms/internship";
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { ProposalComment } from "@/pages";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const InternshipProposalPage = () => {
 | 
					export const InternshipProposalPage = () => {
 | 
				
			||||||
    return <Page title="Zgłoszenie praktyki">
 | 
					    return <Page title="Zgłoszenie praktyki">
 | 
				
			||||||
@ -15,6 +16,7 @@ export const InternshipProposalPage = () => {
 | 
				
			|||||||
            <Page.Title>Zgłoszenie praktyki</Page.Title>
 | 
					            <Page.Title>Zgłoszenie praktyki</Page.Title>
 | 
				
			||||||
        </Page.Header>
 | 
					        </Page.Header>
 | 
				
			||||||
        <Container maxWidth={ "md" }>
 | 
					        <Container maxWidth={ "md" }>
 | 
				
			||||||
 | 
					            <ProposalComment />
 | 
				
			||||||
            <InternshipForm/>
 | 
					            <InternshipForm/>
 | 
				
			||||||
        </Container>
 | 
					        </Container>
 | 
				
			||||||
    </Page>
 | 
					    </Page>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import React, { useMemo } from "react";
 | 
					import React, { HTMLProps, useMemo } from "react";
 | 
				
			||||||
import { Page } from "@/pages/base";
 | 
					import { Page } from "@/pages/base";
 | 
				
			||||||
import { Button, Container, Stepper, StepProps, Theme, Typography } from "@material-ui/core";
 | 
					import { Box, Button, ButtonProps, Container, Stepper, StepProps, Theme, Typography } from "@material-ui/core";
 | 
				
			||||||
import { Link as RouterLink } from "react-router-dom";
 | 
					import { Link as RouterLink } from "react-router-dom";
 | 
				
			||||||
import { route } from "@/routing";
 | 
					import { route } from "@/routing";
 | 
				
			||||||
import { useTranslation } from "react-i18next";
 | 
					import { useTranslation } from "react-i18next";
 | 
				
			||||||
@ -12,6 +12,8 @@ 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 { getInternshipProposalStatus, InternshipProposalState, InternshipProposalStatus } 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 { Alert, AlertTitle } from "@material-ui/lab";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getColorByStatus = (status: InternshipProposalStatus, theme: Theme) => {
 | 
					const getColorByStatus = (status: InternshipProposalStatus, theme: Theme) => {
 | 
				
			||||||
@ -51,18 +53,70 @@ const ProposalStatus = () => {
 | 
				
			|||||||
    return <span className={ classes.foreground }>{ t(`proposal.status.${status}`) }</span>;
 | 
					    return <span className={ classes.foreground }>{ t(`proposal.status.${status}`) }</span>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ProposalActions = () => {
 | 
				
			||||||
 | 
					    const status = useSelector<AppState, InternshipProposalStatus>(state => getInternshipProposalStatus(state.proposal));
 | 
				
			||||||
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ReviewAction = (props: ButtonProps) =>
 | 
				
			||||||
 | 
					        <Button startIcon={ <FileFind /> } { ...props }>{ t('review') }</Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const FormAction   = ({ children = t('steps.internship-proposal.form'), ...props }: ButtonProps) =>
 | 
				
			||||||
 | 
					        <Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink } startIcon={ <ClipboardEditOutline /> } { ...props as any }>
 | 
				
			||||||
 | 
					            { children }
 | 
				
			||||||
 | 
					        </Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ContactAction = (props: ButtonProps) =>
 | 
				
			||||||
 | 
					        <Button startIcon={ <CommentQuestion /> } variant="outlined" color="primary" { ...props }>{ t('contact') }</Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (status) {
 | 
				
			||||||
 | 
					        case "awaiting":
 | 
				
			||||||
 | 
					            return <Actions>
 | 
				
			||||||
 | 
					                <ReviewAction />
 | 
				
			||||||
 | 
					            </Actions>
 | 
				
			||||||
 | 
					        case "accepted":
 | 
				
			||||||
 | 
					            return <Actions>
 | 
				
			||||||
 | 
					                <ReviewAction />
 | 
				
			||||||
 | 
					                <FormAction variant="outlined" color="secondary">{ t('make-changes') }</FormAction>
 | 
				
			||||||
 | 
					            </Actions>
 | 
				
			||||||
 | 
					        case "declined":
 | 
				
			||||||
 | 
					            return <Actions>
 | 
				
			||||||
 | 
					                <FormAction>{ t('fix-errors') }</FormAction>
 | 
				
			||||||
 | 
					                <ContactAction/>
 | 
				
			||||||
 | 
					            </Actions>
 | 
				
			||||||
 | 
					        case "draft":
 | 
				
			||||||
 | 
					            return <Actions>
 | 
				
			||||||
 | 
					                <FormAction color="primary">{ t('steps.internship-proposal.action') }</FormAction>
 | 
				
			||||||
 | 
					            </Actions>
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return <Actions />
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ProposalComment = (props: HTMLProps<HTMLDivElement>) => {
 | 
				
			||||||
 | 
					    const { comment, declined } = useSelector<AppState, InternshipProposalState>(state => state.proposal);
 | 
				
			||||||
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return <Alert severity={declined ? "error" : "warning"} {...props as any}>
 | 
				
			||||||
 | 
					        <AlertTitle>{ t('comments') }</AlertTitle>
 | 
				
			||||||
 | 
					        { comment }
 | 
				
			||||||
 | 
					    </Alert>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProposalStep = (props: StepProps) => {
 | 
					const ProposalStep = (props: StepProps) => {
 | 
				
			||||||
    const { t } = useTranslation();
 | 
					    const { t } = useTranslation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { sent } = 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 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 } label={ t('steps.internship-proposal.header') } active={ true } completed={ sent } until={ deadlines.proposal } state={ <ProposalStatus /> }>
 | 
					    return <Step { ...props }
 | 
				
			||||||
        <p>{ t('steps.internship-proposal.info') }</p>
 | 
					                 label={ t('steps.internship-proposal.header') }
 | 
				
			||||||
 | 
					                 active={ true } completed={ sent } declined={ declined } waiting={ status == "awaiting" }
 | 
				
			||||||
        <Button to={ route("internship_proposal") } variant="contained" color="primary" component={ RouterLink }>
 | 
					                 until={ deadlines.proposal }
 | 
				
			||||||
            { t('steps.internship-proposal.form') }
 | 
					                 state={ <ProposalStatus /> }>
 | 
				
			||||||
        </Button>
 | 
					        <p>{ t(`steps.internship-proposal.info.${status}`) }</p>
 | 
				
			||||||
 | 
					        { comment && <Box pb={2}><ProposalComment /></Box> }
 | 
				
			||||||
 | 
					        <ProposalActions />
 | 
				
			||||||
    </Step>;
 | 
					    </Step>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { Nullable } from "@/helpers";
 | 
					import { Nullable } from "@/helpers";
 | 
				
			||||||
import { emptyCompany, Internship, Mentor } from "@/data";
 | 
					import { emptyBranchOffice, emptyCompany, Internship, Mentor } from "@/data";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const emptyMentor: Mentor = {
 | 
					export const emptyMentor: Mentor = {
 | 
				
			||||||
    phone: null,
 | 
					    phone: null,
 | 
				
			||||||
@ -18,4 +18,6 @@ export const emptyInternship: Nullable<Internship> = {
 | 
				
			|||||||
    lengthInWeeks: 0,
 | 
					    lengthInWeeks: 0,
 | 
				
			||||||
    mentor: emptyMentor,
 | 
					    mentor: emptyMentor,
 | 
				
			||||||
    company: emptyCompany,
 | 
					    company: emptyCompany,
 | 
				
			||||||
 | 
					    hours: 0,
 | 
				
			||||||
 | 
					    office: emptyBranchOffice,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ export interface SendProposalAction extends Action<InternshipProposalActions.Sen
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ReceiveProposalApproveAction extends Action<InternshipProposalActions.Approve> {
 | 
					export interface ReceiveProposalApproveAction extends Action<InternshipProposalActions.Approve> {
 | 
				
			||||||
 | 
					    comment: string | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ReceiveProposalDeclineAction extends Action<InternshipProposalActions.Decline> {
 | 
					export interface ReceiveProposalDeclineAction extends Action<InternshipProposalActions.Decline> {
 | 
				
			||||||
 | 
				
			|||||||
@ -52,7 +52,7 @@ const internshipProposalReducer = (state: InternshipProposalState = defaultInter
 | 
				
			|||||||
                ...state,
 | 
					                ...state,
 | 
				
			||||||
                accepted: true,
 | 
					                accepted: true,
 | 
				
			||||||
                declined: false,
 | 
					                declined: false,
 | 
				
			||||||
                comment: ""
 | 
					                comment: action.comment,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        case InternshipProposalActions.Decline:
 | 
					        case InternshipProposalActions.Decline:
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
@ -74,6 +74,7 @@ const internshipProposalReducer = (state: InternshipProposalState = defaultInter
 | 
				
			|||||||
                sentOn: momentSerializationTransformer.transform(moment()),
 | 
					                sentOn: momentSerializationTransformer.transform(moment()),
 | 
				
			||||||
                accepted: false,
 | 
					                accepted: false,
 | 
				
			||||||
                declined: false,
 | 
					                declined: false,
 | 
				
			||||||
 | 
					                comment: null,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            return state;
 | 
					            return state;
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,12 @@ left: jeszcze {{ left, humanize }}
 | 
				
			|||||||
confirm: zatwierdź
 | 
					confirm: zatwierdź
 | 
				
			||||||
go-back: wstecz
 | 
					go-back: wstecz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					make-changes: wprowadź zmiany
 | 
				
			||||||
 | 
					review: podgląd
 | 
				
			||||||
 | 
					fix-errors: popraw uwagi
 | 
				
			||||||
 | 
					contact: skontaktuj się z pełnomocnikiem
 | 
				
			||||||
 | 
					comments: Zgłoszone uwagi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
 | 
					dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sections:
 | 
					sections:
 | 
				
			||||||
@ -48,9 +54,19 @@ steps:
 | 
				
			|||||||
    form: "Uzupełnij dane"
 | 
					    form: "Uzupełnij dane"
 | 
				
			||||||
  internship-proposal:
 | 
					  internship-proposal:
 | 
				
			||||||
    header: "Zgłoszenie praktyki"
 | 
					    header: "Zgłoszenie praktyki"
 | 
				
			||||||
    info: >
 | 
					    info:
 | 
				
			||||||
      Przed podjęciem praktyki należy ją zgłosić.
 | 
					      draft: >
 | 
				
			||||||
 | 
					        Przed podjęciem praktyki należy ją zgłosić.
 | 
				
			||||||
 | 
					      awaiting: >
 | 
				
			||||||
 | 
					        Twoje zgłoszenie musi zostać zweryfikowane i zatwierdzone. Po weryfikacji zostaniesz poinformowany o
 | 
				
			||||||
 | 
					        akceptacji bądź konieczności wprowadzenia zmian.
 | 
				
			||||||
 | 
					      accepted: >
 | 
				
			||||||
 | 
					        Twoje zgłoszenie zostało zweryfikowane i zaakceptowane.
 | 
				
			||||||
 | 
					      declined: >
 | 
				
			||||||
 | 
					        Twoje zgłoszenie zostało zweryfikowane i odrzucone. Popraw zgłoszone uwagi i wyślij zgłoszenie ponownie. W razie
 | 
				
			||||||
 | 
					        pytań możesz również skontaktować się z pełnomocnikiem ds. praktyk Twojego kierunku.
 | 
				
			||||||
    form: "Formularz zgłaszania praktyki"
 | 
					    form: "Formularz zgłaszania praktyki"
 | 
				
			||||||
 | 
					    action: "zgłoś praktykę"
 | 
				
			||||||
  plan:
 | 
					  plan:
 | 
				
			||||||
    header: "Indywidualny Program Praktyki"
 | 
					    header: "Indywidualny Program Praktyki"
 | 
				
			||||||
    info: ""
 | 
					    info: ""
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user