mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-30 11:54:52 +03:00
Fix browser time format handling (#22694)
* implement hook to return resolved "24hour" | "12hour" string delegate to existing use24HourTime(), which correctly detects the browser's locale preference via Intl.DateTimeFormat * update frontend to use use24HourTime(config) or useTimeFormat(config) instead of directly comparing config.ui.time_format
This commit is contained in:
parent
f44f485f48
commit
257dae11c1
@ -8,6 +8,7 @@ import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTimeFormat } from "@/hooks/use-date-utils";
|
||||
|
||||
const GRAPH_COLORS = ["#3b82f6", "#ef4444"]; // RMS, dBFS
|
||||
|
||||
@ -72,7 +73,7 @@ export function AudioLevelGraph({ cameraName }: AudioLevelGraphProps) {
|
||||
return [last.rms, last.dBFS];
|
||||
}, [audioData]);
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const formatString = useMemo(
|
||||
() =>
|
||||
t(`time.formattedTimestampHourMinuteSecond.${timeFormat}`, {
|
||||
|
||||
@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useDateLocale } from "@/hooks/use-date-locale";
|
||||
import { useTimeFormat } from "@/hooks/use-date-utils";
|
||||
import { useMemo } from "react";
|
||||
|
||||
type DownloadVideoButtonProps = {
|
||||
@ -26,7 +27,7 @@ export function DownloadVideoButton({
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const locale = useDateLocale();
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
return t(`time.formattedTimestampFilename.${timeFormat}`, { ns: "common" });
|
||||
}, [t, timeFormat]);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { baseUrl } from "@/api/baseUrl";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { REVIEW_PADDING, ReviewSegment } from "@/types/review";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
@ -55,9 +55,10 @@ export default function ReviewCard({
|
||||
const { t } = useTranslation(["components/dialog"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
event.start_time,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestampHourMinute.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampHourMinute.12hour", { ns: "common" }),
|
||||
config?.ui.timezone,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import TimeAgo from "../dynamic/TimeAgo";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { SearchResult } from "@/types/search";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import SearchResultActions from "../menu/SearchResultActions";
|
||||
@ -29,9 +29,10 @@ export default function SearchThumbnailFooter({
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
// date
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
searchResult.start_time,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", { ns: "common" }),
|
||||
config?.ui.timezone,
|
||||
|
||||
@ -43,6 +43,7 @@ import {
|
||||
SelectItem,
|
||||
} from "@/components/ui/select";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import FilterSwitch from "@/components/filter/FilterSwitch";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
@ -752,6 +753,7 @@ export function CameraNotificationSwitch({
|
||||
};
|
||||
|
||||
const locale = useDateLocale();
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formatSuspendedUntil = (timestamp: string) => {
|
||||
if (timestamp === "0") return t("time.untilForRestart", { ns: "common" });
|
||||
@ -760,14 +762,13 @@ export function CameraNotificationSwitch({
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
timezone: config?.ui.timezone,
|
||||
date_format:
|
||||
config?.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
locale: locale,
|
||||
});
|
||||
return t("time.untilForTime", { ns: "common", time });
|
||||
|
||||
@ -8,6 +8,7 @@ import { isMobileOnly } from "react-device-detect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MdCircle } from "react-icons/md";
|
||||
import useSWR from "swr";
|
||||
import { useTimeFormat } from "@/hooks/use-date-utils";
|
||||
|
||||
const GRAPH_COLORS = ["#5C7CFA", "#ED5CFA", "#FAD75C"];
|
||||
|
||||
@ -48,7 +49,7 @@ export function CameraLineGraph({
|
||||
|
||||
const locale = useDateLocale();
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
|
||||
ns: "common",
|
||||
@ -203,7 +204,7 @@ export function EventsPerSecondsLineGraph({
|
||||
const locale = useDateLocale();
|
||||
const { t } = useTranslation(["common"]);
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
|
||||
ns: "common",
|
||||
|
||||
@ -8,6 +8,7 @@ import Chart from "react-apexcharts";
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useSWR from "swr";
|
||||
import { useTimeFormat } from "@/hooks/use-date-utils";
|
||||
|
||||
type ThresholdBarGraphProps = {
|
||||
graphId: string;
|
||||
@ -53,7 +54,7 @@ export function ThresholdBarGraph({
|
||||
const locale = useDateLocale();
|
||||
const { t } = useTranslation(["common"]);
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
|
||||
ns: "common",
|
||||
|
||||
@ -50,6 +50,7 @@ import {
|
||||
import { toast } from "sonner";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { MdImageSearch } from "react-icons/md";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
@ -80,6 +81,8 @@ export default function InputWithTags({
|
||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
const is24Hour = use24HourTime(config);
|
||||
const resolvedTimeFormat = is24Hour ? "24hour" : ("12hour" as const);
|
||||
|
||||
const allAudioListenLabels = useMemo<Set<string>>(() => {
|
||||
if (!config) {
|
||||
@ -431,12 +434,8 @@ export default function InputWithTags({
|
||||
const [startTime, endTime] = (filterValues as string)
|
||||
.replace("-", ",")
|
||||
.split(",");
|
||||
return `${
|
||||
config?.ui.time_format === "24hour"
|
||||
? startTime
|
||||
: convertTo12Hour(startTime)
|
||||
} - ${
|
||||
config?.ui.time_format === "24hour" ? endTime : convertTo12Hour(endTime)
|
||||
return `${is24Hour ? startTime : convertTo12Hour(startTime)} - ${
|
||||
is24Hour ? endTime : convertTo12Hour(endTime)
|
||||
}`;
|
||||
} else if (filterType === "min_score" || filterType === "max_score") {
|
||||
return Math.round(Number(filterValues) * 100).toString() + "%";
|
||||
@ -478,7 +477,7 @@ export default function InputWithTags({
|
||||
(filterType === "time_range" &&
|
||||
isValidTimeRange(
|
||||
trimmedValue.replace("-", ","),
|
||||
config?.ui.time_format,
|
||||
resolvedTimeFormat,
|
||||
)) ||
|
||||
((filterType === "min_score" || filterType === "max_score") &&
|
||||
!isNaN(Number(trimmedValue)) &&
|
||||
@ -495,7 +494,7 @@ export default function InputWithTags({
|
||||
? trimmedValue
|
||||
.replace("-", ",")
|
||||
.split(",")
|
||||
.map((time) => to24Hour(time.trim(), config?.ui.time_format))
|
||||
.map((time) => to24Hour(time.trim(), resolvedTimeFormat))
|
||||
.join(",")
|
||||
: trimmedValue,
|
||||
);
|
||||
@ -511,7 +510,7 @@ export default function InputWithTags({
|
||||
setCurrentFilterType(null);
|
||||
}
|
||||
},
|
||||
[allSuggestions, createFilter, config],
|
||||
[allSuggestions, createFilter, resolvedTimeFormat],
|
||||
);
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
@ -598,7 +597,7 @@ export default function InputWithTags({
|
||||
suggestion = suggestion
|
||||
.replace("-", ",")
|
||||
.split(",")
|
||||
.map((time) => to24Hour(time.trim(), config?.ui.time_format))
|
||||
.map((time) => to24Hour(time.trim(), resolvedTimeFormat))
|
||||
.join(",");
|
||||
}
|
||||
createFilter(currentFilterType, suggestion);
|
||||
@ -627,7 +626,7 @@ export default function InputWithTags({
|
||||
|
||||
inputRef.current?.focus();
|
||||
},
|
||||
[createFilter, currentFilterType, allSuggestions, config],
|
||||
[createFilter, currentFilterType, allSuggestions, resolvedTimeFormat],
|
||||
);
|
||||
|
||||
const handleSearch = useCallback(
|
||||
@ -779,10 +778,7 @@ export default function InputWithTags({
|
||||
</li>
|
||||
<li>
|
||||
{t("filter.tips.desc.step5", {
|
||||
exampleTime:
|
||||
config?.ui.time_format == "24hour"
|
||||
? "15:00-16:00"
|
||||
: "3:00PM-4:00PM",
|
||||
exampleTime: is24Hour ? "15:00-16:00" : "3:00PM-4:00PM",
|
||||
})}
|
||||
</li>
|
||||
<li>{t("filter.tips.desc.step6")}</li>
|
||||
|
||||
@ -46,6 +46,7 @@ import {
|
||||
} from "@/api/ws";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDateLocale } from "@/hooks/use-date-locale";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { useIsAdmin } from "@/hooks/use-is-admin";
|
||||
import { CameraNameLabel } from "../camera/FriendlyNameLabel";
|
||||
import { LiveStreamMetadata } from "@/types/live";
|
||||
@ -247,6 +248,8 @@ export default function LiveContextMenu({
|
||||
|
||||
const locale = useDateLocale();
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formatSuspendedUntil = (timestamp: string) => {
|
||||
// Some languages require a change in word order
|
||||
if (timestamp === "0") return t("time.untilForRestart", { ns: "common" });
|
||||
@ -255,14 +258,13 @@ export default function LiveContextMenu({
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
timezone: config?.ui.timezone,
|
||||
date_format:
|
||||
config?.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
locale: locale,
|
||||
});
|
||||
return t("time.untilForTime", { ns: "common", time });
|
||||
|
||||
@ -3,7 +3,7 @@ import { Button } from "../ui/button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||
import { SelectSeparator } from "../ui/select";
|
||||
import { TimeRange } from "@/types/timeline";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { getUTCOffset } from "@/utils/dateUtil";
|
||||
import { TimezoneAwareCalendar } from "./ReviewActivityCalendar";
|
||||
import { FaArrowRight, FaCalendarAlt } from "react-icons/fa";
|
||||
@ -69,16 +69,18 @@ export function CustomTimeSelector({
|
||||
return time;
|
||||
}, [range, latestTime, timezoneOffset, localTimeOffset]);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formattedStart = useFormattedTimestamp(
|
||||
startTime,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestamp.24hour")
|
||||
: t("time.formattedTimestamp.12hour"),
|
||||
);
|
||||
|
||||
const formattedEnd = useFormattedTimestamp(
|
||||
endTime,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestamp.24hour")
|
||||
: t("time.formattedTimestamp.12hour"),
|
||||
);
|
||||
|
||||
@ -2,7 +2,7 @@ import { isDesktop, isIOS, isMobile, isSafari } from "react-device-detect";
|
||||
import { SearchResult } from "@/types/search";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import { useApiHost } from "@/api";
|
||||
import { Button } from "../../ui/button";
|
||||
@ -769,9 +769,10 @@ function ObjectDetailsTab({
|
||||
setShowNavigationButtons,
|
||||
]);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
search?.start_time ?? 0,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestampMonthDayYearHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
|
||||
@ -7,6 +7,7 @@ import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||
import { TrackingDetailsSequence } from "@/types/timeline";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import { LuCircle, LuFolderX } from "react-icons/lu";
|
||||
import { cn } from "@/lib/utils";
|
||||
@ -428,17 +429,18 @@ export function TrackingDetails({
|
||||
[annotationOffset, displaySource, timestampToVideoTime],
|
||||
);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formattedStart = config
|
||||
? formatUnixTimestampToDateTime(event.start_time ?? 0, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestamp.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestamp.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestamp.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestamp.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
})
|
||||
@ -448,14 +450,13 @@ export function TrackingDetails({
|
||||
config && event.end_time != null
|
||||
? formatUnixTimestampToDateTime(event.end_time, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestamp.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestamp.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestamp.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestamp.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
})
|
||||
@ -917,24 +918,25 @@ function LifecycleIconRow({
|
||||
[effectiveTime, item.timestamp],
|
||||
);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formattedEventTimestamp = useMemo(
|
||||
() =>
|
||||
config
|
||||
? formatUnixTimestampToDateTime(item.timestamp ?? 0, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
})
|
||||
: "",
|
||||
[config, item.timestamp, t],
|
||||
[config, is24Hour, item.timestamp, t],
|
||||
);
|
||||
|
||||
const ratio = useMemo(
|
||||
|
||||
@ -12,7 +12,7 @@ import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { isIOS, isMobile, isSafari } from "react-device-detect";
|
||||
import Chip from "@/components/indicators/Chip";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import useImageLoaded from "@/hooks/use-image-loaded";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||
@ -174,9 +174,10 @@ export default function PreviewThumbnailPlayer({
|
||||
|
||||
// date
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
review.start_time,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampMonthDayHourMinute.12hour", { ns: "common" }),
|
||||
config?.ui?.timezone,
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
formatUnixTimestampToDateTime,
|
||||
getDurationFromTimestamps,
|
||||
} from "@/utils/dateUtil";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import AnnotationOffsetSlider from "@/components/overlay/detail/AnnotationOffsetSlider";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
@ -398,12 +399,12 @@ function ReviewGroup({
|
||||
}
|
||||
}, [isActive, alwaysExpandActive]);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const displayTime = formatUnixTimestampToDateTime(start, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", { ns: "common" }),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", { ns: "common" }),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
});
|
||||
@ -787,17 +788,17 @@ function LifecycleItem({
|
||||
);
|
||||
}, [config, item]);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedEventTimestamp = config
|
||||
? formatUnixTimestampToDateTime(item?.timestamp ?? 0, {
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
date_format: is24Hour
|
||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
||||
ns: "common",
|
||||
}),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, useTimeFormat } from "@/hooks/use-date-utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@ -36,7 +36,7 @@ export function MinimapBounds({
|
||||
}: MinimapSegmentProps) {
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const { t } = useTranslation(["common"]);
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
|
||||
const formatKey = dense
|
||||
? `time.formattedTimestampHourMinute.${timeFormat}`
|
||||
@ -104,7 +104,7 @@ export function Timestamp({
|
||||
const { t } = useTranslation(["common"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = t(`time.formattedTimestampHourMinute.${timeFormat}`);
|
||||
|
||||
const formattedTimestamp = useFormattedTimestamp(
|
||||
|
||||
@ -84,6 +84,18 @@ export function use24HourTime(config: FrigateConfig | undefined) {
|
||||
}, [config, localeUses24HourTime]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolved time format key ("24hour" | "12hour") based on config
|
||||
* and browser locale. Use this instead of checking config.ui.time_format directly
|
||||
* to correctly handle the "browser" setting.
|
||||
*/
|
||||
export function useTimeFormat(
|
||||
config: FrigateConfig | undefined,
|
||||
): "24hour" | "12hour" {
|
||||
const is24Hour = use24HourTime(config);
|
||||
return is24Hour ? "24hour" : "12hour";
|
||||
}
|
||||
|
||||
export function useFormattedHour(
|
||||
config: FrigateConfig | undefined,
|
||||
time: string, // hour is assumed to be in 24 hour format per the Date object
|
||||
|
||||
@ -4,6 +4,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import useSWR from "swr";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { useDateLocale } from "./use-date-locale";
|
||||
import { useTimeFormat } from "./use-date-utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useUserInteraction from "./use-user-interaction";
|
||||
|
||||
@ -168,7 +169,7 @@ function useDraggableElement({
|
||||
const { t } = useTranslation(["common"]);
|
||||
const locale = useDateLocale();
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
const formatKey = `time.${
|
||||
segmentDuration < 60 && !dense
|
||||
|
||||
@ -19,7 +19,7 @@ import { useResizeObserver } from "@/hooks/resize-observer";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||
import TimeAgo from "@/components/dynamic/TimeAgo";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
|
||||
const MOTION_HEATMAP_GRID_SIZE = 16;
|
||||
@ -165,9 +165,10 @@ function MotionPreviewClip({
|
||||
const [fallbackFrameIndex, setFallbackFrameIndex] = useState(0);
|
||||
const [fallbackFramesReady, setFallbackFramesReady] = useState(false);
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
range.start_time,
|
||||
config?.ui.time_format == "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
|
||||
ns: "common",
|
||||
})
|
||||
|
||||
@ -43,8 +43,9 @@ import { TimezoneAwareCalendar } from "@/components/overlay/ReviewActivityCalend
|
||||
|
||||
import { useApiHost } from "@/api";
|
||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { getUTCOffset } from "@/utils/dateUtil";
|
||||
import useSWR from "swr";
|
||||
import { cn } from "@/lib/utils";
|
||||
import MotionSearchROICanvas from "./MotionSearchROICanvas";
|
||||
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
||||
@ -452,7 +453,6 @@ export default function MotionSearchDialog({
|
||||
range={searchRange}
|
||||
setRange={setSearchRange}
|
||||
defaultRange={defaultRange}
|
||||
timeFormat={config.ui?.time_format}
|
||||
timezone={timezone}
|
||||
/>
|
||||
|
||||
@ -476,7 +476,6 @@ type SearchRangeSelectorProps = {
|
||||
range?: TimeRange;
|
||||
setRange: React.Dispatch<React.SetStateAction<TimeRange | undefined>>;
|
||||
defaultRange: TimeRange;
|
||||
timeFormat?: "browser" | "12hour" | "24hour";
|
||||
timezone?: string;
|
||||
};
|
||||
|
||||
@ -484,7 +483,6 @@ function SearchRangeSelector({
|
||||
range,
|
||||
setRange,
|
||||
defaultRange,
|
||||
timeFormat,
|
||||
timezone,
|
||||
}: SearchRangeSelectorProps) {
|
||||
const { t } = useTranslation(["views/motionSearch", "common"]);
|
||||
@ -527,15 +525,18 @@ function SearchRangeSelector({
|
||||
return time;
|
||||
}, [range, defaultRange, timezoneOffset, localTimeOffset]);
|
||||
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const is24Hour = use24HourTime(config);
|
||||
|
||||
const formattedStart = useFormattedTimestamp(
|
||||
startTime,
|
||||
timeFormat === "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestamp.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestamp.12hour", { ns: "common" }),
|
||||
);
|
||||
const formattedEnd = useFormattedTimestamp(
|
||||
endTime,
|
||||
timeFormat === "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestamp.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestamp.12hour", { ns: "common" }),
|
||||
);
|
||||
|
||||
@ -51,7 +51,7 @@ import {
|
||||
RecordingSegment,
|
||||
} from "@/types/record";
|
||||
import { VideoResolutionType } from "@/types/live";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
|
||||
import MotionSearchROICanvas from "./MotionSearchROICanvas";
|
||||
import MotionSearchDialog from "./MotionSearchDialog";
|
||||
import { IoMdArrowRoundBack } from "react-icons/io";
|
||||
@ -94,12 +94,13 @@ export default function MotionSearchView({
|
||||
]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const is24Hour = use24HourTime(config);
|
||||
const resultTimestampFormat = useMemo(
|
||||
() =>
|
||||
config.ui?.time_format === "24hour"
|
||||
is24Hour
|
||||
? t("time.formattedTimestamp.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestamp.12hour", { ns: "common" }),
|
||||
[config.ui?.time_format, t],
|
||||
[is24Hour, t],
|
||||
);
|
||||
|
||||
// Refs
|
||||
|
||||
@ -31,6 +31,7 @@ import Chip from "@/components/indicators/Chip";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import SearchActionGroup from "@/components/filter/SearchActionGroup";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
|
||||
|
||||
@ -77,6 +78,7 @@ export default function SearchView({
|
||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
const is24Hour = use24HourTime(config);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { data: exploreEvents } = useSWR<SearchResult[]>(
|
||||
@ -191,10 +193,7 @@ export default function SearchView({
|
||||
sub_labels: allSubLabels,
|
||||
...(hasCustomClassificationModels && { attributes: allAttributes }),
|
||||
search_type: ["thumbnail", "description"] as SearchSource[],
|
||||
time_range:
|
||||
config?.ui.time_format == "24hour"
|
||||
? ["00:00-23:59"]
|
||||
: ["12:00AM-11:59PM"],
|
||||
time_range: is24Hour ? ["00:00-23:59"] : ["12:00AM-11:59PM"],
|
||||
before: [formatDateToLocaleString()],
|
||||
after: [formatDateToLocaleString(-5)],
|
||||
min_score: ["50"],
|
||||
@ -209,6 +208,7 @@ export default function SearchView({
|
||||
}),
|
||||
[
|
||||
config,
|
||||
is24Hour,
|
||||
allLabels,
|
||||
allZones,
|
||||
allSubLabels,
|
||||
|
||||
@ -39,6 +39,7 @@ import { Trigger, TriggerAction, TriggerType } from "@/types/trigger";
|
||||
import { useSearchEffect } from "@/hooks/use-overlay-state";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { use24HourTime } from "@/hooks/use-date-utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTriggers } from "@/api/ws";
|
||||
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
|
||||
@ -89,6 +90,7 @@ export default function TriggerView({
|
||||
const { t } = useTranslation("views/settings");
|
||||
const { data: config, mutate: updateConfig } =
|
||||
useSWR<FrigateConfig>("config");
|
||||
const is24Hour = use24HourTime(config);
|
||||
const { data: trigger_status, mutate } = useSWR(
|
||||
config?.cameras[selectedCamera]?.semantic_search?.triggers &&
|
||||
Object.keys(config.cameras[selectedCamera].semantic_search.triggers)
|
||||
@ -581,20 +583,19 @@ export default function TriggerView({
|
||||
?.last_triggered,
|
||||
{
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t(
|
||||
"time.formattedTimestamp2.24hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"time.formattedTimestamp2.12hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
),
|
||||
date_format: is24Hour
|
||||
? t(
|
||||
"time.formattedTimestamp2.24hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"time.formattedTimestamp2.12hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
},
|
||||
@ -742,20 +743,19 @@ export default function TriggerView({
|
||||
?.last_triggered,
|
||||
{
|
||||
timezone: config.ui.timezone,
|
||||
date_format:
|
||||
config.ui.time_format == "24hour"
|
||||
? t(
|
||||
"time.formattedTimestamp2.24hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"time.formattedTimestamp2.12hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
),
|
||||
date_format: is24Hour
|
||||
? t(
|
||||
"time.formattedTimestamp2.24hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"time.formattedTimestamp2.12hour",
|
||||
{
|
||||
ns: "common",
|
||||
},
|
||||
),
|
||||
time_style: "medium",
|
||||
date_style: "medium",
|
||||
},
|
||||
|
||||
@ -10,7 +10,11 @@ import {
|
||||
import useSWR from "swr";
|
||||
import { CiCircleAlert } from "react-icons/ci";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useFormattedTimestamp, useTimezone } from "@/hooks/use-date-utils";
|
||||
import {
|
||||
useFormattedTimestamp,
|
||||
useTimeFormat,
|
||||
useTimezone,
|
||||
} from "@/hooks/use-date-utils";
|
||||
import { RecordingsSummary } from "@/types/review";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TZDate } from "react-day-picker";
|
||||
@ -81,7 +85,7 @@ export default function StorageMetrics({
|
||||
: null;
|
||||
}, [recordingsSummary, timezone]);
|
||||
|
||||
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
|
||||
const timeFormat = useTimeFormat(config);
|
||||
const format = useMemo(() => {
|
||||
return t(`time.formattedTimestampMonthDayYear.${timeFormat}`, {
|
||||
ns: "common",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user