system-praktyk-front/src/management/report/fields/form.tsx
2021-01-18 23:40:12 +01:00

103 lines
4.6 KiB
TypeScript

import React from "react";
import { ReportFieldDefinition, reportFieldTypes } from "@/data/report";
import { identityTransformer, Transformer } from "@/serialization";
import { useTranslation } from "react-i18next";
import { useSpacing } from "@/styles";
import { Field, FieldArray, FieldProps, useFormikContext } from "formik";
import { TextField as TextFieldFormik, Select } from "formik-material-ui";
import { FormControl, InputLabel, Typography, MenuItem, Card, Box, Button, CardContent, CardHeader, IconButton } from "@material-ui/core";
import { CKEditorField } from "@/forms/ckeditor";
import { Multilingual } from "@/data";
import { Actions } from "@/components";
import { Add } from "@material-ui/icons";
import { TrashCan } from "mdi-material-ui";
import { FieldPreview } from "@/management/report/fields/list";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
export type FieldDefinitionFormValues = ReportFieldDefinition | { type: string };
export const initialFieldFormValues: FieldDefinitionFormValues = {
type: "short-text",
description: {
pl: "",
en: "",
},
label: {
pl: "",
en: "",
},
choices: [],
}
export const fieldFormValuesTransformer: Transformer<ReportFieldDefinition, FieldDefinitionFormValues> = identityTransformer;
export type ChoiceFieldProps = { name: string };
const ChoiceField = ({ field, form, meta }: FieldProps) => {
const { name } = field;
const { t } = useTranslation("management");
const spacing = useSpacing(2);
return <div className={ spacing.vertical }>
<Field label={ t("translation:language.pl") } name={`${name}.pl`} fullWidth component={ TextFieldFormik }/>
<Field label={ t("translation:language.en") } name={`${name}.en`} fullWidth component={ TextFieldFormik }/>
</div>
}
const useStyles = makeStyles((theme: Theme) => createStyles({
preview: {
padding: theme.spacing(2),
backgroundColor: "#e9f0f5",
},
}))
export function FieldDefinitionForm() {
const { t } = useTranslation("management");
const spacing = useSpacing(2);
const { values } = useFormikContext<any>();
const classes = useStyles();
return <div className={ spacing.vertical }>
<FormControl variant="outlined">
<InputLabel htmlFor="report-field-type">{ t("report-field.field.type") }</InputLabel>
<Field
component={Select}
name="type"
label={ t("report-field.field.name") }
inputProps={{ id: 'report-field-type', }}
>
{ reportFieldTypes.map(type => <MenuItem value={ type }>{ t(`report-field.type.${type}`) }</MenuItem>)}
</Field>
</FormControl>
<Typography variant="subtitle2">{ t("report-field.field.label") }</Typography>
<Field label={ t("translation:language.pl") } name="label.pl" fullWidth component={ TextFieldFormik }/>
<Field label={ t("translation:language.en") } name="label.en" fullWidth component={ TextFieldFormik }/>
<Typography variant="subtitle2">{ t("report-field.field.description") }</Typography>
<Field label={ t("translation:language.pl") } name="description.pl" fullWidth component={ CKEditorField }/>
<Field label={ t("translation:language.en") } name="description.en" fullWidth component={ CKEditorField }/>
{ ["radio", "select", "checkbox"].includes(values.type) && <>
<Typography variant="subtitle2">{ t("report-field.field.choices") }</Typography>
<FieldArray name="choices" render={ helper => <>
{ values.choices.map((value: Multilingual<string>, index: number) => <Card>
<CardHeader subheader={ t("report-field.field.choice", { index: index + 1 }) } action={ <>
<IconButton onClick={ () => helper.remove(index) }>
<TrashCan />
</IconButton>
</> }/>
<CardContent>
<Field name={`choices[${index}]`} component={ ChoiceField } />
</CardContent>
</Card>) }
<Actions>
<Button variant="contained" startIcon={ <Add /> } color="primary" onClick={() => helper.push({ pl: "", en: "" })}>{ t("actions.add") }</Button>
</Actions>
</> } />
</> }
<div className={ classes.preview }>
<Typography variant="subtitle2">{ t("report-field.preview") }</Typography>
<FieldPreview field={ fieldFormValuesTransformer.reverseTransform(values) }/>
</div>
</div>
}