diff --git a/src/api/dto/edition.ts b/src/api/dto/edition.ts index 20d47fd..ece5a0f 100644 --- a/src/api/dto/edition.ts +++ b/src/api/dto/edition.ts @@ -4,6 +4,7 @@ import { OneWayTransformer, Transformer } from "@/serialization"; import { Edition } from "@/data/edition"; import moment from "moment-timezone"; import { Subset } from "@/helpers"; +import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type"; export interface ProgramEntryDTO extends Identifiable { description: string; @@ -16,6 +17,7 @@ export interface EditionDTO extends Identifiable { reportingStart: string, course: CourseDTO, availableSubjects: ProgramEntryDTO[], + availableInternshipTypes: InternshipTypeDTO[], } export interface EditionTeaserDTO extends Identifiable { @@ -45,7 +47,8 @@ export const editionDtoTransformer: Transformer = { editionStart: subject.startDate.toISOString(), course: courseDtoTransformer.reverseTransform(subject.course), reportingStart: subject.reportingStart.toISOString(), - availableSubjects: [], + availableSubjects: subject.program.map(entry => programEntryDtoTransformer.reverseTransform(entry)), + availableInternshipTypes: subject.types.map(entry => internshipTypeDtoTransformer.reverseTransform(entry)) }; }, transform(subject: EditionDTO, context: undefined): Edition { @@ -59,6 +62,8 @@ export const editionDtoTransformer: Transformer = { proposalDeadline: moment(subject.reportingStart), reportingStart: moment(subject.reportingStart), reportingEnd: moment(subject.reportingStart).add(1, 'month'), + program: (subject.availableSubjects || []).map(entry => programEntryDtoTransformer.transform(entry)), + types: (subject.availableInternshipTypes || []).map(entry => internshipTypeDtoTransformer.transform(entry)) }; } } diff --git a/src/data/edition.ts b/src/data/edition.ts index 4e11994..84f3ee7 100644 --- a/src/data/edition.ts +++ b/src/data/edition.ts @@ -1,6 +1,7 @@ import { Moment } from "moment-timezone"; import { Course } from "@/data/course"; import { Identifiable } from "@/data/common"; +import { InternshipProgramEntry, InternshipType } from "@/data/internship"; export type Edition = { course: Course; @@ -11,6 +12,8 @@ export type Edition = { reportingEnd: Moment, minimumInternshipHours: number; maximumInternshipHours?: number; + program: InternshipProgramEntry[]; + types: InternshipType[]; } & Identifiable export type Deadlines = { diff --git a/src/management/edition/form.tsx b/src/management/edition/form.tsx index c516a9c..e3fdb7b 100644 --- a/src/management/edition/form.tsx +++ b/src/management/edition/form.tsx @@ -2,19 +2,37 @@ import React, { useCallback } from "react"; import { Edition } from "@/data/edition"; import { Nullable } from "@/helpers"; import { useTranslation } from "react-i18next"; -import { FieldProps, useFormikContext, Field } from "formik"; +import { FieldProps, Field, FieldArrayRenderProps, FieldArray, getIn } from "formik"; import { identityTransformer, Transformer } from "@/serialization"; -import { Grid, TextField, Typography } from "@material-ui/core"; +import { + Button, Card, CardContent, CardHeader, + Checkbox, + Grid, IconButton, + List, + ListItem, + ListItemIcon, + ListItemSecondaryAction, + ListItemText, + Paper, + TextField, + Tooltip, + Typography +} from "@material-ui/core"; import { useSpacing } from "@/styles"; import { Moment } from "moment-timezone"; import { KeyboardDatePicker as DatePicker } from "@material-ui/pickers"; import { TextField as TextFieldFormik } from "formik-material-ui"; -import { Course } from "@/data"; +import { Course, Identifiable, InternshipProgramEntry, InternshipType } from "@/data"; import { Autocomplete } from "@material-ui/lab"; import { useAsync } from "@/hooks"; import api from "@/management/api"; +import { Async } from "@/components/async"; +import { AccountCheck, ShieldCheck, TrashCan } from "mdi-material-ui"; +import { Actions } from "@/components"; +import { Add } from "@material-ui/icons"; export type EditionFormValues = Nullable; + export const initialEditionFormValues: EditionFormValues = { course: null, endDate: null, @@ -22,12 +40,76 @@ export const initialEditionFormValues: EditionFormValues = { proposalDeadline: null, reportingEnd: null, reportingStart: null, - startDate: null + startDate: null, + types: [], + program: [], } export const editionFormValuesTransformer: Transformer = identityTransformer; -export const CoursePickerField = ({ field, form, meta, ...props}: FieldProps) => { +function toggleValueInArray(array: T[], value: T, comparator: (a: T, b: T) => boolean = (a, b) => a == b): T[] { + return array.findIndex(other => comparator(other, value)) === -1 + ? [ ...array, value ] + : array.filter(other => !comparator(other, value)); +} + +export const ProgramField = ({ remove, push, form, name, ...props }: FieldArrayRenderProps) => { + const value = getIn(form.values, name) as InternshipProgramEntry[]; + const setValue = (value: InternshipProgramEntry[]) => form.setFieldValue(name, value, false); + + const { t } = useTranslation("management"); + + return <> + { value.map((entry, index) => + + remove(index) }> + + + } + /> + + { JSON.stringify(entry) } + + ) } + + + + +} + +export const TypesField = ({ field, form, meta, ...props }: FieldProps) => { + const { name, value = [] } = field; + + const types = useAsync(useCallback(() => api.type.all(), [])); + const { t } = useTranslation("management"); + + const toggle = (type: InternshipType) => () => form.setFieldValue(name, toggleValueInArray(value, type, (a, b) => a.id == b.id)); + const isChecked = (type: InternshipType) => value.findIndex(v => v.id == type.id) !== -1; + + return + { types => { + types.map(type => + + + + +
{ type.label.pl }
+ { type.description?.pl } +
+ +
+ { type.requiresDeanApproval && } + { type.requiresInsurance && } +
+
+
) + }
} +
+} + +export const CoursePickerField = ({ field, form, meta, ...props }: FieldProps) => { const courses = useAsync(useCallback(() => api.course.all(), [])); const { t } = useTranslation("management"); @@ -59,7 +141,7 @@ export const EditionForm = () => { const spacing = useSpacing(2); return
- { t("edition.fields.basic") } + { t("edition.fields.basic") } @@ -76,7 +158,7 @@ export const EditionForm = () => { - { t("edition.fields.deadlines") } + { t("edition.fields.deadlines") } @@ -90,5 +172,11 @@ export const EditionForm = () => { + { t("edition.fields.program") } + + { t("edition.fields.types") } + + +
} diff --git a/translations/management.pl.yaml b/translations/management.pl.yaml index ef70f74..7b63159 100644 --- a/translations/management.pl.yaml +++ b/translations/management.pl.yaml @@ -28,6 +28,8 @@ edition: fields: basic: "Podstawowe" deadlines: "Terminy" + program: "Ramowy program praktyk" + types: "Dostępne typy praktyki" report-fields: title: "Pola formularza raportu praktyki" manage: @@ -35,6 +37,8 @@ edition: internships: "Zarządzanie praktykami" settings: title: "Konfiguracja edycji" + program: + entry: "Punkt ramowego programu praktyki #{{ index }}" report-field: preview: Podgląd