Add ability to update and add internship types
This commit is contained in:
parent
092171d27f
commit
f3fd265dad
28
src/management/common/LabelWithIcon.tsx
Normal file
28
src/management/common/LabelWithIcon.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => createStyles({
|
||||
root: {
|
||||
display: "flex",
|
||||
alignItems: "center"
|
||||
},
|
||||
icon: {
|
||||
marginRight: theme.spacing(1),
|
||||
display: "flex",
|
||||
alignItems: "center"
|
||||
}
|
||||
}))
|
||||
|
||||
export type LabelWithIconProps = {
|
||||
icon: React.ReactNode,
|
||||
children: React.ReactChildren,
|
||||
}
|
||||
|
||||
export function LabelWithIcon({ icon, children }: LabelWithIconProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
return <div className={ classes.root }>
|
||||
<div className={ classes.icon }>{ icon }</div>
|
||||
{ children }
|
||||
</div>
|
||||
}
|
47
src/management/type/edit.tsx
Normal file
47
src/management/type/edit.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { Button, Dialog, DialogActions, DialogContent, DialogProps, DialogTitle } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { Form, Formik } from "formik";
|
||||
import { initialStaticPageFormValues, StaticPageForm, StaticPageFormValues, staticPageFormValuesTransformer } from "@/management/page/form";
|
||||
import { Actions } from "@/components";
|
||||
import { Save } from "@material-ui/icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Cancel } from "mdi-material-ui";
|
||||
import { useSpacing } from "@/styles";
|
||||
import { initialInternshipTypeFormValues, InternshipTypeForm, InternshipTypeFormValues, internshipTypeFormValuesTransformer } from "@/management/type/form";
|
||||
import { InternshipType } from "@/data";
|
||||
|
||||
export type EditInternshipTypeDialogProps = {
|
||||
onSave?: (page: InternshipType) => void;
|
||||
value?: InternshipType;
|
||||
} & DialogProps;
|
||||
|
||||
export function EditInternshipTypeDialog({ onSave, value, ...props }: EditInternshipTypeDialogProps) {
|
||||
const { t } = useTranslation("management");
|
||||
const spacing = useSpacing(3);
|
||||
|
||||
const handleSubmit = (values: InternshipTypeFormValues) => {
|
||||
onSave?.(internshipTypeFormValuesTransformer.reverseTransform(values));
|
||||
};
|
||||
|
||||
const initialValues = value
|
||||
? internshipTypeFormValuesTransformer.transform(value)
|
||||
: initialInternshipTypeFormValues;
|
||||
|
||||
return <Dialog { ...props } maxWidth="lg">
|
||||
<Formik initialValues={ initialValues } onSubmit={ handleSubmit }>
|
||||
<Form className={ spacing.vertical }>
|
||||
<DialogTitle>{ t(value ? "type.edit.title" : "type.create.title") }</DialogTitle>
|
||||
<DialogContent>
|
||||
<InternshipTypeForm />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Actions>
|
||||
<Button variant="contained" color="primary" startIcon={ <Save /> } type="submit">{ t("save") }</Button>
|
||||
<Button startIcon={ <Cancel /> } onClick={ ev => props.onClose?.(ev, "escapeKeyDown") }>{ t("cancel") }</Button>
|
||||
</Actions>
|
||||
</DialogActions>
|
||||
</Form>
|
||||
</Formik>
|
||||
</Dialog>
|
||||
}
|
||||
|
55
src/management/type/form.tsx
Normal file
55
src/management/type/form.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
import { InternshipType } from "@/data";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSpacing } from "@/styles";
|
||||
import { Field } from "formik";
|
||||
import { TextField as TextFieldFormik, Checkbox as CheckboxFormik } from "formik-material-ui";
|
||||
import { FormControlLabel, FormGroup, Typography } from "@material-ui/core";
|
||||
import { CKEditorField } from "@/field/ckeditor";
|
||||
import { AccountCheck, ShieldCheck } from "mdi-material-ui";
|
||||
import { identityTransformer, Transformer } from "@/serialization";
|
||||
import { LabelWithIcon } from "@/management/common/LabelWithIcon";
|
||||
|
||||
export type InternshipTypeFormValues = Omit<InternshipType, 'id'>;
|
||||
|
||||
export const initialInternshipTypeFormValues: InternshipTypeFormValues = {
|
||||
label: {
|
||||
pl: "",
|
||||
en: "",
|
||||
},
|
||||
description: {
|
||||
pl: "",
|
||||
en: "",
|
||||
},
|
||||
requiresInsurance: false,
|
||||
requiresDeanApproval: false,
|
||||
}
|
||||
|
||||
export const internshipTypeFormValuesTransformer: Transformer<InternshipType, InternshipTypeFormValues> = identityTransformer;
|
||||
|
||||
export function InternshipTypeForm() {
|
||||
const { t } = useTranslation("management");
|
||||
const spacing = useSpacing(2);
|
||||
|
||||
return <div className={ spacing.vertical }>
|
||||
<Typography variant="subtitle2">{ t("type.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("type.field.description") }</Typography>
|
||||
<Field label={ t("translation:language.pl") } name="description.pl" fullWidth component={ TextFieldFormik }/>
|
||||
<Field label={ t("translation:language.en") } name="description.en" fullWidth component={ TextFieldFormik }/>
|
||||
|
||||
<Typography variant="subtitle2">{ t("type.field.flags") }</Typography>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={ <Field name="requiresDeanApproval" component={ CheckboxFormik }/> }
|
||||
label={ <LabelWithIcon icon={ <AccountCheck /> }>{ t("type.flag.dean-approval") }</LabelWithIcon> }
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={ <Field name="requiresInsurance" component={ CheckboxFormik }/> }
|
||||
label={ <LabelWithIcon icon={ <ShieldCheck /> }>{ t("type.flag.insurance") }</LabelWithIcon> }
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ import { useAsyncState } from "@/hooks";
|
||||
import { InternshipType } from "@/data";
|
||||
import api from "@/management/api";
|
||||
import { Management } from "@/management/main";
|
||||
import { Button, Container, Tooltip, Typography } from "@material-ui/core";
|
||||
import { Button, Container, IconButton, Tooltip, Typography } from "@material-ui/core";
|
||||
import { Async } from "@/components/async";
|
||||
import MaterialTable, { Column } from "material-table";
|
||||
import { MaterialTableTitle } from "@/management/common/MaterialTableTitle";
|
||||
@ -17,6 +17,11 @@ import { BulkActions } from "@/management/common/BulkActions";
|
||||
import { useSpacing } from "@/styles";
|
||||
import { Actions } from "@/components";
|
||||
import { MultilingualCell } from "@/management/common/MultilangualCell";
|
||||
import { default as StaticPage } from "@/data/page";
|
||||
import { Add, Edit } from "@material-ui/icons";
|
||||
import { createPortal } from "react-dom";
|
||||
import { EditStaticPageDialog } from "@/management/page/edit";
|
||||
import { EditInternshipTypeDialog } from "@/management/type/edit";
|
||||
|
||||
const title = "type.index.title";
|
||||
|
||||
@ -41,6 +46,44 @@ export const InternshipTypeManagement = () => {
|
||||
|
||||
const DeleteTypeAction = createDeleteAction({ label, onDelete: handleTypeDelete });
|
||||
|
||||
const CreateTypeAction = () => {
|
||||
const [ open, setOpen ] = useState<boolean>(false);
|
||||
|
||||
const handleTypeCreation = async (value: InternshipType) => {
|
||||
await api.type.save(value);
|
||||
setOpen(false);
|
||||
updateTypeList();
|
||||
}
|
||||
|
||||
return <>
|
||||
<Button variant="contained" color="primary" startIcon={ <Add /> } onClick={ () => setOpen(true) }>{ t("create") }</Button>
|
||||
{ open && createPortal(
|
||||
<EditInternshipTypeDialog open={ open } onSave={ handleTypeCreation } onClose={ () => setOpen(false) }/>,
|
||||
document.getElementById("modals") as Element
|
||||
) }
|
||||
</>
|
||||
}
|
||||
|
||||
const EditTypeAction = ({ resource }: { resource: InternshipType }) => {
|
||||
const [ open, setOpen ] = useState<boolean>(false);
|
||||
|
||||
const handleTypeCreation = async (value: InternshipType) => {
|
||||
await api.type.save(value);
|
||||
setOpen(false);
|
||||
updateTypeList();
|
||||
}
|
||||
|
||||
return <>
|
||||
<Tooltip title={ t("actions.edit") as any }>
|
||||
<IconButton onClick={ () => setOpen(true) }><Edit /></IconButton>
|
||||
</Tooltip>
|
||||
{ open && createPortal(
|
||||
<EditInternshipTypeDialog open={ open } onSave={ handleTypeCreation } value={ resource } onClose={ () => setOpen(false) }/>,
|
||||
document.getElementById("modals") as Element
|
||||
) }
|
||||
</>
|
||||
}
|
||||
|
||||
const columns: Column<InternshipType>[] = [
|
||||
{
|
||||
field: "id",
|
||||
@ -61,16 +104,17 @@ export const InternshipTypeManagement = () => {
|
||||
},
|
||||
{
|
||||
title: t("type.field.flags"),
|
||||
render: type => <>
|
||||
render: type => <div style={{ display: "flex", flexDirection: "column" }}>
|
||||
{ type.requiresDeanApproval && <Tooltip title={ t("type.flag.dean-approval") as string }><AccountCheck/></Tooltip> }
|
||||
{ type.requiresInsurance && <Tooltip title={ t("type.flag.insurance") as string }><ShieldCheck/></Tooltip> }
|
||||
</>,
|
||||
</div>,
|
||||
width: 0,
|
||||
filtering: true,
|
||||
sorting: false,
|
||||
},
|
||||
actionsColumn(type => <>
|
||||
<DeleteTypeAction resource={ type }/>
|
||||
<EditTypeAction resource={ type }/>
|
||||
</>)
|
||||
];
|
||||
|
||||
@ -83,6 +127,7 @@ export const InternshipTypeManagement = () => {
|
||||
</Page.Header>
|
||||
<Container maxWidth="lg" className={ spacing.vertical }>
|
||||
<Actions>
|
||||
<CreateTypeAction />
|
||||
<Button onClick={ updateTypeList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
|
||||
</Actions>
|
||||
{ selected.length > 0 && <BulkActions>
|
||||
|
@ -24,10 +24,14 @@ edition:
|
||||
type:
|
||||
index:
|
||||
title: "Rodzeje praktyki"
|
||||
edit:
|
||||
title: "Edytuj rodzaj praktyki"
|
||||
create:
|
||||
title: "Utwórz rodzaj praktyki"
|
||||
field:
|
||||
label: "Rodzaj praktyki"
|
||||
description: "Opis"
|
||||
flags: "Flagi"
|
||||
flags: "Wymogi"
|
||||
flag:
|
||||
dean-approval: "Wymaga zgody dziekana"
|
||||
insurance: "Wymaga ubezpieczenia"
|
||||
|
Loading…
Reference in New Issue
Block a user