diff --git a/app/admin/competitions/competition-row.tsx b/app/admin/competitions/competition-row.tsx index 5240896e..36f57e3a 100644 --- a/app/admin/competitions/competition-row.tsx +++ b/app/admin/competitions/competition-row.tsx @@ -19,6 +19,7 @@ import { import { CreateEditCompetitionForm } from "@/components/forms/create-edit-competition-form"; import { useState } from "react"; import { formatDate, formatDateTime } from "@/lib/time-utils"; +import { getBrowserTimezone } from "@/hooks/getBrowserTimezone"; import { CompetitionStatusBadge } from "./competition-status-badge"; import { getCompetitionStatusFromObject } from "@/lib/competition-status"; @@ -32,6 +33,7 @@ export default function CompetitionRow({ nResolvedProps: number; }) { const [open, setOpen] = useState(false); + const timezone = getBrowserTimezone(); const status = getCompetitionStatusFromObject(competition); @@ -84,22 +86,22 @@ export default function CompetitionRow({ competition.forecasts_open_date && ( <> Forecasts open{" "} - {formatDate(competition.forecasts_open_date)} + {formatDate(competition.forecasts_open_date, timezone)} > )} {status === "forecasts-open" && competition.forecasts_close_date && ( <> Forecasts close{" "} - {formatDate(competition.forecasts_close_date)} + {formatDate(competition.forecasts_close_date, timezone)} > )} {status === "forecasts-closed" && competition.end_date && ( - <>Ends {formatDate(competition.end_date)}> + <>Ends {formatDate(competition.end_date, timezone)}> )} {status === "ended" && competition.end_date && ( - <>Ended {formatDate(competition.end_date)}> + <>Ended {formatDate(competition.end_date, timezone)}> )} {status === "private" && ( <>Uses per-prop deadlines> @@ -114,17 +116,17 @@ export default function CompetitionRow({ {competition.forecasts_open_date && (
Forecasts Open:{" "} - {formatDateTime(competition.forecasts_open_date)} + {formatDateTime(competition.forecasts_open_date, timezone)}
)} {competition.forecasts_close_date && (Forecasts Close:{" "} - {formatDateTime(competition.forecasts_close_date)} + {formatDateTime(competition.forecasts_close_date, timezone)}
)} {competition.end_date && ( -Ends: {formatDateTime(competition.end_date)}
+Ends: {formatDateTime(competition.end_date, timezone)}
)} )} diff --git a/app/admin/users/[userId]/user-detail-card.tsx b/app/admin/users/[userId]/user-detail-card.tsx index 4e45a86b..70e282f7 100644 --- a/app/admin/users/[userId]/user-detail-card.tsx +++ b/app/admin/users/[userId]/user-detail-card.tsx @@ -14,8 +14,9 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { Copy, Shield, User, UserCheck, UserX } from "lucide-react"; -import { format } from "date-fns"; import { setUserActive } from "@/lib/db_actions/users"; +import { getBrowserTimezone } from "@/hooks/getBrowserTimezone"; +import { formatDate, formatDateTime } from "@/lib/time-utils"; import { startImpersonation } from "@/lib/auth/impersonation"; import { handleServerActionResult } from "@/lib/server-action-helpers"; import { toast } from "@/hooks/use-toast"; @@ -32,6 +33,7 @@ export default function UserDetailCard({ user }: UserDetailCardProps) { const [isImpersonateDialogOpen, setIsImpersonateDialogOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); const router = useRouter(); + const timezone = getBrowserTimezone(); const isActive = user.deactivated_at === null; const canImpersonate = !user.is_admin && isActive; @@ -191,7 +193,7 @@ export default function UserDetailCard({ user }: UserDetailCardProps) { Created - {format(new Date(user.created_at), "MMM d, yyyy")} + {formatDate(new Date(user.created_at), timezone)} @@ -200,7 +202,7 @@ export default function UserDetailCard({ user }: UserDetailCardProps) { Updated - {format(new Date(user.updated_at), "MMM d, yyyy")} + {formatDate(new Date(user.updated_at), timezone)} @@ -210,10 +212,7 @@ export default function UserDetailCard({ user }: UserDetailCardProps) { Deactivated - {format( - new Date(user.deactivated_at), - "MMM d, yyyy 'at' h:mm a", - )} + {formatDateTime(new Date(user.deactivated_at), timezone)} )} diff --git a/app/competitions/[competitionId]/competition-start-end.tsx b/app/competitions/[competitionId]/competition-start-end.tsx index 136a9dd1..dce95f1a 100644 --- a/app/competitions/[competitionId]/competition-start-end.tsx +++ b/app/competitions/[competitionId]/competition-start-end.tsx @@ -1,16 +1,16 @@ "use client"; import { Competition } from "@/types/db_types"; -import { formatInTimeZone } from "date-fns-tz"; import { getCompetitionStatusFromObject } from "@/lib/competition-status"; - -const DATE_FORMAT = "MMM d, yyyy"; +import { getBrowserTimezone } from "@/hooks/getBrowserTimezone"; +import { formatDate } from "@/lib/time-utils"; export default function CompetitionStartEnd({ competition, }: { competition: Competition; }) { + const timezone = getBrowserTimezone(); const status = getCompetitionStatusFromObject(competition); return (Forecasts open{" "} - {formatInTimeZone( - competition.forecasts_open_date, - "UTC", - DATE_FORMAT, - )} + {formatDate(competition.forecasts_open_date, timezone)}
Forecasts close{" "} - {formatInTimeZone( - competition.forecasts_close_date, - "UTC", - DATE_FORMAT, - )} + {formatDate(competition.forecasts_close_date, timezone)}
> )} @@ -42,19 +34,11 @@ export default function CompetitionStartEnd({ <>Forecasts opened{" "} - {formatInTimeZone( - competition.forecasts_open_date, - "UTC", - DATE_FORMAT, - )} + {formatDate(competition.forecasts_open_date, timezone)}
Forecasts close{" "} - {formatInTimeZone( - competition.forecasts_close_date, - "UTC", - DATE_FORMAT, - )} + {formatDate(competition.forecasts_close_date, timezone)}
> )} @@ -64,22 +48,18 @@ export default function CompetitionStartEnd({ <>Forecasts closed{" "} - {formatInTimeZone( - competition.forecasts_close_date, - "UTC", - DATE_FORMAT, - )} + {formatDate(competition.forecasts_close_date, timezone)}
Competition Ends{" "} - {formatInTimeZone(competition.end_date, "UTC", DATE_FORMAT)} + {formatDate(competition.end_date, timezone)}
> )} {status === "ended" && competition.end_date && (Ended{" "} - {formatInTimeZone(competition.end_date, "UTC", DATE_FORMAT)} + {formatDate(competition.end_date, timezone)}
)} {status === "private" && ( diff --git a/app/competitions/[competitionId]/props/[propId]/competition-prop-view.tsx b/app/competitions/[competitionId]/props/[propId]/competition-prop-view.tsx index 84420578..93511910 100644 --- a/app/competitions/[competitionId]/props/[propId]/competition-prop-view.tsx +++ b/app/competitions/[competitionId]/props/[propId]/competition-prop-view.tsx @@ -10,10 +10,12 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { MarkdownRenderer } from "@/components/markdown"; import { useCurrentUser } from "@/hooks/useCurrentUser"; +import { getBrowserTimezone } from "@/hooks/getBrowserTimezone"; import { createForecast, updateForecast } from "@/lib/db_actions"; import { useServerAction } from "@/hooks/use-server-action"; import { Spinner } from "@/components/ui/spinner"; import { PropEditDialog } from "@/components/dialogs/prop-edit-dialog"; +import { formatDateTime } from "@/lib/time-utils"; interface CompetitionPropViewProps { prop: PropWithUserForecast; @@ -68,17 +70,10 @@ const getProbColor = (prob: number | null) => { }; }; -function formatDate(date: Date | string | null): string { +function formatPropDate(date: Date | string | null, timezone: string): string { if (!date) return "No deadline"; const d = typeof date === "string" ? new Date(date) : date; - return d.toLocaleDateString("en-US", { - weekday: "short", - month: "short", - day: "numeric", - year: "numeric", - hour: "numeric", - minute: "2-digit", - }); + return formatDateTime(d, timezone); } function getRelativeDeadline(date: Date | string | null): string | null { @@ -104,6 +99,7 @@ export function CompetitionPropView({ }: CompetitionPropViewProps) { const router = useRouter(); const { user } = useCurrentUser(); + const timezone = getBrowserTimezone(); const [localForecast, setLocalForecast] = useStateForecasts due:{" "} - {watchedForecastsDueDate.toLocaleDateString()} + {formatDate(watchedForecastsDueDate, timezone)}
)}
Ends:{" "}
- {formatDate(competition.end_date)}
+
Ends:{" "}
- {formatDate(competition.end_date)}
+