diff --git a/src/data/repositories/PerformanceOverviewD2Repository.ts b/src/data/repositories/PerformanceOverviewD2Repository.ts index 4987a874..44243d8d 100644 --- a/src/data/repositories/PerformanceOverviewD2Repository.ts +++ b/src/data/repositories/PerformanceOverviewD2Repository.ts @@ -5,7 +5,10 @@ import { apiToFuture, FutureData } from "../api-futures"; import { RTSL_ZEBRA_PROGRAM_ID } from "./consts/DiseaseOutbreakConstants"; import _ from "../../domain/entities/generic/Collection"; import { Future } from "../../domain/entities/generic/Future"; -import { evenTrackerCountsIndicatorMap, IndicatorsId } from "./consts/PerformanceOverviewConstants"; +import { + eventTrackerCountsIndicatorMap, + IndicatorsId, +} from "./consts/PerformanceOverviewConstants"; import moment from "moment"; import { DiseaseOutbreakEventBaseAttrs, @@ -38,12 +41,13 @@ export class PerformanceOverviewD2Repository implements PerformanceOverviewRepos getTotalCardCounts( allProvincesIds: string[], singleSelectFilters?: Record, - multiSelectFilters?: Record + multiSelectFilters?: Record, + dateRangeFilter?: string[] ): FutureData { return apiToFuture( this.api.analytics.get({ dimension: [ - `dx:${evenTrackerCountsIndicatorMap.map(({ id }) => id).join(";")}`, + `dx:${eventTrackerCountsIndicatorMap.map(({ id }) => id).join(";")}`, `ou:${ multiSelectFilters && multiSelectFilters?.province?.length ? multiSelectFilters.province.join(";") @@ -51,12 +55,12 @@ export class PerformanceOverviewD2Repository implements PerformanceOverviewRepos }`, ], startDate: - multiSelectFilters?.duration?.length && multiSelectFilters?.duration[0] - ? multiSelectFilters?.duration[0] + dateRangeFilter?.length && dateRangeFilter[0] + ? dateRangeFilter[0] : DEFAULT_START_DATE, endDate: - multiSelectFilters?.duration?.length && multiSelectFilters?.duration[1] - ? multiSelectFilters?.duration[1] + dateRangeFilter?.length && dateRangeFilter[1] + ? dateRangeFilter[1] : DEFAULT_END_DATE, includeMetadataDetails: true, }) @@ -88,7 +92,7 @@ export class PerformanceOverviewD2Repository implements PerformanceOverviewRepos ): TotalCardCounts[] => { const counts: TotalCardCounts[] = _( rowData.map(([id, _orgUnit, total]) => { - const indicator = evenTrackerCountsIndicatorMap.find(d => d.id === id); + const indicator = eventTrackerCountsIndicatorMap.find(d => d.id === id); if (!indicator || !total) { return null; } diff --git a/src/data/repositories/consts/PerformanceOverviewConstants.ts b/src/data/repositories/consts/PerformanceOverviewConstants.ts index 85ee59dd..8cf8049c 100644 --- a/src/data/repositories/consts/PerformanceOverviewConstants.ts +++ b/src/data/repositories/consts/PerformanceOverviewConstants.ts @@ -190,7 +190,7 @@ export type EventTrackerCountIndicator = | EventTrackerCountDiseaseIndicator | EventTrackerCountHazardIndicator; -export const evenTrackerCountsIndicatorMap: EventTrackerCountIndicator[] = [ +export const eventTrackerCountsIndicatorMap: EventTrackerCountIndicator[] = [ { id: "SGGbbu0AKUv", type: "disease", name: "Acute respiratory", incidentStatus: "Watch" }, { id: "QnhsQnEsp1p", type: "disease", name: "Acute respiratory", incidentStatus: "Alert" }, { id: "Rt5KNVqBEO7", type: "disease", name: "Acute respiratory", incidentStatus: "Respond" }, diff --git a/src/domain/repositories/PerformanceOverviewRepository.ts b/src/domain/repositories/PerformanceOverviewRepository.ts index 0d4e904c..174fc4a3 100644 --- a/src/domain/repositories/PerformanceOverviewRepository.ts +++ b/src/domain/repositories/PerformanceOverviewRepository.ts @@ -12,6 +12,7 @@ export interface PerformanceOverviewRepository { getTotalCardCounts( allProvincesIds: string[], singleSelectFilters?: Record, - multiSelectFilters?: Record + multiSelectFilters?: Record, + dateRangeFilter?: string[] ): FutureData; } diff --git a/src/domain/usecases/GetTotalCardCountsUseCase.ts b/src/domain/usecases/GetTotalCardCountsUseCase.ts index c429004c..939700ff 100644 --- a/src/domain/usecases/GetTotalCardCountsUseCase.ts +++ b/src/domain/usecases/GetTotalCardCountsUseCase.ts @@ -12,14 +12,16 @@ export class GetTotalCardCountsUseCase { ) {} public execute( singleSelectFilters?: Record, - multiSelectFilters?: Record + multiSelectFilters?: Record, + dateRangeFilter?: string[] ): FutureData { return this.options.orgUnitRepository.getByLevel(2).flatMap(allProvinces => { const allProvincesIds = allProvinces.map(province => province.id); return this.options.performanceOverviewRepository.getTotalCardCounts( allProvincesIds, singleSelectFilters, - multiSelectFilters + multiSelectFilters, + dateRangeFilter ); }); } diff --git a/src/webapp/components/date-picker/DatePicker.tsx b/src/webapp/components/date-picker/DatePicker.tsx index 0a1e995e..2bc295f1 100644 --- a/src/webapp/components/date-picker/DatePicker.tsx +++ b/src/webapp/components/date-picker/DatePicker.tsx @@ -16,6 +16,8 @@ type DatePickerProps = { disabled?: boolean; error?: boolean; required?: boolean; + disableFuture?: boolean; + maxDate?: Date; }; const slots = { openPickerIcon: IconCalendar24 }; @@ -31,6 +33,8 @@ export const DatePicker: React.FC = React.memo( errorText = "", error = false, required = false, + disableFuture = false, + maxDate, }) => { const notifyChange = useCallback( (date: Date | null) => { @@ -71,6 +75,8 @@ export const DatePicker: React.FC = React.memo( error={error} disabled={disabled} slotProps={slotProps} + disableFuture={disableFuture} + maxDate={maxDate} /> diff --git a/src/webapp/components/date-picker/DateRangePicker.tsx b/src/webapp/components/date-picker/DateRangePicker.tsx index 253b6745..a28404ba 100644 --- a/src/webapp/components/date-picker/DateRangePicker.tsx +++ b/src/webapp/components/date-picker/DateRangePicker.tsx @@ -1,5 +1,5 @@ import i18n from "../../../utils/i18n"; -import React, { useState, useEffect, useMemo } from "react"; +import React, { useState, useMemo, useCallback } from "react"; import { Popover, InputAdornment, TextField, InputLabel } from "@material-ui/core"; import moment from "moment"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; @@ -16,34 +16,29 @@ type DateRangePickerProps = { placeholder?: string; }; +const ID = "date-range-picker"; + export const DateRangePicker: React.FC = React.memo( ({ label = "", value, placeholder = "", onChange }) => { const [anchorEl, setAnchorEl] = useState(null); const [startDate, setStartDate] = useState(null); const [endDate, setEndDate] = useState(null); - const id = "date-range-picker"; - - useEffect(() => { - if (!value || value.length !== 2) { - setStartDate(moment().startOf("month").toDate()); - setEndDate(moment().toDate()); - } - }, [value]); - // Adjust startDate if endDate < startDate - useEffect(() => { - if (endDate && startDate && moment(endDate).isBefore(startDate)) { - setStartDate(endDate); - } - }, [startDate, endDate]); - - const handleOpen = (event: React.MouseEvent) => { + const handleOpen = useCallback((event: React.MouseEvent) => { setAnchorEl(event.currentTarget); - }; + }, []); - const handleClose = () => { + const onCleanValues = useCallback(() => { + setStartDate(null); + setEndDate(null); + }, []); + + const handleClose = useCallback(() => { setAnchorEl(null); - }; + if (!value.length) { + onCleanValues(); + } + }, [onCleanValues, value.length]); const formatDurationValue = useMemo(() => { if (!value || value.length !== 2) { @@ -55,12 +50,13 @@ export const DateRangePicker: React.FC = React.memo( )}`; }, [startDate, endDate, placeholder, value]); - const onReset = () => { + const onReset = useCallback(() => { onChange([]); + onCleanValues(); setAnchorEl(null); - }; + }, [onChange, onCleanValues]); - const onSave = () => { + const onSave = useCallback(() => { if (startDate && endDate) { setAnchorEl(null); onChange([ @@ -68,14 +64,14 @@ export const DateRangePicker: React.FC = React.memo( moment(endDate).format("YYYY-MM-DD"), ]); } - }; + }, [endDate, onChange, startDate]); return ( - {label && } + {label && } = React.memo( label="Start Date" value={startDate} onChange={date => setStartDate(date)} + maxDate={endDate ?? undefined} + disableFuture /> setEndDate(date)} + disableFuture /> @@ -140,6 +139,7 @@ const PopoverContainer = styled.div` const Container = styled.div` width: 100%; display: flex; + gap: 5px; justify-content: space-between; `; diff --git a/src/webapp/components/map/MapSection.tsx b/src/webapp/components/map/MapSection.tsx index 1edcdccb..ebf58741 100644 --- a/src/webapp/components/map/MapSection.tsx +++ b/src/webapp/components/map/MapSection.tsx @@ -12,13 +12,20 @@ type MapSectionProps = { mapKey: MapKey; singleSelectFilters?: Record; multiSelectFilters?: Record; + dateRangeFilter?: string[]; eventDiseaseCode?: string; eventHazardCode?: string; }; export const MapSection: React.FC = React.memo(props => { - const { mapKey, singleSelectFilters, multiSelectFilters, eventDiseaseCode, eventHazardCode } = - props; + const { + mapKey, + singleSelectFilters, + multiSelectFilters, + dateRangeFilter, + eventDiseaseCode, + eventHazardCode, + } = props; const { orgUnits } = useAppContext(); const snackbar = useSnackbar(); @@ -32,6 +39,7 @@ export const MapSection: React.FC = React.memo(props => { allOrgUnitsIds: allProvincesIds, singleSelectFilters: singleSelectFilters, multiSelectFilters: multiSelectFilters, + dateRangeFilter: dateRangeFilter, eventDiseaseCode: eventDiseaseCode, eventHazardCode: eventHazardCode, }); @@ -53,9 +61,9 @@ export const MapSection: React.FC = React.memo(props => { > {mapConfigState.kind === "loaded" && allProvincesIds.length !== 0 ? ( ) : null} diff --git a/src/webapp/components/map/useMap.ts b/src/webapp/components/map/useMap.ts index c8e11306..952506ae 100644 --- a/src/webapp/components/map/useMap.ts +++ b/src/webapp/components/map/useMap.ts @@ -49,6 +49,7 @@ export function useMap(params: { allOrgUnitsIds: string[]; eventDiseaseCode?: string; eventHazardCode?: string; + dateRangeFilter?: string[]; singleSelectFilters?: Record; multiSelectFilters?: Record; }): MapState { @@ -57,6 +58,7 @@ export function useMap(params: { allOrgUnitsIds, eventDiseaseCode, eventHazardCode, + dateRangeFilter, singleSelectFilters, multiSelectFilters, } = params; @@ -65,23 +67,16 @@ export function useMap(params: { const [mapConfigState, setMapConfigState] = useState({ kind: "loading", }); + const [defaultStartDate, setDefaultStartDate] = useState(""); useEffect(() => { if (mapConfigState.kind !== "loaded") return; const newStartDate = - multiSelectFilters?.duration?.length && - multiSelectFilters.duration[0] && - multiSelectFilters.duration[0] !== mapConfigState.data.startDate - ? multiSelectFilters.duration[0] - : null; + dateRangeFilter?.length && dateRangeFilter[0] ? dateRangeFilter[0] : defaultStartDate; const newEndDate = - multiSelectFilters?.duration?.length && - multiSelectFilters.duration[1] && - multiSelectFilters.duration[1] !== mapConfigState.data.endDate - ? multiSelectFilters.duration[1] - : null; + dateRangeFilter?.length && dateRangeFilter[1] ? dateRangeFilter[1] : undefined; const isDashboardMapAndThereAreFilters = mapKey === "dashboard" && @@ -117,7 +112,12 @@ export function useMap(params: { ? allOrgUnitsIds : null; - if (!newMapIndicator && !newOrgUnits && !newStartDate && !newEndDate) { + if ( + !newMapIndicator && + !newOrgUnits && + newStartDate === mapConfigState.data.startDate && + newEndDate === mapConfigState.data.endDate + ) { return; } else { setMapConfigState(prevMapConfigState => { @@ -135,10 +135,8 @@ export function useMap(params: { orgUnits: newOrgUnits ? newOrgUnits : prevMapConfigState.data.orgUnits, - startDate: newStartDate - ? newStartDate - : prevMapConfigState.data.startDate, - endDate: newEndDate ? newEndDate : prevMapConfigState.data.endDate, + startDate: newStartDate, + endDate: newEndDate, }, }; } else { @@ -151,7 +149,8 @@ export function useMap(params: { if ( mapKey === "event_tracker" && (eventDiseaseCode || eventHazardCode) && - (newStartDate || newEndDate) + (newStartDate !== mapConfigState.data.startDate || + newEndDate !== mapConfigState.data.endDate) ) { setMapConfigState(prevMapConfigState => { if (prevMapConfigState.kind === "loaded") { @@ -159,10 +158,8 @@ export function useMap(params: { kind: "loaded", data: { ...prevMapConfigState.data, - startDate: newStartDate - ? newStartDate - : prevMapConfigState.data.startDate, - endDate: newEndDate ? newEndDate : prevMapConfigState.data.endDate, + startDate: newStartDate, + endDate: newEndDate, }, }; } else { @@ -179,6 +176,8 @@ export function useMap(params: { mapProgramIndicators, multiSelectFilters, singleSelectFilters, + dateRangeFilter, + defaultStartDate, ]); useEffect(() => { @@ -189,6 +188,7 @@ export function useMap(params: { compositionRoot.maps.getConfig.execute(mapKey).run( config => { setMapProgramIndicators(config.programIndicators); + setDefaultStartDate(config.startDate); const mapProgramIndicator = mapKey === "dashboard" diff --git a/src/webapp/components/selector/MultipleSelector.tsx b/src/webapp/components/selector/MultipleSelector.tsx index ad9db1d8..06fc0d6e 100644 --- a/src/webapp/components/selector/MultipleSelector.tsx +++ b/src/webapp/components/selector/MultipleSelector.tsx @@ -72,7 +72,7 @@ export function MultipleSelector({ error={error} renderValue={(selected: unknown) => (selected as Value[])?.length ? ( -
+ {(selected as Value[]).map(value => ( ({ onMouseDown={event => handleDelete(event, value)} /> ))} -
+ ) : ( placeholder ) @@ -130,7 +130,7 @@ const StyledFormHelperText = styled(FormHelperText)<{ error?: boolean }>` `; const StyledSelect = styled(Select)<{ error?: boolean }>` - height: 40px; + min-height: 40px; .MuiOutlinedInput-notchedOutline { border-color: ${props => props.error ? props.theme.palette.common.red600 : props.theme.palette.common.grey500}; @@ -138,7 +138,7 @@ const StyledSelect = styled(Select)<{ error?: boolean }>` .MuiSelect-root { padding-inline-start: 12px; padding-inline-end: 6px; - padding-block: 10px; + padding-block: 1px; &:focus { background-color: ${props => props.theme.palette.common.white}; } @@ -158,3 +158,10 @@ const SelectedChip = styled(Chip)` } } `; + +const SelectedContainer = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + gap: 5px; +`; diff --git a/src/webapp/pages/dashboard/DashboardPage.tsx b/src/webapp/pages/dashboard/DashboardPage.tsx index 30b29903..cc69015f 100644 --- a/src/webapp/pages/dashboard/DashboardPage.tsx +++ b/src/webapp/pages/dashboard/DashboardPage.tsx @@ -20,11 +20,12 @@ import { DateRangePicker } from "../../components/date-picker/DateRangePicker"; export const DashboardPage: React.FC = React.memo(() => { const { - filtersConfig, + selectorFiltersConfig, singleSelectFilters, setSingleSelectFilters, multiSelectFilters, setMultiSelectFilters, + dateRangeFilter, } = useAlertsActiveVerifiedFilters(); const { @@ -37,7 +38,11 @@ export const DashboardPage: React.FC = React.memo(() => { editRiskAssessmentColumns, } = usePerformanceOverview(); - const { cardCounts } = useCardCounts(singleSelectFilters, multiSelectFilters); + const { cardCounts } = useCardCounts( + singleSelectFilters, + multiSelectFilters, + dateRangeFilter.value + ); const { goTo } = useRoutes(); const { resetCurrentEventTracker: resetCurrentEventTrackerId } = useCurrentEventTracker(); @@ -55,41 +60,49 @@ export const DashboardPage: React.FC = React.memo(() => { return (
- - {filtersConfig.map(({ id, label, placeholder, options, type }) => - type === "multiselector" ? ( - setMultiSelectFilters(id, values)} - /> - ) : ( - setSingleSelectFilters(id, value)} - allowClear - /> - ) - )} - setMultiSelectFilters("duration", dates)} - placeholder={i18n.t("Select duration")} - label={i18n.t("Duration")} - /> - + + {selectorFiltersConfig.map(({ id, label, placeholder, options, type }) => { + return ( + + {type === "multiselector" ? ( + + setMultiSelectFilters(id, values) + } + /> + ) : ( + + setSingleSelectFilters(id, value) + } + allowClear + /> + )} + + ); + })} + + + + {cardCounts.map((cardCount, index) => ( - { mapKey="dashboard" singleSelectFilters={singleSelectFilters} multiSelectFilters={multiSelectFilters} + dateRangeFilter={dateRangeFilter.value} />
TBD
@@ -127,18 +141,34 @@ export const DashboardPage: React.FC = React.memo(() => { const GridWrapper = styled.div` width: 100%; display: grid; - grid-template-columns: repeat(5, 1fr); - gap: 0.5rem; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 10px; +`; + +const StyledStatsCard = styled(StatsCard)` + width: 220px; `; const StatisticTableWrapper = styled.div` display: grid; `; -const Container = styled.div` +const FiltersContainer = styled.div` display: flex; - justify-content: space-between; align-items: center; + flex-wrap: wrap; margin-bottom: 1rem; gap: 1rem; `; + +const FilterContainer = styled.div` + display: flex; + width: 250px; + max-width: 250px; + justify-content: flex-end; + @media (max-width: 700px) { + flex-wrap: wrap; + justify-content: flex-start; + width: 100%; + } +`; diff --git a/src/webapp/pages/dashboard/useAlertsActiveVerifiedFilters.ts b/src/webapp/pages/dashboard/useAlertsActiveVerifiedFilters.ts index 644ce5b7..0c28b9f5 100644 --- a/src/webapp/pages/dashboard/useAlertsActiveVerifiedFilters.ts +++ b/src/webapp/pages/dashboard/useAlertsActiveVerifiedFilters.ts @@ -3,9 +3,9 @@ import _c from "../../../domain/entities/generic/Collection"; import { useAppContext } from "../../contexts/app-context"; import { OrgUnit } from "../../../domain/entities/OrgUnit"; import { Option } from "../../components/utils/option"; -import { evenTrackerCountsIndicatorMap } from "../../../data/repositories/consts/PerformanceOverviewConstants"; +import { eventTrackerCountsIndicatorMap } from "../../../data/repositories/consts/PerformanceOverviewConstants"; -export type FiltersConfig = { +export type SelectorFiltersConfig = { id: string; label: string; placeholder: string; @@ -13,7 +13,19 @@ export type FiltersConfig = { options: Option[]; }; -export function useAlertsActiveVerifiedFilters() { +type State = { + selectorFiltersConfig: SelectorFiltersConfig[]; + singleSelectFilters: Record; + setSingleSelectFilters: (id: string, value: string) => void; + multiSelectFilters: Record; + setMultiSelectFilters: (id: string, values: string[]) => void; + dateRangeFilter: { + onChange: (value: string[]) => void; + value: string[]; + }; +}; + +export function useAlertsActiveVerifiedFilters(): State { const { compositionRoot } = useAppContext(); const [singleSelectFilters, setSingleSelectsFilters] = useState>({ @@ -23,10 +35,13 @@ export function useAlertsActiveVerifiedFilters() { }); const [multiSelectFilters, setMultiSelectFilters] = useState>({ province: [], - duration: [], }); + const [provincesOptions, setProvincesOptions] = useState([]); - const [filtersConfig, setFiltersConfig] = useState([]); + + const [selectedRangeDateFilter, setSelectedRangeDateFilter] = useState([]); + + const [selectorFiltersConfig, setSelectorFiltersConfig] = useState([]); useEffect(() => { compositionRoot.orgUnits.getProvinces.execute().run( @@ -58,11 +73,11 @@ export function useAlertsActiveVerifiedFilters() { })); }, []); - // Initialize filter options based on diseasesTotal + // Initialize filter options based on eventTrackerCountsIndicatorMap useEffect(() => { - const buildFiltersConfig = (): FiltersConfig[] => { + const buildSelectorFiltersConfig = (): SelectorFiltersConfig[] => { const createOptions = (key: "disease" | "hazard") => - _c(evenTrackerCountsIndicatorMap) + _c(eventTrackerCountsIndicatorMap) .filter(value => value.type === key) .uniqBy(value => value.name) .map(value => ({ @@ -110,15 +125,20 @@ export function useAlertsActiveVerifiedFilters() { }, ]; }; - setFiltersConfig(buildFiltersConfig()); + + setSelectorFiltersConfig(buildSelectorFiltersConfig()); }, [provincesOptions]); return { - filtersConfig, + selectorFiltersConfig, singleSelectFilters, setSingleSelectFilters: handleSetSingleSelectFilters, multiSelectFilters, setMultiSelectFilters: handleSetMultiSelectFilters, + dateRangeFilter: { + onChange: setSelectedRangeDateFilter, + value: selectedRangeDateFilter, + }, }; } diff --git a/src/webapp/pages/dashboard/useCardCounts.ts b/src/webapp/pages/dashboard/useCardCounts.ts index 10d065ca..7ebaef4e 100644 --- a/src/webapp/pages/dashboard/useCardCounts.ts +++ b/src/webapp/pages/dashboard/useCardCounts.ts @@ -7,7 +7,8 @@ export type Order = { name: string; direction: "asc" | "desc" }; export function useCardCounts( singleSelectFilters: Record, - multiSelectFilters: Record + multiSelectFilters: Record, + dateRangeFilter: string[] ) { const { compositionRoot } = useAppContext(); const [cardCounts, setCardCounts] = useState([]); @@ -16,7 +17,7 @@ export function useCardCounts( useEffect(() => { setIsLoading(true); compositionRoot.performanceOverview.getTotalCardCounts - .execute(singleSelectFilters, multiSelectFilters) + .execute(singleSelectFilters, multiSelectFilters, dateRangeFilter) .run( diseasesTotal => { setCardCounts(diseasesTotal); @@ -27,7 +28,7 @@ export function useCardCounts( setIsLoading(false); } ); - }, [compositionRoot, singleSelectFilters, multiSelectFilters]); + }, [compositionRoot, singleSelectFilters, multiSelectFilters, dateRangeFilter]); return { cardCounts, diff --git a/src/webapp/pages/dashboard/useFilters.ts b/src/webapp/pages/dashboard/useFilters.ts deleted file mode 100644 index b801f899..00000000 --- a/src/webapp/pages/dashboard/useFilters.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { useCallback, useEffect, useState } from "react"; -import { FiltersConfig } from "../../components/table/statistic-table/StatisticTable"; -import { evenTrackerCountsIndicatorMap } from "../../../data/repositories/consts/PerformanceOverviewConstants"; -import _c from "../../../domain/entities/generic/Collection"; - -export function useFilters() { - const [filters, setFilters] = useState>({}); - const [filterOptions, setFilterOptions] = useState([]); - - const buildFilterOptions = useCallback((): FiltersConfig[] => { - const createOptions = (key: "disease" | "hazard") => - _c(evenTrackerCountsIndicatorMap) - .filter(value => value.type === key) - .uniqBy(value => value.name) - .map(value => ({ - value: value.name, - label: value.name, - })) - - .value(); - - const diseaseOptions = createOptions("disease"); - const hazardOptions = createOptions("hazard"); - - return [ - { - value: "incidentStatus", - label: "Incident Status", - type: "multiselector", - options: [ - { value: "Respond", label: "Respond" }, - { value: "Alert", label: "Alert" }, - { value: "Watch", label: "Watch" }, - ], - }, - { - value: "disease", - label: "Disease", - type: "multiselector", - options: diseaseOptions, - }, - { - value: "hazard", - label: "Hazard Type", - type: "multiselector", - options: hazardOptions, - }, - ]; - }, []); - - const handleSetFilters = useCallback( - (newFilters: Record) => { - setFilters(newFilters); - setFilterOptions( - filterOptions.map(option => ({ - ...option, - disabled: - (newFilters.disease && newFilters.disease.length > 0 - ? option.value === "hazard" - : false) || - (newFilters.hazard && newFilters.hazard.length > 0 - ? option.value === "disease" - : false), - })) - ); - }, - [filterOptions] - ); - - // Initialize filter options based on diseasesTotal - useEffect(() => { - setFilterOptions(buildFilterOptions()); - }, [buildFilterOptions]); - - return { filters, filterOptions, setFilters: handleSetFilters }; -} diff --git a/src/webapp/pages/event-tracker/EventTrackerPage.tsx b/src/webapp/pages/event-tracker/EventTrackerPage.tsx index 611ed063..5a32e60f 100644 --- a/src/webapp/pages/event-tracker/EventTrackerPage.tsx +++ b/src/webapp/pages/event-tracker/EventTrackerPage.tsx @@ -53,7 +53,7 @@ export const EventTrackerPage: React.FC = React.memo(() => { const { changeCurrentEventTracker: changeCurrentEventTrackerId, getCurrentEventTracker } = useCurrentEventTracker(); - const { multiSelectFilters, setMultiSelectFilters } = useMapFilters(); + const { dateRangeFilter } = useMapFilters(); useEffect(() => { if (eventTrackerDetails) changeCurrentEventTrackerId(eventTrackerDetails); @@ -76,13 +76,8 @@ export const EventTrackerPage: React.FC = React.memo(() => { > - setMultiSelectFilters({ - ...multiSelectFilters, - duration: dates, - }) - } + value={dateRangeFilter.value || []} + onChange={dateRangeFilter.onChange} placeholder={i18n.t("Select duration")} label={i18n.t("Duration")} /> @@ -97,7 +92,7 @@ export const EventTrackerPage: React.FC = React.memo(() => { mapKey="event_tracker" eventDiseaseCode={getCurrentEventTracker()?.suspectedDiseaseCode} eventHazardCode={getCurrentEventTracker()?.hazardType} - multiSelectFilters={multiSelectFilters} + dateRangeFilter={dateRangeFilter.value || []} /> diff --git a/src/webapp/pages/event-tracker/useMapFilters.ts b/src/webapp/pages/event-tracker/useMapFilters.ts index c8b97574..54ef3950 100644 --- a/src/webapp/pages/event-tracker/useMapFilters.ts +++ b/src/webapp/pages/event-tracker/useMapFilters.ts @@ -1,17 +1,19 @@ -import { Dispatch, SetStateAction, useState } from "react"; +import { useState } from "react"; export type MapFiltersState = { - multiSelectFilters: Record; - setMultiSelectFilters: Dispatch>>; + dateRangeFilter: { + onChange: (value: string[]) => void; + value: string[]; + }; }; export function useMapFilters(): MapFiltersState { - const [multiSelectFilters, setMultiSelectFilters] = useState>({ - duration: [], - }); + const [selectedRangeDateFilter, setSelectedRangeDateFilter] = useState([]); return { - multiSelectFilters, - setMultiSelectFilters, + dateRangeFilter: { + onChange: setSelectedRangeDateFilter, + value: selectedRangeDateFilter, + }, }; }