From 0297de2ac5e8d19c58d79a0aae8980ac5b8d812b Mon Sep 17 00:00:00 2001 From: Claire Dagan Date: Thu, 19 Sep 2024 09:15:21 +0200 Subject: [PATCH 1/3] [Dashboard] create Dashboard page and add NavBar --- frontend/src/components/NavBar.tsx | 99 +++++++++++++++++++ frontend/src/domain/entities/sideWindow.ts | 2 + .../components/DashboardMapButton.tsx | 5 +- .../components/DashboardsList/index.tsx | 16 +++ .../Dashboard/components/DashboardsNavBar.tsx | 44 +++++++++ .../components/ReportingsList/index.tsx | 13 +-- frontend/src/features/SideWindow/index.tsx | 16 ++- frontend/src/features/SideWindow/style.ts | 8 ++ .../features/missions/MissionsList/index.tsx | 13 +-- .../src/features/missions/MissionsNavBar.tsx | 93 +---------------- frontend/src/utils/routes.ts | 10 ++ 11 files changed, 208 insertions(+), 111 deletions(-) create mode 100644 frontend/src/components/NavBar.tsx create mode 100644 frontend/src/features/Dashboard/components/DashboardsList/index.tsx create mode 100644 frontend/src/features/Dashboard/components/DashboardsNavBar.tsx diff --git a/frontend/src/components/NavBar.tsx b/frontend/src/components/NavBar.tsx new file mode 100644 index 000000000..9455a6f21 --- /dev/null +++ b/frontend/src/components/NavBar.tsx @@ -0,0 +1,99 @@ +import { useAppSelector } from '@hooks/useAppSelector' +import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui' +import ResponsiveNav from '@rsuite/responsive-nav' +import styled from 'styled-components' + +export function NavBar({ children, onClose, onSelect }) { + const currentPath = useAppSelector(state => state.sideWindow.currentPath) + + return ( + } + onItemRemove={onClose} + onSelect={onSelect} + removable + > + {children} + + ) +} + +const StyledResponsiveNav = styled(ResponsiveNav)` + display: flex; + box-shadow: 0px 3px 4px #7077854d; + height: 48px; + width: 100%; + + > .rs-nav-item { + width: 360px; + border-radius: 0px !important; + color: ${p => p.theme.color.slateGray}; + font-size: 14px; + border-right: 1px solid ${p => p.theme.color.lightGray}; + display: flex; + align-items: center; + + &.rs-nav-item-active { + background-color: ${p => p.theme.color.blueGray25}; + color: ${p => p.theme.color.gunMetal}; + font-weight: 500; + border-radius: 0px; + border: 0px !important; + + > .rs-icon { + color: ${p => p.theme.color.slateGray} !important; + } + } + + > span:not(.Element-IconBox) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + } + + > .rs-icon { + color: ${p => p.theme.color.slateGray}; + } + &:hover { + border-radius: 0px !important; + background-color: ${p => p.theme.color.blueYonder25}; + } + &:first-child { + > svg { + display: none; + } + } + } + > .rs-dropdown { + > .rs-dropdown-toggle { + height: 100%; + border-radius: 0px !important; + > .rs-icon { + display: none; + } + } + > .rs-dropdown-menu { + > .rs-dropdown-item { + color: ${p => p.theme.color.slateGray}; + display: flex; + flex-direction: row; + align-items: center; + &:hover { + background-color: ${p => p.theme.color.blueYonder25}; + } + &.rs-dropdown-item-active { + background-color: ${p => p.theme.color.blueGray25}; + color: ${p => p.theme.color.gunMetal}; + } + } + } + } + > .rs-nav-bar { + border-top: 0px; + } +` diff --git a/frontend/src/domain/entities/sideWindow.ts b/frontend/src/domain/entities/sideWindow.ts index 6a55d1910..52aa203d2 100644 --- a/frontend/src/domain/entities/sideWindow.ts +++ b/frontend/src/domain/entities/sideWindow.ts @@ -10,6 +10,8 @@ export const sideWindowMenu = { } export const sideWindowPaths = { + DASHBOARD: '/dashboard/:id', + DASHBOARDS: '/dashboards', HOME: '/', MISSION: '/mission/:id', MISSIONS: '/missions', diff --git a/frontend/src/features/Dashboard/components/DashboardMapButton.tsx b/frontend/src/features/Dashboard/components/DashboardMapButton.tsx index b65e34608..6c1354364 100644 --- a/frontend/src/features/Dashboard/components/DashboardMapButton.tsx +++ b/frontend/src/features/Dashboard/components/DashboardMapButton.tsx @@ -1,8 +1,10 @@ import { DialogButton, DialogSeparator, StyledMapMenuDialogContainer } from '@components/style' import { MenuWithCloseButton } from '@features/commonStyles/map/MenuWithCloseButton' +import { sideWindowActions } from '@features/SideWindow/slice' import { useAppDispatch } from '@hooks/useAppDispatch' import { useAppSelector } from '@hooks/useAppSelector' import { Accent, Button, Icon, MapMenuDialog, Size } from '@mtes-mct/monitor-ui' +import { sideWindowPaths } from 'domain/entities/sideWindow' import { globalActions, setDisplayedItems } from 'domain/shared_slices/Global' import { reduceReportingFormOnMap } from 'domain/use_cases/reporting/reduceReportingFormOnMap' import styled from 'styled-components' @@ -21,6 +23,7 @@ export function DashboardMapButton() { ) dispatch(reduceReportingFormOnMap()) } + const gotToDashboardsList = () => dispatch(sideWindowActions.focusAndGoTo(sideWindowPaths.DASHBOARDS)) return ( <> @@ -35,7 +38,7 @@ export function DashboardMapButton() { Créer un tableau de bord - {}}> + Voir les briefs déjà créés diff --git a/frontend/src/features/Dashboard/components/DashboardsList/index.tsx b/frontend/src/features/Dashboard/components/DashboardsList/index.tsx new file mode 100644 index 000000000..400d29744 --- /dev/null +++ b/frontend/src/features/Dashboard/components/DashboardsList/index.tsx @@ -0,0 +1,16 @@ +import { SideWindowContent } from '@features/SideWindow/style' +import styled from 'styled-components' + +export function DashboardsList() { + return ( + + Tableaux de bord + + ) +} + +const Title = styled.h1` + color: ${p => p.theme.color.gunMetal}; + font-size: 22px; + line-height: 50px; +` diff --git a/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx new file mode 100644 index 000000000..9453626b2 --- /dev/null +++ b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx @@ -0,0 +1,44 @@ +import { NavBar } from '@components/NavBar' +import { Icon, THEME } from '@mtes-mct/monitor-ui' +import ResponsiveNav from '@rsuite/responsive-nav' +import { sideWindowPaths } from 'domain/entities/sideWindow' +import { useMemo } from 'react' +import { generatePath } from 'react-router' + +export function DashboardsNavBar() { + const tabs = useMemo(() => { + const dashboardsList = { + icon: , + label: 'Liste des tableaux de bords', + nextPath: sideWindowPaths.DASHBOARDS + } + + // TODO 19/09 : replace with real data + const openDashboards = { + icon: , + label: Tab XX/XX/XX, + nextPath: generatePath(sideWindowPaths.MISSION, { id: 1 }) + } + + return [dashboardsList, openDashboards] + }, []) + + const selectDashboard = () => {} + + const closeDashboard = () => {} + + return ( + + {tabs.map((item, index) => ( + + {item.label} + + ))} + + ) +} diff --git a/frontend/src/features/Reportings/components/ReportingsList/index.tsx b/frontend/src/features/Reportings/components/ReportingsList/index.tsx index 54b2323aa..48914222c 100644 --- a/frontend/src/features/Reportings/components/ReportingsList/index.tsx +++ b/frontend/src/features/Reportings/components/ReportingsList/index.tsx @@ -1,5 +1,6 @@ import { ReportingsFilters } from '@features/Reportings/Filters' import { useGetFilteredReportingsQuery } from '@features/Reportings/hooks/useGetFilteredReportingsQuery' +import { SideWindowContent } from '@features/SideWindow/style' import { useAppDispatch } from '@hooks/useAppDispatch' import { useGetControlPlans } from '@hooks/useGetControlPlans' import { Button, Icon } from '@mtes-mct/monitor-ui' @@ -20,7 +21,7 @@ export function ReportingsList() { } return ( - + Signalements @@ -34,18 +35,10 @@ export function ReportingsList() { ) : ( )} - + ) } -const StyledReportingsContainer = styled.div` - display: flex; - flex: 1; - flex-direction: column; - padding: 40px; - overflow: auto; -` - const StyledHeader = styled.div` display: flex; flex-direction: row; diff --git a/frontend/src/features/SideWindow/index.tsx b/frontend/src/features/SideWindow/index.tsx index 11c3372be..e1212b196 100644 --- a/frontend/src/features/SideWindow/index.tsx +++ b/frontend/src/features/SideWindow/index.tsx @@ -1,3 +1,5 @@ +import { DashboardsList } from '@features/Dashboard/components/DashboardsList' +import { DashboardsNavBar } from '@features/Dashboard/components/DashboardsNavBar' import { REPORTING_EVENT_UNSYNCHRONIZED_PROPERTIES } from '@features/Reportings/components/ReportingForm/constants' import { useListenReportingEventUpdates } from '@features/Reportings/components/ReportingForm/hooks/useListenReportingEventUpdates' import { ReportingsList } from '@features/Reportings/components/ReportingsList' @@ -18,7 +20,7 @@ import { ReportingContext } from '../../domain/shared_slices/Global' import { switchTab } from '../../domain/use_cases/missions/switchTab' import { useAppDispatch } from '../../hooks/useAppDispatch' import { useAppSelector } from '../../hooks/useAppSelector' -import { isMissionOrMissionsPage, isMissionPage, isReportingsPage } from '../../utils/routes' +import { isDashboardsPage, isMissionOrMissionsPage, isMissionPage, isReportingsPage } from '../../utils/routes' import { MissionFormWrapper } from '../missions/MissionForm' import { MISSION_EVENT_UNSYNCHRONIZED_PROPERTIES } from '../missions/MissionForm/constants' import { useListenMissionEventUpdates } from '../missions/MissionForm/hooks/useListenMissionEventUpdates' @@ -37,6 +39,7 @@ export function SideWindow() { const isMissionButtonIsActive = useMemo(() => isMissionOrMissionsPage(currentPath), [currentPath]) const isReportingsButtonIsActive = useMemo(() => isReportingsPage(currentPath), [currentPath]) + const isDashboardsButtonIsActive = useMemo(() => isDashboardsPage(currentPath), [currentPath]) /** * Use to update mission opened in the side window but not actives @@ -106,6 +109,12 @@ export function SideWindow() { onClick={() => navigate(generatePath(sideWindowPaths.REPORTINGS))} title="Signalements" /> + navigate(generatePath(sideWindowPaths.DASHBOARDS))} + title="Tableaux de bord" + /> @@ -113,6 +122,11 @@ export function SideWindow() { } path={[sideWindowPaths.MISSIONS, sideWindowPaths.MISSION]} /> } path={sideWindowPaths.MISSIONS} /> } path={sideWindowPaths.MISSION} /> + } + path={[sideWindowPaths.DASHBOARDS, sideWindowPaths.DASHBOARD]} + /> + } path={sideWindowPaths.DASHBOARDS} /> {isReportingsButtonIsActive && ( diff --git a/frontend/src/features/SideWindow/style.ts b/frontend/src/features/SideWindow/style.ts index 5fc656d7e..aa1cb717c 100644 --- a/frontend/src/features/SideWindow/style.ts +++ b/frontend/src/features/SideWindow/style.ts @@ -26,3 +26,11 @@ export const StyledRouteContainer = styled.section` flex-direction: column; width: calc(100vw - 64px); ` + +export const SideWindowContent = styled.div` + display: flex; + flex: 1; + flex-direction: column; + padding: 40px; + overflow: auto; +` diff --git a/frontend/src/features/missions/MissionsList/index.tsx b/frontend/src/features/missions/MissionsList/index.tsx index 939df2d20..d9d6b265a 100644 --- a/frontend/src/features/missions/MissionsList/index.tsx +++ b/frontend/src/features/missions/MissionsList/index.tsx @@ -1,3 +1,4 @@ +import { SideWindowContent } from '@features/SideWindow/style' import { Button, Icon } from '@mtes-mct/monitor-ui' import styled from 'styled-components' @@ -17,7 +18,7 @@ export function Missions() { } return ( - + Missions et contrôles @@ -34,18 +35,10 @@ export function Missions() { ) : ( )} - + ) } -const StyledMissionsContainer = styled.div` - display: flex; - flex: 1; - flex-direction: column; - padding: 40px; - overflow: auto; -` - const StyledHeader = styled.div` display: flex; flex-direction: row; diff --git a/frontend/src/features/missions/MissionsNavBar.tsx b/frontend/src/features/missions/MissionsNavBar.tsx index 0bb21bf0c..b23a6a86f 100644 --- a/frontend/src/features/missions/MissionsNavBar.tsx +++ b/frontend/src/features/missions/MissionsNavBar.tsx @@ -1,4 +1,5 @@ -import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui' +import { NavBar } from '@components/NavBar' +import { Icon } from '@mtes-mct/monitor-ui' import ResponsiveNav from '@rsuite/responsive-nav' import { useMemo } from 'react' import { generatePath } from 'react-router-dom' @@ -24,7 +25,6 @@ function MissionStatus({ mission }) { } export function MissionsNavBar() { - const currentPath = useAppSelector(state => state.sideWindow.currentPath) const selectedMissions = useAppSelector(state => state.missionForms.missions) const dispatch = useAppDispatch() @@ -65,101 +65,16 @@ export function MissionsNavBar() { } return ( - } - onItemRemove={removeTab} - onSelect={selectTab} - removable - > + {tabs.map((item, index) => ( {item.label} ))} - + ) } -const StyledResponsiveNav = styled(ResponsiveNav)` - display: flex; - box-shadow: 0px 3px 4px #7077854d; - height: 48px; - width: 100%; - - > .rs-nav-item { - width: 360px; - border-radius: 0px !important; - color: ${p => p.theme.color.slateGray}; - font-size: 14px; - border-right: 1px solid ${p => p.theme.color.lightGray}; - display: flex; - align-items: center; - - &.rs-nav-item-active { - background-color: ${p => p.theme.color.blueGray25}; - color: ${p => p.theme.color.gunMetal}; - font-weight: 500; - border-radius: 0px; - border: 0px !important; - - > .rs-icon { - color: ${p => p.theme.color.slateGray} !important; - } - } - - > span:not(.Element-IconBox) { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; - } - - > .rs-icon { - color: ${p => p.theme.color.slateGray}; - } - &:hover { - border-radius: 0px !important; - background-color: ${p => p.theme.color.blueYonder25}; - } - &:first-child { - > svg { - display: none; - } - } - } - > .rs-dropdown { - > .rs-dropdown-toggle { - height: 100%; - border-radius: 0px !important; - > .rs-icon { - display: none; - } - } - > .rs-dropdown-menu { - > .rs-dropdown-item { - color: ${p => p.theme.color.slateGray}; - display: flex; - flex-direction: row; - align-items: center; - &:hover { - background-color: ${p => p.theme.color.blueYonder25}; - } - &.rs-dropdown-item-active { - background-color: ${p => p.theme.color.blueGray25}; - color: ${p => p.theme.color.gunMetal}; - } - } - } - } - > .rs-nav-bar { - border-top: 0px; - } -` - export const StyledStatus = styled.div<{ borderColor: string | undefined; color: string }>` height: 12px; width: 12px; diff --git a/frontend/src/utils/routes.ts b/frontend/src/utils/routes.ts index 57a0b2db7..4e0b0b8a3 100644 --- a/frontend/src/utils/routes.ts +++ b/frontend/src/utils/routes.ts @@ -42,3 +42,13 @@ export function isReportingsPage(path: string) { path as string ) } + +export function isDashboardsPage(path: string) { + return !!matchPath( + { + end: true, + path: sideWindowPaths.DASHBOARDS + }, + path as string + ) +} From eb7d429ec8a1a5c781569af47db56394215edd8f Mon Sep 17 00:00:00 2001 From: Claire Dagan Date: Thu, 19 Sep 2024 11:32:55 +0200 Subject: [PATCH 2/3] [Tech] add NavBar Props --- frontend/src/components/NavBar.tsx | 10 ++++++++-- .../features/Dashboard/components/DashboardsNavBar.tsx | 2 +- frontend/src/features/missions/MissionsNavBar.tsx | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/NavBar.tsx b/frontend/src/components/NavBar.tsx index 9455a6f21..8e941dda9 100644 --- a/frontend/src/components/NavBar.tsx +++ b/frontend/src/components/NavBar.tsx @@ -3,14 +3,20 @@ import { Accent, Icon, IconButton } from '@mtes-mct/monitor-ui' import ResponsiveNav from '@rsuite/responsive-nav' import styled from 'styled-components' -export function NavBar({ children, onClose, onSelect }) { +type NavBarProps = { + children: React.ReactNode[] + name: string + onClose: (eventKey: string | number | undefined) => void + onSelect: (eventKey: string | number | undefined) => void +} +export function NavBar({ children, name, onClose, onSelect }: NavBarProps) { const currentPath = useAppSelector(state => state.sideWindow.currentPath) return ( } onItemRemove={onClose} diff --git a/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx index 9453626b2..edf1418ce 100644 --- a/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx +++ b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx @@ -28,7 +28,7 @@ export function DashboardsNavBar() { const closeDashboard = () => {} return ( - + {tabs.map((item, index) => ( + {tabs.map((item, index) => ( {item.label} From be2c46bc3ca17ce05de841c165331628dc26f55b Mon Sep 17 00:00:00 2001 From: Claire Dagan Date: Fri, 20 Sep 2024 16:07:06 +0200 Subject: [PATCH 3/3] [Dashboard] add link to go to dashboard page --- .../Dashboard/components/DashboardForm/index.tsx | 7 +++++++ .../features/Dashboard/components/DashboardsNavBar.tsx | 10 ++++++++-- frontend/src/features/SideWindow/index.tsx | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 frontend/src/features/Dashboard/components/DashboardForm/index.tsx diff --git a/frontend/src/features/Dashboard/components/DashboardForm/index.tsx b/frontend/src/features/Dashboard/components/DashboardForm/index.tsx new file mode 100644 index 000000000..72f548a61 --- /dev/null +++ b/frontend/src/features/Dashboard/components/DashboardForm/index.tsx @@ -0,0 +1,7 @@ +export function DashboardForm() { + return ( +
+

Dashboard Form

+
+ ) +} diff --git a/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx index edf1418ce..f66a665b2 100644 --- a/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx +++ b/frontend/src/features/Dashboard/components/DashboardsNavBar.tsx @@ -1,4 +1,6 @@ import { NavBar } from '@components/NavBar' +import { sideWindowActions } from '@features/SideWindow/slice' +import { useAppDispatch } from '@hooks/useAppDispatch' import { Icon, THEME } from '@mtes-mct/monitor-ui' import ResponsiveNav from '@rsuite/responsive-nav' import { sideWindowPaths } from 'domain/entities/sideWindow' @@ -6,6 +8,8 @@ import { useMemo } from 'react' import { generatePath } from 'react-router' export function DashboardsNavBar() { + const dispatch = useAppDispatch() + const tabs = useMemo(() => { const dashboardsList = { icon: , @@ -17,13 +21,15 @@ export function DashboardsNavBar() { const openDashboards = { icon: , label: Tab XX/XX/XX, - nextPath: generatePath(sideWindowPaths.MISSION, { id: 1 }) + nextPath: generatePath(sideWindowPaths.DASHBOARD, { id: 1 }) } return [dashboardsList, openDashboards] }, []) - const selectDashboard = () => {} + const selectDashboard = path => { + dispatch(sideWindowActions.setCurrentPath(path)) + } const closeDashboard = () => {} diff --git a/frontend/src/features/SideWindow/index.tsx b/frontend/src/features/SideWindow/index.tsx index e1212b196..d2145c8e8 100644 --- a/frontend/src/features/SideWindow/index.tsx +++ b/frontend/src/features/SideWindow/index.tsx @@ -1,3 +1,4 @@ +import { DashboardForm } from '@features/Dashboard/components/DashboardForm' import { DashboardsList } from '@features/Dashboard/components/DashboardsList' import { DashboardsNavBar } from '@features/Dashboard/components/DashboardsNavBar' import { REPORTING_EVENT_UNSYNCHRONIZED_PROPERTIES } from '@features/Reportings/components/ReportingForm/constants' @@ -127,6 +128,7 @@ export function SideWindow() { path={[sideWindowPaths.DASHBOARDS, sideWindowPaths.DASHBOARD]} /> } path={sideWindowPaths.DASHBOARDS} /> + } path={sideWindowPaths.DASHBOARD} /> {isReportingsButtonIsActive && (