diff --git a/package.json b/package.json index d86d312f..11e1bb7e 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,8 @@ "@togglecorp/fujs": "^2.1.1", "@togglecorp/re-map": "^0.2.0-beta-6", "@togglecorp/toggle-form": "^2.0.4", - "@turf/bbox": "^6.5.0", - "@turf/buffer": "^6.5.0", "graphql": "^16.8.1", "mapbox-gl": "^1.13.0", - "patch-package": "^8.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.22.3" diff --git a/src/utils/constants.ts b/src/utils/constants.ts index fec55790..b60c1ab9 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -4,7 +4,6 @@ export const DEFAULT_MAP_PADDING = 50; // Colors export const COLOR_LIGHT_GREY = '#e0e0e0'; -export const COLOR_RED = '#f5333f'; export const COLOR_PRIMARY_RED = '#f5333f'; export const COLOR_WHITE = '#ffffff'; export const COLOR_TEXT = '#313131'; diff --git a/src/views/AlertMap/AlertDetails/index.tsx b/src/views/AlertMap/AlertDetails/index.tsx deleted file mode 100644 index 5f916098..00000000 --- a/src/views/AlertMap/AlertDetails/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -function AlertDetails() { - return ( - <>Alert Details - ); -} - -export default AlertDetails; diff --git a/src/views/AlertMap/AlertListItem/i18n.json b/src/views/AlertMap/AlertListItem/i18n.json deleted file mode 100644 index 23311122..00000000 --- a/src/views/AlertMap/AlertListItem/i18n.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "namespace": "alertDetails", - "strings": { - "alertViewDetails": "View Details" - } -} \ No newline at end of file diff --git a/src/views/AlertMap/AlertListItem/index.tsx b/src/views/AlertMap/AlertListItem/index.tsx deleted file mode 100644 index 956d78d1..00000000 --- a/src/views/AlertMap/AlertListItem/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { ChevronRightLineIcon } from '@ifrc-go/icons'; -import { - Button, - Container, -} from '@ifrc-go/ui'; -import { useTranslation } from '@ifrc-go/ui/hooks'; - -import { AlertsInfoQuery } from '#generated/types'; - -import i18n from './i18n.json'; -import styles from './styles.module.css'; - -type Alert = NonNullable['alerts']>['items']>[number]; - -export interface Props { - data: Alert; - onExpandClick: (alertId: string | undefined) => void; -} - -function AlertListItem(props: Props) { - const { - data, - onExpandClick, - } = props; - - const strings = useTranslation(i18n); - - return ( - alert.event)} - actions={( - - )} - /> - ); -} - -export default AlertListItem; diff --git a/src/views/AlertMap/AlertListItem/styles.module.css b/src/views/AlertMap/AlertListItem/styles.module.css deleted file mode 100644 index fdad5d7c..00000000 --- a/src/views/AlertMap/AlertListItem/styles.module.css +++ /dev/null @@ -1,32 +0,0 @@ -.alert-info { - .alert-list-item { - gap: 0; - - .icon { - align-self: flex-end; - font-size: var(--go-ui-height-icon-multiplier); - }:hover { - .icon { - animation: wiggle var(--go-ui-duration-transition-slow) ease-in-out; - } - } - } - - @keyframes wiggle { - 0% { - transform: translateX(0); - } - - 25% { - transform: translateX(-0.1rem); - } - - 50% { - transform: translateX(0.1rem); - } - - 100% { - transform: translateX(0); - } - } -} \ No newline at end of file diff --git a/src/views/AlertMap/CountryListItem/index.tsx b/src/views/AlertMap/CountryListItem/index.tsx index 71c9606f..85bbcc24 100644 --- a/src/views/AlertMap/CountryListItem/index.tsx +++ b/src/views/AlertMap/CountryListItem/index.tsx @@ -12,12 +12,12 @@ import styles from './styles.module.css'; type CountryType = NonNullable['countries']>['items']>[number]; -export interface Props { +export interface CountryProps { data: CountryType; onExpandClick: (alertId: string | undefined) => void; } -function CountryListItem(props: Props) { +function CountryListItem(props: CountryProps) { const { data, onExpandClick, diff --git a/src/views/AlertMap/Filters/i18n.json b/src/views/AlertMap/Filters/i18n.json index 8514d8db..f9dadf6b 100644 --- a/src/views/AlertMap/Filters/i18n.json +++ b/src/views/AlertMap/Filters/i18n.json @@ -1,10 +1,9 @@ { - "namespace": "common", + "namespace": "alertFilters", "strings": { - "riskAllCountries": "All countries", - "riskSelectHazardTypes": "Select Hazard types", - "riskSelectMonths": "Select months", - "riskNormalize": "Normalize by population", - "riskCopingCapacity": "Include coping capacity" + "alertCountries": "All countries", + "alertUrgency": "Select Urgency type", + "alertSeverity": "Select Severity type", + "alertCertainty": "Select Certainty type" } } diff --git a/src/views/AlertMap/Filters/index.tsx b/src/views/AlertMap/Filters/index.tsx index 9f620c04..1df4e838 100644 --- a/src/views/AlertMap/Filters/index.tsx +++ b/src/views/AlertMap/Filters/index.tsx @@ -1,32 +1,44 @@ -import { useCallback, useMemo } from 'react'; -import { - MultiSelectInput, -} from '@ifrc-go/ui'; -import { gql } from '@apollo/client'; +import { useCallback } from 'react'; +import { MultiSelectInput } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { - stringNameSelector, -} from '@ifrc-go/ui/utils'; -import { listToGroupList } from '@togglecorp/fujs'; +import { stringNameSelector } from '@ifrc-go/ui/utils'; import { EntriesAsList } from '@togglecorp/toggle-form'; -import { CountryListQuery } from '#generated/types'; +import { + AlertEnumsQuery, + CountryListQuery, +} from '#generated/types'; import i18n from './i18n.json'; +import styles from './styles.module.css'; type CountryType = NonNullable['countries']>['items']>[number]; +interface AlertFilters { + key: string; + label: string; +} + const countryKeySelector = (country: CountryType) => country?.id; +const keySelector = (alert: AlertFilters) => alert?.key; +const labelSelector = (alert: AlertFilters) => alert?.label; + export interface FilterValue { countries: string[]; regions: string[]; + urgencyList: string[]; + severityList: string[]; + certaintyList: string[]; } interface Props { value: FilterValue; onChange: React.Dispatch>; countries?: NonNullable; + urgencyList?: NonNullable; + severityList?: NonNullable; + certaintyList?: NonNullable; } function Filters(props: Props) { @@ -34,6 +46,9 @@ function Filters(props: Props) { value, onChange, countries, + urgencyList, + severityList, + certaintyList, } = props; const strings = useTranslation(i18n); @@ -50,16 +65,45 @@ function Filters(props: Props) { ); return ( - +
+ + + + +
); } diff --git a/src/views/AlertMap/Filters/styles.module.css b/src/views/AlertMap/Filters/styles.module.css index 4d1ce575..07a3bfcd 100644 --- a/src/views/AlertMap/Filters/styles.module.css +++ b/src/views/AlertMap/Filters/styles.module.css @@ -1,5 +1,5 @@ .filters { display: grid; - grid-gap: var(--go-ui-spacing-md); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); + grid-gap: var(--go-ui-spacing-md); } diff --git a/src/views/AlertMap/RegionListItem/i18n.json b/src/views/AlertMap/RegionListItem/i18n.json new file mode 100644 index 00000000..fd58cb69 --- /dev/null +++ b/src/views/AlertMap/RegionListItem/i18n.json @@ -0,0 +1,6 @@ +{ + "namespace": "ongoingAlertRegion", + "strings": { + "regionList": "Region List" + } +} diff --git a/src/views/AlertMap/RegionListItem/index.tsx b/src/views/AlertMap/RegionListItem/index.tsx new file mode 100644 index 00000000..1d3643f5 --- /dev/null +++ b/src/views/AlertMap/RegionListItem/index.tsx @@ -0,0 +1,79 @@ +import { useMemo } from 'react'; +import { + gql, + useQuery, +} from '@apollo/client'; +import { + BlockLoading, + Container, +} from '@ifrc-go/ui'; +import { useTranslation } from '@ifrc-go/ui/hooks'; + +import { + Admin1ListQuery, + Admin1ListQueryVariables, +} from '#generated/types'; + +import i18n from './i18n.json'; +import styles from './styles.module.css'; + +const ADMIN1_LIST = gql` +query Admin1List { + public { + admin1s { + items { + countryId + name + } + } + } + } +`; + +export interface RegionProps { + countryId: string | undefined; +} + +function RegionListItem(props: RegionProps) { + const { + countryId, + } = props; + + const strings = useTranslation(i18n); + + const { + data: admin1ListResponse, + loading: admin1ListLoading, + } = useQuery( + ADMIN1_LIST, + ); + + const filteredAdmins = useMemo(() => { + if (!countryId || !admin1ListResponse?.public?.admin1s?.items) return []; + + return admin1ListResponse.public.admin1s.items + .filter((item) => countryId.includes(item.countryId)) + .map((item) => item.name); + }, [countryId, admin1ListResponse]); + + return ( + + {admin1ListLoading && } +
+ {filteredAdmins.map((name) => ( +
+ {name} +
+ ))} +
+
+ ); +} + +export default RegionListItem; diff --git a/src/views/AlertMap/RegionListItem/styles.module.css b/src/views/AlertMap/RegionListItem/styles.module.css new file mode 100644 index 00000000..1fbd139c --- /dev/null +++ b/src/views/AlertMap/RegionListItem/styles.module.css @@ -0,0 +1,13 @@ +.alerts { + .content { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-lg); + + .alert-details { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-2xs); + } + } +} diff --git a/src/views/AlertMap/index.tsx b/src/views/AlertMap/index.tsx index faf3b19d..14705e2c 100644 --- a/src/views/AlertMap/index.tsx +++ b/src/views/AlertMap/index.tsx @@ -10,7 +10,6 @@ import { } from '@apollo/client'; import { ChevronLeftLineIcon } from '@ifrc-go/icons'; import { - BlockLoading, Button, Container, List, @@ -34,15 +33,14 @@ import type { import BaseMap from '#components/domain/BaseMap'; import MapPopup from '#components/MapPopup'; -import useDebouncedValue from '#hooks/useDebouncedValue'; -import useInputState from '#hooks/useInputState'; - import { - AlertsInfoQuery, - AlertsInfoQueryVariables, + AlertEnumsQuery, + AlertEnumsQueryVariables, CountryListQuery, CountryListQueryVariables, } from '#generated/types'; +import useDebouncedValue from '#hooks/useDebouncedValue'; +import useInputState from '#hooks/useInputState'; import { COLOR_LIGHT_GREY, COLOR_PRIMARY_RED, @@ -50,88 +48,12 @@ import { DURATION_MAP_ZOOM, } from '#utils/constants'; -import CountryListItem from './CountryListItem'; -import i18n from './i18n.json'; -import styles from './styles.module.css'; +import CountryListItem, { CountryProps } from './CountryListItem'; import Filters, { FilterValue } from './Filters'; +import RegionListItem from './RegionListItem'; -const ALERTS_INFO = gql` -query AlertsInfo { - public { - alerts { - items { - id - addresses - country { - centroid - continent { - id - } - admin1s { - countryId - id - isUnknown - maxLatitude - maxLongitude - minLatitude - minLongitude - multipolygon - name - country { - id - iso3 - name - admin1s { - country { - id - name - iso3 - } - countryId - id - } - } - } - iso3 - id - name - region { - id - name - centroid - } - regionId - } - infos { - alertId - audience - category - categoryDisplay - certainty - certaintyDisplay - contact - effective - event - eventCode - expires - headline - id - instruction - language - onset - parameter - parameters { - id - } - } - countryId - } - limit - offset - } - } - } -`; +import i18n from './i18n.json'; +import styles from './styles.module.css'; const COUNTRIES_LIST = gql` query CountryList { @@ -143,10 +65,6 @@ query CountryList { admin1s { name id - country { - iso3 - name - } } iso3 } @@ -154,46 +72,54 @@ query CountryList { } }`; +const ALERT_ENUMS = gql` +query AlertEnums { + enums { + AlertInfoCertainty { + key + label + } + AlertInfoUrgency { + label + key + } + AlertInfoSeverity { + key + label + } + } +}`; + const defaultFilterValue: FilterValue = { countries: [], regions: [], + urgencyList: [], + severityList: [], + certaintyList: [], }; -type AlertType = NonNullable['alerts']>['items']>[number]; - type CountryType = NonNullable['countries']>['items']>[number]; -type Footprint = GeoJSON.FeatureCollection | undefined; +export type AlertPointFeature = GeoJSON.Feature; -type EventPointProperties = { +type AlertPointProperties = { id: string | number, - alert_type: AlertType, } -export type EventPointFeature = GeoJSON.Feature; -type Props = { +type Props = { className?: string; bbox: LngLatBoundsLike | undefined; - onActiveCountryChange: (countryId: | undefined) => void; - footprintSelector: (activeCountryExposure: EXPOSURE | undefined) => Footprint | undefined; - pointFeatureSelector: (countryId: EVENT) => EventPointFeature | undefined; - activeCountryExposurePending: boolean; - activeCountryExposure: EXPOSURE | undefined; + onActiveCountryChange: (countryId: string | undefined) => void; } -const keySelector = (alert: AlertType) => alert?.id; - const countryKeySelector = (country: CountryType) => country?.id; interface ClickedPoint { - feature: GeoJSON.Feature; + feature: GeoJSON.Feature; lngLat: mapboxgl.LngLatLike; } -function OngoingAlertMap< - EVENT, - EXPOSURE, ->(props: Props) { +function OngoingAlertMap(props: Props) { const { className, bbox, @@ -201,14 +127,7 @@ function OngoingAlertMap< } = props; const strings = useTranslation(i18n); - const [activeCountryId, setActiveCountryId] = useState(undefined); - - const { - data: alertsResponse, - loading: alertLoading, - } = useQuery( - ALERTS_INFO, - ); + const [activeCountryId, setActiveCountryId] = useState(undefined); const { data: countryResponse, @@ -217,23 +136,28 @@ function OngoingAlertMap< COUNTRIES_LIST, ); + const { + data: alertEnumsResponse, + } = useQuery( + ALERT_ENUMS, + ); - const activeAlerts = useMemo( + const activeCountry = useMemo( () => { if (isNotDefined(activeCountryId)) { return undefined; } - return alertsResponse?.public.alerts.items?.filter( - ({ countryId }) => activeCountryId === countryId, + return countryResponse?.public.countries.items?.filter( + ({ id }) => activeCountryId === id, ); }, - [activeCountryId, alertsResponse], + [activeCountryId, countryResponse], ); const bounds = useMemo( () => { - if (isNotDefined(activeCountryId)) { + if (isNotDefined(activeCountry)) { return bbox; } @@ -241,6 +165,7 @@ function OngoingAlertMap< }, [ bbox, + activeCountry, ], ); @@ -258,30 +183,20 @@ function OngoingAlertMap< [setClickedPointProperties], ); - const setActiveAlertIdSafe = useCallback( - (countryId: string | number | undefined) => { - const countryIdSafe = countryId; - - setActiveCountryId(countryIdSafe); - onActiveCountryChange(countryIdSafe); + const setActiveCountryIdSafe = useCallback( + (countryId: string | undefined) => { + setActiveCountryId(countryId); + onActiveCountryChange(countryId); }, - [onActiveCountryChange], - ); - - const eventListRendererParams = useCallback( - (_: string | number, alert: AlertType) => ({ - data: alert, - onExpandClick: setActiveAlertIdSafe, - }), - [setActiveAlertIdSafe], + [onActiveCountryChange, setActiveCountryId], ); const countryListRendererParams = useCallback( - (_: string | number, country: CountryType) => ({ + (_: string | number, country: CountryType): CountryProps => ({ data: country, - // onExpandClick: setActiveAlertIdSafe, + onExpandClick: setActiveCountryIdSafe, }), - [], + [setActiveCountryIdSafe], ); const handleCountryClick = useCallback(( @@ -329,7 +244,7 @@ function OngoingAlertMap< visibility: 'visible', }, }; - }, [alertsResponse]); + }, [countryResponse]); const [filters, setFilters] = useInputState(defaultFilterValue); @@ -353,6 +268,9 @@ function OngoingAlertMap< countries={countryResponse?.public?.countries.items} value={filters} onChange={setFilters} + urgencyList={alertEnumsResponse?.enums?.AlertInfoUrgency} + severityList={alertEnumsResponse?.enums?.AlertInfoSeverity} + certaintyList={alertEnumsResponse?.enums?.AlertInfoCertainty} /> )} > @@ -389,7 +307,6 @@ function OngoingAlertMap< )} @@ -409,7 +326,7 @@ function OngoingAlertMap< )} > - {isDefined(countryResponse) && ( + {isDefined(countryResponse) && isNotDefined(activeCountryId) && ( )} - {alertLoading && } - {/* {isDefined(alertsResponse) && ( - - )} */} + )}
);