Add edition breadcrumb
This commit is contained in:
parent
1deaebda3d
commit
a38409e2d0
11
src/app.tsx
11
src/app.tsx
@ -1,6 +1,6 @@
|
||||
import React, { HTMLProps, useEffect } from 'react';
|
||||
import { Link, Route, Switch } from "react-router-dom"
|
||||
import { processMiddlewares, route, routes } from "@/routing";
|
||||
import { processMiddlewares, route, Routes, routes } from "@/routing";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState } from "@/state/reducer";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
@ -97,14 +97,7 @@ function App() {
|
||||
</Container>
|
||||
</header>
|
||||
<main id="content">
|
||||
{ <Switch>
|
||||
{ routes.map(({ name, content, middlewares = [], ...route }) =>
|
||||
<Route { ...route } key={ name } render={ () => {
|
||||
const Next = () => processMiddlewares([ ...middlewares, content ])
|
||||
return <Next />
|
||||
} } />
|
||||
) }
|
||||
</Switch> }
|
||||
<Routes routes={ routes.filter(route => !route.tags || route.tags.length == 0) }/>
|
||||
</main>
|
||||
<footer className="footer">
|
||||
<Container style={{ display: 'flex', alignItems: "center" }}>
|
||||
|
@ -1,17 +1,17 @@
|
||||
import React, { useCallback } from "react";
|
||||
import React, { useCallback, useContext } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useRouteMatch } from "react-router-dom";
|
||||
import { useAsync } from "@/hooks";
|
||||
import api from "@/management/api";
|
||||
import { useRouteMatch, Link as RouterLink } from "react-router-dom";
|
||||
import { Page } from "@/pages/base";
|
||||
import { Container, Paper, Typography } from "@material-ui/core";
|
||||
import { Container, Link, Paper, Typography } from "@material-ui/core";
|
||||
import { Management, ManagementLink } from "@/management/main";
|
||||
import { Edition } from "@/data/edition";
|
||||
import { Async } from "@/components/async";
|
||||
import { AccountMultiple, BriefcaseAccount, CertificateOutline, CogOutline, FileChartOutline, FormatPageBreak } from "mdi-material-ui";
|
||||
import { route } from "@/routing";
|
||||
import { route, routes, Routes } from "@/routing";
|
||||
import { useSpacing } from "@/styles";
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||
import { useAsync } from "@/hooks";
|
||||
import api from "@/management/api";
|
||||
import { Async } from "@/components/async";
|
||||
|
||||
const useSectionStyles = makeStyles((theme: Theme) => createStyles({
|
||||
header: {
|
||||
@ -23,60 +23,85 @@ const useSectionStyles = makeStyles((theme: Theme) => createStyles({
|
||||
}))
|
||||
|
||||
export function title(edition: Edition) {
|
||||
return `${edition.course.name} - ${edition.startDate.year()}`
|
||||
return `${ edition.course.name } - ${ edition.startDate.year() }`
|
||||
}
|
||||
|
||||
export const ManageEditionPage = () => {
|
||||
export const EditionContext = React.createContext<Edition | null>(null);
|
||||
|
||||
export const EditionManagement = ({ edition }: EditionManagementProps) => {
|
||||
const { t } = useTranslation("management");
|
||||
const { params } = useRouteMatch();
|
||||
|
||||
const edition = useAsync<Edition>(useCallback(() => api.edition.details(params.edition), [params.edition]))
|
||||
const spacing = useSpacing(2);
|
||||
const classes = useSectionStyles();
|
||||
|
||||
return <Page>
|
||||
<Async async={ edition }>{ edition =>
|
||||
<>
|
||||
<Page.Header>
|
||||
<Management.Breadcrumbs>
|
||||
<Typography color="textPrimary">{ title(edition) }</Typography>
|
||||
</Management.Breadcrumbs>
|
||||
<Page.Title>{ title(edition) }</Page.Title>
|
||||
</Page.Header>
|
||||
<Container className={ spacing.vertical }>
|
||||
<Paper elevation={ 2 }>
|
||||
<Typography className={ classes.header }>{ t("edition.manage.internships") }</Typography>
|
||||
<Management.Menu>
|
||||
<ManagementLink icon={ <AccountMultiple/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.students.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <BriefcaseAccount/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.internships.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.ipp.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <FileChartOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.reports.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <CertificateOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.dean-approvals.title") }
|
||||
</ManagementLink>
|
||||
</Management.Menu>
|
||||
</Paper>
|
||||
<Paper elevation={ 2 }>
|
||||
<Typography className={ classes.header }>{ t("edition.manage.management") }</Typography>
|
||||
<Management.Menu>
|
||||
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.report-fields.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <CogOutline/> } route={ route("management:edition_settings", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.settings.title") }
|
||||
</ManagementLink>
|
||||
</Management.Menu>
|
||||
</Paper>
|
||||
</Container>
|
||||
</>
|
||||
}</Async>
|
||||
<Page.Header>
|
||||
<Management.Breadcrumbs>
|
||||
<Typography color="textPrimary">{ title(edition) }</Typography>
|
||||
</Management.Breadcrumbs>
|
||||
<Page.Title>{ title(edition) }</Page.Title>
|
||||
</Page.Header>
|
||||
<Container className={ spacing.vertical }>
|
||||
<Paper elevation={ 2 }>
|
||||
<Typography className={ classes.header }>{ t("edition.manage.internships") }</Typography>
|
||||
<Management.Menu>
|
||||
<ManagementLink icon={ <AccountMultiple/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.students.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <BriefcaseAccount/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.internships.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.ipp.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <FileChartOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.reports.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <CertificateOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.dean-approvals.title") }
|
||||
</ManagementLink>
|
||||
</Management.Menu>
|
||||
</Paper>
|
||||
<Paper elevation={ 2 }>
|
||||
<Typography className={ classes.header }>{ t("edition.manage.management") }</Typography>
|
||||
<Management.Menu>
|
||||
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.report-fields.title") }
|
||||
</ManagementLink>
|
||||
<ManagementLink icon={ <CogOutline/> } route={ route("management:edition_settings", { edition: edition.id || "" }) }>
|
||||
{ t("management:edition.settings.title") }
|
||||
</ManagementLink>
|
||||
</Management.Menu>
|
||||
</Paper>
|
||||
</Container>
|
||||
</Page>
|
||||
}
|
||||
|
||||
EditionManagement.Breadcrumbs = ({ children }: { children: React.ReactChild }) => {
|
||||
const edition = useContext<Edition | null>(EditionContext);
|
||||
|
||||
return <Management.Breadcrumbs>
|
||||
{ edition && (children
|
||||
? <Link to={ route("management:edition_manage", { edition: edition.id || "" }) } component={ RouterLink }>{ title(edition) }</Link>
|
||||
: <Typography color="textPrimary">{ title(edition) }</Typography>
|
||||
) }
|
||||
{ children }
|
||||
</Management.Breadcrumbs>
|
||||
}
|
||||
|
||||
export type EditionManagementProps = {
|
||||
edition: Edition;
|
||||
}
|
||||
|
||||
export const EditionRouter = () => {
|
||||
const { params } = useRouteMatch();
|
||||
|
||||
const edition = useAsync<Edition>(useCallback(() => api.edition.details(params.edition), [params.edition]));
|
||||
|
||||
return <Async async={ edition }>{
|
||||
result => <EditionContext.Provider value={ result }>
|
||||
<Routes routes={ routes.filter(route => (route.tags || []).includes("edition")) } edition={ result }/>
|
||||
</EditionContext.Provider>
|
||||
}</Async>
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import { Edit } from "@material-ui/icons";
|
||||
import { createPortal } from "react-dom";
|
||||
import { createDeleteAction } from "@/management/common/DeleteResourceAction";
|
||||
import { EditFieldDefinitionDialog } from "@/management/edition/report/fields/edit";
|
||||
import { EditionManagement } from "../../manage";
|
||||
|
||||
const title = "edition.report-fields.title";
|
||||
|
||||
@ -67,9 +68,9 @@ export const EditionReportFields = () => {
|
||||
|
||||
return <Page>
|
||||
<Page.Header maxWidth="lg">
|
||||
<Management.Breadcrumbs>
|
||||
<EditionManagement.Breadcrumbs>
|
||||
<Typography color="textPrimary">{ t(title) }</Typography>
|
||||
</Management.Breadcrumbs>
|
||||
</EditionManagement.Breadcrumbs>
|
||||
<Page.Title>{ t(title) }</Page.Title>
|
||||
</Page.Header>
|
||||
<Container maxWidth="lg">
|
||||
|
@ -14,6 +14,7 @@ import { EditionForm } from "@/management/edition/form";
|
||||
import { Actions } from "@/components";
|
||||
import { Save } from "@material-ui/icons";
|
||||
import { Cancel } from "mdi-material-ui";
|
||||
import { EditionManagement } from "./manage";
|
||||
|
||||
const title = "edition.settings.title";
|
||||
|
||||
@ -28,9 +29,9 @@ export function EditionSettings() {
|
||||
|
||||
return <Page>
|
||||
<Page.Header maxWidth="md">
|
||||
<Management.Breadcrumbs>
|
||||
<EditionManagement.Breadcrumbs>
|
||||
<Typography color="textPrimary">{ t(title) }</Typography>
|
||||
</Management.Breadcrumbs>
|
||||
</EditionManagement.Breadcrumbs>
|
||||
<Page.Title>{ t(title) }</Page.Title>
|
||||
</Page.Header>
|
||||
<Container maxWidth="md">
|
||||
|
@ -5,16 +5,17 @@ import React from "react";
|
||||
import { ManagementIndex } from "@/management/main";
|
||||
import StaticPageManagement from "@/management/page/list";
|
||||
import { InternshipTypeManagement } from "@/management/type/list";
|
||||
import { ManageEditionPage } from "@/management/edition/manage";
|
||||
import { EditionRouter, EditionManagement } from "@/management/edition/manage";
|
||||
import { EditionReportFields } from "@/management/edition/report/fields/list";
|
||||
import { EditionSettings } from "@/management/edition/settings";
|
||||
|
||||
export const managementRoutes: Route[] = ([
|
||||
{ name: "index", path: "/", content: ManagementIndex, exact: true },
|
||||
|
||||
{ name: "edition_report_form", path: "/editions/:edition/report", content: EditionReportFields },
|
||||
{ name: "edition_settings", path: "/editions/:edition/settings", content: EditionSettings },
|
||||
{ name: "edition_manage", path: "/editions/:edition", content: ManageEditionPage },
|
||||
{ name: "edition_router", path: "/editions/:edition", content: EditionRouter },
|
||||
{ name: "edition_report_form", path: "/editions/:edition/report", content: EditionReportFields, tags: ["edition"] },
|
||||
{ name: "edition_settings", path: "/editions/:edition/settings", content: EditionSettings, tags: ["edition"] },
|
||||
{ name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"] },
|
||||
{ name: "editions", path: "/editions", content: EditionsManagement },
|
||||
|
||||
{ name: "types", path: "/types", content: InternshipTypeManagement },
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { ReactComponentElement } from "react";
|
||||
import { MainPage } from "@/pages/main";
|
||||
import { RouteProps } from "react-router-dom";
|
||||
import { RouteProps, Switch, Route as RouteComponent } from "react-router-dom";
|
||||
import { InternshipProposalFormPage, InternshipProposalPreviewPage } from "@/pages/internship/proposal";
|
||||
import { FallbackPage } from "@/pages/fallback";
|
||||
import SubmitPlanPage from "@/pages/internship/plan";
|
||||
@ -15,7 +15,8 @@ import SubmitReportPage from "@/pages/internship/report";
|
||||
|
||||
export type Route = {
|
||||
name?: string;
|
||||
content: () => ReactComponentElement<any>,
|
||||
tags?: string[];
|
||||
content: (props?: any) => ReactComponentElement<any>,
|
||||
condition?: () => boolean,
|
||||
middlewares?: Middleware<any, any>[],
|
||||
} & RouteProps;
|
||||
@ -56,7 +57,7 @@ export const routes: Route[] = [
|
||||
|
||||
// fallback route for 404 pages
|
||||
{ name: "fallback", path: "*", content: () => <FallbackPage/> },
|
||||
]
|
||||
].map(route => ({ tags: [], ...route }))
|
||||
|
||||
const routeNameMap = new Map(routes.filter(({ name }) => !!name).map(({ name, path }) => [name, path instanceof Array ? path[0] : path])) as Map<string, string>
|
||||
|
||||
@ -80,3 +81,19 @@ export const query = (url: string, params: URLParams) => {
|
||||
|
||||
return url + (query.length > 0 ? `?${ query }` : '');
|
||||
}
|
||||
|
||||
export type RoutesProps = {
|
||||
routes: Route[];
|
||||
[prop: string]: any;
|
||||
};
|
||||
|
||||
export function Routes({ routes, ...props }: RoutesProps) {
|
||||
return <Switch>
|
||||
{ routes.map(({ name, content, middlewares = [], ...route }) =>
|
||||
<RouteComponent { ...route } key={ name } render={ () => {
|
||||
const Next = () => processMiddlewares([ ...middlewares, (_, ...props) => content(...props) ], props)
|
||||
return <Next />
|
||||
} } />
|
||||
) }
|
||||
</Switch>
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user