Skip to content

Commit

Permalink
refactor: mui layout (#966)
Browse files Browse the repository at this point in the history
* feat: layout mui

* feat: navigation expand

* fix: offline header + layout title

* fix: test

---------

Co-authored-by: Victor Zeinstra <[email protected]>
  • Loading branch information
Viczei and Victor Zeinstra authored Jul 24, 2023
1 parent 5e23454 commit c3f0116
Show file tree
Hide file tree
Showing 10 changed files with 523 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export type QueryQuestion = Pick<Question, "id" | "content"> & {

export type QueryResult = {
contribution_questions: QueryQuestion[];
contribution_questions_aggregate: { aggregate: { count: number } };
};

export type QuestionListQueryProps = {
Expand Down
34 changes: 34 additions & 0 deletions targets/frontend/src/components/layout/LogoAdmin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Link from "next/link";
import { Box, Stack } from "@mui/material";

export function LogoAdmin() {
return (
<Link
href="/"
style={{
alignItems: "center",
color: "#3e486e",
textDecoration: "none",
}}
>
<Stack direction="row">
<Box
component="img"
src="/img/logo.png"
alt="Ministère du travail"
sx={{
width: "77px",
}}
/>
<Stack direction="column" justifyContent="center" textAlign="center">
<Box sx={{ fontSize: "large", lineHeight: "heading" }}>
veille & administration
</Box>
<Box sx={{ fontSize: "small", fontWeight: 300 }}>
Code du travail numérique
</Box>
</Stack>
</Stack>
</Link>
);
}
143 changes: 143 additions & 0 deletions targets/frontend/src/components/layout/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { List } from "@mui/material";
import { useNavigationAggregation } from "./NavigationAggregation.query";
import { slugifyRepository } from "src/models";
import { NavigationItem } from "./NavigationItem";
import { NavigationGroup } from "./NavigationGroup";
import { useState } from "react";
import { useRouter } from "next/router";

type NavigationScheme = {
[key: string]: {
order: number;
label: string;
links: {
href: string;
label: string;
aggregateCount?: number;
}[];
};
};

export function Navigation() {
const navAggregation = useNavigationAggregation();
const [expanded, setExpanded] = useState<string | false>();
const router = useRouter();

const navigation: NavigationScheme = {
system: {
order: 1,
label: "Systèmes",
links: [{ href: "/users", label: "Gestion des utilisateurs" }],
},
contents: {
order: 3,
label: "Contenus",
links: [
{
href: "/contenus",
label: "Contenus",
},
{
href: "/contenus?source=information",
label: "Contenus éditoriaux",
},
{
href: "/contenus?source=highlights",
label: "À la une",
},
{
href: "/contenus?source=prequalified",
label: "Requetes pré-qualifiées",
},
{
href: "/glossary",
label: "Glossaire",
},
{
href: "/themes",
label: "Thèmes",
},
{
href: "/kali/blocks",
label: "Blocs KALI",
},
{
href: "/fichiers",
label: "Fichiers",
},
{
href: "/unthemed",
label: "Contenus sans thème",
},
{
href: "/contenus/fiches-sp",
label: "fiches service-public",
},
{
href: "/duplicates",
label: "Élements en Doublons",
},
{
href: "/ghost-documents",
label: "Références inaccessibles",
},
{
href: "/mises-a-jour",
label: "Mises à jour",
},
],
},
contributions: {
order: 4,
label: "Contributions",
links: [{ href: "/contributions", label: "Questions" }],
},
};
if (navAggregation) {
navigation.alerts = {
order: 2,
label: "Alertes",
links: navAggregation.map(({ label, repository, aggregateCount }) => ({
label,
href: `/alerts/${slugifyRepository(repository)}`,
aggregateCount,
})),
};
}

Object.entries(navigation).forEach(([key, { links }]) => {
if (
!expanded &&
links.some(({ href }) => {
return router?.asPath?.includes(href);
})
) {
setExpanded(key);
}
});

return (
<List>
{Object.entries(navigation)
.sort(([, { order: orderA }], [, { order: orderB }]) =>
orderA > orderB ? 1 : -1
)
.map(([key, { label, links }]) => {
return (
<NavigationGroup
key={key}
id={key}
label={label}
expanded={expanded === key}
onExpand={setExpanded}
aggregateCount={links?.reduce(
(sum, { aggregateCount }) => sum + (aggregateCount ?? 0),
0
)}
items={links}
/>
);
})}
</List>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useQuery } from "urql";

export const getAlertsQuery = `
query getAlerts {
sources(order_by:{label:asc}) {
repository,
label,
alerts: alerts_aggregate(where: {status: {_eq: "todo"}}) {
aggregate {
count
}
}
}
}
`;

export type Source = {
repository: string;
label: string;
alerts: {
aggregate: {
count: number;
};
};
};

export type GetAlertsOutput = {
sources: Source[];
};

export type NavigationAggregationResult = {
repository: string;
label: string;
aggregateCount: number;
};

export const useNavigationAggregation = ():
| NavigationAggregationResult[]
| undefined => {
const [result] = useQuery<GetAlertsOutput>({
query: getAlertsQuery,
requestPolicy: "cache-and-network",
});
return result.data?.sources?.map(({ repository, label, alerts }) => ({
repository,
label,
aggregateCount: alerts.aggregate.count,
}));
};
74 changes: 74 additions & 0 deletions targets/frontend/src/components/layout/NavigationGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
Accordion,
AccordionSummary,
Typography,
AccordionDetails,
Badge,
Stack,
} from "@mui/material";
import { styled } from "@mui/material/styles";
import ArrowForwardIosSharpIcon from "@mui/icons-material/ArrowForwardIosSharp";
import { NavigationItem, NavigationItemProps } from "./NavigationItem";

type NavigationGroupProps = {
id: string;
label: string;
aggregateCount?: number;
expanded: boolean;
onExpand: (id: string) => void;
items?: NavigationItemProps[];
};

export function NavigationGroup({
id,
label,
expanded,
onExpand,
aggregateCount = 0,
items = [],
}: NavigationGroupProps) {
return (
<Accordion expanded={expanded} onChange={() => onExpand(id)} disableGutters>
<AccordionHeader
aria-controls="panel1d-content"
id="panel1d-header"
expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: "0.9rem" }} />}
>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
width="100%"
>
<Typography>{label}</Typography>
{aggregateCount > 0 && (
<Badge
badgeContent={aggregateCount}
color="error"
invisible={!aggregateCount}
/>
)}
</Stack>
</AccordionHeader>
<AccordionDetails>
{items.map((props) => (
<NavigationItem key={props.label} {...props}></NavigationItem>
))}
</AccordionDetails>
</Accordion>
);
}

