import { useTranslation } from './useTranslation'; import { useAuth } from '@/lib/auth/AuthContext'; import { format as dateFnsFormat, formatDistanceToNow as dateFnsFormatDistanceToNow, formatDistance as dateFnsFormatDistance, formatRelative as dateFnsFormatRelative, } from 'date-fns'; import { formatInTimeZone } from 'date-fns-tz'; import { enUS, es, fr, ptBR, zhCN, de, it, type Locale } from 'date-fns/locale'; /** * Map of i18next language codes to date-fns locales */ const localeMap: Record = { 'en': enUS, 'en-US': enUS, 'es': es, 'es-ES': es, 'fr': fr, 'fr-FR': fr, 'pt': ptBR, 'pt-BR': ptBR, 'zh': zhCN, 'zh-CN': zhCN, 'de': de, 'de-DE': de, 'it': it, 'it-IT': it, }; /** * Custom hook for localized date formatting using date-fns * Automatically applies the correct locale, timezone, and time format based on user preferences */ export function useLocalizedDate() { const { language } = useTranslation(); const { user } = useAuth(); // Get the locale for the current language, fallback to enUS const locale = localeMap[language] || enUS; // Get timezone from user preferences, fallback to UTC or browser timezone const timezone = user?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'; // Get time format preference (12h or 24h) const timeFormat = user?.preferences?.timeFormat || '12h'; /** * Format a date using date-fns with the current locale and timezone * @param date - The date to format * @param formatStr - The format string (e.g., 'PPP', 'MM/dd/yyyy', 'p' for time) * @param options - Optional formatting options */ const format = ( date: Date | number | string, formatStr: string, options?: { useTimezone?: boolean } ): string => { const dateObj = typeof date === 'string' ? new Date(date) : date; // Replace time format tokens with 12h/24h based on preference let adjustedFormat = formatStr; if (timeFormat === '24h') { // Convert 12h format to 24h format adjustedFormat = formatStr.replace(/h:mm a/gi, 'HH:mm').replace(/p/g, 'HH:mm'); } // Use timezone if requested if (options?.useTimezone && timezone) { return formatInTimeZone(dateObj, timezone, adjustedFormat, { locale }); } return dateFnsFormat(dateObj, adjustedFormat, { locale }); }; /** * Format a date as a distance to now (e.g., "2 hours ago") * @param date - The date to format * @param options - Optional options for formatDistanceToNow */ const formatDistanceToNow = ( date: Date | number | string, options?: { addSuffix?: boolean; includeSeconds?: boolean } ): string => { const dateObj = typeof date === 'string' ? new Date(date) : date; return dateFnsFormatDistanceToNow(dateObj, { ...options, locale }); }; /** * Format the distance between two dates * @param date - The later date * @param baseDate - The earlier date * @param options - Optional options for formatDistance */ const formatDistance = ( date: Date | number, baseDate: Date | number, options?: { addSuffix?: boolean; includeSeconds?: boolean } ): string => { return dateFnsFormatDistance(date, baseDate, { ...options, locale }); }; /** * Format a date relative to now (e.g., "today at 5:00 PM") * @param date - The date to format * @param baseDate - Optional base date (defaults to now) */ const formatRelative = ( date: Date | number, baseDate?: Date | number ): string => { return dateFnsFormatRelative(date, baseDate || new Date(), { locale }); }; /** * Format a time string with the user's preferred time format * @param date - The date/time to format */ const formatTime = (date: Date | number | string): string => { const dateObj = typeof date === 'string' ? new Date(date) : date; const formatStr = timeFormat === '24h' ? 'HH:mm' : 'h:mm a'; return dateFnsFormat(dateObj, formatStr, { locale }); }; /** * Format a date and time with the user's timezone and time format * @param date - The date/time to format */ const formatDateTime = (date: Date | number | string): string => { const dateObj = typeof date === 'string' ? new Date(date) : date; const timeFormatStr = timeFormat === '24h' ? 'HH:mm' : 'h:mm a'; const fullFormat = `PPP ${timeFormatStr}`; if (timezone) { return formatInTimeZone(dateObj, timezone, fullFormat, { locale }); } return dateFnsFormat(dateObj, fullFormat, { locale }); }; return { format, formatDistanceToNow, formatDistance, formatRelative, formatTime, formatDateTime, locale, timezone, timeFormat, }; }