140 lines
5.3 KiB
TypeScript
140 lines
5.3 KiB
TypeScript
import { Page } from "@/pages/base";
|
|
import React, { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useAsyncState } from "@/hooks";
|
|
import { Course } from "@/data";
|
|
import api from "@/management/api";
|
|
import { Management } from "@/management/main";
|
|
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";
|
|
import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
|
|
import { AccountCheck, Delete, Refresh, ShieldCheck } from "mdi-material-ui";
|
|
import { OneOrMany } from "@/helpers";
|
|
import { createDeleteAction } from "@/management/common/DeleteResourceAction";
|
|
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 { EditCourseDialog } from "@/management/course/edit";
|
|
|
|
const title = "course.index.title";
|
|
|
|
const label = (course: Course) => course?.name;
|
|
|
|
export const CourseManagement = () => {
|
|
const { t } = useTranslation("management");
|
|
const [result, setCoursesPromise] = useAsyncState<Course[]>();
|
|
const [selected, setSelected] = useState<Course[]>([]);
|
|
const spacing = useSpacing(2);
|
|
|
|
const updateCourseList = () => {
|
|
setCoursesPromise(api.course.all());
|
|
}
|
|
|
|
const handleCourseDelete = async (type: OneOrMany<Course>) => {
|
|
await api.course.remove(type);
|
|
updateCourseList();
|
|
}
|
|
|
|
useEffect(updateCourseList, []);
|
|
|
|
const DeleteCourseAction = createDeleteAction({ label, onDelete: handleCourseDelete });
|
|
|
|
const CreateCourseAction = () => {
|
|
const [ open, setOpen ] = useState<boolean>(false);
|
|
|
|
const handleCourseCreation = async (value: Course) => {
|
|
await api.course.save(value);
|
|
setOpen(false);
|
|
updateCourseList();
|
|
}
|
|
|
|
return <>
|
|
<Button variant="contained" color="primary" startIcon={ <Add /> } onClick={ () => setOpen(true) }>{ t("create") }</Button>
|
|
{ open && createPortal(
|
|
<EditCourseDialog open={ open } onSave={ handleCourseCreation } onClose={ () => setOpen(false) }/>,
|
|
document.getElementById("modals") as Element
|
|
) }
|
|
</>
|
|
}
|
|
|
|
const EditCourseAction = ({ resource }: { resource: Course }) => {
|
|
const [ open, setOpen ] = useState<boolean>(false);
|
|
|
|
const handleCourseCreation = async (value: Course) => {
|
|
await api.course.save(value);
|
|
setOpen(false);
|
|
updateCourseList();
|
|
}
|
|
|
|
return <>
|
|
<Tooltip title={ t("actions.edit") as any }>
|
|
<IconButton onClick={ () => setOpen(true) }><Edit /></IconButton>
|
|
</Tooltip>
|
|
{ open && createPortal(
|
|
<EditCourseDialog open={ open } onSave={ handleCourseCreation } value={ resource } onClose={ () => setOpen(false) }/>,
|
|
document.getElementById("modals") as Element
|
|
) }
|
|
</>
|
|
}
|
|
|
|
const columns: Column<Course>[] = [
|
|
{
|
|
field: "id",
|
|
title: "ID",
|
|
width: 0,
|
|
defaultSort: "asc",
|
|
filtering: false,
|
|
},
|
|
{
|
|
title: t("course.field.name"),
|
|
render: type => type.name,
|
|
customSort: (a, b) => a.name.localeCompare(b.name),
|
|
},
|
|
{
|
|
title: t("course.field.desiredSemesters"),
|
|
render: type => type.desiredSemesters.slice().sort().join(", "),
|
|
sorting: false
|
|
},
|
|
actionsColumn(type => <>
|
|
<DeleteCourseAction resource={ type }/>
|
|
<EditCourseAction resource={ type }/>
|
|
</>)
|
|
];
|
|
|
|
return <Page>
|
|
<Page.Header maxWidth="lg">
|
|
<Management.Breadcrumbs>
|
|
<Typography color="textPrimary">{ t(title) }</Typography>
|
|
</Management.Breadcrumbs>
|
|
<Page.Title>{ t(title) }</Page.Title>
|
|
</Page.Header>
|
|
<Container maxWidth="lg" className={ spacing.vertical }>
|
|
<Actions>
|
|
<CreateCourseAction />
|
|
<Button onClick={ updateCourseList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
|
|
</Actions>
|
|
{ selected.length > 0 && <BulkActions>
|
|
<DeleteCourseAction resource={ selected }>
|
|
{ action => <Button startIcon={ <Delete /> } onClick={ action }>{ t("actions.delete") }</Button> }
|
|
</DeleteCourseAction>
|
|
</BulkActions> }
|
|
<Async async={ result } keepValue>{
|
|
pages => <MaterialTable
|
|
title={ <MaterialTableTitle result={ result } label={ t(title) }/> }
|
|
columns={ columns }
|
|
data={ pages }
|
|
onSelectionChange={ pages => setSelected(pages) }
|
|
options={ { selection: true, pageSize: 10 } }
|
|
/>
|
|
}</Async>
|
|
</Container>
|
|
</Page>
|
|
}
|