const AccordionHeader = styled(AccordionSummary)(({ theme }) => ({
backgroundColor:
theme.palette.mode === "dark"
? "rgba(255, 255, 255, .05)"
: "rgba(0, 0, 0, .03)",
flexDirection: "row-reverse",
"& .MuiAccordionSummary-expandIconWrapper.Mui-expanded": {
transform: "rotate(90deg)",
},
"& .MuiAccordionSummary-content": {
marginLeft: theme.spacing(1),
},
}));
48 changes: 48 additions & 0 deletions targets/frontend/src/components/layout/NavigationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Link from "next/link";
import {
ListItem,
ListItemButton,
ListItemText,
Stack,
Badge,
} from "@mui/material";

export type NavigationItemProps = {
href: string;
label: string;
aggregateCount?: number;
};

export function NavigationItem({
href,
label,
aggregateCount,
}: NavigationItemProps) {
return (
<ListItem
disablePadding
component={Link}
href={href}
style={{ textDecoration: "none" }}
>
<ListItemButton>
<ListItemText
primary={
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
>
<div style={{ color: "rgb(62, 72, 110)" }}>{label}</div>
<Badge
badgeContent={aggregateCount}
color="error"
invisible={!aggregateCount}
/>
</Stack>
}
/>
</ListItemButton>
</ListItem>
);
}
Loading

0 comments on commit c3f0116

Please sign in to comment.