From 1340e00b61af79c4467daa922c4c6ac6807e535e Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Mon, 9 Feb 2026 00:02:43 +0530 Subject: [PATCH] feat: extract timestamp formatting and text truncation into separate utility functions --- frontend/src/app/agents/[agentId]/page.tsx | 37 ++------------ frontend/src/app/agents/page.tsx | 44 ++--------------- .../src/app/board-groups/[groupId]/page.tsx | 13 +---- frontend/src/app/board-groups/page.tsx | 13 +---- frontend/src/app/boards/page.tsx | 13 +---- .../src/app/gateways/[gatewayId]/page.tsx | 13 +---- frontend/src/app/gateways/page.tsx | 19 +------ frontend/src/app/organization/page.tsx | 13 +---- frontend/src/lib/formatters.ts | 49 +++++++++++++++++++ 9 files changed, 64 insertions(+), 150 deletions(-) create mode 100644 frontend/src/lib/formatters.ts diff --git a/frontend/src/app/agents/[agentId]/page.tsx b/frontend/src/app/agents/[agentId]/page.tsx index 8ddfe119..b5a153e0 100644 --- a/frontend/src/app/agents/[agentId]/page.tsx +++ b/frontend/src/app/agents/[agentId]/page.tsx @@ -22,6 +22,10 @@ import { type listBoardsApiV1BoardsGetResponse, useListBoardsApiV1BoardsGet, } from "@/api/generated/boards/boards"; +import { + formatRelativeTimestamp as formatRelative, + formatTimestamp, +} from "@/lib/formatters"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { ActivityEventRead, @@ -41,39 +45,6 @@ import { DialogTitle, } from "@/components/ui/dialog"; -const parseTimestamp = (value?: string | null) => { - if (!value) return null; - const hasTz = /[zZ]|[+-]\d\d:\d\d$/.test(value); - const normalized = hasTz ? value : `${value}Z`; - const date = new Date(normalized); - if (Number.isNaN(date.getTime())) return null; - return date; -}; - -const formatTimestamp = (value?: string | null) => { - const date = parseTimestamp(value); - if (!date) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - -const formatRelative = (value?: string | null) => { - const date = parseTimestamp(value); - if (!date) return "—"; - const diff = Date.now() - date.getTime(); - const minutes = Math.round(diff / 60000); - if (minutes < 1) return "Just now"; - if (minutes < 60) return `${minutes}m ago`; - const hours = Math.round(minutes / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.round(hours / 24); - return `${days}d ago`; -}; - export default function AgentDetailPage() { const { isSignedIn } = useAuth(); const router = useRouter(); diff --git a/frontend/src/app/agents/page.tsx b/frontend/src/app/agents/page.tsx index effa2824..c0889076 100644 --- a/frontend/src/app/agents/page.tsx +++ b/frontend/src/app/agents/page.tsx @@ -41,48 +41,14 @@ import { getListBoardsApiV1BoardsGetQueryKey, useListBoardsApiV1BoardsGet, } from "@/api/generated/boards/boards"; +import { + formatRelativeTimestamp as formatRelative, + formatTimestamp, + truncateText as truncate, +} from "@/lib/formatters"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { AgentRead } from "@/api/generated/model"; -const parseTimestamp = (value?: string | null) => { - if (!value) return null; - const hasTz = /[zZ]|[+-]\d\d:\d\d$/.test(value); - const normalized = hasTz ? value : `${value}Z`; - const date = new Date(normalized); - if (Number.isNaN(date.getTime())) return null; - return date; -}; - -const formatTimestamp = (value?: string | null) => { - const date = parseTimestamp(value); - if (!date) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - -const formatRelative = (value?: string | null) => { - const date = parseTimestamp(value); - if (!date) return "—"; - const diff = Date.now() - date.getTime(); - const minutes = Math.round(diff / 60000); - if (minutes < 1) return "Just now"; - if (minutes < 60) return `${minutes}m ago`; - const hours = Math.round(minutes / 60); - if (hours < 24) return `${hours}h ago`; - const days = Math.round(hours / 24); - return `${days}d ago`; -}; - -const truncate = (value?: string | null, max = 18) => { - if (!value) return "—"; - if (value.length <= max) return value; - return `${value.slice(0, max)}…`; -}; - export default function AgentsPage() { const { isSignedIn } = useAuth(); const queryClient = useQueryClient(); diff --git a/frontend/src/app/board-groups/[groupId]/page.tsx b/frontend/src/app/board-groups/[groupId]/page.tsx index 2d1be6a1..bdaf3d7d 100644 --- a/frontend/src/app/board-groups/[groupId]/page.tsx +++ b/frontend/src/app/board-groups/[groupId]/page.tsx @@ -45,21 +45,10 @@ import { BoardChatComposer } from "@/components/BoardChatComposer"; import { Button, buttonVariants } from "@/components/ui/button"; import { createExponentialBackoff } from "@/lib/backoff"; import { apiDatetimeToMs } from "@/lib/datetime"; +import { formatTimestamp } from "@/lib/formatters"; import { cn } from "@/lib/utils"; import { usePageActive } from "@/hooks/usePageActive"; -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - const statusLabel = (value?: string | null) => { switch (value) { case "inbox": diff --git a/frontend/src/app/board-groups/page.tsx b/frontend/src/app/board-groups/page.tsx index b7386f45..36525a18 100644 --- a/frontend/src/app/board-groups/page.tsx +++ b/frontend/src/app/board-groups/page.tsx @@ -34,18 +34,7 @@ import { DialogTitle, } from "@/components/ui/dialog"; import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; - -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; +import { formatTimestamp } from "@/lib/formatters"; export default function BoardGroupsPage() { const { isSignedIn } = useAuth(); diff --git a/frontend/src/app/boards/page.tsx b/frontend/src/app/boards/page.tsx index b8cf9373..6c984f00 100644 --- a/frontend/src/app/boards/page.tsx +++ b/frontend/src/app/boards/page.tsx @@ -25,6 +25,7 @@ import { type listBoardGroupsApiV1BoardGroupsGetResponse, useListBoardGroupsApiV1BoardGroupsGet, } from "@/api/generated/board-groups/board-groups"; +import { formatTimestamp } from "@/lib/formatters"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { BoardGroupRead, BoardRead } from "@/api/generated/model"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; @@ -40,18 +41,6 @@ import { } from "@/components/ui/dialog"; import { SignedOutPanel } from "@/components/auth/SignedOutPanel"; -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - const compactId = (value: string) => value.length > 8 ? `${value.slice(0, 8)}…` : value; diff --git a/frontend/src/app/gateways/[gatewayId]/page.tsx b/frontend/src/app/gateways/[gatewayId]/page.tsx index 0ba90171..7fda895d 100644 --- a/frontend/src/app/gateways/[gatewayId]/page.tsx +++ b/frontend/src/app/gateways/[gatewayId]/page.tsx @@ -18,22 +18,11 @@ import { type listAgentsApiV1AgentsGetResponse, useListAgentsApiV1AgentsGet, } from "@/api/generated/agents/agents"; +import { formatTimestamp } from "@/lib/formatters"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout"; import { Button } from "@/components/ui/button"; -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - const maskToken = (value?: string | null) => { if (!value) return "—"; if (value.length <= 8) return "••••"; diff --git a/frontend/src/app/gateways/page.tsx b/frontend/src/app/gateways/page.tsx index ecb56a1d..b652e50a 100644 --- a/frontend/src/app/gateways/page.tsx +++ b/frontend/src/app/gateways/page.tsx @@ -34,27 +34,10 @@ import { useDeleteGatewayApiV1GatewaysGatewayIdDelete, useListGatewaysApiV1GatewaysGet, } from "@/api/generated/gateways/gateways"; +import { formatTimestamp, truncateText as truncate } from "@/lib/formatters"; import { useOrganizationMembership } from "@/lib/use-organization-membership"; import type { GatewayRead } from "@/api/generated/model"; -const truncate = (value?: string | null, max = 24) => { - if (!value) return "—"; - if (value.length <= max) return value; - return `${value.slice(0, max)}…`; -}; - -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - export default function GatewaysPage() { const { isSignedIn } = useAuth(); const queryClient = useQueryClient(); diff --git a/frontend/src/app/organization/page.tsx b/frontend/src/app/organization/page.tsx index f039970f..fef746ab 100644 --- a/frontend/src/app/organization/page.tsx +++ b/frontend/src/app/organization/page.tsx @@ -59,20 +59,9 @@ import { SelectValue, } from "@/components/ui/select"; import { DashboardShell } from "@/components/templates/DashboardShell"; +import { formatTimestamp } from "@/lib/formatters"; import { cn } from "@/lib/utils"; -const formatTimestamp = (value?: string | null) => { - if (!value) return "—"; - const date = new Date(`${value}${value.endsWith("Z") ? "" : "Z"}`); - if (Number.isNaN(date.getTime())) return "—"; - return date.toLocaleString(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }); -}; - type AccessScope = "all" | "custom"; type BoardAccessState = Record; diff --git a/frontend/src/lib/formatters.ts b/frontend/src/lib/formatters.ts new file mode 100644 index 00000000..0812f6f6 --- /dev/null +++ b/frontend/src/lib/formatters.ts @@ -0,0 +1,49 @@ +const DASH = "—"; + +export const truncateText = ( + value?: string | null, + max = 24, + fallback = DASH, +): string => { + if (!value) return fallback; + if (value.length <= max) return value; + return `${value.slice(0, max)}…`; +}; + +export const parseTimestamp = (value?: string | null): Date | null => { + if (!value) return null; + const hasTimeZone = /[zZ]|[+-]\d\d:\d\d$/.test(value); + const normalized = hasTimeZone ? value : `${value}Z`; + const date = new Date(normalized); + return Number.isNaN(date.getTime()) ? null : date; +}; + +export const formatTimestamp = ( + value?: string | null, + fallback = DASH, +): string => { + const date = parseTimestamp(value); + if (!date) return fallback; + return date.toLocaleString(undefined, { + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); +}; + +export const formatRelativeTimestamp = ( + value?: string | null, + fallback = DASH, +): string => { + const date = parseTimestamp(value); + if (!date) return fallback; + const diff = Date.now() - date.getTime(); + const minutes = Math.round(diff / 60000); + if (minutes < 1) return "Just now"; + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.round(minutes / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.round(hours / 24); + return `${days}d ago`; +};