Skip to content

Commit

Permalink
feat: implement date-range filter
Browse files Browse the repository at this point in the history
Ref: #183
  • Loading branch information
stdavis committed Oct 22, 2024
1 parent 273b603 commit b2b1541
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 15 deletions.
16 changes: 4 additions & 12 deletions src/components/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import FeatureLayer from '@arcgis/core/layers/FeatureLayer';
import { Button, TextField } from '@ugrc/utah-design-system';
import { useEffect, useRef } from 'react';
import { useFilter } from './contexts/FilterProvider';
import DateRange from './filters/DateRange';
import Purpose from './filters/Purpose';
import { useMap } from './hooks';
import { getStationQuery } from './queryHelpers';
Expand Down Expand Up @@ -46,6 +47,9 @@ export default function Filter(): JSX.Element {
<div className="flex flex-col gap-4 rounded border border-zinc-200 p-3 dark:border-zinc-700">
<Purpose />
</div>
<div className="flex flex-col gap-4 rounded border border-zinc-200 p-3 dark:border-zinc-700">
<DateRange />
</div>
<div className="flex flex-col gap-4 rounded border border-zinc-200 p-3 dark:border-zinc-700">
<h3 className="text-lg font-semibold">Species and length</h3>
<div className="flex flex-col gap-2">
Expand All @@ -61,18 +65,6 @@ export default function Filter(): JSX.Element {
</div>
</div>
</div>
<div className="flex flex-col gap-4 rounded border border-zinc-200 p-3 dark:border-zinc-700">
<h3 className="text-lg font-semibold">Date range</h3>
<div className="flex flex-col gap-2">
<div className="ml-2 flex gap-1">
<TextField label="from" className="w-20" />
<TextField label="to" className="w-20" />
</div>
<div className="w-30 flex justify-end">
<Button variant="secondary">clear all</Button>
</div>
</div>
</div>
<div className="flex flex-col gap-4 rounded border border-zinc-200 p-3 dark:border-zinc-700">
<h3 className="text-lg font-semibold">Water body</h3>
<div className="flex flex-col gap-2">
Expand Down
2 changes: 1 addition & 1 deletion src/components/contexts/FilterProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type QueryInfo = {
table: string;
};
type FilterState = Record<string, QueryInfo>;
type FilterKeys = 'purpose';
type FilterKeys = 'purpose' | 'date';
type Action =
| {
type: 'UPDATE_TABLE';
Expand Down
15 changes: 15 additions & 0 deletions src/components/filters/DateRange.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FilterProvider } from '../contexts/FilterProvider';
import DateRange from './DateRange';

export default {
title: 'DateRange',
component: DateRange,
};

export const Default = () => (
<div className="w-[304px] rounded border p-3">
<FilterProvider>
<DateRange />
</FilterProvider>
</div>
);
69 changes: 69 additions & 0 deletions src/components/filters/DateRange.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Button, TextField } from '@ugrc/utah-design-system';
import { useEffect, useState } from 'react';
import config from '../../config';
import { useFilter } from '../contexts/FilterProvider';

const fieldName = config.fieldNames.EVENT_DATE;
const emptyState = { from: '', to: '' };
const filterKey = 'date';

export default function DateRange() {
const [dates, setDates] = useState(emptyState);
const { filterDispatch } = useFilter();

const onChange = (newDate: string, key: 'from' | 'to') => {
setDates((prev) => ({ ...prev, [key]: newDate }));
};

const from = Date.parse(dates.from);
const to = Date.parse(dates.to);

const isInvalid = from > to;

useEffect(() => {
if (!dates.from || !dates.to || isInvalid) {
filterDispatch({ type: 'CLEAR_TABLE', filterKey });
} else {
filterDispatch({
type: 'UPDATE_TABLE',
filterKey,
value: {
where: `${fieldName} >= '${dates.from}' AND ${fieldName} <= '${dates.to}'`,
table: config.tableNames.events,
},
});
}
}, [dates, isInvalid, filterDispatch]);

return (
<div>
<h3 className="text-lg font-semibold">Date Range</h3>
<div className="flex flex-col gap-2">
<div className="flex gap-1">
<TextField
label="From"
className="w-32"
type="date"
value={dates.from}
onChange={(newDate: string) => onChange(newDate, 'from')}
isInvalid={isInvalid}
/>
<TextField
label="To"
className="w-32"
type="date"
value={dates.to}
onChange={(newDate: string) => onChange(newDate, 'to')}
isInvalid={isInvalid}
/>
</div>
{isInvalid && <p className="text-sm text-red-500">"From" must be before "To"</p>}
<div className="w-30 flex justify-end">
<Button variant="secondary" onPress={() => setDates(emptyState)}>
Clear
</Button>
</div>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions src/components/filters/Purpose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Purpose(): JSX.Element {
<h3 className="text-lg font-semibold">Purpose</h3>
<CheckboxGroup onChange={setSelectedValues} value={selectedValues}>
{purposesDomain.data?.map(({ name, code }) => (
<div key={code} className="ml-2 flex gap-1">
<div key={code} className="flex gap-1">
<Checkbox type="checkbox" id={code} name={code} value={code} />
<label htmlFor={code}>{name}</label>
</div>
Expand All @@ -69,7 +69,7 @@ export default function Purpose(): JSX.Element {
</div>
<div className="w-30 flex justify-end">
<Button variant="secondary" onPress={() => setSelectedValues([])}>
clear all
Clear
</Button>
</div>
</>
Expand Down

0 comments on commit b2b1541

Please sign in to comment.