diff --git a/.unimportedrc.json b/.unimportedrc.json index 6a496219..57c0f43a 100644 --- a/.unimportedrc.json +++ b/.unimportedrc.json @@ -1,15 +1,22 @@ { "entry": ["./src/index.tsx"], - "ignorePatterns": ["**/node_modules/**", "build/**"], + "ignorePatterns": ["**/node_modules/**", "build/**", "**/generated/**"], "ignoreUnimported": ["**/*.d.ts", "**/*.test.*", "**/generated/**"], "ignoreUnused": [ "@apollo/client", "@graphql-codegen/introspection", "@graphql-codegen/typescript-operations", - "@togglecorp/re-map", + "patch-package", "@sentry/react" ], - "ignoreUnresolved": ["@graphql-typed-document-node/core"], + "ignoreUnresolved": [ + [ + "@graphql-typed-document-node/core", + [ + "generated/types/graphql.ts" + ] + ] + ], "extensions": [".ts", ".js", ".tsx", ".jsx"], "aliases": { "#utils/*": ["./src/utils/*"], diff --git a/package.json b/package.json index b6c98859..fa31a972 100644 --- a/package.json +++ b/package.json @@ -23,13 +23,12 @@ "@graphql-codegen/introspection": "^4.0.3", "@graphql-codegen/typescript-operations": "^4.2.0", "@ifrc-go/icons": "^1.3.3", - "@ifrc-go/ui": "^1.0.0", + "@ifrc-go/ui": "^1.1.0", "@mapbox/mapbox-gl-draw": "^1.4.3", "@sentry/react": "^7.81.1", "@togglecorp/fujs": "^2.1.1", "@togglecorp/re-map": "^0.2.0-beta-6", "@turf/bbox": "^6.5.0", - "@turf/buffer": "^6.5.0", "graphql": "^16.8.1", "mapbox-gl": "^1.13.0", "patch-package": "^8.0.0", diff --git a/patches/@turf+buffer+6.5.0.patch b/patches/@turf+buffer+6.5.0.patch deleted file mode 100644 index fdc9ff92..00000000 --- a/patches/@turf+buffer+6.5.0.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/node_modules/@turf/buffer/package.json b/node_modules/@turf/buffer/package.json -index f350d3e..8fe4032 100644 ---- a/node_modules/@turf/buffer/package.json -+++ b/node_modules/@turf/buffer/package.json -@@ -35,11 +35,11 @@ - "exports": { - "./package.json": "./package.json", - ".": { -+ "types": "./index.d.ts", - "import": "./dist/es/index.js", - "require": "./dist/js/index.js" - } - }, -- "types": "index.d.ts", - "sideEffects": false, - "files": [ - "dist", diff --git a/src/views/Home/AlertsTable/i18n.json b/src/views/Home/AlertsTable/i18n.json index 30574946..42f2be34 100644 --- a/src/views/Home/AlertsTable/i18n.json +++ b/src/views/Home/AlertsTable/i18n.json @@ -7,6 +7,7 @@ "alertTableRegionTitle":"Region", "alertTableCountryTitle":"Country", "alertTableViewDetailsTitle":"View Details", + "alertTableActionsTitle":"Actions", "alertTableAdminsTitle":"Admin1s", "alertTableSentLabel":"Sent" } diff --git a/src/views/Home/AlertsTable/index.tsx b/src/views/Home/AlertsTable/index.tsx index a52a37c3..b4e07cfe 100644 --- a/src/views/Home/AlertsTable/index.tsx +++ b/src/views/Home/AlertsTable/index.tsx @@ -1,4 +1,8 @@ -import { useMemo } from 'react'; +import { + ComponentType, + HTMLProps, + useMemo, +} from 'react'; import { gql, useQuery, @@ -12,6 +16,7 @@ import { SortContext } from '@ifrc-go/ui/contexts'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { createDateColumn, + createListDisplayColumn, createStringColumn, } from '@ifrc-go/ui/utils'; import { isNotDefined } from '@togglecorp/fujs'; @@ -24,6 +29,7 @@ import useFilterState from '#hooks/useFilterState'; import { createLinkColumn } from '#utils/domain/tableHelpers'; import i18n from './i18n.json'; +import styles from './styles.module.css'; const ALERT_INFORMATIONS = gql` query AlertInformations($pagination: OffsetPaginationInput) { @@ -60,9 +66,11 @@ const ALERT_INFORMATIONS = gql` `; type AlertType = NonNullable['alerts']>['items']>[number]; +type Country = AlertType['country']; +type Admin1 = Country['admin1s'][number]; const alertKeySelector = (item: AlertType) => item.id; -const PAGE_SIZE = 10; +const PAGE_SIZE = 20; function AlertsTable() { const strings = useTranslation(i18n); @@ -111,44 +119,59 @@ function AlertsTable() { 'event', strings.alertTableEventTitle, (item) => item.info?.event, - { sortable: true }, + { + sortable: true, + columnClassName: styles.event, + }, ), createStringColumn( 'category', strings.alertTableCategoryTitle, (item) => item.info?.category, + { columnClassName: styles.category }, ), createStringColumn( 'region', strings.alertTableRegionTitle, (item) => (item.country.region.name), + { columnClassName: styles.region }, ), createStringColumn( - 'countries_details', + 'country', strings.alertTableCountryTitle, (item) => (item.country.name), - { sortable: true }, + { + sortable: true, + columnClassName: styles.country, + }, ), - - createStringColumn( - 'admin', + createListDisplayColumn>( + 'admin1s', strings.alertTableAdminsTitle, - (item) => item.country.admin1s?.map((admin) => admin?.name)?.join(', '), + (item) => ({ + list: item.country.admin1s, + keySelector: ({ id }) => id, + renderer: 'span' as unknown as ComponentType>, + rendererParams: ({ name }) => ({ children: name }), + }), + { columnClassName: styles.admins }, ), createDateColumn( 'sent', strings.alertTableSentLabel, (item) => (item.sent), + { columnClassName: styles.sent }, ), createLinkColumn( - 'view_details', - strings.alertTableViewDetailsTitle, + 'actions', + strings.alertTableActionsTitle, () => strings.alertTableViewDetailsTitle, (item) => ({ to: '/', urlParams: { detailId: item.id }, }), + { columnClassName: styles.actions }, ), ]), [ @@ -158,12 +181,14 @@ function AlertsTable() { strings.alertTableCountryTitle, strings.alertTableAdminsTitle, strings.alertTableSentLabel, + strings.alertTableActionsTitle, strings.alertTableViewDetailsTitle, ], ); return ( = React.Dispatch>; +type SetStateFn = (newValue: T | undefined) => void; + +export interface AlertContextProps { + bbox: unknown; + setBbox: SetStateFn; + activeCountryName: string | undefined; + + activeCountryId: Id | undefined; + activeAdmin1Id: Id | undefined; + activeAlertId: Id | undefined; + + activeGoCountryId: Id | undefined; + activeGoAdmin1Id: Id | undefined; + + setActiveCountryId: SetStateFn; + setActiveAdmin1Id: SetStateFn; + + setActiveGoCountryId: SetStateFn; + setActiveGoAdmin1Id: SetStateFn; + + setActiveAlertId: SetStateFn; + setActiveCountryName: SetStateFn; +} + +const AlertContext = createContext({ + bbox: undefined, + activeCountryId: undefined, + activeGoCountryId: undefined, + activeCountryName: undefined, + activeAdmin1Id: undefined, + activeGoAdmin1Id: undefined, + activeAlertId: undefined, + setBbox: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setBbox called without provider'); + }, + setActiveAdmin1Id: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveAlertId called without provider'); + }, + setActiveGoAdmin1Id: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveGoAlertId called without provider'); + }, + setActiveGoCountryId: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveGoCountryId called without provider'); + }, + setActiveCountryId: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveCountryId called without provider'); + }, + setActiveAlertId: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveAlertId called without provider'); + }, + setActiveCountryName: () => { + // eslint-disable-next-line no-console + console.warn('AlertContext::setActiveCountryName called without provider'); + }, +}); + +export default AlertContext; diff --git a/src/views/Home/AlertsView/AlertsAside/Admin1Alerts/index.tsx b/src/views/Home/AlertsView/AlertsAside/Admin1Alerts/index.tsx new file mode 100644 index 00000000..a4cdb259 --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/Admin1Alerts/index.tsx @@ -0,0 +1,156 @@ +import { + useCallback, + useContext, + useMemo, + useState, +} from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + Container, + Pager, + RawList, +} from '@ifrc-go/ui'; +import { + isDefined, + isNotDefined, +} from '@togglecorp/fujs'; + +import { + Admin1AlertsQuery, + Admin1AlertsQueryVariables, + Admin1DetailQuery, + Admin1DetailQueryVariables, +} from '#generated/types/graphql'; +import { stringIdSelector } from '#utils/selectors'; + +import AlertContext from '../../AlertContext'; +import AlertListItem from '../AlertListItem'; + +const ADMIN1_DETAIL = gql` +query Admin1Detail( + $admin1Id: ID! +){ + public { + admin1(pk: $admin1Id) { + bbox + ifrcGoId + name + id + } + } +} +`; + +const ADMIN1_ALERTS = gql` +query Admin1Alerts( + $admin1Id: ID!, + $pagination: OffsetPaginationInput +){ + public { + alerts( + filters: {admin1: $admin1Id} + pagination: $pagination + ) { + count + items { + id + info { + event + categoryDisplay + } + } + } + } +} +`; + +type Alert = NonNullable['alerts']>['items']>[number]; + +const MAX_ITEM_PER_PAGE = 20; + +interface Props { + admin1Id: string; +} + +function Admin1Alerts(props: Props) { + const { admin1Id } = props; + const { setActiveAlertId, setBbox } = useContext(AlertContext); + + const [activePage, setActivePage] = useState(1); + + const variables = useMemo(() => ({ + admin1Id, + pagination: { + offset: (activePage - 1) * MAX_ITEM_PER_PAGE, + limit: MAX_ITEM_PER_PAGE, + }, + }), [ + activePage, + admin1Id, + ]); + + const { + data: admin1AlertList, + error: admin1AlertError, + loading: admin1AlertPending, + } = useQuery( + ADMIN1_ALERTS, + { + variables, + skip: isNotDefined(admin1Id), + }, + ); + + const { + data: admin1Details, + } = useQuery( + ADMIN1_DETAIL, + { + variables: { admin1Id }, + skip: isNotDefined(admin1Id), + onCompleted: (response) => { + setBbox(response.public.admin1?.bbox); + }, + }, + ); + + const alertRendererParams = useCallback( + (_: string, value: Alert) => ({ + data: value, + onClick: setActiveAlertId, + }), + [setActiveAlertId], + ); + + return ( + + )} + filtered={false} + errored={isDefined(admin1AlertError)} + pending={admin1AlertPending} + contentViewType="vertical" + empty={admin1AlertList?.public?.alerts?.items?.length === 0} + > + + + ); +} + +export default Admin1Alerts; diff --git a/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/index.tsx b/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/index.tsx index b6848e3c..fe13c8fb 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/index.tsx +++ b/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/index.tsx @@ -1,5 +1,4 @@ import { - SelectInput, TabPanel, TextOutput, } from '@ifrc-go/ui'; @@ -8,16 +7,15 @@ import { useTranslation } from '@ifrc-go/ui/hooks'; import { AlertInfoQuery } from '#generated/types/graphql'; import i18n from './i18n.json'; +import styles from './styles.module.css'; -type InfosDetail = NonNullable['alert']>['infos']>[number]; +type InfoAlertType = NonNullable['alert']>; +type InfosDetail = InfoAlertType['infos'][number]; interface Props { data: InfosDetail; } -const keySelector = (alert: InfosDetail) => alert.id; -const labelSelector = (alert: InfosDetail) => alert.areas; - function AlertInfo(props: Props) { const { data, @@ -26,40 +24,34 @@ function AlertInfo(props: Props) { const strings = useTranslation(i18n); return ( - - { }} - /> - + ); diff --git a/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/styles.module.css b/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/styles.module.css new file mode 100644 index 00000000..2a015a09 --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/AlertDetail/AlertInfo/styles.module.css @@ -0,0 +1,5 @@ +.alert-info { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-xs); +} diff --git a/src/views/Home/AlertsView/AlertsAside/AlertDetail/i18n.json b/src/views/Home/AlertsView/AlertsAside/AlertDetail/i18n.json index 02014679..eae92d45 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertDetail/i18n.json +++ b/src/views/Home/AlertsView/AlertsAside/AlertDetail/i18n.json @@ -1,9 +1,11 @@ { "namespace": "alertDetail", "strings": { + "alertDetailsHeading": "Alert Details", "alertUnknownAdmin1": "Unknown Admin 1", "alertOrigin": "Origin", - "alertSender": "Sender", + "alertSentBy": "Sent by", + "alertSentOn": "Sent on", "alertIdentifier": "Identifier", "alertScope": "Scope", "alertRestriction": "Restriction", diff --git a/src/views/Home/AlertsView/AlertsAside/AlertDetail/index.tsx b/src/views/Home/AlertsView/AlertsAside/AlertDetail/index.tsx index 5da853bb..e9116970 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertDetail/index.tsx +++ b/src/views/Home/AlertsView/AlertsAside/AlertDetail/index.tsx @@ -4,20 +4,35 @@ import { useState, } from 'react'; import { Link } from 'react-router-dom'; -import { ShareBoxFillIcon } from '@ifrc-go/icons'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + ChevronRightLineIcon, + ShareBoxFillIcon, +} from '@ifrc-go/icons'; import { Container, - DateOutput, - List, - Tab, - TabList, + RadioInput, + RawList, Tabs, TextOutput, } from '@ifrc-go/ui'; -import { useTranslation } from '@ifrc-go/ui/hooks'; -import { listToMap } from '@togglecorp/fujs'; +import { + useButtonFeatures, + useTranslation, +} from '@ifrc-go/ui/hooks'; +import { + isNotDefined, + listToMap, +} from '@togglecorp/fujs'; -import { AlertInfoQuery } from '#generated/types/graphql'; +import { + AlertInfoQuery, + AlertInfoQueryVariables, +} from '#generated/types/graphql'; +import { stringIdSelector } from '#utils/selectors'; import AlertInfo from './AlertInfo'; @@ -25,24 +40,87 @@ import i18n from './i18n.json'; import styles from './styles.module.css'; type InfoAlertType = NonNullable['alert']>; +type InfosDetail = InfoAlertType['infos'][number]; + +const ALERT_INFO = gql` +query AlertInfo($alert: ID!) { + public { + alert(pk: $alert) { + info { + event + categoryDisplay + category + language + responseType + responseTypeDisplay + urgencyDisplay + severityDisplay + certaintyDisplay + id + } + infos { + id + language + event + urgencyDisplay + severityDisplay + responseTypeDisplay + certaintyDisplay + parameters { + id + value + valueName + } + parameter + areas { + polygons { + value + id + alertInfoAreaId + } + id + } + } + sender + sent + admin1s { + isUnknown + } + url + identifier + scope + restriction + references + } + } + } +`; -export interface AlertProps { - data: InfoAlertType; +export interface Props { + alertId: string; } -type TabKey = string[]; -const keySelector = (info: string) => Number(info); +function AlertDetail(props: Props) { + const { alertId } = props; -function AlertDetail(props: AlertProps) { + const [activeTab, setActiveTab] = useState(); const { - data, - } = props; + data: alertInfoResponse, + } = useQuery( + ALERT_INFO, + { + variables: { alert: alertId }, + onCompleted: (response) => { + setActiveTab(response.public.alert?.infos?.[0]?.id); + }, + }, + ); const strings = useTranslation(i18n); - const [tabKeys, setTabKeys] = useState([]); - const [activeTab, setActiveTab] = useState(tabKeys?.[0]); - const unknownAdmin1Alerts = data?.admin1s?.map((admin) => admin.isUnknown); + const data = alertInfoResponse?.public?.alert; + + const unknownAdmin1Alerts = data?.admin1s?.some((admin) => admin.isUnknown); useMemo(() => { const newList = listToMap( @@ -50,97 +128,117 @@ function AlertDetail(props: AlertProps) { (d) => d.id, (d) => d?.language, ); - setTabKeys(Object.keys(newList)); setActiveTab(Object.keys(newList)?.[0]); return newList; }, [data?.infos]); - // NOTE: tab are dynamic as per language - const getTabName = useCallback((index: number) => `Info ${index + 1}`, []); + const rendererParams = useCallback( + (_: string, info: InfosDetail) => ({ + data: info, + }), + [], + ); + + const originLinkProps = useButtonFeatures({ + icons: , + children: strings.alertOrigin, + }); - const rendererParams = useCallback((key: number, info: InfoAlertType) => ({ - infoId: key, - data: info, - } - ), []); + const moreDetailsLinkProps = useButtonFeatures({ + actions: , + children: 'View more details', + }); return ( - {unknownAdmin1Alerts && ( -
+ headingLevel={3} + contentViewType="vertical" + headerDescription={unknownAdmin1Alerts && ( +
{strings.alertUnknownAdmin1}
)} - - {data?.sender} - {' '} - ( - - ) - + spacing="comfortable" + > +
+ + + {data?.url && ( + )} - withoutLabelColon - /> - {data?.url && ( - - - {strings.alertOrigin} - - )} - - - - -
+ + + + +
+ - - {/* TODO: use list for tab */} - {tabKeys?.map((tab, index: number) => ( - - {getTabName(index)} - - ))} - - language ?? '--'} + keySelector={stringIdSelector} + value={activeTab} + onChange={setActiveTab} + /> + -
+ + ); } diff --git a/src/views/Home/AlertsView/AlertsAside/AlertDetail/styles.module.css b/src/views/Home/AlertsView/AlertsAside/AlertDetail/styles.module.css index 25abd8b5..43780b7d 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertDetail/styles.module.css +++ b/src/views/Home/AlertsView/AlertsAside/AlertDetail/styles.module.css @@ -1,29 +1,22 @@ .alert-details { - .content { + .tag { display: flex; - flex-direction: column; - gap: var(--go-ui-border-radius-lg); + align-items: center; + border-radius: var(--go-ui-border-radius-2xl); + background-color: var(--go-ui-color-gray-30); + padding: var(--go-ui-spacing-4xs) var(--go-ui-spacing-sm); + width: fit-content; + text-decoration: none; + font-weight: var(--go-ui-font-weight-medium); + } - .alert-button { - display: flex; - gap: var(--go-ui-border-radius-sm); - align-items: center; - border-radius: var(--go-ui-border-radius-2xl); - background-color: var(--go-ui-color-primary-red); - padding: var(--go-ui-spacing-4xs) var(--go-ui-spacing-sm); - width: fit-content; - text-decoration: none; - color: var(--go-ui-color-white); - font-weight: var(--go-ui-font-weight-medium); - } + .reference-value { + word-break: break-word; + } - .alert-button:hover { - text-decoration: underline; - } - .alert-tabs { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-lg); - } + .metadata { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-xs); } } diff --git a/src/views/Home/AlertsView/AlertsAside/AlertListItem/index.tsx b/src/views/Home/AlertsView/AlertsAside/AlertListItem/index.tsx index 7f2452a2..9e5753f6 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertListItem/index.tsx +++ b/src/views/Home/AlertsView/AlertsAside/AlertListItem/index.tsx @@ -1,46 +1,36 @@ -import { - Button, - Container, - Header, -} from '@ifrc-go/ui'; +import { Button } from '@ifrc-go/ui'; -import { CountryAlertsListQuery } from '#generated/types/graphql'; +import { CountryAlertsQuery } from '#generated/types/graphql'; import styles from './styles.module.css'; -type Alert = NonNullable['alerts']>['items'][number]; +type Alert = NonNullable['alerts']>['items'][number]; export interface Props { data: Alert; - onCountryClick: (id: string) => void; + onClick: (id: string) => void; } function AlertListItem(props: Props) { const { data, - onCountryClick, + onClick, } = props; return ( - + {data.info?.categoryDisplay} +
+ )} > - -
+ {data.info?.event} + ); } diff --git a/src/views/Home/AlertsView/AlertsAside/AlertListItem/styles.module.css b/src/views/Home/AlertsView/AlertsAside/AlertListItem/styles.module.css index c120a701..c31c5c34 100644 --- a/src/views/Home/AlertsView/AlertsAside/AlertListItem/styles.module.css +++ b/src/views/Home/AlertsView/AlertsAside/AlertListItem/styles.module.css @@ -1,22 +1,11 @@ .alert-list-item { - display: flex; - - .header { - display: flex; - - .heading-container { - display: flex; - flex-direction: column; - - .heading { - flex-grow: 0; - } - } + text-align: left; + + .tag { + border-radius: var(--go-ui-font-size-sm); + background-color: var(--go-ui-color-gray-30); + padding: var(--go-ui-spacing-4xs) var(--go-ui-spacing-xs); + font-size: var(--go-ui-font-size-xs); + font-weight: var(--go-ui-font-weight-normal); } - - .info { - display: flex; - overflow-y: hidden; - } - -} \ No newline at end of file +} diff --git a/src/views/Home/AlertsView/AlertsAside/CountryAdmin1List/index.tsx b/src/views/Home/AlertsView/AlertsAside/CountryAdmin1List/index.tsx new file mode 100644 index 00000000..2a7108ae --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/CountryAdmin1List/index.tsx @@ -0,0 +1,96 @@ +import { + useCallback, + useContext, + useMemo, +} from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + Container, + RawList, +} from '@ifrc-go/ui'; +import { isNotDefined } from '@togglecorp/fujs'; + +import { + CountryAdmin1Query, + CountryAdmin1QueryVariables, +} from '#generated/types/graphql'; +import { stringIdSelector } from '#utils/selectors'; + +import AlertContext from '../../AlertContext'; +import Admin1ListItem from '../Admin1ListItem'; + +type CountryAdmin1 = NonNullable['country']>['admin1s'][number]; + +const COUNTRY_ADMIN1 = gql` +query CountryAdmin1($countryId: ID!) { + public { + id + country(pk: $countryId) { + id + name + alertCount + ifrcGoId + admin1s(alertFilters: {}) { + id + name + ifrcGoId + filteredAlertCount + } + } + } + } +`; + +interface Props { + countryId: string; +} + +function CountryAdmin1List(props: Props) { + const { countryId } = props; + const { setActiveAdmin1Id } = useContext(AlertContext); + + const variables = useMemo( + () => ({ countryId }), + [countryId], + ); + + const { + data: countryAdmin1Response, + } = useQuery( + COUNTRY_ADMIN1, + { + skip: isNotDefined(variables), + variables, + }, + ); + + const admin1RendererParams = useCallback( + (_: string, value: CountryAdmin1) => ({ + data: value, + onAdmin1Click: setActiveAdmin1Id, + }), + [setActiveAdmin1Id], + ); + + return ( + + + + ); +} + +export default CountryAdmin1List; diff --git a/src/views/Home/AlertsView/AlertsAside/CountryAlerts/index.tsx b/src/views/Home/AlertsView/AlertsAside/CountryAlerts/index.tsx new file mode 100644 index 00000000..3453a817 --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/CountryAlerts/index.tsx @@ -0,0 +1,125 @@ +import { + useCallback, + useContext, + useMemo, + useState, +} from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + Container, + Pager, + RawList, +} from '@ifrc-go/ui'; +import { + isDefined, + isNotDefined, +} from '@togglecorp/fujs'; + +import { + CountryAlertsQuery, + CountryAlertsQueryVariables, +} from '#generated/types/graphql'; +import { stringIdSelector } from '#utils/selectors'; + +import AlertContext from '../../AlertContext'; +import AlertListItem from '../AlertListItem'; + +const COUNTRY_ALERTS = gql` +query CountryAlerts( + $countryId: ID!, + $pagination: OffsetPaginationInput +){ + public { + alerts( + filters: {country: {pk: $countryId}} + pagination: $pagination + ) { + count + items { + id + info { + event + categoryDisplay + } + } + } + } +} +`; + +type Alert = NonNullable['alerts']>['items']>[number]; + +const MAX_ITEM_PER_PAGE = 15; + +interface Props { + countryId: string; +} + +function CountryAlerts(props: Props) { + const { countryId } = props; + const { setActiveAlertId } = useContext(AlertContext); + + const [activePage, setActivePage] = useState(1); + + const variables = useMemo(() => ({ + countryId, + pagination: { + offset: (activePage - 1) * MAX_ITEM_PER_PAGE, + limit: MAX_ITEM_PER_PAGE, + }, + }), [ + activePage, + countryId, + ]); + + const { + previousData, + data: countryAlertList = previousData, + error: countryAlertError, + loading: countryAlertPending, + } = useQuery( + COUNTRY_ALERTS, + { + variables, + skip: isNotDefined(countryId), + }, + ); + + const alertRendererParams = useCallback( + (_: string, value: Alert) => ({ + data: value, + onClick: setActiveAlertId, + }), + [setActiveAlertId], + ); + + return ( + + )} + // TODO: add filtered state + filtered={false} + errored={isDefined(countryAlertError)} + pending={countryAlertPending} + contentViewType="vertical" + > + + + ); +} + +export default CountryAlerts; diff --git a/src/views/Home/AlertsView/AlertsAside/CountryDetail/i18n.json b/src/views/Home/AlertsView/AlertsAside/CountryDetail/i18n.json new file mode 100644 index 00000000..d6be3dcd --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/CountryDetail/i18n.json @@ -0,0 +1,8 @@ +{ + "namespace": "countryDetail", + "strings": { + "alertBack": "Back", + "alertsAsideAlert": "Alerts", + "alertsAsideAdmin": "Admin-1" + } +} diff --git a/src/views/Home/AlertsView/AlertsAside/CountryDetail/index.tsx b/src/views/Home/AlertsView/AlertsAside/CountryDetail/index.tsx new file mode 100644 index 00000000..4df782d6 --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/CountryDetail/index.tsx @@ -0,0 +1,146 @@ +import { + useContext, + useMemo, + useState, +} from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + Container, + Tab, + TabList, + TabPanel, + Tabs, +} from '@ifrc-go/ui'; +import { useTranslation } from '@ifrc-go/ui/hooks'; +import { + isDefined, + isNotDefined, +} from '@togglecorp/fujs'; + +import { + CountryDetailQuery, + CountryDetailQueryVariables, +} from '#generated/types/graphql'; + +import AlertContext from '../../AlertContext'; +import Admin1Alerts from '../Admin1Alerts'; +import AlertDetail from '../AlertDetail'; +import CountryAdmin1List from '../CountryAdmin1List'; +import CountryAlerts from '../CountryAlerts'; + +import i18n from './i18n.json'; +import styles from './styles.module.css'; + +const COUNTRY_DETAIL = gql` +query CountryDetail($countryId: ID!) { + public { + country(pk: $countryId) { + filteredAlertCount + bbox + name + iso3 + ifrcGoId + alertCount + admin1s { + countryId + filteredAlertCount + id + name + } + id + } + } +} +`; + +interface Props { + countryId: string; +} + +function CountryDetail(props: Props) { + const { countryId } = props; + const strings = useTranslation(i18n); + const { + setBbox, + activeAlertId, + activeAdmin1Id, + setActiveCountryName, + setActiveGoCountryId, + } = useContext(AlertContext); + + useQuery( + COUNTRY_DETAIL, + { + variables: isDefined(countryId) ? { countryId } : undefined, + skip: isNotDefined(countryId), + onCompleted: (response) => { + setBbox(response.public.country?.bbox); + setActiveCountryName(response.public.country?.name); + setActiveGoCountryId(response.public.country?.ifrcGoId ?? undefined); + }, + }, + ); + + type TabKey = 'alerts' | 'admin1'; + const [activeTab, setActiveTab] = useState('alerts'); + + const children = useMemo( + () => { + if (isDefined(activeAlertId)) { + return ( + + ); + } + + if (isDefined(activeAdmin1Id)) { + return ( + + ); + } + + return ( + + + + + {strings.alertsAsideAlert} + + + {strings.alertsAsideAdmin} + + + + + + + + + + + ); + }, + [activeAlertId, activeAdmin1Id, activeTab, strings, countryId], + ); + + return children; +} + +export default CountryDetail; diff --git a/src/views/Home/AlertsView/AlertsAside/CountryDetail/styles.module.css b/src/views/Home/AlertsView/AlertsAside/CountryDetail/styles.module.css new file mode 100644 index 00000000..75c7450a --- /dev/null +++ b/src/views/Home/AlertsView/AlertsAside/CountryDetail/styles.module.css @@ -0,0 +1,6 @@ +.country-details { + .tab-list { + display: flex; + align-self: center; + } +} diff --git a/src/views/Home/AlertsView/AlertsAside/CountryListItem/index.tsx b/src/views/Home/AlertsView/AlertsAside/CountryListItem/index.tsx index 6ea7a427..b0e2cc7c 100644 --- a/src/views/Home/AlertsView/AlertsAside/CountryListItem/index.tsx +++ b/src/views/Home/AlertsView/AlertsAside/CountryListItem/index.tsx @@ -11,7 +11,7 @@ type Country = NonNullable['allCountries export interface CountryProps { data: Country; - onCountryClick: (id: string) => void; + onCountryClick: (id: string | undefined) => void; } function CountryListItem(props: CountryProps) { diff --git a/src/views/Home/AlertsView/AlertsAside/i18n.json b/src/views/Home/AlertsView/AlertsAside/i18n.json index 0f65c9aa..f9afc5f4 100644 --- a/src/views/Home/AlertsView/AlertsAside/i18n.json +++ b/src/views/Home/AlertsView/AlertsAside/i18n.json @@ -2,8 +2,6 @@ "namespace": "alertsAside", "strings": { "alertCountries": "Countries", - "alertBack": "Back", - "alertsAsideAlert": "Alerts", - "alertsAsideAdmin": "Admin-1" + "alertBack": "Back to countries" } -} \ No newline at end of file +} diff --git a/src/views/Home/AlertsView/AlertsAside/index.tsx b/src/views/Home/AlertsView/AlertsAside/index.tsx index a9592da6..a4d60f10 100644 --- a/src/views/Home/AlertsView/AlertsAside/index.tsx +++ b/src/views/Home/AlertsView/AlertsAside/index.tsx @@ -1,22 +1,12 @@ import { useCallback, - useMemo, - useState, + useContext, } from 'react'; -import { - gql, - useQuery, -} from '@apollo/client'; import { ChevronLeftLineIcon } from '@ifrc-go/icons'; import { Button, Container, - List, - Pager, - Tab, - TabList, - TabPanel, - Tabs, + RawList, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { @@ -25,162 +15,57 @@ import { isNotDefined, } from '@togglecorp/fujs'; -import { - Admin1AlertListQuery, - AlertInfoQuery, - CountryAdmin1Query, - CountryAdmin1QueryVariables, - CountryAlertsListQuery, - CountryListQuery, -} from '#generated/types/graphql'; +import { CountryListQuery } from '#generated/types/graphql'; import { stringIdSelector } from '#utils/selectors'; -import Admin1ListItem from './Admin1ListItem'; -import AlertDetail from './AlertDetail'; -import AlertListItem from './AlertListItem'; +import AlertContext from '../AlertContext'; +import CountryDetail from './CountryDetail'; import CountryListItem from './CountryListItem'; import i18n from './i18n.json'; import styles from './styles.module.css'; -const COUNTRY_ADMIN1 = gql` -query CountryAdmin1($pk: ID!) { - public { - id - country(pk: $pk) { - id - name - alertCount - ifrcGoId - admin1s(alertFilters: {}) { - id - name - ifrcGoId - filteredAlertCount - } - } - } - } -`; - type Country = NonNullable['allCountries']>[number]; -type CountryAdmin1 = NonNullable['country']>['admin1s'][number]; - -type Alert = NonNullable['alerts']>['items']>[number]; - -type AlertInfoDetail = NonNullable['alert']>['info']>; - -type Admin1Alerts = NonNullable['alerts']>['items'][number]; - interface Props { className?: string; countriesWithAlert?: Country[]; - alertsPending: boolean; - alertsFetchError: boolean; - alertsFiltered: boolean; - activeCountryId?: string; - handleCountryClick: (id: string | undefined) => void; - activeCountryName?: string; - countryAlerts?: Alert[]; - activePage: number; - setActivePage: (page: number) => void; - totalAlertCount: number; - activeAlertId?: string; - handleAlertClick: (id: string | undefined) => void; - alertInfo?: AlertInfoDetail[]; - activeAdmin1Id?: string; - setActiveAdmin1Id?: (id: string | undefined) => void; - admin1Alerts: Admin1Alerts[]; - activeAdmin1Page: number; - setActiveAdmin1Page: (page: number) => void; - admin1AlertCount: number; } -const defaultMaxItemsPerPage = 10; - export type TabKeys = 'admin1' | 'alert'; function AlertsAside(props: Props) { const { className, countriesWithAlert, - alertsPending, - alertsFetchError, - alertsFiltered, - handleCountryClick, - activeCountryId, - activeCountryName, - countryAlerts, - activePage, - setActivePage, - totalAlertCount, - handleAlertClick, - activeAlertId, - alertInfo, - activeAdmin1Id, - setActiveAdmin1Id, - admin1Alerts, - activeAdmin1Page, - setActiveAdmin1Page, - admin1AlertCount, } = props; const strings = useTranslation(i18n); - const [activeTab, setActiveTab] = useState('alert'); - - const variables: CountryAdmin1QueryVariables = useMemo(() => ({ - pk: activeCountryId, - }), [activeCountryId]); - const { - data: countryAdmin1Response, - } = useQuery( - COUNTRY_ADMIN1, - { - skip: isNotDefined(variables), - variables, - }, - ); + const { activeCountryId, activeCountryName, setActiveCountryId } = useContext(AlertContext); const countryRendererParams = useCallback( (_: string, value: Country) => ({ data: value, - onCountryClick: handleCountryClick, + onCountryClick: setActiveCountryId, }), - [handleCountryClick], - ); - - const alertRendererParams = useCallback( - (_: string, value: Alert) => ({ - data: value, - onCountryClick: handleAlertClick, - }), - [handleAlertClick], - ); - - const admin1RendererParams = useCallback( - (_: string, value: CountryAdmin1) => ({ - data: value, - onAdmin1Click: setActiveAdmin1Id, - }), - [setActiveAdmin1Id], + [setActiveCountryId], ); return ( @@ -189,117 +74,22 @@ function AlertsAside(props: Props) { {strings.alertBack} )} + withInternalPadding + contentViewType="vertical" > {isNotDefined(activeCountryId) && ( - )} -
- {isDefined(activeCountryId) && ( - - - - {strings.alertsAsideAlert} - - - {strings.alertsAsideAdmin} - - - - {isDefined(activeCountryId) && isNotDefined(activeAlertId) && ( - - )} - > - - - )} - {isDefined(activeAlertId) && isDefined(activeCountryId) && ( - - )} - - - {isDefined(activeCountryId) && isNotDefined(activeAdmin1Id) && ( - - )} - - - )} -
- {isDefined(activeAdmin1Id) && ( - - )} - > - - + {isDefined(activeCountryId) && ( + )} - { - isDefined(activeAlertId) - && isDefined(activeCountryId) - && isDefined(activeAdmin1Id) && ( - - ) - }
); } diff --git a/src/views/Home/AlertsView/AlertsAside/styles.module.css b/src/views/Home/AlertsView/AlertsAside/styles.module.css index 6f7e4a1e..3fefe5de 100644 --- a/src/views/Home/AlertsView/AlertsAside/styles.module.css +++ b/src/views/Home/AlertsView/AlertsAside/styles.module.css @@ -1,15 +1,7 @@ .alert-aside { - .alert-tabs { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-lg); - } + background-color: var(--go-ui-color-background); .main-content { - .country-list { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xs); - } + overflow: auto; } -} \ No newline at end of file +} diff --git a/src/views/Home/AlertsView/AlertsMap/index.tsx b/src/views/Home/AlertsView/AlertsMap/index.tsx index e06a67c7..f8df1589 100644 --- a/src/views/Home/AlertsView/AlertsMap/index.tsx +++ b/src/views/Home/AlertsView/AlertsMap/index.tsx @@ -1,6 +1,10 @@ -import { useMemo } from 'react'; +import { + useContext, + useMemo, +} from 'react'; import { _cs, + isDefined, isNotDefined, unique, } from '@togglecorp/fujs'; @@ -10,7 +14,10 @@ import { MapLayer, } from '@togglecorp/re-map'; import getBbox from '@turf/bbox'; -import { type FillLayer } from 'mapbox-gl'; +import { + type FillLayer, + LngLatBoundsLike, +} from 'mapbox-gl'; import BaseMap from '#components/domain/BaseMap'; import { CountryListQuery } from '#generated/types/graphql'; @@ -19,30 +26,33 @@ import { COLOR_PRIMARY_RED, } from '#utils/constants'; +import AlertContext from '../AlertContext'; + import styles from './styles.module.css'; type CountryType = NonNullable['allCountries']>[number]; const DURATION_MAP_ZOOM = 1000; const DEFAULT_MAP_PADDING = 50; +const defaultBounds: LngLatBoundsLike = [-160, -60, 190, 80]; interface Props { className: string; countriesWithAlert?: CountryType[]; - countryBbox?: GeoJSON.FeatureCollection; - adminBbox?: GeoJSON.FeatureCollection; } function AlertsMap(props: Props) { const { countriesWithAlert, className, - countryBbox, - adminBbox, } = props; - const countryBounds = countryBbox ? getBbox(countryBbox) : undefined; - const adminbounds = adminBbox ? getBbox(adminBbox) : undefined; + const { + bbox, + activeGoCountryId, + } = useContext(AlertContext); + + const bounds = isDefined(bbox) ? getBbox(bbox) : defaultBounds; const countryFillOptions = useMemo>(() => { if (isNotDefined(countriesWithAlert)) { @@ -69,7 +79,17 @@ function AlertsMap(props: Props) { ...uniqueCountries.flatMap( (country) => [ country.iso3.toUpperCase(), - COLOR_PRIMARY_RED, + isDefined(activeGoCountryId) && country.ifrcGoId !== activeGoCountryId + ? COLOR_LIGHT_GREY + : [ + 'interpolate', + ['linear'], + ['number', Math.log(country.filteredAlertCount ?? 0)], + 0, + COLOR_LIGHT_GREY, + 10, + COLOR_PRIMARY_RED, + ], ], ), COLOR_LIGHT_GREY, @@ -79,7 +99,7 @@ function AlertsMap(props: Props) { visibility: 'visible', }, }; - }, [countriesWithAlert]); + }, [countriesWithAlert, activeGoCountryId]); return (
@@ -95,16 +115,9 @@ function AlertsMap(props: Props) { - {countryBounds && ( - - )} - {adminBbox && ( + {bounds && ( diff --git a/src/views/Home/AlertsView/AlertsMap/styles.module.css b/src/views/Home/AlertsView/AlertsMap/styles.module.css index 36d04f43..7124a2c4 100644 --- a/src/views/Home/AlertsView/AlertsMap/styles.module.css +++ b/src/views/Home/AlertsView/AlertsMap/styles.module.css @@ -3,6 +3,7 @@ .map-container { flex-grow: 1; + height: 40rem; } } diff --git a/src/views/Home/AlertsView/index.tsx b/src/views/Home/AlertsView/index.tsx index 700ce74e..a0d12ad9 100644 --- a/src/views/Home/AlertsView/index.tsx +++ b/src/views/Home/AlertsView/index.tsx @@ -13,21 +13,15 @@ import { useTranslation } from '@ifrc-go/ui/hooks'; import { _cs, isDefined, + isNotDefined, } from '@togglecorp/fujs'; import { - Admin1AlertListQuery, - Admin1AlertListQueryVariables, - Admin1ListQuery, - Admin1ListQueryVariables, - AlertInfoQuery, - AlertInfoQueryVariables, - CountryAlertsListQuery, - CountryAlertsListQueryVariables, CountryListQuery, CountryListQueryVariables, } from '#generated/types/graphql'; +import AlertContext, { AlertContextProps } from './AlertContext'; import AlertsAside from './AlertsAside'; import AlertsMap from './AlertsMap'; @@ -43,152 +37,15 @@ query CountryList { id iso3 filteredAlertCount - bbox + ifrcGoId } } } `; -const ADMIN1_LIST = gql` -query Admin1List { - public { - admin1s(filters: {}) { - items { - countryId - alertCount - name - id - bbox - } - } - } - } -`; - -const COUNTRY_ALERTS_LIST = gql` - query CountryAlertsList( - $country: ID!, - $pagination: OffsetPaginationInput - ) { - public { - alerts( - filters: { - country: { - pk: $country - } - } - pagination: $pagination - ) { - items { - infos { - event - category - headline - onset - severityDisplay - } - id - info { - event - category - } - } - limit - offset - count - } - } - } -`; - -const ALERT_INFO = gql` -query AlertInfo($alert: ID!) { - public { - alert(pk: $alert) { - info { - event - categoryDisplay - category - language - responseType - responseTypeDisplay - urgencyDisplay - severityDisplay - certaintyDisplay - id - } - infos { - id - language - event - urgencyDisplay - severityDisplay - responseTypeDisplay - certaintyDisplay - parameters { - id - value - valueName - } - parameter - areas { - polygons { - value - id - alertInfoAreaId - } - id - } - } - sender - sent - admin1s { - isUnknown - } - url - identifier - scope - restriction - references - } - } - } -`; - -const ADMIN1_ALERT_LIST = gql` -query Admin1AlertList( - $admin: ID!, - $pagination: OffsetPaginationInput -) { - public { - alerts(filters: { - admin1: $admin - }, pagination: $pagination) { - items { - id - info { - id - event - description - } - admin1s { - bbox - id - } - } - limit - offset - count - } - } - } -`; - export type AlertPointFeature = GeoJSON.Feature; export type TabKeys = 'admin1' | 'alert'; -const defaultMaxItemsPerPage = 15; - type AlertPointProperties = { id: string | number, } @@ -203,107 +60,70 @@ function AlertsView(props: Props) { const strings = useTranslation(i18n); const [activeCountryId, setActiveCountryId] = useState(undefined); + const [activeGoCountryId, setActiveGoCountryId] = useState(undefined); const [activeAlertId, setActiveAlertId] = useState(undefined); - const [activePage, setActivePage] = useState(1); const [activeAdmin1Id, setActiveAdmin1Id] = useState(undefined); + const [activeGoAdmin1Id, setActiveGoAdmin1Id] = useState(undefined); const { - data: countryResponse, - loading: countryLoading, - error: countryError, + data: countryListResponse, + loading: countryListLoading, + error: countryListError, } = useQuery( COUNTRIES_LIST, ); - const { - data: admin1Response, - } = useQuery( - ADMIN1_LIST, - ); - - const variables = useMemo(() => { - const countryId = activeCountryId ?? ''; - return { - country: countryId, - pagination: { - offset: (activePage - 1) * defaultMaxItemsPerPage, - limit: defaultMaxItemsPerPage, - }, - alert: activeAlertId, - }; - }, [ - activePage, - activeCountryId, - activeAlertId, - ]); - - const { - data: countryAlertsResponse, - loading: countryAlertsLoading, - } = useQuery( - COUNTRY_ALERTS_LIST, - { - variables, - }, - ); - - const { - data: admin1AlertsListResponse, - } = useQuery( - ADMIN1_ALERT_LIST, - { - variables: { admin: activeAdmin1Id }, + const countriesWithAlert = useMemo(() => countryListResponse?.public.allCountries.filter( + (country) => (country?.filteredAlertCount ?? 0) > 0, + ), [countryListResponse?.public.allCountries]); + + const [bbox, setBbox] = useState(); + const [activeCountryName, setActiveCountryName] = useState(); + + const setActiveCountryIdSafe = useCallback( + (countryId: string | undefined) => { + setActiveCountryId(countryId); + setActiveCountryName(undefined); + setActiveAlertId(undefined); + setActiveAdmin1Id(undefined); + setActiveGoAdmin1Id(undefined); + setActiveGoCountryId(undefined); + if (isNotDefined(countryId)) { + setBbox(undefined); + } }, + [], ); - const { - data: alertInfoResponse, - } = useQuery( - ALERT_INFO, - { - variables: { alert: activeAlertId }, - }, + const alertContextValue = useMemo( + () => ({ + bbox, + setBbox, + activeAlertId, + activeCountryId, + activeCountryName, + activeAdmin1Id, + activeGoAdmin1Id, + activeGoCountryId, + setActiveAlertId, + setActiveGoCountryId, + setActiveGoAdmin1Id, + setActiveCountryId: setActiveCountryIdSafe, + setActiveAdmin1Id, + setActiveCountryName, + }), + [ + bbox, + activeCountryName, + activeAlertId, + activeGoCountryId, + activeGoAdmin1Id, + activeAdmin1Id, + activeCountryId, + setActiveCountryIdSafe, + ], ); - const setActiveCountryIdSafe = useCallback((countryId: string | number | undefined) => { - const countryIdSafe = countryId as string | undefined; - setActiveCountryId(countryIdSafe); - }, [setActiveCountryId]); - - const countriesWithAlert = useMemo(() => countryResponse?.public.allCountries.filter( - (country) => (country?.filteredAlertCount ?? 0) > 0, - ), [countryResponse?.public.allCountries]); - - const activeCountry = useMemo(() => { - if (isDefined(activeCountryId) && countriesWithAlert) { - return countriesWithAlert.find((country) => country.id === activeCountryId); - } - return undefined; - }, [ - activeCountryId, - countriesWithAlert, - ]); - - const activeAdmin1 = useMemo(() => { - if (isDefined(activeAdmin1Id) && admin1AlertsListResponse?.public?.alerts?.items) { - return admin1AlertsListResponse?.public?.alerts?.items?.find( - (admin) => admin.id === activeAlertId, - ); - } - return undefined; - }, [ - activeAdmin1Id, - admin1AlertsListResponse, - ]); - - const setActiveAlertIdSafe = useCallback((alertId: string | number | undefined) => { - const alertIdSafe = alertId as string | undefined; - setActiveAlertId(alertIdSafe); - }, [setActiveAlertId]); - - const totalAlertCount = countryAlertsResponse?.public.alerts.count ?? 0; - const admin1AlertCount = admin1AlertsListResponse?.public?.alerts?.count ?? 0; - return ( )} + pending={countryListLoading} + errored={isDefined(countryListError)} + errorMessage={countryListError?.message} + contentViewType="grid" + numPreferredGridContentColumns={3} > - - + + + + ); } diff --git a/src/views/Home/AlertsView/styles.module.css b/src/views/Home/AlertsView/styles.module.css index 513aeceb..e291b1cd 100644 --- a/src/views/Home/AlertsView/styles.module.css +++ b/src/views/Home/AlertsView/styles.module.css @@ -3,25 +3,15 @@ flex-direction: column; .main-content { - display: flex; - flex-grow: 1; - gap: var(--go-ui-spacing-md); - height: 45rem; - .alerts-map { - flex-grow: 1; + grid-column: span 2; } .alerts-aside { - display: flex; - flex-basis: 30%; + height: 40rem; overflow: auto; } - .alert-tab { - display: flex; - } - @media screen and (max-width: 50rem) { flex-direction: column; height: initial; diff --git a/src/views/Home/index.tsx b/src/views/Home/index.tsx index 31ec0ab5..0885e278 100644 --- a/src/views/Home/index.tsx +++ b/src/views/Home/index.tsx @@ -22,35 +22,37 @@ export function Component() { const [activeTab, setActiveTab] = useState('map'); return ( - - + + { strings.mapTabTitle } + + + { strings.tableTabTitle } + + + )} > - - - { strings.mapTabTitle } - - - { strings.tableTabTitle } - - - - + + ); } diff --git a/src/views/Home/styles.module.css b/src/views/Home/styles.module.css index 9b6e67e0..51c7cd65 100644 --- a/src/views/Home/styles.module.css +++ b/src/views/Home/styles.module.css @@ -4,8 +4,9 @@ flex-direction: column; gap: var(--go-ui-spacing-2xl); } - .heading-description { - max-width: var(--go-ui-page-header-description-width-max); - text-align: center; + + .tab-section { + display: flex; + justify-content: center; } } diff --git a/yarn.lock b/yarn.lock index 3c35f821..80b903f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1679,10 +1679,10 @@ resolved "https://registry.yarnpkg.com/@ifrc-go/icons/-/icons-1.3.3.tgz#6a4aaf8a06ba237d2de269e84a1561f0a395deb1" integrity sha512-43sLUn0jH3v+gkJC0bT6oYWlsPg9isAT/x/qYhmZHb53iQOlWjUC9fNNSQq3nzklH7+mvHhXFXBbotSeFEtLhw== -"@ifrc-go/ui@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@ifrc-go/ui/-/ui-1.0.0.tgz#e990e1940ef77d27b1cbce409e81b782f3974e68" - integrity sha512-ehnXZmDoUleR3OyfbkyguUhoTeae50gkztcnorp8NrdmEkzwTwu2cHRd8WShLBM8fUY2XNMO+ukuOogwmbH1HA== +"@ifrc-go/ui@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@ifrc-go/ui/-/ui-1.1.0.tgz#cef4c8b1f2649e462808c92a5cdbdea8d3f12ad8" + integrity sha512-IJDVQMk0ChnYoS5GNuY4UWMDxs1iU2yQVgxHywziNq4b0n7KQdh02tnc6zWlmo61+Eus1xJM4lFDZABeu8SikA== dependencies: "@changesets/cli" "^2.27.1" "@togglecorp/fujs" "^2.1.1" @@ -2431,34 +2431,6 @@ "@turf/helpers" "^6.5.0" "@turf/meta" "^6.5.0" -"@turf/buffer@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/buffer/-/buffer-6.5.0.tgz#22bd0d05b4e1e73eaebc69b8f574a410ff704842" - integrity sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg== - dependencies: - "@turf/bbox" "^6.5.0" - "@turf/center" "^6.5.0" - "@turf/helpers" "^6.5.0" - "@turf/meta" "^6.5.0" - "@turf/projection" "^6.5.0" - d3-geo "1.7.1" - turf-jsts "*" - -"@turf/center@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/center/-/center-6.5.0.tgz#3bcb6bffcb8ba147430cfea84aabaed5dbdd4f07" - integrity sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ== - dependencies: - "@turf/bbox" "^6.5.0" - "@turf/helpers" "^6.5.0" - -"@turf/clone@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/clone/-/clone-6.5.0.tgz#895860573881ae10a02dfff95f274388b1cda51a" - integrity sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw== - dependencies: - "@turf/helpers" "^6.5.0" - "@turf/helpers@^6.5.0": version "6.5.0" resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e" @@ -2471,15 +2443,6 @@ dependencies: "@turf/helpers" "^6.5.0" -"@turf/projection@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/projection/-/projection-6.5.0.tgz#d2aad862370bf03f2270701115464a8406c144b2" - integrity sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg== - dependencies: - "@turf/clone" "^6.5.0" - "@turf/helpers" "^6.5.0" - "@turf/meta" "^6.5.0" - "@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" @@ -4710,18 +4673,6 @@ csv@^5.5.3: csv-stringify "^5.6.5" stream-transform "^2.1.3" -d3-array@1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - -d3-geo@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.7.1.tgz#44bbc7a218b1fd859f3d8fd7c443ca836569ce99" - integrity sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw== - dependencies: - d3-array "1" - damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -10108,11 +10059,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -turf-jsts@*: - version "1.2.3" - resolved "https://registry.yarnpkg.com/turf-jsts/-/turf-jsts-1.2.3.tgz#59757f542afbff9a577bbf411f183b8f48d38aa4" - integrity sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA== - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"