Handle single lists

This commit is contained in:
Nicolas Mowen 2024-09-10 08:18:13 -06:00
parent 09824c19a4
commit c59aae718d
3 changed files with 96 additions and 5 deletions

View File

@ -417,7 +417,9 @@ function ZoneFilterButton({
<div
className={`hidden md:block ${selectedZones?.length ? "text-selected-foreground" : "text-primary"}`}
>
{selectedZones?.length ? `${selectedZones.length} Zones` : "All Zones"}
{selectedZones?.length
? `${selectedZones.length} Zone${selectedZones.length > 1 ? "s" : ""}`
: "All Zones"}
</div>
</Button>
);
@ -558,6 +560,7 @@ export function ZoneFilterContent({
<Button
onClick={() => {
setCurrentZones?.(undefined);
updateZoneFilter?.(undefined);
}}
>
Reset
@ -731,7 +734,7 @@ export function SubFilterContent({
</Button>
<Button
onClick={() => {
setCurrentSubLabels(undefined);
updateSubLabelFilter(undefined);
}}
>
Reset

View File

@ -1,5 +1,6 @@
import { FilterType } from "@/types/filter";
import { useMemo, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
type useApiFilterReturn<F extends FilterType> = [
filter: F | undefined,
@ -41,3 +42,90 @@ export default function useApiFilter<
return [filter, setFilter, searchParams];
}
export function useApiFilterArgs<
F extends FilterType,
>(): useApiFilterReturn<F> {
const location = useLocation();
const navigate = useNavigate();
const setFilter = useCallback(
(filter: F) => {
let search = "";
Object.entries(filter).forEach(([key, value]) => {
let char = "";
if (search.length == 0) {
char = "?";
} else {
char = "&";
}
if (Array.isArray(value)) {
if (value.length == 0) {
// empty array means all so ignore
} else {
search += `${char}${key}=${value.join(",")}`;
}
} else {
if (value != undefined) {
search += `${char}${key}=${value}`;
}
}
});
navigate(`${location.pathname}${search}`, { ...location.state });
},
[location, navigate],
);
const filter = useMemo<F>(() => {
const search = location?.search?.substring(1);
if (search == undefined || search.length == 0) {
return {} as F;
}
const filter: { [key: string]: unknown } = {};
search.split("&").forEach((full) => {
const [key, value] = full.split("=");
if (isNaN(parseFloat(value))) {
filter[key] = value.includes(",") ? value.split(",") : [value];
} else {
if (value != undefined) {
filter[key] = `${value}`;
}
}
});
return filter as F;
}, [location?.search]);
const searchParams = useMemo(() => {
if (filter == undefined || Object.keys(filter).length == 0) {
return {};
}
const search: { [key: string]: string } = {};
Object.entries(filter).forEach(([key, value]) => {
if (Array.isArray(value)) {
if (value.length == 0) {
// empty array means all so ignore
} else {
search[key] = value.join(",");
}
} else {
if (value != undefined) {
search[key] = `${value}`;
}
}
});
return search;
}, [filter]);
return [filter, setFilter, searchParams];
}

View File

@ -1,4 +1,4 @@
import useApiFilter from "@/hooks/use-api-filter";
import { useApiFilterArgs } from "@/hooks/use-api-filter";
import { useCameraPreviews } from "@/hooks/use-camera-previews";
import { useOverlayState } from "@/hooks/use-overlay-state";
import { FrigateConfig } from "@/types/frigateConfig";
@ -27,7 +27,7 @@ export default function Search() {
// search filter
const [searchFilter, setSearchFilter, searchSearchParams] =
useApiFilter<SearchFilter>();
useApiFilterArgs<SearchFilter>();
const onUpdateFilter = useCallback(
(newFilter: SearchFilter) => {