11import { GlobeAltIcon , GlobeAmericasIcon } from "@heroicons/react/20/solid" ;
2+ import { useRouteLoaderData } from "@remix-run/react" ;
23import { Laptop } from "lucide-react" ;
34import { memo , type ReactNode , useMemo , useSyncExternalStore } from "react" ;
45import { CopyButton } from "./CopyButton" ;
@@ -19,7 +20,7 @@ function getLocalTimeZone(): string {
1920// For SSR compatibility: returns "UTC" on server, actual timezone on client
2021function subscribeToTimeZone ( ) {
2122 // No-op - timezone doesn't change
22- return ( ) => { } ;
23+ return ( ) => { } ;
2324}
2425
2526function getTimeZoneSnapshot ( ) : string {
@@ -39,6 +40,18 @@ export function useLocalTimeZone(): string {
3940 return useSyncExternalStore ( subscribeToTimeZone , getTimeZoneSnapshot , getServerTimeZoneSnapshot ) ;
4041}
4142
43+ /**
44+ * Hook to get the user's preferred timezone.
45+ * Returns the timezone stored in the user's preferences cookie (from root loader),
46+ * falling back to the browser's local timezone if not set.
47+ */
48+ export function useUserTimeZone ( ) : string {
49+ const rootData = useRouteLoaderData ( "root" ) as { timezone ?: string } | undefined ;
50+ const localTimeZone = useLocalTimeZone ( ) ;
51+ // Use stored timezone from cookie, or fall back to browser's local timezone
52+ return rootData ?. timezone && rootData . timezone !== "UTC" ? rootData . timezone : localTimeZone ;
53+ }
54+
4255type DateTimeProps = {
4356 date : Date | string ;
4457 timeZone ?: string ;
@@ -63,15 +76,15 @@ export const DateTime = ({
6376 hour12 = true ,
6477} : DateTimeProps ) => {
6578 const locales = useLocales ( ) ;
66- const localTimeZone = useLocalTimeZone ( ) ;
79+ const userTimeZone = useUserTimeZone ( ) ;
6780
6881 const realDate = useMemo ( ( ) => ( typeof date === "string" ? new Date ( date ) : date ) , [ date ] ) ;
6982
7083 const formattedDateTime = (
7184 < span suppressHydrationWarning >
7285 { formatDateTime (
7386 realDate ,
74- timeZone ?? localTimeZone ,
87+ timeZone ?? userTimeZone ,
7588 locales ,
7689 includeSeconds ,
7790 includeTime ,
@@ -91,7 +104,7 @@ export const DateTime = ({
91104 < TooltipContent
92105 realDate = { realDate }
93106 timeZone = { timeZone }
94- localTimeZone = { localTimeZone }
107+ localTimeZone = { userTimeZone }
95108 locales = { locales }
96109 />
97110 }
@@ -167,7 +180,7 @@ export function formatDateTimeISO(date: Date, timeZone: string): string {
167180// New component that only shows date when it changes
168181export const SmartDateTime = ( { date, previousDate = null , hour12 = true } : DateTimeProps ) => {
169182 const locales = useLocales ( ) ;
170- const localTimeZone = useLocalTimeZone ( ) ;
183+ const userTimeZone = useUserTimeZone ( ) ;
171184 const realDate = typeof date === "string" ? new Date ( date ) : date ;
172185 const realPrevDate = previousDate
173186 ? typeof previousDate === "string"
@@ -180,8 +193,8 @@ export const SmartDateTime = ({ date, previousDate = null, hour12 = true }: Date
180193
181194 // Format with appropriate function
182195 const formattedDateTime = showDatePart
183- ? formatSmartDateTime ( realDate , localTimeZone , locales , hour12 )
184- : formatTimeOnly ( realDate , localTimeZone , locales , hour12 ) ;
196+ ? formatSmartDateTime ( realDate , userTimeZone , locales , hour12 )
197+ : formatTimeOnly ( realDate , userTimeZone , locales , hour12 ) ;
185198
186199 return < span suppressHydrationWarning > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ span > ;
187200} ;
@@ -235,14 +248,16 @@ function formatTimeOnly(
235248
236249const DateTimeAccurateInner = ( {
237250 date,
238- timeZone = "UTC" ,
251+ timeZone,
239252 previousDate = null ,
240253 showTooltip = true ,
241254 hideDate = false ,
242255 hour12 = true ,
243256} : DateTimeProps ) => {
244257 const locales = useLocales ( ) ;
245- const localTimeZone = useLocalTimeZone ( ) ;
258+ const userTimeZone = useUserTimeZone ( ) ;
259+ // Use provided timeZone prop if available, otherwise fall back to user's preferred timezone
260+ const displayTimeZone = timeZone ?? userTimeZone ;
246261 const realDate = typeof date === "string" ? new Date ( date ) : date ;
247262 const realPrevDate = previousDate
248263 ? typeof previousDate === "string"
@@ -253,13 +268,13 @@ const DateTimeAccurateInner = ({
253268 // Smart formatting based on whether date changed
254269 const formattedDateTime = useMemo ( ( ) => {
255270 return hideDate
256- ? formatTimeOnly ( realDate , localTimeZone , locales , hour12 )
271+ ? formatTimeOnly ( realDate , displayTimeZone , locales , hour12 )
257272 : realPrevDate
258273 ? isSameDay ( realDate , realPrevDate )
259- ? formatTimeOnly ( realDate , localTimeZone , locales , hour12 )
260- : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 )
261- : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 ) ;
262- } , [ realDate , localTimeZone , locales , hour12 , hideDate , previousDate ] ) ;
274+ ? formatTimeOnly ( realDate , displayTimeZone , locales , hour12 )
275+ : formatDateTimeAccurate ( realDate , displayTimeZone , locales , hour12 )
276+ : formatDateTimeAccurate ( realDate , displayTimeZone , locales , hour12 ) ;
277+ } , [ realDate , displayTimeZone , locales , hour12 , hideDate , previousDate ] ) ;
263278
264279 if ( ! showTooltip )
265280 return < span suppressHydrationWarning > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ span > ;
@@ -268,7 +283,7 @@ const DateTimeAccurateInner = ({
268283 < TooltipContent
269284 realDate = { realDate }
270285 timeZone = { timeZone }
271- localTimeZone = { localTimeZone }
286+ localTimeZone = { userTimeZone }
272287 locales = { locales }
273288 />
274289 ) ;
@@ -328,9 +343,9 @@ function formatDateTimeAccurate(
328343
329344export const DateTimeShort = ( { date, hour12 = true } : DateTimeProps ) => {
330345 const locales = useLocales ( ) ;
331- const localTimeZone = useLocalTimeZone ( ) ;
346+ const userTimeZone = useUserTimeZone ( ) ;
332347 const realDate = typeof date === "string" ? new Date ( date ) : date ;
333- const formattedDateTime = formatDateTimeShort ( realDate , localTimeZone , locales , hour12 ) ;
348+ const formattedDateTime = formatDateTimeShort ( realDate , userTimeZone , locales , hour12 ) ;
334349
335350 return < span suppressHydrationWarning > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ span > ;
336351} ;
0 commit comments