refactor(webui): use Core date-time formatting

This commit is contained in:
2026-07-21 13:52:59 +02:00
parent 7237679a85
commit 5dc9392290

View File

@@ -8,6 +8,7 @@ import {
DismissibleAlert,
ExplorerTree,
fetchAuthGroups,
formatDateTime,
FormField,
LoadingFrame,
PasswordField,
@@ -19,7 +20,8 @@ import {
hasScope,
type ApiSettings,
type AuthInfo,
type AuthUpdate
type AuthUpdate,
type FormatDateTimeOptions
} from "@govoplan/core-webui";
import {
createAddressBook,
@@ -291,14 +293,17 @@ function syncSourceLabel(source: AddressSyncSource): string {
return source.display_name || source.external_address_book_ref || source.connector_type;
}
function formatDateTime(value?: string | null): string {
if (!value) return "Never";
try {
return new Intl.DateTimeFormat(undefined, { dateStyle: "short", timeStyle: "short" }).format(new Date(value));
} catch {
return value;
}
}
const ADDRESS_DATE_TIME_OPTIONS: FormatDateTimeOptions = {
fallback: "Never",
year: undefined,
month: undefined,
day: undefined,
hour: undefined,
minute: undefined,
timeZoneName: undefined,
dateStyle: "short",
timeStyle: "short"
};
function planSummary(plan: AddressSyncPlan | null): string {
if (!plan) return "No preview loaded.";
@@ -1740,7 +1745,7 @@ export default function AddressBookPage({ settings, auth, onAuthChange }: Props)
{selectedBookSyncSources.map((source) => (
<p key={source.id}>
{syncSourceLabel(source)} · {source.connector_type} · {source.status}
{source.last_success_at ? ` · last success ${formatDateTime(source.last_success_at)}` : ""}
{source.last_success_at ? ` · last success ${formatDateTime(source.last_success_at, ADDRESS_DATE_TIME_OPTIONS)}` : ""}
{source.last_error ? ` · ${source.last_error}` : ""}
</p>
))}
@@ -2314,7 +2319,7 @@ export default function AddressBookPage({ settings, auth, onAuthChange }: Props)
<StatusBadge status={syncInspector.source.status} />
{syncInspector.source.read_only && <StatusBadge status="read-only" />}
</div>
<p className="muted">Last attempt: {formatDateTime(syncInspector.source.last_attempted_at)} · Last success: {formatDateTime(syncInspector.source.last_success_at)}</p>
<p className="muted">Last attempt: {formatDateTime(syncInspector.source.last_attempted_at, ADDRESS_DATE_TIME_OPTIONS)} · Last success: {formatDateTime(syncInspector.source.last_success_at, ADDRESS_DATE_TIME_OPTIONS)}</p>
{syncInspector.source.last_error && <DismissibleAlert tone="danger" resetKey={syncInspector.source.last_error}>{syncInspector.source.last_error}</DismissibleAlert>}
<div className="button-row compact-actions">
<Button
@@ -2383,7 +2388,7 @@ export default function AddressBookPage({ settings, auth, onAuthChange }: Props)
<div className="address-sync-record-list">
{syncTombstones.slice(0, 20).map((tombstone) => (
<div className="address-sync-record-row" key={tombstone.id}>
<span><strong>{tombstone.remote_uid || tombstone.resource_href || tombstone.contact_id}</strong><small>{formatDateTime(tombstone.synced_at || tombstone.remote_deleted_at || tombstone.local_deleted_at)}</small></span>
<span><strong>{tombstone.remote_uid || tombstone.resource_href || tombstone.contact_id}</strong><small>{formatDateTime(tombstone.synced_at || tombstone.remote_deleted_at || tombstone.local_deleted_at, ADDRESS_DATE_TIME_OPTIONS)}</small></span>
</div>
))}
</div>