From 0e94ad36b580534877871ece247ed6085b5749ef Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sun, 6 Jul 2025 18:26:41 +0000 Subject: feat: Add a new timezone user setting --- apps/web/components/settings/UserOptions.tsx | 80 ++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) (limited to 'apps/web/components') diff --git a/apps/web/components/settings/UserOptions.tsx b/apps/web/components/settings/UserOptions.tsx index 4f18a2e3..02c27145 100644 --- a/apps/web/components/settings/UserOptions.tsx +++ b/apps/web/components/settings/UserOptions.tsx @@ -1,13 +1,13 @@ "use client"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useClientConfig } from "@/lib/clientConfig"; import { useTranslation } from "@/lib/i18n/client"; import { useInterfaceLang } from "@/lib/userLocalSettings/bookmarksLayout"; import { updateInterfaceLang } from "@/lib/userLocalSettings/userLocalSettings"; import { useUserSettings } from "@/lib/userSettings"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Archive, Bookmark, Globe } from "lucide-react"; +import { Archive, Bookmark, Clock, Globe } from "lucide-react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -71,6 +71,9 @@ export default function UserOptions() { }); }, }); + const [timezones, setTimezones] = useState< + { label: string; value: string }[] | null + >(null); const bookmarkClickActionTranslation: Record< ZUserSettings["bookmarkClickAction"], @@ -92,6 +95,39 @@ export default function UserOptions() { hide: t("settings.info.user_settings.archive_display_behaviour.hide"), }; + // Get all supported timezones and format them nicely + useEffect(() => { + try { + const browserTimezones = Intl.supportedValuesOf("timeZone"); + setTimezones( + browserTimezones + .map((tz) => { + // Create a more readable label by replacing underscores with spaces + // and showing the current time offset + const now = new Date(); + const formatter = new Intl.DateTimeFormat("en", { + timeZone: tz, + timeZoneName: "short", + }); + const parts = formatter.formatToParts(now); + const timeZoneName = + parts.find((part) => part.type === "timeZoneName")?.value || ""; + + // Format the timezone name for display + const displayName = tz.replace(/_/g, " ").replace("/", " / "); + const label = timeZoneName + ? `${displayName} (${timeZoneName})` + : displayName; + + return { value: tz, label }; + }) + .sort((a, b) => a.label.localeCompare(b.label)), + ); + } catch { + setTimezones(null); + } + }, []); + const form = useForm>({ resolver: zodResolver(zUserSettingsSchema), defaultValues: data, @@ -119,9 +155,47 @@ export default function UserOptions() { + ( +
+ + +
+ )} + /> + -
+