From 8903de8cc2d1c7cc60d976a8d8c35e519fccb2b5 Mon Sep 17 00:00:00 2001 From: sonwr Date: Sat, 28 Feb 2026 15:11:25 +0900 Subject: [PATCH 1/3] fix: show reset datetime in tooltip --- src/components/provider-card.test.tsx | 28 +++++++++++++++++++++++++++ src/components/provider-card.tsx | 26 ++++++++++++++++++++++++- src/lib/reset-tooltip.test.ts | 18 +++++++++++++++++ src/lib/reset-tooltip.ts | 10 ++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/lib/reset-tooltip.test.ts create mode 100644 src/lib/reset-tooltip.ts diff --git a/src/components/provider-card.test.tsx b/src/components/provider-card.test.tsx index ed2f965..4e19fc7 100644 --- a/src/components/provider-card.test.tsx +++ b/src/components/provider-card.test.tsx @@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest" import { openUrl } from "@tauri-apps/plugin-opener" import { ProviderCard } from "@/components/provider-card" import { groupLinesByType } from "@/lib/group-lines-by-type" +import { formatResetTooltipText } from "@/lib/reset-tooltip" import { REFRESH_COOLDOWN_MS } from "@/lib/settings" import { formatFixedPrecisionNumber } from "@/lib/utils" @@ -260,9 +261,35 @@ describe("ProviderCard", () => { /> ) expect(screen.getByText("Resets in 1h 5m")).toBeInTheDocument() + expect(screen.getByText(`Next reset: ${new Intl.DateTimeFormat(undefined, { + dateStyle: "medium", + timeStyle: "short", + }).format(Date.parse("2026-02-02T01:05:00.000Z"))}`)).toBeInTheDocument() vi.useRealTimers() }) + it("does not render reset tooltip for invalid reset timestamps", () => { + render( + + ) + + expect(screen.getByText("100% cap")).toBeInTheDocument() + expect(screen.queryByText(/^Next reset:/)).not.toBeInTheDocument() + }) + it("shows 'Resets soon' when reset is under 5 minutes away", () => { vi.useFakeTimers() const now = new Date("2026-02-02T00:00:00.000Z") @@ -386,6 +413,7 @@ describe("ProviderCard", () => { ) const resetButton = screen.getByRole("button", { name: /^Resets today at / }) expect(resetButton).toBeInTheDocument() + expect(screen.getByText(formatResetTooltipText(resetsAt)!)).toBeInTheDocument() fireEvent.click(resetButton) expect(onToggle).toHaveBeenCalledTimes(1) vi.useRealTimers() diff --git a/src/components/provider-card.tsx b/src/components/provider-card.tsx index b26e8f5..b555086 100644 --- a/src/components/provider-card.tsx +++ b/src/components/provider-card.tsx @@ -15,6 +15,7 @@ import { groupLinesByType } from "@/lib/group-lines-by-type" import { clamp01, formatCountNumber, formatFixedPrecisionNumber } from "@/lib/utils" import { calculateDeficit, calculatePaceStatus, type PaceStatus } from "@/lib/pace-status" import { buildPaceDetailText, formatCompactDuration, formatDeficitText, formatRunsOutText, getPaceStatusText } from "@/lib/pace-tooltip" +import { formatResetTooltipText } from "@/lib/reset-tooltip" interface ProviderCardProps { name: string @@ -423,6 +424,7 @@ function MetricLineRenderer({ ? formatResetAt(now, line.resetsAt) : formatResetIn(now, line.resetsAt) : null + const resetTooltipText = line.resetsAt ? formatResetTooltipText(line.resetsAt) : null const secondaryText = resetLabel ?? @@ -494,7 +496,29 @@ function MetricLineRenderer({ {primaryText} {secondaryText && ( - resetLabel && onResetTimerDisplayModeToggle ? ( + resetTooltipText ? ( + + + resetLabel && onResetTimerDisplayModeToggle ? ( + + ) : ( + + {secondaryText} + + ) + } + /> + {resetTooltipText} + + ) : resetLabel && onResetTimerDisplayModeToggle ? (