mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-17 11:25:48 +02:00
fix(frontend): #1602 render print-run / spool-usage / camera-token / SpoolBuddy timestamps in local time
Four frontend formatDate / formatDateTime helpers called new Date(iso) directly on backend timestamps that have no timezone indicator. Per ECMAScript, a bare "2026-06-02T07:50:00" is parsed as local time, so a UTC-stored value got displayed as if its numeric components were already local — visually identical to UTC. Same shape as the #504 fix from Feb 2026, which patched 13 sites but missed these four: PrintLogTable and SpoolUsageHistory hadn't been written yet; CameraTokensPage and SpoolBuddySettingsPage existed but were overlooked. Reporter #2 (@IndividualGhost1905) confirmed with a UTC+3 host: print log shows UTC clock value, system date shows local. PrintLogTable is the "logs/completion time" they called out; the other three are the same pattern in nearby surfaces. Replaced the bare new Date(iso) calls with parseUTCDate(iso) from utils/date.ts — the same helper every other date formatter in the codebase already uses. It appends "Z" to naive ISO strings and parses TZ-tagged strings as-is. CameraTokensPage.isExpired got the same fix because comparing a misparsed Date against Date.now() would produce false "not expired" / "expired" results around the TZ-offset boundary. Reporter #1's printer-card ETA complaint (10:50 + 57m showing 09:48) is NOT addressed by this fix. That ETA comes from formatETA(remainingMinutes) which is purely client-side (new Date() plus minutes from the WebSocket payload, then toLocaleTimeString) — for it to render UTC the browser timezone itself would need to be UTC, which is a browser / OS config issue. Audit confirmed no other regressions: grepped every new Date( call in frontend/src/. Remaining sites either pass an epoch-ms number, use the result only for .getTime() arithmetic where the offset cancels, already wrap in parseUTCDate fallback, or consume a backend timestamp that includes "+00:00" (FailureDetectionSettings reads obico_detection.py's tz-aware isoformat).
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { api } from '../api/client';
|
||||
import { parseUTCDate } from '../utils/date';
|
||||
|
||||
interface PrintLogTableProps {
|
||||
archiveId: number;
|
||||
@@ -17,8 +18,8 @@ function formatDuration(seconds: number | null): string {
|
||||
|
||||
function formatDate(isoString: string | null): string {
|
||||
if (!isoString) return '—';
|
||||
const d = new Date(isoString);
|
||||
return d.toLocaleString();
|
||||
const d = parseUTCDate(isoString);
|
||||
return d ? d.toLocaleString() : '—';
|
||||
}
|
||||
|
||||
export function PrintLogTable({ archiveId }: PrintLogTableProps) {
|
||||
|
||||
@@ -5,8 +5,10 @@ import { api } from '../api/client';
|
||||
import type { SpoolUsageRecord } from '../api/client';
|
||||
import { Button } from './Button';
|
||||
import { useToast } from '../contexts/ToastContext';
|
||||
import { parseUTCDate } from '../utils/date';
|
||||
function formatDate(dateStr: string): string {
|
||||
const date = new Date(dateStr);
|
||||
const date = parseUTCDate(dateStr);
|
||||
if (!date) return '';
|
||||
return date.toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: '2-digit' }) +
|
||||
' ' + date.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
@@ -21,18 +21,20 @@ import { Copy, Plus, Trash2, AlertTriangle } from 'lucide-react';
|
||||
import { api, type LongLivedCameraToken } from '../api/client';
|
||||
import { useToast } from '../contexts/ToastContext';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { parseUTCDate } from '../utils/date';
|
||||
|
||||
const DEFAULT_LIFETIME_DAYS = 90;
|
||||
const MAX_LIFETIME_DAYS = 365;
|
||||
|
||||
function formatDate(iso: string | null): string {
|
||||
if (!iso) return '—';
|
||||
const d = new Date(iso);
|
||||
return d.toLocaleString();
|
||||
const d = parseUTCDate(iso);
|
||||
return d ? d.toLocaleString() : '—';
|
||||
}
|
||||
|
||||
function isExpired(iso: string): boolean {
|
||||
return new Date(iso).getTime() < Date.now();
|
||||
const d = parseUTCDate(iso);
|
||||
return d ? d.getTime() < Date.now() : false;
|
||||
}
|
||||
|
||||
interface CreateTokenFormProps {
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { SpoolBuddyOutletContext } from '../../components/spoolbuddy/SpoolB
|
||||
import { spoolbuddyApi, type SpoolBuddyDevice } from '../../api/client';
|
||||
import { DiagnosticModal } from '../../components/spoolbuddy/DiagnosticModal';
|
||||
import { FileText, Wand2, Zap } from 'lucide-react';
|
||||
import { parseUTCDate } from '../../utils/date';
|
||||
|
||||
|
||||
function formatUptime(seconds: number): string {
|
||||
@@ -18,13 +19,10 @@ function formatUptime(seconds: number): string {
|
||||
|
||||
function formatDateTime(iso: string | null): string {
|
||||
if (!iso) return '-';
|
||||
try {
|
||||
const d = new Date(iso);
|
||||
return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) + ' ' +
|
||||
d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
|
||||
} catch {
|
||||
return '-';
|
||||
}
|
||||
const d = parseUTCDate(iso);
|
||||
if (!d) return '-';
|
||||
return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) + ' ' +
|
||||
d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
const BLANK_OPTIONS = [
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -26,7 +26,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-BuuCTvNJ.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DLXkorBx.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-C3FyyVE7.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user