Skip to content

Commit

Permalink
Refactor: header and menu (#46)
Browse files Browse the repository at this point in the history
* wip: new menu

* feat: add report search modal
  • Loading branch information
ledouxm committed Jan 7, 2025
1 parent 073dabb commit 50d0d42
Show file tree
Hide file tree
Showing 11 changed files with 447 additions and 392 deletions.
1 change: 0 additions & 1 deletion packages/frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { useAuthContext } from "./contexts/AuthContext";
import { routeTree } from "./routeTree.gen";
import { useEffect } from "react";

export const App = () => {
const [auth] = useAuthContext();
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type PropsWithChildren, createContext, useContext, useEffect, useState
import { safeParseLocalStorage } from "../utils";
import { useQuery } from "@tanstack/react-query";
import { api, setToken, type RouterOutputs } from "../api";
import { menuActor } from "../features/menu/menuMachine";

const initialAuth = safeParseLocalStorage("crvif/auth");
if (!initialAuth) localStorage.setItem("crvif/version", "1");
Expand Down Expand Up @@ -86,6 +87,7 @@ export const useLogout = () => {
const [data, setData] = useAuthContext();

return () => {
menuActor.send({ type: "CLOSE" });
setData({ ...data, token: undefined, user: undefined, refreshToken: undefined });
};
};
Expand Down
189 changes: 189 additions & 0 deletions packages/frontend/src/features/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { CompatibilityAlert } from "#components/CompatibilityAlert.tsx";
import { ReportSearch } from "#components/ReportSearch.tsx";
import { css, cx } from "#styled-system/css";
import { Box, styled } from "#styled-system/jsx";
import { Flex } from "#styled-system/jsx";
import Badge from "@codegouvfr/react-dsfr/Badge";
import Button from "@codegouvfr/react-dsfr/Button";
import Header from "@codegouvfr/react-dsfr/Header/Header";
import { Link, useRouter } from "@tanstack/react-router";
import { type PropsWithChildren, useRef } from "react";
import { useIsLoggedIn } from "../contexts/AuthContext";
import { MenuButton, MenuModal } from "../features/menu/MenuButton";
import { useIsDesktop } from "../hooks/useIsDesktop";

export const Layout = ({ children }: PropsWithChildren) => {
return (
<Flex pos="relative" flexDir={"column"} h="100vh">
<AppHeader />
<CompatibilityAlert />
<Box flex="1">{children}</Box>
{/* <TanStackRouterDevtools /> */}

<AppFooter />
</Flex>
);
};

const AppFooter = () => {
return (
<footer id="fr-footer" className="fr-footer" role="contentinfo" style={{ border: "none", borderBottomWidth: 0 }}>
<div className="fr-container">
<div className="fr-footer__body">
<div className="fr-footer__brand fr-enlarge-link">
<a className="active" title="Compte rendu vif" href="/" data-status="active">
<p className="fr-logo">
Ministère
<br /> de la culture
</p>
</a>
</div>
<div className="fr-footer__content">
<ul className="fr-footer__content-list">
<li className="fr-footer__content-item">
<a
className="fr-footer__content-link"
target="_blank"
href="https://legifrance.gouv.fr"
title="legifrance.gouv.fr - ouvre une nouvelle fenêtre"
>
legifrance.gouv.fr
</a>
</li>
<li className="fr-footer__content-item">
<a
className="fr-footer__content-link"
target="_blank"
href="https://gouvernement.fr"
title="gouvernement.fr - ouvre une nouvelle fenêtre"
>
gouvernement.fr
</a>
</li>
<li className="fr-footer__content-item">
<a
className="fr-footer__content-link"
target="_blank"
href="https://service-public.fr"
title="service-public.fr - ouvre une nouvelle fenêtre"
>
service-public.fr
</a>
</li>
<li className="fr-footer__content-item">
<a
className="fr-footer__content-link"
target="_blank"
href="https://data.gouv.fr"
title="data.gouv.fr - ouvre une nouvelle fenêtre"
>
data.gouv.fr
</a>
</li>
</ul>
</div>
</div>
<div className="fr-footer__bottom">
<ul className="fr-footer__bottom-list">
<li className="fr-footer__bottom-item">
<span className="fr-footer__bottom-link">Accessibilité: partiellement conforme</span>
</li>
</ul>

<Flex flexDir="column">
<VersionDisplay />
<div className="fr-footer__bottom-copy">
<p>
Sauf mention explicite de propriété intellectuelle détenue par des tiers, les contenus de ce site sont
proposés sous{" "}
<a
href="https://github.com/etalab/licence-ouverte/blob/master/LO.md"
target="_blank"
title="licence etalab-2.0 - ouvre une nouvelle fenêtre"
>
licence etalab-2.0
</a>
</p>
</div>
</Flex>
</div>
</div>
</footer>
);
};

const VersionDisplay = () => {
const version = window.APP_VERSION;

if (!version) return null;
return (
<div className="fr-footer__bottom-copy">
<styled.p mb="10px">Version {version}</styled.p>
</div>
);
};

const AppHeader = () => {
const isDesktop = useIsDesktop();
const isLoggedIn = useIsLoggedIn();

return (
<>
<header
role="banner"
id="fr-header"
className="fr-header [&amp;_.fr-btn--menu]:opacity_0 [&amp;_.fr-btn--menu]:pointer-events_none"
>
<div className="fr-header__body">
<div
className={cx(
"fr-container",
css({
marginLeft: { base: "0", lg: "auto" },
marginRight: { base: "0", lg: "auto" },
paddingX: { base: "0", lg: "1rem" },
}),
)}
>
<div
className={cx("fr-header__body-row", css({ justifyContent: "space-between", w: "100%", margin: "0" }))}
>
<div className="fr-header__brand ">
<div className="fr-header__brand-top">
<div className="fr-header__logo">
<p className="fr-logo" style={{ position: "relative" }}>
<Link to="/" title="Compte rendu vif">
Ministère
<br /> de la culture
</Link>
</p>
</div>
</div>
<div className="fr-header__service d_none lg:d_unset">
<p className="fr-header__service-title">
{isDesktop ? (
<>
Compte-rendu VIF{" "}
<Badge as="span" noIcon severity="success">
Beta
</Badge>
</>
) : undefined}
</p>
</div>
</div>
<div
className={css({
display: "flex",
alignItems: "center",
})}
>
{isLoggedIn ? <MenuButton /> : null}
</div>
</div>
</div>
</div>
</header>
</>
);
};
5 changes: 3 additions & 2 deletions packages/frontend/src/features/menu/HelpMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import Button from "@codegouvfr/react-dsfr/Button";
import { MenuTitle } from "./MenuTitle";
import { clearDb } from "../../db/db";
import { css } from "#styled-system/css";
import { menuActor } from "./menuMachine";

export const HelpMenu = ({ backButtonOnClick }: { backButtonOnClick: () => void }) => {
export const HelpMenu = () => {
const deleteLocalData = () => {
localStorage.clear();
indexedDB.deleteDatabase("crvif.db");
Expand All @@ -15,7 +16,7 @@ export const HelpMenu = ({ backButtonOnClick }: { backButtonOnClick: () => void
};
return (
<>
<MenuTitle backButtonOnClick={backButtonOnClick}>Assistance technique</MenuTitle>
<MenuTitle backButtonOnClick={() => menuActor.send({ type: "BACK" })}>Assistance technique</MenuTitle>
<Divider height="2px" my={{ base: "27px", lg: "0" }} mb={{ base: 0, lg: "27px" }} color="#C1C1FB" />
<Stack>
<styled.div px="20px" fontWeight="bold">
Expand Down
19 changes: 7 additions & 12 deletions packages/frontend/src/features/menu/MenuActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,24 @@ import { Center, Divider, Stack, styled } from "#styled-system/jsx";
import { css } from "#styled-system/css";
import Button from "@codegouvfr/react-dsfr/Button";
import { useLogout } from "../../contexts/AuthContext";
import { NestedMenu } from "./MenuButton";
import { menuStore } from "./menuStore";
import { Fragment } from "react/jsx-runtime";
import { MenuTitle } from "./MenuTitle";
import { menuActor } from "./menuMachine";

export const MenuActions = ({ menu }: { menu: NestedMenu | null }) => {
const setMenu = (menu: NestedMenu) => {
menuStore.send({ type: "setMenu", menu });
};

export const MenuActions = () => {
const logout = useLogout();

const actions = [
{ text: "Partage des CR", onClick: () => setMenu("share") },
{ text: "Clauses départementales", onClick: () => setMenu("clauses-departementales") },
{ text: "Clauses nationales", onClick: () => setMenu("clauses-nationales") },
{ text: "Assistance technique", onClick: () => setMenu("help") },
{ text: "Partage des CR", onClick: () => menuActor.send({ type: "GO_TO_SHARE" }) },
{ text: "Clauses départementales", onClick: () => menuActor.send({ type: "GO_TO_CLAUSES_DEPT" }) },
{ text: "Clauses nationales", onClick: () => menuActor.send({ type: "GO_TO_CLAUSES_NAT" }) },
{ text: "Assistance technique", onClick: () => menuActor.send({ type: "GO_TO_HELP" }) },
{ text: "Se déconnecter", onClick: logout, dataTestId: "logout" },
];

return (
<>
<styled.div hideFrom={menu === null ? "lg" : undefined}>
<styled.div hideFrom="lg">
<MenuTitle hideDivider>Mon compte</MenuTitle>
</styled.div>
<Stack
Expand Down
Loading

0 comments on commit 50d0d42

Please sign in to comment.