Fix error with resubmitting ipp
This commit is contained in:
parent
f3fd265dad
commit
3d827317f0
74
src/components/contact.tsx
Normal file
74
src/components/contact.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSpacing } from "@/styles";
|
||||||
|
import { Field, Form, Formik } from "formik";
|
||||||
|
import { Button, Dialog, DialogActions, DialogContent, DialogProps, DialogTitle, Typography } from "@material-ui/core";
|
||||||
|
import { CKEditorField } from "@/field/ckeditor";
|
||||||
|
import { Actions } from "@/components/actions";
|
||||||
|
import { Cancel, Send } from "mdi-material-ui";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
import { capitalize } from "@/helpers";
|
||||||
|
|
||||||
|
export type ContactFormValues = {
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialContactFormValues: ContactFormValues = {
|
||||||
|
content: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ContactDialogProps = {
|
||||||
|
onSend: (values: ContactFormValues) => void;
|
||||||
|
} & DialogProps;
|
||||||
|
|
||||||
|
export function ContactForm() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const spacing = useSpacing(2);
|
||||||
|
|
||||||
|
return <div className={ spacing.vertical } style={{ overflow: 'hidden' }}>
|
||||||
|
<Field label={ t("forms.contact.field.content") } name="content" component={ CKEditorField }/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ContactDialog({ onSend, ...props }: ContactDialogProps) {
|
||||||
|
const spacing = useSpacing(2);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return <Dialog { ...props } maxWidth="lg">
|
||||||
|
<Formik initialValues={ initialContactFormValues } onSubmit={ onSend }>
|
||||||
|
<Form className={ spacing.vertical }>
|
||||||
|
<DialogTitle>{ capitalize(t("forms.contact.title")) }</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<ContactForm />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Actions>
|
||||||
|
<Button variant="contained" color="primary" startIcon={ <Send /> } type="submit">{ t("send") }</Button>
|
||||||
|
<Button startIcon={ <Cancel /> } onClick={ ev => props.onClose?.(ev, "escapeKeyDown") }>{ t("cancel") }</Button>
|
||||||
|
</Actions>
|
||||||
|
</DialogActions>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
</Dialog>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ContactActionProps = {
|
||||||
|
children: (props: { action: () => void }) => React.ReactNode
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ContactAction({ children }: ContactActionProps) {
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleClose = () => { setOpen(false) };
|
||||||
|
const handleSubmit = (values: ContactFormValues) => {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{ children({ action: () => setOpen(true) }) }
|
||||||
|
{ createPortal(
|
||||||
|
<ContactDialog open={ open } onSend={ handleSubmit } onClose={ handleClose }/>,
|
||||||
|
document.getElementById("modals") as HTMLElement
|
||||||
|
) }
|
||||||
|
</>
|
||||||
|
}
|
@ -112,7 +112,7 @@ const InternshipProgramForm = () => {
|
|||||||
if (ev.target.checked) {
|
if (ev.target.checked) {
|
||||||
setSelectedProgramEntries([ ...selectedProgramEntries, entry ]);
|
setSelectedProgramEntries([ ...selectedProgramEntries, entry ]);
|
||||||
} else {
|
} else {
|
||||||
setSelectedProgramEntries(selectedProgramEntries.filter(cur => cur != entry));
|
setSelectedProgramEntries(selectedProgramEntries.filter(cur => cur.id != entry.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +133,7 @@ const InternshipProgramForm = () => {
|
|||||||
onBlur={ handleBlur }
|
onBlur={ handleBlur }
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{ values.kind?.requiresDeanApproval && <Grid item xs={ 12 }><Alert severity="warning">{ t("internship.kind-requires-dean-approval") }</Alert></Grid> }
|
||||||
{/*<Grid item md={ 8 }>*/}
|
{/*<Grid item md={ 8 }>*/}
|
||||||
{/* {*/}
|
{/* {*/}
|
||||||
{/* values.kind === InternshipType.Other &&*/}
|
{/* values.kind === InternshipType.Other &&*/}
|
||||||
@ -159,6 +160,7 @@ const InternshipProgramForm = () => {
|
|||||||
|
|
||||||
const InternshipDurationForm = () => {
|
const InternshipDurationForm = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const edition = useCurrentEdition();
|
||||||
const {
|
const {
|
||||||
values: { startDate, endDate, workingHours },
|
values: { startDate, endDate, workingHours },
|
||||||
errors,
|
errors,
|
||||||
@ -174,6 +176,8 @@ const InternshipDurationForm = () => {
|
|||||||
const hours = useMemo(() => overrideHours !== null ? overrideHours : computedHours || null, [overrideHours, computedHours]);
|
const hours = useMemo(() => overrideHours !== null ? overrideHours : computedHours || null, [overrideHours, computedHours]);
|
||||||
const weeks = useMemo(() => hours !== null ? Math.floor(hours / workingHours) : null, [ hours ]);
|
const weeks = useMemo(() => hours !== null ? Math.floor(hours / workingHours) : null, [ hours ]);
|
||||||
|
|
||||||
|
const requiresDeanApproval = useMemo(() => edition?.startDate?.isAfter(startDate) || edition?.endDate?.isBefore(endDate), [ startDate, endDate ])
|
||||||
|
|
||||||
useUpdateEffect(() => {
|
useUpdateEffect(() => {
|
||||||
setFieldTouched("hours", true);
|
setFieldTouched("hours", true);
|
||||||
setFieldValue("hours", hours, true);
|
setFieldValue("hours", hours, true);
|
||||||
@ -200,6 +204,9 @@ const InternshipDurationForm = () => {
|
|||||||
minDate={ startDate }
|
minDate={ startDate }
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{ requiresDeanApproval && <Grid item xs={ 12 }>
|
||||||
|
<Alert severity="warning">{ t("internship.duration-requires-dean-approval") }</Alert>
|
||||||
|
</Grid> }
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<Field component={ TextFieldFormik }
|
<Field component={ TextFieldFormik }
|
||||||
name="workingHours"
|
name="workingHours"
|
||||||
|
@ -32,9 +32,10 @@ export const PlanForm = () => {
|
|||||||
|
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
destination = await api.upload.create(UploadType.Ipp);
|
destination = await api.upload.create(UploadType.Ipp);
|
||||||
dispatch({ type: InternshipPlanActions.Send, document: destination });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch({ type: InternshipPlanActions.Send, document: destination });
|
||||||
|
|
||||||
await api.upload.upload(destination, file);
|
await api.upload.upload(destination, file);
|
||||||
|
|
||||||
history.push("/");
|
history.push("/");
|
||||||
|
@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { useFormikContext } from "formik";
|
import { useFormikContext } from "formik";
|
||||||
import { InternshipFormValues } from "@/forms/internship";
|
import { InternshipFormValues } from "@/forms/internship";
|
||||||
import { useCurrentEdition } from "@/hooks";
|
import { useCurrentEdition } from "@/hooks";
|
||||||
|
import { ContactAction } from "@/components/contact";
|
||||||
|
|
||||||
export const StudentForm = () => {
|
export const StudentForm = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -36,8 +37,10 @@ export const StudentForm = () => {
|
|||||||
<TextField label={ t("forms.internship.fields.semester") } value={ student.semester || "" } disabled fullWidth/>
|
<TextField label={ t("forms.internship.fields.semester") } value={ student.semester || "" } disabled fullWidth/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }>
|
<Alert severity="warning" action={ <ContactAction>{
|
||||||
Powyższe dane nie są poprawne?
|
({ action }) => <Button color="inherit" size="small" onClick={ action }>{ t("contact") }</Button>
|
||||||
|
}</ContactAction> }>
|
||||||
|
{ t("incorrect-data-question") }
|
||||||
</Alert>
|
</Alert>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -43,3 +43,7 @@ export function one<T>(value: OneOrMany<T>): T {
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function capitalize(value: string): string {
|
||||||
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { createStyles, makeStyles } from "@material-ui/core/styles";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CommentQuestion } from "mdi-material-ui/index";
|
import { CommentQuestion } from "mdi-material-ui/index";
|
||||||
|
import { ContactAction } from "@/components/contact";
|
||||||
|
|
||||||
export const getColorByStatus = (status: SubmissionStatus, theme: Theme) => {
|
export const getColorByStatus = (status: SubmissionStatus, theme: Theme) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -46,8 +47,12 @@ export const Status = ({ submission } : SubmissionStatusProps) => {
|
|||||||
return <span className={ classes.foreground }>{ t(`submission.status.${ status }`) }</span>;
|
return <span className={ classes.foreground }>{ t(`submission.status.${ status }`) }</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContactAction = (props: ButtonProps) => {
|
export const ContactButton = (props: ButtonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return <Button startIcon={ <CommentQuestion/> } variant="outlined" color="primary" { ...props }>{ t('contact') }</Button>
|
return <ContactAction>{
|
||||||
|
({ action }) => <Button startIcon={ <CommentQuestion/> } variant="outlined" color="primary" { ...props } onClick={ action}>
|
||||||
|
{ t('contact') }
|
||||||
|
</Button> }
|
||||||
|
</ContactAction>
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { InsuranceState } from "@/state/reducer/insurance";
|
|||||||
import { Actions, Step } from "@/components";
|
import { Actions, Step } from "@/components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ContactAction } from "@/pages/steps/common";
|
import { ContactButton } from "@/pages/steps/common";
|
||||||
import { useDeadlines } from "@/hooks";
|
import { useDeadlines } from "@/hooks";
|
||||||
import { StepProps } from "@material-ui/core";
|
import { StepProps } from "@material-ui/core";
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export const InsuranceStep = (props: StepProps) => {
|
|||||||
return <Step { ...props } label={ t("steps.insurance.header") } until={ deadline } completed={ insurance.signed } active={ !insurance.signed }>
|
return <Step { ...props } label={ t("steps.insurance.header") } until={ deadline } completed={ insurance.signed } active={ !insurance.signed }>
|
||||||
<p>{ t(`steps.insurance.instructions`) }</p>
|
<p>{ t(`steps.insurance.instructions`) }</p>
|
||||||
<Actions>
|
<Actions>
|
||||||
<ContactAction />
|
<ContactButton />
|
||||||
</Actions>
|
</Actions>
|
||||||
</Step>
|
</Step>
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { Link as RouterLink, useHistory } from "react-router-dom";
|
|||||||
import { Actions, Step } from "@/components";
|
import { Actions, Step } from "@/components";
|
||||||
import React, { HTMLProps } from "react";
|
import React, { HTMLProps } from "react";
|
||||||
import { Alert, AlertTitle } from "@material-ui/lab";
|
import { Alert, AlertTitle } from "@material-ui/lab";
|
||||||
import { ContactAction, Status } from "@/pages/steps/common";
|
import { ContactButton, Status } from "@/pages/steps/common";
|
||||||
import { Description as DescriptionIcon } from "@material-ui/icons";
|
import { Description as DescriptionIcon } from "@material-ui/icons";
|
||||||
import { useDeadlines } from "@/hooks";
|
import { useDeadlines } from "@/hooks";
|
||||||
import { InternshipDocument } from "@/api/dto/internship-registration";
|
import { InternshipDocument } from "@/api/dto/internship-registration";
|
||||||
@ -56,9 +56,9 @@ const PlanActions = () => {
|
|||||||
</Actions>
|
</Actions>
|
||||||
case "declined":
|
case "declined":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
<FormAction>{ t('fix-errors') }</FormAction>
|
<FormAction>{ t('send-again') }</FormAction>
|
||||||
<TemplateAction />
|
<TemplateAction />
|
||||||
<ContactAction/>
|
<ContactButton/>
|
||||||
</Actions>
|
</Actions>
|
||||||
case "draft":
|
case "draft":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
|
@ -10,7 +10,7 @@ import { Actions, Step } from "@/components";
|
|||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
import { ClipboardEditOutline, FileFind } from "mdi-material-ui/index";
|
import { ClipboardEditOutline, FileFind } from "mdi-material-ui/index";
|
||||||
import { ContactAction, Status } from "@/pages/steps/common";
|
import { ContactButton, Status } from "@/pages/steps/common";
|
||||||
import { useDeadlines } from "@/hooks";
|
import { useDeadlines } from "@/hooks";
|
||||||
|
|
||||||
const ProposalActions = () => {
|
const ProposalActions = () => {
|
||||||
@ -43,7 +43,7 @@ const ProposalActions = () => {
|
|||||||
case "declined":
|
case "declined":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
<FormAction>{ t('fix-errors') }</FormAction>
|
<FormAction>{ t('fix-errors') }</FormAction>
|
||||||
<ContactAction />
|
<ContactButton />
|
||||||
</Actions>
|
</Actions>
|
||||||
case "draft":
|
case "draft":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
|
@ -26,12 +26,15 @@ contact: skontaktuj się z pełnomocnikiem
|
|||||||
comments: Zgłoszone uwagi
|
comments: Zgłoszone uwagi
|
||||||
send-again: wyślij ponownie
|
send-again: wyślij ponownie
|
||||||
cancel: anuluj
|
cancel: anuluj
|
||||||
|
send: wyślij
|
||||||
|
|
||||||
accept: zaakceptuj
|
accept: zaakceptuj
|
||||||
accept-with-comments: zaakceptuj z uwagami
|
accept-with-comments: zaakceptuj z uwagami
|
||||||
accept-without-comments: zaakceptuj bez uwag
|
accept-without-comments: zaakceptuj bez uwag
|
||||||
discard: zgłoś uwagi
|
discard: zgłoś uwagi
|
||||||
|
|
||||||
|
incorrect-data-question: "Powyższe dane nie są poprawne?"
|
||||||
|
|
||||||
dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
|
dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
|
||||||
|
|
||||||
pages:
|
pages:
|
||||||
@ -63,6 +66,10 @@ forms:
|
|||||||
sections:
|
sections:
|
||||||
personal: "Dane osobowe"
|
personal: "Dane osobowe"
|
||||||
studies: "Dane kierunkowe"
|
studies: "Dane kierunkowe"
|
||||||
|
contact:
|
||||||
|
title: $t(contact)
|
||||||
|
field:
|
||||||
|
content: "Treść"
|
||||||
internship:
|
internship:
|
||||||
fields:
|
fields:
|
||||||
start-date: Data rozpoczęcia praktyki
|
start-date: Data rozpoczęcia praktyki
|
||||||
@ -128,6 +135,8 @@ internship:
|
|||||||
intern:
|
intern:
|
||||||
semester: semestr {{ semester, roman }}
|
semester: semestr {{ semester, roman }}
|
||||||
album: "numer albumu {{ album }}"
|
album: "numer albumu {{ album }}"
|
||||||
|
kind-requires-dean-approval: "Ten rodzaj praktyki/umowy wymaga akceptacji przez dziekana!"
|
||||||
|
duration-requires-dean-approval: "Taki okres trwania praktyki wymaga akceptacji przez dziekana!"
|
||||||
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
|
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
|
||||||
duration_2: "{{ duration, weeks }} tygodni"
|
duration_2: "{{ duration, weeks }} tygodni"
|
||||||
duration_0: "{{ duration, weeks }} tydzień"
|
duration_0: "{{ duration, weeks }} tydzień"
|
||||||
@ -195,7 +204,7 @@ steps:
|
|||||||
draft: >
|
draft: >
|
||||||
W porozumieniu z firmą w której odbywają się praktyki należy sporządzić Indywidualny Plan Praktyk zgodnie z
|
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. Indywidualny Plan Praktyk musi zostać zatwierdzony
|
załączonym szablonem a następnie wysłać go do weryfikacji. Indywidualny Plan Praktyk musi zostać zatwierdzony
|
||||||
oraz podpisany przez Twojego zakłądowego opiekuna praktyki.
|
oraz podpisany przez Twojego zakładowego opiekuna praktyki.
|
||||||
awaiting: >
|
awaiting: >
|
||||||
Twój indywidualny program praktyki został poprawnie zapisany w systemie. Musi on jeszcze zostać zweryfikowany i
|
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.
|
zatwierdzony. Po weryfikacji zostaniesz poinformowany o akceptacji bądź konieczności wprowadzenia zmian.
|
||||||
|
Loading…
Reference in New Issue
Block a user