From 985b2d7b27e4a9252e690eb39df2c41e138b7b7a Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Thu, 28 Mar 2024 08:43:05 -0600 Subject: [PATCH] Cleanup event filters (#10724) * Add specific button / switch for showing reviewed items and use intermediate drawer for mobile * Match design for filters --- .../components/filter/ReviewFilterGroup.tsx | 227 ++++++++++++------ .../overlay/MobileReviewSettingsDrawer.tsx | 71 +++--- web/src/views/events/EventView.tsx | 2 +- 3 files changed, 186 insertions(+), 114 deletions(-) diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index c0f97cbee..fa26722e6 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -13,19 +13,35 @@ import { import { ReviewFilter, ReviewSummary } from "@/types/review"; import { getEndOfDayTimestamp } from "@/utils/dateUtil"; import { useFormattedTimestamp } from "@/hooks/use-date-utils"; -import { FaCalendarAlt, FaFilter, FaRunning, FaVideo } from "react-icons/fa"; -import { isMobile } from "react-device-detect"; +import { + FaCalendarAlt, + FaCheckCircle, + FaFilter, + FaRunning, + FaVideo, +} from "react-icons/fa"; +import { isDesktop, isMobile } from "react-device-detect"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { Switch } from "../ui/switch"; import { Label } from "../ui/label"; import FilterCheckBox from "./FilterCheckBox"; import ReviewActivityCalendar from "../overlay/ReviewActivityCalendar"; +import MobileReviewSettingsDrawer, { + DrawerFeatures, +} from "../overlay/MobileReviewSettingsDrawer"; const ATTRIBUTES = ["amazon", "face", "fedex", "license_plate", "ups"]; -const REVIEW_FILTERS = ["cameras", "date", "general", "motionOnly"] as const; +const REVIEW_FILTERS = [ + "cameras", + "reviewed", + "date", + "general", + "motionOnly", +] as const; type ReviewFilters = (typeof REVIEW_FILTERS)[number]; const DEFAULT_REVIEW_FILTERS: ReviewFilters[] = [ "cameras", + "reviewed", "date", "general", "motionOnly", @@ -94,6 +110,20 @@ export default function ReviewFilterGroup({ ); }, [config]); + const mobileSettingsFeatures = useMemo(() => { + const features: DrawerFeatures[] = []; + + if (filters.includes("date")) { + features.push("calendar"); + } + + if (filters.includes("general")) { + features.push("filter"); + } + + return features; + }, [filters]); + // handle updating filters const onUpdateSelectedDay = useCallback( @@ -119,7 +149,15 @@ export default function ReviewFilterGroup({ }} /> )} - {filters.includes("date") && ( + {filters.includes("reviewed") && ( + + onUpdateFilter({ ...filter, showReviewed: reviewed }) + } + /> + )} + {isDesktop && filters.includes("date") && ( )} - {filters.includes("general") && ( + {isDesktop && filters.includes("general") && ( { onUpdateFilter({ ...filter, labels: newLabels }); }} - showReviewed={filter?.showReviewed || 0} - setShowReviewed={(reviewed) => - onUpdateFilter({ ...filter, showReviewed: reviewed }) - } + /> + )} + {isMobile && mobileSettingsFeatures.length > 0 && ( + {}} + setRange={() => {}} /> )} @@ -307,6 +355,41 @@ function CamerasFilterButton({ ); } +type ShowReviewedFilterProps = { + showReviewed?: 0 | 1; + setShowReviewed: (reviewed?: 0 | 1) => void; +}; +function ShowReviewFilter({ + showReviewed, + setShowReviewed, +}: ShowReviewedFilterProps) { + return ( + <> +
+ setShowReviewed(showReviewed == 0 ? 1 : 0)} + /> + +
+ + + + ); +} + type CalendarFilterButtonProps = { reviewSummary?: ReviewSummary; day?: Date; @@ -371,19 +454,14 @@ function CalendarFilterButton({ type GeneralFilterButtonProps = { allLabels: string[]; selectedLabels: string[] | undefined; - showReviewed?: 0 | 1; updateLabelFilter: (labels: string[] | undefined) => void; - setShowReviewed: (reviewed?: 0 | 1) => void; }; function GeneralFilterButton({ allLabels, selectedLabels, - showReviewed, updateLabelFilter, - setShowReviewed, }: GeneralFilterButtonProps) { const [open, setOpen] = useState(false); - const [reviewed, setReviewed] = useState(showReviewed ?? 0); const [currentLabels, setCurrentLabels] = useState( selectedLabels, ); @@ -399,12 +477,8 @@ function GeneralFilterButton({ allLabels={allLabels} selectedLabels={selectedLabels} currentLabels={currentLabels} - showReviewed={showReviewed} - reviewed={reviewed} updateLabelFilter={updateLabelFilter} - setShowReviewed={setShowReviewed} setCurrentLabels={setCurrentLabels} - setReviewed={setReviewed} onClose={() => setOpen(false)} /> ); @@ -415,7 +489,6 @@ function GeneralFilterButton({ open={open} onOpenChange={(open) => { if (!open) { - setReviewed(showReviewed ?? 0); setCurrentLabels(selectedLabels); } @@ -435,7 +508,6 @@ function GeneralFilterButton({ open={open} onOpenChange={(open) => { if (!open) { - setReviewed(showReviewed ?? 0); setCurrentLabels(selectedLabels); } @@ -443,7 +515,7 @@ function GeneralFilterButton({ }} > {trigger} - {content} + {content} ); } @@ -452,87 +524,84 @@ type GeneralFilterContentProps = { allLabels: string[]; selectedLabels: string[] | undefined; currentLabels: string[] | undefined; - showReviewed?: 0 | 1; - reviewed: 0 | 1; updateLabelFilter: (labels: string[] | undefined) => void; setCurrentLabels: (labels: string[] | undefined) => void; - setShowReviewed: (reviewed?: 0 | 1) => void; - setReviewed: (reviewed: 0 | 1) => void; onClose: () => void; }; export function GeneralFilterContent({ allLabels, selectedLabels, currentLabels, - showReviewed, - reviewed, updateLabelFilter, setCurrentLabels, - setShowReviewed, - setReviewed, onClose, }: GeneralFilterContentProps) { return ( <> -
- setReviewed(reviewed == 0 ? 1 : 0)} - /> - -
- - - Filter Labels - -
- { - if (isChecked) { - setCurrentLabels(undefined); - } - }} - /> - - {allLabels.map((item) => ( - + + { if (isChecked) { - const updatedLabels = currentLabels ? [...currentLabels] : []; - - updatedLabels.push(item); - setCurrentLabels(updatedLabels); - } else { - const updatedLabels = currentLabels ? [...currentLabels] : []; - - // can not deselect the last item - if (updatedLabels.length > 1) { - updatedLabels.splice(updatedLabels.indexOf(item), 1); - setCurrentLabels(updatedLabels); - } + setCurrentLabels(undefined); } }} /> - ))} +
+ +
+ {allLabels.map((item) => ( +
+ + { + if (isChecked) { + const updatedLabels = currentLabels + ? [...currentLabels] + : []; + + updatedLabels.push(item); + setCurrentLabels(updatedLabels); + } else { + const updatedLabels = currentLabels + ? [...currentLabels] + : []; + + // can not deselect the last item + if (updatedLabels.length > 1) { + updatedLabels.splice(updatedLabels.indexOf(item), 1); + setCurrentLabels(updatedLabels); + } + } + }} + /> +
+ ))} +
- - + {features.includes("export") && ( + + )} + {features.includes("calendar") && ( + + )} + {features.includes("filter") && ( + + )}
); } else if (drawerMode == "export") { @@ -230,17 +246,13 @@ export default function MobileReviewSettingsDrawer({ onUpdateFilter({ ...filter, labels: newLabels }) } - setShowReviewed={() => {}} - setReviewed={() => {}} onClose={() => setDrawerMode("select")} /> @@ -280,10 +292,3 @@ export default function MobileReviewSettingsDrawer({ ); } - -/** - * - */ diff --git a/web/src/views/events/EventView.tsx b/web/src/views/events/EventView.tsx index a1b7a8eac..3dccce110 100644 --- a/web/src/views/events/EventView.tsx +++ b/web/src/views/events/EventView.tsx @@ -257,7 +257,7 @@ export default function EventView({ filters={ severity == "significant_motion" ? ["cameras", "date", "motionOnly"] - : ["cameras", "date", "general"] + : ["cameras", "reviewed", "date", "general"] } reviewSummary={reviewSummary} filter={filter}