Handle time range in am/pm based on browser

This commit is contained in:
Nicolas Mowen 2024-09-25 08:29:44 -06:00
parent 28d2f72a96
commit ce2bb45c55
3 changed files with 72 additions and 7 deletions

View File

@ -17,6 +17,8 @@ import {
SearchFilter, SearchFilter,
SearchFilters, SearchFilters,
SearchSource, SearchSource,
DEFAULT_TIME_RANGE_AFTER,
DEFAULT_TIME_RANGE_BEFORE,
} from "@/types/search"; } from "@/types/search";
import { DateRange } from "react-day-picker"; import { DateRange } from "react-day-picker";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@ -26,6 +28,7 @@ import { MdLabel } from "react-icons/md";
import SearchSourceIcon from "../icons/SearchSourceIcon"; import SearchSourceIcon from "../icons/SearchSourceIcon";
import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog"; import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog";
import { FaArrowRight, FaClock } from "react-icons/fa"; import { FaArrowRight, FaClock } from "react-icons/fa";
import { useFormattedHour } from "@/hooks/use-date-utils";
type SearchFilterGroupProps = { type SearchFilterGroupProps = {
className: string; className: string;
@ -172,6 +175,7 @@ export default function SearchFilterGroup({
)} )}
{filters.includes("time") && ( {filters.includes("time") && (
<TimeRangeFilterButton <TimeRangeFilterButton
config={config}
timeRange={filter?.time_range} timeRange={filter?.time_range}
updateTimeRange={(time_range) => updateTimeRange={(time_range) =>
onUpdateFilter({ ...filter, time_range }) onUpdateFilter({ ...filter, time_range })
@ -395,10 +399,12 @@ export function GeneralFilterContent({
} }
type TimeRangeFilterButtonProps = { type TimeRangeFilterButtonProps = {
config?: FrigateConfig;
timeRange?: string; timeRange?: string;
updateTimeRange: (range: string | undefined) => void; updateTimeRange: (range: string | undefined) => void;
}; };
function TimeRangeFilterButton({ function TimeRangeFilterButton({
config,
timeRange, timeRange,
updateTimeRange, updateTimeRange,
}: TimeRangeFilterButtonProps) { }: TimeRangeFilterButtonProps) {
@ -408,7 +414,7 @@ function TimeRangeFilterButton({
const [afterHour, beforeHour] = useMemo(() => { const [afterHour, beforeHour] = useMemo(() => {
if (!timeRange || !timeRange.includes(",")) { if (!timeRange || !timeRange.includes(",")) {
return ["00:00", "24:00"]; return [DEFAULT_TIME_RANGE_AFTER, DEFAULT_TIME_RANGE_BEFORE];
} }
return timeRange.split(","); return timeRange.split(",");
@ -417,6 +423,13 @@ function TimeRangeFilterButton({
const [selectedAfterHour, setSelectedAfterHour] = useState(afterHour); const [selectedAfterHour, setSelectedAfterHour] = useState(afterHour);
const [selectedBeforeHour, setSelectedBeforeHour] = useState(beforeHour); const [selectedBeforeHour, setSelectedBeforeHour] = useState(beforeHour);
// format based on locale
const formattedAfter = useFormattedHour(config, afterHour);
const formattedBefore = useFormattedHour(config, beforeHour);
const formattedSelectedAfter = useFormattedHour(config, selectedAfterHour);
const formattedSelectedBefore = useFormattedHour(config, selectedBeforeHour);
const trigger = ( const trigger = (
<Button <Button
size="sm" size="sm"
@ -429,7 +442,7 @@ function TimeRangeFilterButton({
<div <div
className={`${timeRange ? "text-selected-foreground" : "text-primary"}`} className={`${timeRange ? "text-selected-foreground" : "text-primary"}`}
> >
{timeRange ? `${afterHour} - ${beforeHour}` : "All Times"} {timeRange ? `${formattedAfter} - ${formattedBefore}` : "All Times"}
</div> </div>
</Button> </Button>
); );
@ -456,7 +469,7 @@ function TimeRangeFilterButton({
setEndOpen(false); setEndOpen(false);
}} }}
> >
{selectedAfterHour} {formattedSelectedAfter}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="flex flex-col items-center"> <PopoverContent className="flex flex-col items-center">
@ -493,7 +506,7 @@ function TimeRangeFilterButton({
setStartOpen(false); setStartOpen(false);
}} }}
> >
{selectedBeforeHour} {formattedSelectedBefore}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="flex flex-col items-center"> <PopoverContent className="flex flex-col items-center">
@ -519,7 +532,10 @@ function TimeRangeFilterButton({
<Button <Button
variant="select" variant="select"
onClick={() => { onClick={() => {
if (selectedAfterHour == "00:00" && selectedBeforeHour == "24:00") { if (
selectedAfterHour == DEFAULT_TIME_RANGE_AFTER &&
selectedBeforeHour == DEFAULT_TIME_RANGE_BEFORE
) {
updateTimeRange(undefined); updateTimeRange(undefined);
} else { } else {
updateTimeRange(`${selectedAfterHour},${selectedBeforeHour}`); updateTimeRange(`${selectedAfterHour},${selectedBeforeHour}`);
@ -532,8 +548,8 @@ function TimeRangeFilterButton({
</Button> </Button>
<Button <Button
onClick={() => { onClick={() => {
setSelectedAfterHour("00:00"); setSelectedAfterHour(DEFAULT_TIME_RANGE_AFTER);
setSelectedBeforeHour("24:00"); setSelectedBeforeHour(DEFAULT_TIME_RANGE_BEFORE);
}} }}
> >
Reset Reset

View File

@ -43,3 +43,49 @@ export function useTimezone(config: FrigateConfig | undefined) {
); );
}, [config]); }, [config]);
} }
function use24HourTime(config: FrigateConfig | undefined) {
const localeUses24HourTime = useMemo(
() =>
new Intl.DateTimeFormat(undefined, {
hour: "numeric",
})
?.formatToParts(new Date(2020, 0, 1, 13))
?.find((part) => part.type === "hour")?.value?.length === 2,
[],
);
return useMemo(() => {
if (!config) {
return false;
}
if (config.ui.time_format != "browser") {
return config.ui.time_format == "24hour";
}
return localeUses24HourTime;
}, [config, localeUses24HourTime]);
}
export function useFormattedHour(
config: FrigateConfig | undefined,
time: string, // hour is assumed to be in 24 hour format per the Date object
) {
const hour24 = use24HourTime(config);
return useMemo(() => {
if (hour24) {
return time;
}
const [hour, minute] = time.includes(":") ? time.split(":") : [time, "00"];
const hourNum = parseInt(hour);
if (hourNum < 12) {
return `${hourNum}:${minute} AM`;
} else {
return `${hourNum - 12}:${minute} PM`;
}
}, [hour24, time]);
}

View File

@ -61,6 +61,9 @@ export type SearchFilter = {
event_id?: string; event_id?: string;
}; };
export const DEFAULT_TIME_RANGE_AFTER = "00:00";
export const DEFAULT_TIME_RANGE_BEFORE = "23:59";
export type SearchQueryParams = { export type SearchQueryParams = {
cameras?: string[]; cameras?: string[];
labels?: string[]; labels?: string[];