From af6cdfabcc25fff2defc8718440944b7dea93a24 Mon Sep 17 00:00:00 2001 From: benjamin Date: Mon, 18 May 2026 21:09:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E5=A2=9E=E5=8A=A0=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E9=85=8D=E9=A2=9D=E6=97=B6=E9=97=B4=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- frontend/src/types/index.ts | 1 + frontend/src/utils/subscriptionQuota.ts | 42 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 frontend/src/utils/subscriptionQuota.ts diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index ec7d0636..2a24f332 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1480,6 +1480,7 @@ export interface UserSubscription { user_id: number group_id: number status: 'active' | 'expired' | 'revoked' + starts_at: string daily_usage_usd: number weekly_usage_usd: number monthly_usage_usd: number diff --git a/frontend/src/utils/subscriptionQuota.ts b/frontend/src/utils/subscriptionQuota.ts new file mode 100644 index 00000000..719737be --- /dev/null +++ b/frontend/src/utils/subscriptionQuota.ts @@ -0,0 +1,42 @@ +import type { UserSubscription } from '@/types' + +const ONE_DAY_MS = 24 * 60 * 60 * 1000 + +export interface RemainingDurationParts { + days: number + hours: number + minutes: number +} + +export function isOneTimeDailyQuota( + subscription: Pick +): boolean { + if (!subscription.starts_at || !subscription.expires_at) return false + + const startsAt = new Date(subscription.starts_at).getTime() + const expiresAt = new Date(subscription.expires_at).getTime() + + if (!Number.isFinite(startsAt) || !Number.isFinite(expiresAt)) return false + + return expiresAt <= startsAt + ONE_DAY_MS +} + +export function getRemainingDurationParts( + targetAt: Date | string, + now: Date = new Date() +): RemainingDurationParts | null { + const targetTime = targetAt instanceof Date ? targetAt.getTime() : new Date(targetAt).getTime() + const nowTime = now.getTime() + + if (!Number.isFinite(targetTime) || !Number.isFinite(nowTime)) return null + + const diffMs = targetTime - nowTime + if (diffMs <= 0) return null + + const totalMinutes = Math.floor(diffMs / (1000 * 60)) + const days = Math.floor(totalMinutes / (24 * 60)) + const hours = Math.floor((totalMinutes % (24 * 60)) / 60) + const minutes = totalMinutes % 60 + + return { days, hours, minutes } +}