From 3e6f788560d613e516eec89eaaf0c29093157981 Mon Sep 17 00:00:00 2001 From: M <120020483+VWSCoronaDashboard30@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:35:59 +0100 Subject: [PATCH] feature/COR-1917_site-archive-compatible-gemeente-map (#4989) * feat(COR-1917): Added new icons and prop drill for MenuItemLink * feat(COR-1917): Main functionality ready, abstraction and correction needed * feat(COR-1917): Added keys to the page and components * feat(COR-1917): Fixed bug with list button displayed on other pages * feat(COR-1917): Added omitted file * feat(COR-1917): Fixed compile issue --- packages/app/src/components/aside/menu.tsx | 11 +- packages/app/src/components/aside/title.tsx | 32 +++- .../app/src/components/layout/app-content.tsx | 24 ++- packages/app/src/domain/layout/gm-layout.tsx | 64 +++++-- packages/app/src/next-config/rewrites.js | 2 +- packages/app/src/pages/gemeente/index.tsx | 10 +- .../app/src/pages/gemeente/lijstweergave.tsx | 172 ++++++++++++++++++ packages/cms/src/lokalize/key-mutations.csv | 9 + packages/common/src/data/reverse-router.ts | 1 + packages/icons/icons.md | 2 + packages/icons/src/icon-name2filename.ts | 4 + packages/icons/src/svg/list.svg | 9 + packages/icons/src/svg/map.svg | 11 ++ 13 files changed, 319 insertions(+), 32 deletions(-) create mode 100644 packages/app/src/pages/gemeente/lijstweergave.tsx create mode 100644 packages/icons/src/svg/list.svg create mode 100644 packages/icons/src/svg/map.svg diff --git a/packages/app/src/components/aside/menu.tsx b/packages/app/src/components/aside/menu.tsx index 1cf045326d..6882bfa179 100644 --- a/packages/app/src/components/aside/menu.tsx +++ b/packages/app/src/components/aside/menu.tsx @@ -100,9 +100,10 @@ interface MenuItemLinkProps { icon?: ReactNode; href?: Url; showArrow?: boolean; + isLinkForMainMenu?: boolean; } -export function MenuItemLink({ href, title }: MenuItemLinkProps) { +export function MenuItemLink({ href, title, icon, isLinkForMainMenu = true }: MenuItemLinkProps) { const router = useRouter(); const breakpoints = useBreakpoints(true); @@ -121,8 +122,8 @@ export function MenuItemLink({ href, title }: MenuItemLinkProps) { return (
  • - - + +
  • @@ -166,10 +167,10 @@ const Unavailable = styled.span( }) ); -const StyledAnchor = styled(Anchor)<{ isActive: boolean }>((anchorProps) => +const StyledAnchor = styled(Anchor)<{ isActive: boolean; isLinkForMainMenu: boolean }>((anchorProps) => css({ padding: space[2], - paddingLeft: '3rem', + paddingLeft: anchorProps.isLinkForMainMenu ? '3rem' : '0.5rem', display: 'block', borderRight: '5px solid transparent', color: anchorProps.isActive ? colors.blue8 : 'black', diff --git a/packages/app/src/components/aside/title.tsx b/packages/app/src/components/aside/title.tsx index 7f144ab1b6..5da8a9fdeb 100644 --- a/packages/app/src/components/aside/title.tsx +++ b/packages/app/src/components/aside/title.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import { space } from '~/style/theme'; import { Box } from '../base'; import { Text } from '../typography'; +import css from '@styled-system/css'; type TitleProps = { title: string; @@ -13,13 +14,17 @@ type TitleProps = { showArrow?: boolean; }; -export const AsideTitle = ({ title, subtitle, showArrow }: TitleProps) => { +export const AsideTitle = ({ title, subtitle, showArrow, icon }: TitleProps) => { return ( - {title} + + {icon && {icon}} + {title} + + {showArrow && } @@ -36,3 +41,26 @@ const AsideArrow = styled(ChevronRight)` height: 20px; width: ${space[3]}; `; + +const Icon = ({ children }: { children: ReactNode }) => { + return ( + + ); +}; diff --git a/packages/app/src/components/layout/app-content.tsx b/packages/app/src/components/layout/app-content.tsx index d2aed25adf..6196fb3de7 100644 --- a/packages/app/src/components/layout/app-content.tsx +++ b/packages/app/src/components/layout/app-content.tsx @@ -16,9 +16,10 @@ interface AppContentProps { sidebarComponent: React.ReactNode; searchComponent?: React.ReactNode; hideBackButton?: boolean; + displayAsFlex?: boolean; } -export function AppContent({ children, sidebarComponent, searchComponent, hideBackButton }: AppContentProps) { +export function AppContent({ children, sidebarComponent, searchComponent, hideBackButton, displayAsFlex = false }: AppContentProps) { const router = useRouter(); const reverseRouter = useReverseRouter(); const { commonTexts } = useIntl(); @@ -28,7 +29,6 @@ export function AppContent({ children, sidebarComponent, searchComponent, hideBa const currentCode = router.query.code as string | undefined; const backButtonConfig = { currentPageScope, currentCode, isMenuOpen, reverseRouter, commonTexts }; const backButtonValues = getBackButtonValues(backButtonConfig); - return ( @@ -47,12 +47,12 @@ export function AppContent({ children, sidebarComponent, searchComponent, hideBa flexShrink={0} minHeight={{ lg: '35em' }} width={{ md: '18rem', lg: '21rem' }} + display={displayAsFlex ? 'flex' : 'block'} zIndex={3} + justifyContent="center" > - - {searchComponent} - {sidebarComponent} - + {searchComponent} + {sidebarComponent} {/* id is for hash navigation */} @@ -114,3 +114,15 @@ const ResponsiveVisible = styled.div` display: block; } `; + +const ResponsiveVisibleAside = styled.div` + display: ${({ isVisible }) => (isVisible ? 'flex' : 'none')}; + + @media ${mediaQueries.md} { + display: ${({ isVisible }) => (!isVisible ? 'flex' : undefined)}; + } + + .has-no-js & { + display: block; + } +`; diff --git a/packages/app/src/domain/layout/gm-layout.tsx b/packages/app/src/domain/layout/gm-layout.tsx index 0929ecf76d..b523a46177 100644 --- a/packages/app/src/domain/layout/gm-layout.tsx +++ b/packages/app/src/domain/layout/gm-layout.tsx @@ -1,18 +1,24 @@ -import Head from 'next/head'; -import { useRouter } from 'next/router'; -import { Menu, MenuRenderer } from '~/components/aside/menu'; +import { AppContent } from '~/components/layout/app-content'; import { Box } from '~/components/base'; import { ErrorBoundary } from '~/components/error-boundary'; -import { AppContent } from '~/components/layout/app-content'; +import { GmComboBox } from './components/gm-combo-box'; import { Heading } from '~/components/typography'; -import { VisuallyHidden } from '~/components/visually-hidden'; -import { useIntl } from '~/intl'; +import { List } from '@corona-dashboard/icons'; +import { Menu, MenuItemLink, MenuRenderer } from '~/components/aside/menu'; import { space } from '~/style/theme'; -import { GmComboBox } from './components/gm-combo-box'; +import { useIntl } from '~/intl'; +import { useReverseRouter } from '~/utils'; +import { useRouter } from 'next/router'; import { useSidebar } from './logic/use-sidebar'; +import { VisuallyHidden } from '~/components/visually-hidden'; +import Head from 'next/head'; +import React from 'react'; type GmLayoutProps = { children?: React.ReactNode; + asideComponent?: React.ReactNode; + displayListButton?: React.ReactNode; + displayAsFlex?: boolean; getLink?: (code: string) => string; } & ( | { @@ -35,23 +41,50 @@ type GmLayoutProps = { * ## States * * ### Mobile - * - /gemeente -> only show aside + * - /gemeente && /gemeente/lijstweergave-> only show aside * - /gemeente/[metric] -> only show content (children) * * ### Desktop - * - /gemeente -> shows aside and content (children) + * - /gemeente && /gemeente/lijstweergave -> shows aside and content (children) * - /gemeente/[metric] -> shows aside and content (children) * * More info on persistent layouts: * https://adamwathan.me/2019/10/17/persistent-layout-patterns-in-nextjs/ */ export function GmLayout(props: GmLayoutProps) { - const { children, municipalityName, code, getLink } = props; - + const reverseRouter = useReverseRouter(); const { commonTexts } = useIntl(); + + const { + children, + municipalityName, + code, + getLink, + displayListButton, + asideComponent = displayListButton ? ( + + + + + + + } title={commonTexts.gemeente_layout.list.go_to_list_label} href={reverseRouter.gm.lijstweergave()} showArrow isLinkForMainMenu={false} /> + + + + ) : ( + + + + + + ), + displayAsFlex = false, + } = props; + const router = useRouter(); - const showMetricLinks = router.route !== '/gemeente'; + const showMetricLinks = router.route !== '/gemeente' && router.route !== '/gemeente/lijstweergave'; const isMainRoute = router.route === '/gemeente'; @@ -74,11 +107,7 @@ export function GmLayout(props: GmLayoutProps) { - - - } + searchComponent={asideComponent} sidebarComponent={ <> {showMetricLinks && ( @@ -107,6 +136,7 @@ export function GmLayout(props: GmLayoutProps) { )} } + displayAsFlex={displayAsFlex} > {children} diff --git a/packages/app/src/next-config/rewrites.js b/packages/app/src/next-config/rewrites.js index 13a5be3463..2741b150d5 100644 --- a/packages/app/src/next-config/rewrites.js +++ b/packages/app/src/next-config/rewrites.js @@ -19,7 +19,7 @@ async function rewrites() { * 3. /gemeente/gblah */ { - source: '/gemeente/((?!gm|GM|gM|Gm).*):slug*', + source: '/gemeente/((?!gm|GM|gM|Gm|lijstweergave).*):slug*', destination: '/gemeente/code/404', }, /** diff --git a/packages/app/src/pages/gemeente/index.tsx b/packages/app/src/pages/gemeente/index.tsx index ee402b4bac..e8fe25bffb 100644 --- a/packages/app/src/pages/gemeente/index.tsx +++ b/packages/app/src/pages/gemeente/index.tsx @@ -8,7 +8,9 @@ import { GmComboBox } from '~/domain/layout/components/gm-combo-box'; import { GmLayout } from '~/domain/layout/gm-layout'; import { Heading } from '~/components/typography'; import { Layout } from '~/domain/layout/layout'; +import { List } from '@corona-dashboard/icons'; import { Markdown } from '~/components/markdown'; +import { Menu, MenuItemLink } from '~/components/aside/menu'; import { space } from '~/style/theme'; import { TooltipContent } from '~/components/choropleth/tooltips'; import { useBreakpoints } from '~/utils/use-breakpoints'; @@ -44,7 +46,7 @@ const Municipality = (props: StaticProps) => { return ( - + {!breakpoints.md && ( @@ -84,6 +86,12 @@ const Municipality = (props: StaticProps) => { + + {!breakpoints.md && ( + + } title={commonTexts.gemeente_layout.list.go_to_list_label} href={reverseRouter.gm.lijstweergave()} showArrow isLinkForMainMenu={false} /> + + )} ); diff --git a/packages/app/src/pages/gemeente/lijstweergave.tsx b/packages/app/src/pages/gemeente/lijstweergave.tsx new file mode 100644 index 0000000000..c77041ae37 --- /dev/null +++ b/packages/app/src/pages/gemeente/lijstweergave.tsx @@ -0,0 +1,172 @@ +import _ from 'lodash'; +import { Box } from '~/components/base'; +import { CollapsibleSection } from '~/components'; +import { colors, gmData, MunicipalityInfo } from '@corona-dashboard/common'; +import { createGetStaticProps, StaticProps } from '~/static-props/create-get-static-props'; +import { getLastGeneratedDate } from '~/static-props/get-data'; +import { GmLayout, Layout } from '~/domain/layout'; +import { Heading } from '~/components/typography'; +import { Link } from '~/utils/link'; +import { Map } from '@corona-dashboard/icons'; +import { Menu, MenuItemLink } from '~/components/aside/menu'; +import { radii, space } from '~/style/theme'; +import { useBreakpoints } from '~/utils/use-breakpoints'; +import { useIntl } from '~/intl'; +import { useReverseRouter } from '~/utils'; +import { useRouter } from 'next/router'; +import React, { Fragment } from 'react'; +import styled from 'styled-components'; + +export const getStaticProps = createGetStaticProps(getLastGeneratedDate); + +enum MunicipalityLetter { + A = 'A', + B = 'B', + C = 'C', + D = 'D', + E = 'E', + G = 'G', + H = 'H', + I = 'I', + K = 'K', + L = 'L', + M = 'M', + N = 'N', + O = 'O', + P = 'P', + R = 'R', + S = 'S', + T = 'T', + U = 'U', + V = 'V', + W = 'W', + Z = 'Z', +} + +const MunicipalityListOverview = (props: StaticProps) => { + const { lastGenerated } = props; + const { commonTexts } = useIntl(); + const reverseRouter = useReverseRouter(); + const router = useRouter(); + const breakpoints = useBreakpoints(); + + const sortedGmData = _.sortBy(gmData, [(municipality) => (municipality.displayName ? municipality.displayName : municipality.name)]); + const groupedGmData = _.groupBy( + sortedGmData, + (municipality) => (municipality.displayName ? municipality.displayName : municipality.name)[0].toUpperCase() as MunicipalityLetter + ); + + const code = router.query.code as string; + + const metadata = { + ...commonTexts.gemeente_index.metadata, + }; + + return ( + + + + + } title={commonTexts.gemeente_layout.list.go_to_map_label} href={reverseRouter.gm.index()} showArrow isLinkForMainMenu={false} /> + + + + } + isLandingPage + code={code} + > + + {commonTexts.gemeente_layout.list.list_label} + + {Object.entries(MunicipalityLetter).map(([letterKey, letterValue], index) => ( + + + + {letterValue} + + + + ))} + + + <> + {Object.entries(MunicipalityLetter).map(([letterKey, letterValue], index) => ( + + {!breakpoints.sm ? ( + + + {groupedGmData[letterKey].map((item, index) => ( + + + + {item.name} + + + + ))} + + + ) : ( + + + {letterValue} + + + + {groupedGmData[letterKey].map((item, index) => ( + + + + {item.displayName ? item.displayName : item.name} + + + + ))} + + + )} + + ))} + + + + + ); +}; + +export default MunicipalityListOverview; + +const StyledLetter = styled(Box)` + text-decoration: underline; + + width: 24px; + height: 24px; + + a { + color: black; + } +`; + +const StyledCollapsibleSection = styled(CollapsibleSection)` + border: 1px solid ${colors.blue8}; + border-radius: ${radii[1]}px; + color: black; +`; + +const StyledAnchor = styled(Box)` + text-decoration: underline; + text-decoration-color: ${colors.blue8}; +`; + +const ColumnContainer = styled(Box)` + column-count: 4; + column-gap: 20px; + width: 100%; +`; +const ColumnItem = styled(Box)` + break-inside: avoid-column; + page-break-inside: avoid; + padding: ${space[1]} 0; +`; diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index d16c26e664..ace26655a5 100644 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1,4 +1,13 @@ timestamp,action,key,document_id,move_to +2024-02-29T16:56:00.034Z,add,pages.municipality_list_page.gm.go_to_list_label,Nj97lpO3jQh76onlHCRsla,__ +2024-02-29T16:56:00.971Z,add,pages.municipality_list_page.gm.go_to_map_label,Nj97lpO3jQh76onlHCRt42,__ +2024-02-29T16:56:02.195Z,add,pages.municipality_list_page.gm.list_label,aLsER6e7bVv6SzRxzsorn7,__ +2024-02-29T17:08:19.417Z,add,common.gemeente_layout.list.go_to_list_label,jsGiCtokn2h16No2XOCjsg,__ +2024-02-29T17:08:21.363Z,add,common.gemeente_layout.list.go_to_map_label,aIhqVlpPHSWN4KBoRtCqN3,__ +2024-02-29T17:08:22.547Z,add,common.gemeente_layout.list.list_label,P56mtwcJXH3ayG8JPz9lUD,__ +2024-02-29T17:08:22.554Z,delete,pages.municipality_list_page.gm.go_to_list_label,Nj97lpO3jQh76onlHCRsla,__ +2024-02-29T17:08:22.556Z,delete,pages.municipality_list_page.gm.go_to_map_label,Nj97lpO3jQh76onlHCRt42,__ +2024-02-29T17:08:22.557Z,delete,pages.municipality_list_page.gm.list_label,aLsER6e7bVv6SzRxzsorn7,__ 2024-02-22T14:50:50.064Z,add,common.common.metadata.metrics_json_links.metrics_json_source,BDRHgHFora2UCq5UG30sAv,__ 2024-02-22T14:50:50.989Z,add,common.common.metadata.metrics_json_links.metrics_national_json.href,2z0g0X7Nweo2izzuiKMmnu,__ 2024-02-22T14:50:51.987Z,add,common.common.metadata.metrics_json_links.metrics_national_json.text,BDRHgHFora2UCq5UG30sFf,__ diff --git a/packages/common/src/data/reverse-router.ts b/packages/common/src/data/reverse-router.ts index 1f00c20599..43524c907f 100644 --- a/packages/common/src/data/reverse-router.ts +++ b/packages/common/src/data/reverse-router.ts @@ -44,6 +44,7 @@ export function getReverseRouter(isMobile: boolean) { patientenInBeeld: (code: string) => `/gemeente/${code}/patienten-in-beeld`, rioolwater: (code: string) => `/gemeente/${code}/rioolwater`, deCoronaprik: (code: string) => `/gemeente/${code}/de-coronaprik`, + lijstweergave: () => '/gemeente/lijstweergave', }, } as const; diff --git a/packages/icons/icons.md b/packages/icons/icons.md index b791afa664..ef5370ddea 100644 --- a/packages/icons/icons.md +++ b/packages/icons/icons.md @@ -76,10 +76,12 @@ See below an overview of all the available icons in this package. This file is g | KunstCultuur |
    KunstCultuur
    | | KunstcultuurMusea |
    KunstcultuurMusea
    | | Line |
    Line
    | +| List |
    List
    | | Locaties |
    Locaties
    | | Location |
    Location
    | | Lopend |
    Lopend
    | | Maatregelen |
    Maatregelen
    | +| Map |
    Map
    | | MaxAantalBezoekers |
    MaxAantalBezoekers
    | | MaxVisitors |
    MaxVisitors
    | | MedischeScreening |
    MedischeScreening
    | diff --git a/packages/icons/src/icon-name2filename.ts b/packages/icons/src/icon-name2filename.ts index 307f71583c..31575d5691 100644 --- a/packages/icons/src/icon-name2filename.ts +++ b/packages/icons/src/icon-name2filename.ts @@ -71,10 +71,12 @@ export type IconName = | 'KunstCultuur' | 'KunstcultuurMusea' | 'Line' + | 'List' | 'Locaties' | 'Location' | 'Lopend' | 'Maatregelen' + | 'Map' | 'MaxAantalBezoekers' | 'MaxVisitors' | 'MedischeScreening' @@ -211,10 +213,12 @@ export const iconName2filename: Record = { KunstCultuur: 'kunst_cultuur.svg', KunstcultuurMusea: 'kunstcultuur_musea.svg', Line: 'line.svg', + List: 'list.svg', Locaties: 'locaties.svg', Location: 'location.svg', Lopend: 'lopend.svg', Maatregelen: 'maatregelen.svg', + Map: 'map.svg', MaxAantalBezoekers: 'max_aantal_bezoekers.svg', MaxVisitors: 'max_visitors.svg', MedischeScreening: 'medische_screening.svg', diff --git a/packages/icons/src/svg/list.svg b/packages/icons/src/svg/list.svg new file mode 100644 index 0000000000..d07ca08e19 --- /dev/null +++ b/packages/icons/src/svg/list.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/icons/src/svg/map.svg b/packages/icons/src/svg/map.svg new file mode 100644 index 0000000000..1039dfa39b --- /dev/null +++ b/packages/icons/src/svg/map.svg @@ -0,0 +1,11 @@ + + + + + + + + + + +