mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
fix(codebuddy-cn): show bonus packs as one-time, not monthly-replenishing
CodeBuddy CN bonus packs ("Bonus Pack N") are one-shot credits whose
CycleEndTime equals DeductionEndTime — they expire for good and never
replenish. The dashboard rendered their resetAt as "Reset in Xd",
implying a monthly refill.
Tag bonus packs recurring:false (refill packs recurring:true) in the
usage handler, forward the flag through parseQuotaData, and word the
quota table / progress bar as "Expires in" / "Expires at" for
one-shot packs.
This commit is contained in:
@@ -165,6 +165,7 @@ export default function ProviderLimitCard({
|
||||
percentage={percentage}
|
||||
unlimited={unlimited}
|
||||
resetTime={quota.resetAt}
|
||||
recurring={quota.recurring !== false}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -69,12 +69,17 @@ export default function QuotaProgressBar({
|
||||
used = 0,
|
||||
total = 0,
|
||||
unlimited = false,
|
||||
resetTime = null
|
||||
resetTime = null,
|
||||
recurring = true,
|
||||
}) {
|
||||
const colors = getColorClasses(percentage);
|
||||
const countdown = formatResetTime(resetTime);
|
||||
const resetDisplay = formatResetTimeDisplay(resetTime);
|
||||
|
||||
|
||||
// recurring defaults true. One-shot packs (e.g. CodeBuddy CN bonus packs)
|
||||
// set recurring:false: resetTime is a hard expiry, so word it as "expires".
|
||||
const resetWord = recurring ? "Reset" : "Expires";
|
||||
|
||||
// percentage is already remaining percentage (from ProviderLimitCard)
|
||||
const remaining = percentage;
|
||||
|
||||
@@ -111,7 +116,7 @@ export default function QuotaProgressBar({
|
||||
{countdown !== "-" && (
|
||||
<div className="flex items-center gap-1">
|
||||
<span>•</span>
|
||||
<span className="font-medium">Reset in {countdown}</span>
|
||||
<span className="font-medium">{resetWord} in {countdown}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -119,7 +124,7 @@ export default function QuotaProgressBar({
|
||||
{/* Reset time display */}
|
||||
{resetDisplay && (
|
||||
<div className="text-xs text-text-muted/70">
|
||||
Reset at {resetDisplay}
|
||||
{resetWord} at {resetDisplay}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -153,6 +153,11 @@ export default function QuotaTable({
|
||||
const colors = getColorClasses(quota.remaining);
|
||||
const countdown = formatResetTime(quota.resetAt);
|
||||
const resetDisplay = formatResetTimeDisplay(quota.resetAt);
|
||||
// recurring defaults true: a missing flag means the quota
|
||||
// refreshes at resetAt. Bonus/one-shot packs set recurring:false
|
||||
// and their resetAt is a hard expiry, so word it as "expires".
|
||||
const recurring = quota.recurring !== false;
|
||||
const countdownLabel = recurring ? `in ${countdown}` : `expires in ${countdown}`;
|
||||
|
||||
return (
|
||||
<tr
|
||||
@@ -197,13 +202,13 @@ export default function QuotaTable({
|
||||
className={`${resetPrimary} text-text-primary font-medium truncate`}
|
||||
title={resetDisplay || ""}
|
||||
>
|
||||
{countdown !== "-" ? `in ${countdown}` : resetDisplay}
|
||||
{countdown !== "-" ? countdownLabel : resetDisplay}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-0.5">
|
||||
{countdown !== "-" && (
|
||||
<div className={`${resetPrimary} text-text-primary font-medium`}>
|
||||
in {countdown}
|
||||
{countdownLabel}
|
||||
</div>
|
||||
)}
|
||||
{resetDisplay && (
|
||||
|
||||
@@ -433,6 +433,24 @@ export function parseQuotaData(provider, data) {
|
||||
}
|
||||
break;
|
||||
|
||||
case "codebuddy-cn":
|
||||
// CodeBuddy CN mixes recurring refill packs ("Monthly"/"Weekly"/...)
|
||||
// with one-shot bonus packs ("Bonus Pack N"). Forward `recurring`
|
||||
// so the UI can show "Expires in" for bonus packs (whose resetAt is
|
||||
// a hard expiry, not a refresh) instead of "Reset in".
|
||||
if (data.quotas) {
|
||||
Object.entries(data.quotas).forEach(([name, quota]) => {
|
||||
normalizedQuotas.push({
|
||||
name,
|
||||
used: quota.used || 0,
|
||||
total: quota.total || 0,
|
||||
resetAt: quota.resetAt || null,
|
||||
recurring: quota.recurring !== false,
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Generic fallback for unknown providers
|
||||
if (data.quotas) {
|
||||
|
||||
Reference in New Issue
Block a user