fix(ai-chat): show reset date for future credits
This commit is contained in:
parent
6765523d6f
commit
a9860eac10
|
|
@ -0,0 +1,78 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { computeRateLimitMessage } from "./rate-limit"
|
||||
|
||||
vi.mock("~/i18n", () => ({
|
||||
getI18n: () => ({
|
||||
language: "en-GB",
|
||||
resolvedLanguage: "en-GB",
|
||||
t: (key: string, options?: Record<string, unknown>) => {
|
||||
switch (key) {
|
||||
case "rate_limit.depleted": {
|
||||
return "AI credits depleted"
|
||||
}
|
||||
case "rate_limit.minute": {
|
||||
return "minute"
|
||||
}
|
||||
case "rate_limit.minutes": {
|
||||
return "minutes"
|
||||
}
|
||||
case "rate_limit.resets_at": {
|
||||
return `resets at ${options?.time as string}`
|
||||
}
|
||||
case "rate_limit.resets_in": {
|
||||
return `resets in ${options?.value as string}`
|
||||
}
|
||||
case "rate_limit.credits_left": {
|
||||
return `${options?.count as number} credits left`
|
||||
}
|
||||
case "rate_limit.upgrade_to_get_more": {
|
||||
return "Start free trial to get more AI credits."
|
||||
}
|
||||
default: {
|
||||
return key
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
describe("computeRateLimitMessage", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it("shows only the time when credits reset later today", () => {
|
||||
vi.setSystemTime(new Date(2026, 3, 10, 8, 0))
|
||||
|
||||
const message = computeRateLimitMessage(undefined, {
|
||||
usage: {
|
||||
total: 5_000_000,
|
||||
used: 5_000_000,
|
||||
remaining: 0,
|
||||
resetAt: new Date(2026, 3, 10, 20, 45),
|
||||
},
|
||||
})
|
||||
|
||||
expect(message).toBe("AI credits depleted · resets at 20:45")
|
||||
})
|
||||
|
||||
it("includes the date when credits reset on a future day", () => {
|
||||
vi.setSystemTime(new Date(2026, 3, 10, 8, 0))
|
||||
|
||||
const message = computeRateLimitMessage(undefined, {
|
||||
usage: {
|
||||
total: 5_000_000,
|
||||
used: 5_000_000,
|
||||
remaining: 0,
|
||||
resetAt: new Date(2026, 3, 12, 20, 45),
|
||||
},
|
||||
})
|
||||
|
||||
expect(message).toBe("AI credits depleted · resets at 12 Apr, 20:45")
|
||||
})
|
||||
})
|
||||
|
|
@ -20,6 +20,7 @@ const formatResetTime = (windowResetTime: Date) => {
|
|||
const now = new Date()
|
||||
const diffMs = resetDate.getTime() - now.getTime()
|
||||
const diffMinutes = Math.ceil(diffMs / (1000 * 60))
|
||||
const locale = i18n.language || i18n.resolvedLanguage || undefined
|
||||
|
||||
if (diffMinutes < 60 && diffMinutes > 0) {
|
||||
const unit =
|
||||
|
|
@ -30,12 +31,31 @@ const formatResetTime = (windowResetTime: Date) => {
|
|||
return t("rate_limit.resets_in", { ns: "ai", value })
|
||||
}
|
||||
|
||||
const timeFormatter = new Intl.DateTimeFormat("en-GB", {
|
||||
const isSameCalendarDay =
|
||||
resetDate.getFullYear() === now.getFullYear() &&
|
||||
resetDate.getMonth() === now.getMonth() &&
|
||||
resetDate.getDate() === now.getDate()
|
||||
|
||||
const time = new Intl.DateTimeFormat(locale, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
})
|
||||
return t("rate_limit.resets_at", { ns: "ai", time: timeFormatter.format(resetDate) })
|
||||
}).format(resetDate)
|
||||
|
||||
if (isSameCalendarDay) {
|
||||
return t("rate_limit.resets_at", { ns: "ai", time })
|
||||
}
|
||||
|
||||
const dateTime = new Intl.DateTimeFormat(locale, {
|
||||
...(resetDate.getFullYear() !== now.getFullYear() ? { year: "numeric" as const } : {}),
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
}).format(resetDate)
|
||||
|
||||
return t("rate_limit.resets_at", { ns: "ai", time: dateTime })
|
||||
}
|
||||
|
||||
export function computeIsRateLimited(
|
||||
|
|
|
|||
Loading…
Reference in New Issue