diff --git a/src/components/common/cqlFilters.tsx b/src/components/common/cqlFilters.tsx index c2c55de9..e614023e 100644 --- a/src/components/common/cqlFilters.tsx +++ b/src/components/common/cqlFilters.tsx @@ -7,6 +7,7 @@ import { dateDefault } from "./constants"; import { Feature, Polygon, GeoJsonProperties } from "geojson"; import * as wellknown from "wellknown"; import { Category } from "./store/componentParamReducer"; +import { DatasetFrequency } from "./store/searchReducer"; // TODO: refactor this, naming like this is not ideal for readability, // what are T, J, R, p, i , j, c, d, x, y, z, etc. actually mean? @@ -23,6 +24,7 @@ export type CategoriesIn = SingleArgumentFunction< Array, string | undefined >; +export type UpdateFrequency = SingleArgumentFunction; /** * common key is the search text input that belongs to both "suggest_phrases" and "discovery_parameters". e.g. temperature * the OGC API needs to query this type of search text input differently; @@ -42,7 +44,11 @@ export type FilterTypes = | CategoriesIn | TemporalDuring | TemporalAfterOrBefore - | PolygonOperation; + | PolygonOperation + | UpdateFrequency; + +const funcUpdateFrequency: UpdateFrequency = (freq: DatasetFrequency) => + `update_frequency='${freq}'`; const funcTemporalAfter: TemporalAfterOrBefore = (s: number) => `temporal AFTER ${dayjs(s).format(dateDefault["DATE_TIME_FORMAT"])}`; @@ -127,6 +133,6 @@ cqlDefaultFilters .set("AFTER_TIME", funcTemporalAfter) .set("BEFORE_TIME", funcTemporalBefore) .set("INTERSECT_POLYGON", funcIntersectPolygon) - .set("REAL_TIME_ONLY", "update_frequency='real-time'"); + .set("UPDATE_FREQUENCY", funcUpdateFrequency); export { cqlDefaultFilters }; diff --git a/src/components/common/filters/AdvanceFilters.tsx b/src/components/common/filters/AdvanceFilters.tsx index 35a21f28..adde03f4 100644 --- a/src/components/common/filters/AdvanceFilters.tsx +++ b/src/components/common/filters/AdvanceFilters.tsx @@ -5,6 +5,7 @@ import { updateCategories, updateDateTimeFilterRange, updateImosOnly, + updateUpdateFreq, } from "../store/componentParamReducer"; import store, { AppDispatch, getComponentState } from "../store/store"; import { @@ -70,31 +71,34 @@ const AdvanceFilters: FC = ({ }, []); // TODO: implement DataDeliveryModeFilter and DepthFilter when backend supports this query - const handleApplyFilter = useCallback(() => { - if (filter.dateTimeFilterRange) { - dispatch(updateDateTimeFilterRange(filter.dateTimeFilterRange)); - } else { - dispatch(updateDateTimeFilterRange({})); - } - if (filter.categories) { - dispatch(updateCategories(filter.categories)); - } else { - dispatch(updateCategories([])); - } - if (filter.isImosOnlyDataset) { - dispatch(updateImosOnly(filter.isImosOnlyDataset)); - } else { - dispatch(updateImosOnly(false)); - } - setShowFilters(false); - setFilter({}); - }, [ - dispatch, - filter.categories, - filter.dateTimeFilterRange, - filter.isImosOnlyDataset, - setShowFilters, - ]); + const handleApplyFilter = useCallback( + (filter: ParameterState) => { + // Must use await so that it happen one by one, otherwise the update will be messed + if (filter.dateTimeFilterRange) { + dispatch(updateDateTimeFilterRange(filter.dateTimeFilterRange)); + } else { + dispatch(updateDateTimeFilterRange({})); + } + if (filter.categories) { + dispatch(updateCategories(filter.categories)); + } else { + dispatch(updateCategories([])); + } + if (filter.isImosOnlyDataset) { + dispatch(updateImosOnly(filter.isImosOnlyDataset)); + } else { + dispatch(updateImosOnly(false)); + } + if (filter.updateFreq) { + dispatch(updateUpdateFreq(filter.updateFreq)); + } else { + dispatch(updateUpdateFreq(undefined)); + } + setShowFilters(false); + setFilter({}); + }, + [dispatch, setShowFilters] + ); return ( <> @@ -205,7 +209,7 @@ const AdvanceFilters: FC = ({ backgroundColor: color.blue.darkSemiTransparent, }, }} - onClick={handleApplyFilter} + onClick={() => handleApplyFilter(filter)} > Apply diff --git a/src/components/common/filters/DataDeliveryModeFilter.tsx b/src/components/common/filters/DataDeliveryModeFilter.tsx index 3fbbe495..316462dd 100644 --- a/src/components/common/filters/DataDeliveryModeFilter.tsx +++ b/src/components/common/filters/DataDeliveryModeFilter.tsx @@ -1,8 +1,9 @@ -import { FC, useCallback, useState } from "react"; +import { FC, useCallback, useEffect, useState } from "react"; import { Grid, SxProps, Theme } from "@mui/material"; import { StyledToggleButton } from "../buttons/StyledToggleButton"; import { StyledToggleButtonGroup } from "../buttons/StyledToggleButtonGroup"; import { ParameterState } from "../store/componentParamReducer"; +import { DatasetFrequency } from "../store/searchReducer"; interface DataDeliveryModeFilterProps { filter: ParameterState; @@ -10,7 +11,24 @@ interface DataDeliveryModeFilterProps { sx?: SxProps; } -const DELIVERY_MODES = ["Real-time", "Delayed", "One-off"]; +const DELIVERY_MODES = new Map([ + ["Real-time", DatasetFrequency.REALTIME], + ["Delayed", DatasetFrequency.DELAYED], + ["Other", DatasetFrequency.OTHER], +]); + +const findDeliveryModesLabel = ( + mode: DatasetFrequency | undefined +): string | undefined => { + if (mode) { + for (const [key, val] of DELIVERY_MODES) { + if (val === mode) { + return key; + } + } + } + return undefined; +}; const DataDeliveryModeFilter: FC = ({ filter, @@ -18,10 +36,36 @@ const DataDeliveryModeFilter: FC = ({ sx, }) => { // TODO: implement DataDeliveryModeFilter when backend supports this query - const [values, setValues] = useState>([]); - const handleChange = useCallback((_: any, newAlignment: any) => { - setValues(newAlignment); - }, []); + const [values, setValues] = useState( + findDeliveryModesLabel(filter.updateFreq) + ); + + const handleChange = useCallback( + (_: any, newAlignment: string) => { + // If user already selected it, click on it again should + // unselect + setValues((v) => (v === newAlignment ? undefined : newAlignment)); + + setFilter((filter) => { + // For exclusive toggle, it must be string + switch (newAlignment) { + case "Real-time": + case "Delayed": + case "Other": + filter.updateFreq = DELIVERY_MODES.get(newAlignment); + break; + default: + filter.updateFreq = undefined; + } + return { ...filter }; + }); + }, + [setFilter] + ); + + useEffect(() => { + findDeliveryModesLabel(filter.updateFreq); + }, [filter.updateFreq]); return ( @@ -31,7 +75,7 @@ const DataDeliveryModeFilter: FC = ({ exclusive onChange={handleChange} > - {DELIVERY_MODES.map((mode, index) => ( + {Array.from(DELIVERY_MODES.keys()).map((mode, index) => ( {mode} diff --git a/src/components/common/filters/ImosOnlySwitch.tsx b/src/components/common/filters/ImosOnlySwitch.tsx index 7b3766c1..ab236eca 100644 --- a/src/components/common/filters/ImosOnlySwitch.tsx +++ b/src/components/common/filters/ImosOnlySwitch.tsx @@ -52,7 +52,6 @@ const ImosOnlySwitch: FC = ({ filter, setFilter }) => { justifyContent="center" > diff --git a/src/components/common/store/componentParamReducer.tsx b/src/components/common/store/componentParamReducer.tsx index 79d81a0d..f831793a 100644 --- a/src/components/common/store/componentParamReducer.tsx +++ b/src/components/common/store/componentParamReducer.tsx @@ -4,6 +4,7 @@ */ import { bboxPolygon } from "@turf/turf"; import { Feature, Polygon, GeoJsonProperties } from "geojson"; +import { DatasetFrequency } from "./searchReducer"; const UPDATE_PARAMETER_STATES = "UPDATE_PARAMETER_STATES"; const UPDATE_DATETIME_FILTER_VARIABLE = "UPDATE_DATETIME_FILTER_VARIABLE"; @@ -13,6 +14,7 @@ const UPDATE_IMOS_ONLY_DATASET_FILTER_VARIABLE = "UPDATE_IMOS_ONLY_DATASET_FILTER_VARIABLE"; const UPDATE_POLYGON_FILTER_VARIABLE = "UPDATE_POLYGON_FILTER_VARIABLE"; const UPDATE_CATEGORY_FILTER_VARIABLE = "UPDATE_CATEGORY_FILTER_VARIABLE"; +const UPDATE_UPDATE_FREQ_VARIABLE = "UPDATE_UPDATE_FREQ_VARIABLE"; const UPDATE_SORT_BY_VARIABLE = "UPDATE_SORT_BY_VARIABLE"; interface DataTimeFilterRange { @@ -28,6 +30,7 @@ export interface ParameterState { searchText?: string; commonKey?: string; categories?: Array; + updateFreq?: DatasetFrequency | undefined; sortby?: string; } // Function use to test an input value is of type Category @@ -105,6 +108,15 @@ const updateCategories = (input: Array): ActionType => { }; }; +const updateUpdateFreq = (input: DatasetFrequency | undefined): ActionType => { + return { + type: UPDATE_UPDATE_FREQ_VARIABLE, + payload: { + updateFreq: input, + } as ParameterState, + }; +}; + const updateSortBy = ( input: Array<{ field: string; order: "ASC" | "DESC" }> ): ActionType => { @@ -198,6 +210,11 @@ const paramReducer = ( ...state, categories: action.payload.categories, }; + case UPDATE_UPDATE_FREQ_VARIABLE: + return { + ...state, + updateFreq: action.payload.updateFreq, + }; case UPDATE_SORT_BY_VARIABLE: return { ...state, @@ -341,4 +358,5 @@ export { updateParameterStates, updateSortBy, updateCommonKey, + updateUpdateFreq, }; diff --git a/src/components/common/store/searchReducer.tsx b/src/components/common/store/searchReducer.tsx index 5367dad7..97fb2369 100644 --- a/src/components/common/store/searchReducer.tsx +++ b/src/components/common/store/searchReducer.tsx @@ -10,6 +10,7 @@ import { PolygonOperation, TemporalAfterOrBefore, TemporalDuring, + UpdateFrequency, } from "../cqlFilters"; import { OGCCollection, OGCCollections } from "./OGCCollectionDefinitions"; import { @@ -18,6 +19,12 @@ import { } from "../../../utils/ErrorBoundary"; import { mergeWithDefaults } from "../utils"; +export enum DatasetFrequency { + REALTIME = "real-time", + DELAYED = "delayed", + OTHER = "other", +} + export type SuggesterParameters = { input?: string; filter?: string; @@ -321,6 +328,11 @@ const createSearchParamFrom = ( ); } + if (i.updateFreq) { + const f = cqlDefaultFilters.get("UPDATE_FREQUENCY") as UpdateFrequency; + p.filter = appendFilter(p.filter, f(i.updateFreq)); + } + if ( i.dateTimeFilterRange && (i.dateTimeFilterRange.start || i.dateTimeFilterRange.end) @@ -376,17 +388,9 @@ const createSearchParamFrom = ( return p; }; -const createSearchParamForImosRealTime = () => { - const p: SearchParameters = {}; - p.filter = cqlDefaultFilters.get("REAL_TIME_ONLY") as string; - - return p; -}; - export { createSuggesterParamFrom, createSearchParamFrom, - createSearchParamForImosRealTime, fetchSuggesterOptions, fetchResultWithStore, fetchResultNoStore, diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx new file mode 100644 index 00000000..e69de29b