system-praktyk-front/src/forms/user.tsx
2020-10-03 19:59:00 +02:00

134 lines
4.7 KiB
TypeScript

import { Student } from "@/data";
import { Transformer } from "@/serialization";
import React, { useMemo } from "react";
import { Field, Formik, useFormikContext } from "formik";
import api from "@/api";
import { Button, Grid, Typography } from "@material-ui/core";
import { TextField as TextFieldFormik } from "formik-material-ui";
import { useTranslation } from "react-i18next";
import { Actions } from "@/components";
import { Nullable } from "@/helpers";
import * as Yup from "yup";
import { StudentActions, useDispatch } from "@/state/actions";
interface StudentFormValues {
firstName: string;
lastName: string;
email: string;
albumNumber: number | "";
semester: number | "";
}
type StudentFormProps = {
student: Student;
}
const studentToFormValuesTransformer: Transformer<Nullable<Student>, StudentFormValues, { current: Student }> = {
transform(subject: Nullable<Student>, context: { current: Student }): StudentFormValues {
return {
firstName: subject.name || "",
lastName: subject.surname || "",
albumNumber: subject.albumNumber || "",
semester: subject.semester || "",
email: subject.email || "",
};
},
reverseTransform(subject: StudentFormValues, { current }: { current: Student }): Nullable<Student> {
return {
...current,
name: subject.firstName,
surname: subject.lastName,
albumNumber: subject.albumNumber ? subject.albumNumber : null,
semester: subject.semester ? subject.semester : null,
email: subject.email,
};
},
}
export const StudentForm = ({ student }: StudentFormProps) => {
const { t } = useTranslation();
const dispatch = useDispatch();
const validationSchema = useMemo(() => Yup.object<StudentFormValues>({
semester: Yup.number().required().min(1).max(10),
albumNumber: Yup.number().required(),
email: Yup.string().required(),
firstName: Yup.string().required(),
lastName: Yup.string().required(),
}), []);
const initialValues: StudentFormValues = useMemo(
() => studentToFormValuesTransformer.transform(student, { current: student }),
[ student ]
)
const handleFormSubmit = async (values: StudentFormValues) => {
const update = studentToFormValuesTransformer.reverseTransform(values, { current: student }) as Student;
const updated = await api.student.update(update);
dispatch({
type: StudentActions.Set,
student: updated,
})
}
const InnerForm = () => {
const { handleSubmit } = useFormikContext();
return <form onSubmit={ handleSubmit }>
<Typography variant="subtitle1">{ t("forms.student.sections.personal") }</Typography>
<Grid container>
<Grid item md={ 6 }>
<Field component={ TextFieldFormik }
name="firstName"
label={ t("forms.student.fields.first-name") }
fullWidth
/>
</Grid>
<Grid item md={ 6 }>
<Field component={ TextFieldFormik }
name="lastName"
label={ t("forms.student.fields.last-name") }
fullWidth
/>
</Grid>
<Grid item>
<Field component={ TextFieldFormik }
name="email"
label={ t("forms.student.fields.email") }
fullWidth
/>
</Grid>
</Grid>
<Typography variant="subtitle1">{ t("forms.student.sections.studies")}</Typography>
<Grid container>
<Grid item md={ 6 }>
<Field component={ TextFieldFormik }
name="albumNumber"
label={ t("forms.student.fields.album-number") }
fullWidth
/>
</Grid>
<Grid item md={ 6 }>
<Field component={ TextFieldFormik }
name="semester"
label={ t("forms.student.fields.semester") }
fullWidth
/>
</Grid>
</Grid>
<Actions>
<Button variant="contained" type="submit" color="primary">{ t("save") }</Button>
</Actions>
</form>
}
return <Formik initialValues={ initialValues } onSubmit={ handleFormSubmit } validationSchema={ validationSchema }>
<InnerForm />
</Formik>
}
export default StudentForm;