From 526757388076067872a5e17a0121f63077887a51 Mon Sep 17 00:00:00 2001 From: Adam Bowker Date: Tue, 7 Apr 2026 11:58:05 -0700 Subject: [PATCH] feat(code): show PR comments in review panel --- .../archive/components/ArchivedTasksView.tsx | 28 +--------- .../sidebar/components/items/TaskItem.tsx | 23 +------- apps/code/src/renderer/utils/time.ts | 52 +++++++++++++++++++ 3 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 apps/code/src/renderer/utils/time.ts diff --git a/apps/code/src/renderer/features/archive/components/ArchivedTasksView.tsx b/apps/code/src/renderer/features/archive/components/ArchivedTasksView.tsx index 39c1e202d..888c6bee3 100644 --- a/apps/code/src/renderer/features/archive/components/ArchivedTasksView.tsx +++ b/apps/code/src/renderer/features/archive/components/ArchivedTasksView.tsx @@ -28,6 +28,7 @@ import type { Task } from "@shared/types"; import type { ArchivedTask } from "@shared/types/archive"; import { useNavigationStore } from "@stores/navigationStore"; import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { formatRelativeTimeLong } from "@utils/time"; import { toast } from "@utils/toast"; import { useMemo, useState } from "react"; @@ -35,32 +36,7 @@ const BRANCH_NOT_FOUND_PATTERN = /Branch '(.+)' does not exist/; function formatRelativeDate(isoDate: string | undefined): string { if (!isoDate) return "—"; - const date = new Date(isoDate); - const now = new Date(); - const diffMs = now.getTime() - date.getTime(); - const diffSeconds = Math.floor(diffMs / 1000); - const diffMinutes = Math.floor(diffSeconds / 60); - const diffHours = Math.floor(diffMinutes / 60); - const diffDays = Math.floor(diffHours / 24); - - if (diffSeconds < 60) { - return "just now"; - } - if (diffMinutes < 60) { - return diffMinutes === 1 ? "1 minute ago" : `${diffMinutes} minutes ago`; - } - if (diffHours < 24) { - return diffHours === 1 ? "1 hour ago" : `${diffHours} hours ago`; - } - if (diffDays < 7) { - return diffDays === 1 ? "1 day ago" : `${diffDays} days ago`; - } - - return date.toLocaleDateString(undefined, { - month: "short", - day: "numeric", - year: "numeric", - }); + return formatRelativeTimeLong(isoDate); } function getRepoName(repository: string | null | undefined): string { diff --git a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx index 11477222d..cd4c50758 100644 --- a/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx +++ b/apps/code/src/renderer/features/sidebar/components/items/TaskItem.tsx @@ -12,6 +12,7 @@ import { PushPin, } from "@phosphor-icons/react"; import { selectIsFocusedOnWorktree, useFocusStore } from "@stores/focusStore"; +import { formatRelativeTimeShort } from "@utils/time"; import { useCallback, useEffect, useRef, useState } from "react"; import { SidebarItem } from "../SidebarItem"; @@ -44,26 +45,6 @@ interface TaskItemProps { onEditCancel?: () => void; } -function formatRelativeTime(timestamp: number): string { - const now = Date.now(); - const diff = now - timestamp; - - const minutes = Math.floor(diff / (1000 * 60)); - const hours = Math.floor(diff / (1000 * 60 * 60)); - const days = Math.floor(diff / (1000 * 60 * 60 * 24)); - const weeks = Math.floor(days / 7); - const months = Math.floor(days / 30); - const years = Math.floor(days / 365); - - if (years > 0) return `${years}y`; - if (months > 0) return `${months}mo`; - if (weeks > 0) return `${weeks}w`; - if (days > 0) return `${days}d`; - if (hours > 0) return `${hours}h`; - if (minutes > 0) return `${minutes}m`; - return "now"; -} - interface TaskHoverToolbarProps { isPinned: boolean; onTogglePin?: () => void; @@ -252,7 +233,7 @@ export function TaskItem({ const timestampNode = timestamp ? ( - {formatRelativeTime(timestamp)} + {formatRelativeTimeShort(timestamp)} ) : null; diff --git a/apps/code/src/renderer/utils/time.ts b/apps/code/src/renderer/utils/time.ts new file mode 100644 index 000000000..5b49aa831 --- /dev/null +++ b/apps/code/src/renderer/utils/time.ts @@ -0,0 +1,52 @@ +/** + * Format a timestamp as a short relative string (e.g. "3m", "2h", "5d"). + * Accepts either a Unix ms timestamp or an ISO date string. + */ +export function formatRelativeTimeShort(timestamp: number | string): string { + const ms = + typeof timestamp === "string" ? new Date(timestamp).getTime() : timestamp; + const diff = Date.now() - ms; + + const minutes = Math.floor(diff / 60_000); + const hours = Math.floor(diff / 3_600_000); + const days = Math.floor(diff / 86_400_000); + const weeks = Math.floor(days / 7); + const months = Math.floor(days / 30); + const years = Math.floor(days / 365); + + if (years > 0) return `${years}y`; + if (months > 0) return `${months}mo`; + if (weeks > 0) return `${weeks}w`; + if (days > 0) return `${days}d`; + if (hours > 0) return `${hours}h`; + if (minutes > 0) return `${minutes}m`; + return "now"; +} + +/** + * Format a timestamp as a longer relative string (e.g. "3 minutes ago", "1 day ago"). + * Falls back to a locale date for anything older than a week. + * Accepts either a Unix ms timestamp or an ISO date string. + */ +export function formatRelativeTimeLong(timestamp: number | string): string { + const date = + typeof timestamp === "string" ? new Date(timestamp) : new Date(timestamp); + const diff = Date.now() - date.getTime(); + + const seconds = Math.floor(diff / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + if (seconds < 60) return "just now"; + if (minutes < 60) + return minutes === 1 ? "1 minute ago" : `${minutes} minutes ago`; + if (hours < 24) return hours === 1 ? "1 hour ago" : `${hours} hours ago`; + if (days < 7) return days === 1 ? "1 day ago" : `${days} days ago`; + + return date.toLocaleDateString(undefined, { + month: "short", + day: "numeric", + year: "numeric", + }); +}