diff --git a/public/admin/app-data.js b/public/admin/app-data.js index b1e9b87..b36410f 100644 --- a/public/admin/app-data.js +++ b/public/admin/app-data.js @@ -797,6 +797,34 @@ async function refreshAccount(id) { } } +function resetResultToast(result) { + const windows = + typeof result?.windowsReset === "number" && result.windowsReset > 0 + ? ` (${result.windowsReset} window${result.windowsReset === 1 ? "" : "s"} reset)` + : ""; + switch (result?.code) { + case "reset": + return { message: `Limits restored${windows}`, type: "success" }; + case "nothing_to_reset": + return { + message: "Nothing to reset - limits are already clear", + type: "info", + }; + case "no_credit": + return { + message: "No reset credit available on this account", + type: "error", + }; + case "already_redeemed": + return { message: `Credit was already redeemed${windows}`, type: "info" }; + default: + return { + message: `Codex reset result: ${result?.code || "complete"}`, + type: "info", + }; + } +} + async function redeemResetCredit(accountId, creditId) { const account = accountById(accountId); const label = account?.label || account?.accountId || accountId; @@ -820,7 +848,8 @@ async function redeemResetCredit(accountId, creditId) { { method: "POST", body: JSON.stringify(body) } ); state.pendingResetRedemptions.delete(redemptionKey); - toast(`Codex reset result: ${response.result?.code || "complete"}`); + const { message, type } = resetResultToast(response.result); + toast(message, type); await loadAccounts(); } catch (e) { const redeemRequestId = e.body?.redeemRequestId; diff --git a/public/admin/app-render.js b/public/admin/app-render.js index 9876000..2043877 100644 --- a/public/admin/app-render.js +++ b/public/admin/app-render.js @@ -102,18 +102,32 @@ function codexLimitsBody(account, data) { const available = data.resetCredits?.availableCount ?? status?.resetCreditsAvailable; - const actions = (data.resetCredits?.credits || []) + const availableCredits = (data.resetCredits?.credits || []) .filter((credit) => credit.status === "available") - .map( - (credit) => - `` + .sort( + (a, b) => + (quotaTimestamp(a.expiresAt) ?? Number.POSITIVE_INFINITY) - + (quotaTimestamp(b.expiresAt) ?? Number.POSITIVE_INFINITY) ); + const actions = availableCredits.map((credit) => { + const expiry = quotaTimestamp(credit.expiresAt); + const expiryLabel = expiry + ? `credit expires ${relativeTime(expiry)}` + : "credit does not expire"; + const title = `${credit.description || "Consume a reset credit to restore limits"} \u00b7 ${expiryLabel}`; + return ``; + }); if (!actions.length && typeof available === "number" && available > 0) { actions.push( `` ); } + const soonestExpiry = quotaTimestamp(availableCredits[0]?.expiresAt); + if (soonestExpiry) { + chips.push(`reset credit expires ${relativeTime(soonestExpiry)}`); + } + return { rows, chips, actions }; }