Skip to content

UI: sidebar chat list, credit usage, theme#498

Open
skylerwww wants to merge 3 commits intoOpenSecretCloud:masterfrom
skylerwww:cursor/sidebar-credit-ui-polish
Open

UI: sidebar chat list, credit usage, theme#498
skylerwww wants to merge 3 commits intoOpenSecretCloud:masterfrom
skylerwww:cursor/sidebar-credit-ui-polish

Conversation

@skylerwww
Copy link
Copy Markdown
Contributor

@skylerwww skylerwww commented Apr 27, 2026

Summary

Polish sidebar chat history, CreditUsage card behavior, and related theme/assets.

Changes

  • Chat history list: layout, icons, menu alignment, sections
  • CreditUsage: single rich layout; token detail on bar hover; mock preview
  • Sidebar / nav spacing above projects
  • Theme, CSS, wordmark, logos, and small route/chat tweaks

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Enhanced error messages for project operations for better clarity.
  • Style

    • Improved chat text readability with adjusted typography (font size, line height, letter spacing).
    • Refined sidebar layout and expanded width for better content display.
    • Redesigned credit usage display for clearer information presentation.
    • Added refined scrollbar styling across the interface.
    • Adjusted logo and navigation layout for improved visual alignment.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

The PR refactors conversation project API calls from instance-based to module-level functions, adds mock sidebar chat generation for development, updates component styling and layout (widening sidebar from 280px to 296px), refactors CreditUsage to use mockScenario prop, and implements CSS variable-based font and scrollbar theming across multiple frontend components and utilities.

Changes

Cohort / File(s) Summary
Typography & Styling
frontend/src/chat.css, frontend/src/index.css
Updated markdown typography (font-size 14px→15px, line-height 1.5→1.65, added letter-spacing 0.1px). Added configurable font-family CSS variable and theme-aware scrollbar styling with .maple-thin-scrollbar and .sidebar-scrollbar classes.
Sidebar & Layout
frontend/src/components/Sidebar.tsx, frontend/src/components/TopNav.tsx, frontend/src/components/MapleWordmark.tsx
Increased sidebar width from 280px to 296px, refactored scrolling/padding logic with gradient fade overlays and flex constraints. Updated TopNav logo layout with tighter Tailwind classes. Adjusted MapleWordmark viewBox and added vertical translation.
Chat History & Mock Data
frontend/src/components/ChatHistoryList.tsx, frontend/src/utils/mockSidebarChats.ts
Introduced mock sidebar conversations via new utility module with getMockSidebarChatCount and buildMockSidebarConversations. Refactored selection/navigation to ignore mock chat IDs, updated row UI with ellipsis triggers and consistent icon stroke width, disabled interaction affordances for mocks.
Conversation Project Refactoring
frontend/src/utils/paginatedLists.ts, frontend/src/components/ConversationProjectPicker.tsx, frontend/src/components/ProjectDetailView.tsx, frontend/src/components/ConversationProjectDialog.tsx
Moved conversation project API calls from instance-based (os.*ConversationProject) to module-level functions (createConversationProject, updateConversationProject, deleteConversationProject). Removed os parameter from listAllConversationProjects. Enhanced error message handling in dialog submission.
Credit Usage & Account Menu
frontend/src/components/CreditUsage.tsx, frontend/src/components/AccountMenu.tsx
Refactored CreditUsage from layout prop to mockScenario prop, removed ring/gradient logic, unified bar-based presentation, and normalized plan labels. Added DEV-only fallback flag (useMockCreditPreview) in AccountMenu for unavailable billing status.
Markdown & Chat Components
frontend/src/components/markdown.tsx, frontend/src/components/UnifiedChat.tsx
Added maple-thin-scrollbar class to ResponsiveTable, removed fontSize and fontFamily props from Markdown component. Updated UnifiedChat markdown rendering and adjusted initial heading styling.
Theme Management
frontend/src/contexts/ThemeContext.tsx, frontend/src/tailwind.config.js
Refactored theme application into applyRootTheme helper to reduce duplication. Added configurable --app-font-family CSS variable to Tailwind fontFamily.sans config.
Responsive Grid Updates
frontend/src/routes/_auth.chat.$chatId.tsx
Updated sidebar column sizing from 280px to 296px across pending, not-found, and normal chat display render paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 The sidebar grows wider, the chats multiply,
Mock conversations now dance and fly,
Fonts dance via variables, scrollbars sleek and thin,
Credit usage sparkles with a dev-mode grin—
Typography refined, the journey complete!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'UI: sidebar chat list, credit usage, theme' directly addresses the three major UI components modified in the changeset, matching the PR's stated objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@AnthonyRonning
Copy link
Copy Markdown
Contributor

I like a lot of this. One thing that I'm really unsure about is the chats under the project.

  1. The vertifical spacing and font size is different than pinned and recents.
  2. It's straight for them to be all the way left aligned when they're under the project folder.
Screenshot 2026-04-27 at 8 44 05 PM

- Refine chat history rows, project layout, and ellipsis/pin alignment
- Simplify CreditUsage to rich card; hover for token details
- Sidebar nav spacing; theme, logos, and wordmark tweaks

Made-with: Cursor
@skylerwww skylerwww force-pushed the cursor/sidebar-credit-ui-polish branch from 4d4244e to 050dc36 Compare April 29, 2026 00:55
@AnthonyRonning AnthonyRonning marked this pull request as ready for review April 30, 2026 20:52
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review


const totalLive = billingStatus?.total_tokens;
const usedLive = billingStatus?.used_tokens;
const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null && usedLive > 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CreditUsage returns null for users with 0 used tokens, hiding plan info that was previously shown by the removed Plan Badge

The PR removes the standalone Plan Badge from AccountMenu.tsx (old lines 297-305) that previously always showed the plan name when billingStatus existed. Plan name display is now solely handled by CreditUsage. However, CreditUsage.tsx:132 requires usedLive > 0 in the hasRealUsage check: when a user has a paid plan but used_tokens === 0 (e.g., new subscriber, or right after a billing cycle reset), hasRealUsage is false, useMock is false in production, and CreditUsage returns null at line 139. This means these users will see no plan name, no credit bar, and no token info in the sidebar — a regression from the old UI where the Badge always displayed the plan name.

Affected condition in CreditUsage.tsx

Line 132: const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null && usedLive > 0;

The usedLive > 0 clause causes hasRealUsage to be false when a user has legitimately 0 used tokens. This was fine when the Plan Badge existed independently, but now that CreditUsage is the only component showing plan info, it needs to handle the usedLive === 0 case.

Prompt for agents
The hasRealUsage check at CreditUsage.tsx:132 requires usedLive > 0, but since the Plan Badge was removed from AccountMenu.tsx and CreditUsage is now the only component that shows the plan name in the sidebar, this condition causes CreditUsage to return null for users with 0 used tokens (new subscribers, post-billing-reset). The fix should relax the condition to allow CreditUsage to render when billing data exists with total_tokens > 0, even if used_tokens is 0. For example, change the condition to: `const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null;` — removing the `usedLive > 0` requirement. Verify that the rest of the component handles usedLive === 0 gracefully (percentUsed would be 0, percentRemaining 100, tokensRemaining equals total — all valid states for the new bar UI).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/src/components/UnifiedChat.tsx (1)

3233-3255: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the fixed banner offsets for the 296px sidebar.

The error and TTS alerts still use md:left-[calc(50%+140px)], which was tuned for the old 280px layout. After the sidebar width change they’ll sit 8px too far left on desktop.

Suggested fix
-          <div className="fixed top-16 left-1/2 -translate-x-1/2 z-50 w-full max-w-2xl px-4 md:left-[calc(50%+140px)]">
+          <div className="fixed top-16 left-1/2 -translate-x-1/2 z-50 w-full max-w-2xl px-4 md:left-[calc(50%+148px)]">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/UnifiedChat.tsx` around lines 3233 - 3255, The fixed
alert banners still use md:left-[calc(50%+140px)] which centers them for the old
280px sidebar; update those instances in UnifiedChat.tsx (the error alert block
and the playbackError alert block) to md:left-[calc(50%+148px)] to match the new
296px sidebar width (and search for any other occurrences of
md:left-[calc(50%+140px)] and replace similarly).
frontend/src/components/ProjectDetailView.tsx (1)

642-656: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add an accessible label to the row actions button.

The icon-only MoreHorizontal trigger has no accessible name, so screen readers won’t announce what it does.

Suggested fix
 <Button
   type="button"
   variant="ghost"
   size="icon"
   className="absolute right-2 top-2 h-8 w-8 text-foreground/40 transition-colors hover:text-foreground group-hover:text-foreground focus-visible:text-foreground"
+  aria-label="Chat actions"
   onClick={(event) => {
     event.preventDefault();
     event.stopPropagation();
   }}
 >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/ProjectDetailView.tsx` around lines 642 - 656, The
MoreHorizontal icon trigger is icon-only and lacks an accessible name; update
the DropdownMenuTrigger/Button (inside the !isSelectionMode branch) to include a
concise accessible label (e.g., add aria-label="Row actions" or
aria-label={`More actions for ${rowId || 'row'}`}) and also add
aria-haspopup="menu" (and aria-expanded bound to menu state if available) so
screen readers announce it as a menu trigger; modify the Button props where
MoreHorizontal is rendered to include these attributes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/ChatHistoryList.tsx`:
- Around line 1257-1265: Add accessible names to the icon-only overflow menu
buttons in ChatHistoryList.tsx by adding an explicit aria-label (and optionally
title) to the button elements that use SIDEBAR_ELLIPSIS_BTN and render the
<MoreHorizontal ... /> icon (e.g., the button with onClick that calls
event.preventDefault()/event.stopPropagation()); update each occurrence
(including the other instances using MoreHorizontal at the other noted spots) to
include a descriptive aria-label like "Open row menu" or "More options for this
chat" so screen readers can identify the control.
- Around line 1237-1249: The selection checkbox is rendered for mock rows even
when selection is blocked; update the conditional around the Checkbox in
ChatHistoryList (the isSelectionMode block that renders Checkbox and uses
toggleSelection and conversation.id) to also check that the row is not a mock
(e.g., conversation.isMock or conversation.mock !== true) so mock rows do not
render the checkbox or respond to clicks; keep existing stopPropagation handlers
and onCheckedChange/toggleSelection logic for real rows.

In `@frontend/src/components/CreditUsage.tsx`:
- Around line 50-53: The toPlanNameLabel helper returns " Plan" when rawPlanName
is blank/whitespace; change it to default to "Pro" after trimming by first
normalizing rawPlanName to an empty string, trimming, then using a fallback:
const cleaned = (rawPlanName ?? "").trim() || "Pro"; then detect hasPlanSuffix
and return cleaned or `${cleaned} Plan`; update within the toPlanNameLabel
function.
- Around line 127-153: The component CreditUsage treats a zero used token state
as "no real usage" because hasRealUsage checks usedLive > 0; change the
condition to treat any non-null usedLive (including 0) as real usage when
totalLive > 0 (e.g., hasRealUsage should be totalLive != null && totalLive > 0
&& usedLive != null), so the real-zero state shows the billing card and prevents
DEV mock from overriding it; update the dependent logic (useMock,
total/used/productName/usageResetDate/apiBalance) to rely on this corrected
hasRealUsage so mockPreset/scenario only apply when no real billing data exists.

---

Outside diff comments:
In `@frontend/src/components/ProjectDetailView.tsx`:
- Around line 642-656: The MoreHorizontal icon trigger is icon-only and lacks an
accessible name; update the DropdownMenuTrigger/Button (inside the
!isSelectionMode branch) to include a concise accessible label (e.g., add
aria-label="Row actions" or aria-label={`More actions for ${rowId || 'row'}`})
and also add aria-haspopup="menu" (and aria-expanded bound to menu state if
available) so screen readers announce it as a menu trigger; modify the Button
props where MoreHorizontal is rendered to include these attributes.

In `@frontend/src/components/UnifiedChat.tsx`:
- Around line 3233-3255: The fixed alert banners still use
md:left-[calc(50%+140px)] which centers them for the old 280px sidebar; update
those instances in UnifiedChat.tsx (the error alert block and the playbackError
alert block) to md:left-[calc(50%+148px)] to match the new 296px sidebar width
(and search for any other occurrences of md:left-[calc(50%+140px)] and replace
similarly).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b12eeb6d-05c3-4a17-b00d-2de2b84b64c3

📥 Commits

Reviewing files that changed from the base of the PR and between a612b1e and 26ffd43.

⛔ Files ignored due to path filters (2)
  • frontend/public/maple-logo-dark.svg is excluded by !**/*.svg
  • frontend/public/maple-logo.svg is excluded by !**/*.svg
📒 Files selected for processing (18)
  • frontend/src/chat.css
  • frontend/src/components/AccountMenu.tsx
  • frontend/src/components/ChatHistoryList.tsx
  • frontend/src/components/ConversationProjectDialog.tsx
  • frontend/src/components/ConversationProjectPicker.tsx
  • frontend/src/components/CreditUsage.tsx
  • frontend/src/components/MapleWordmark.tsx
  • frontend/src/components/ProjectDetailView.tsx
  • frontend/src/components/Sidebar.tsx
  • frontend/src/components/TopNav.tsx
  • frontend/src/components/UnifiedChat.tsx
  • frontend/src/components/markdown.tsx
  • frontend/src/contexts/ThemeContext.tsx
  • frontend/src/index.css
  • frontend/src/routes/_auth.chat.$chatId.tsx
  • frontend/src/utils/mockSidebarChats.ts
  • frontend/src/utils/paginatedLists.ts
  • frontend/tailwind.config.js

Comment on lines +1237 to +1249
{isSelectionMode ? (
<div
className={`absolute left-1.5 top-1/2 ${ROW_CHECKBOX_Z} -translate-y-1/2`}
onClick={(e) => e.stopPropagation()}
>
<Checkbox
checked={isSelected}
onCheckedChange={() => toggleSelection(conversation.id)}
onClick={(event) => event.stopPropagation()}
className="data-[state=checked]:bg-primary"
/>
</div>
) : null}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hide selection checkboxes for mock rows in selection mode.

Mock rows still render a checkbox even though selection is intentionally blocked, which creates a confusing no-op control.

💡 Suggested patch
-        {isSelectionMode ? (
+        {isSelectionMode && !isMockRow ? (
           <div
             className={`absolute left-1.5 top-1/2 ${ROW_CHECKBOX_Z} -translate-y-1/2`}
             onClick={(e) => e.stopPropagation()}
           >
             <Checkbox
               checked={isSelected}
               onCheckedChange={() => toggleSelection(conversation.id)}
               onClick={(event) => event.stopPropagation()}
               className="data-[state=checked]:bg-primary"
             />
           </div>
         ) : null}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/ChatHistoryList.tsx` around lines 1237 - 1249, The
selection checkbox is rendered for mock rows even when selection is blocked;
update the conditional around the Checkbox in ChatHistoryList (the
isSelectionMode block that renders Checkbox and uses toggleSelection and
conversation.id) to also check that the row is not a mock (e.g.,
conversation.isMock or conversation.mock !== true) so mock rows do not render
the checkbox or respond to clicks; keep existing stopPropagation handlers and
onCheckedChange/toggleSelection logic for real rows.

Comment on lines +1257 to +1265
<button
className={SIDEBAR_ELLIPSIS_BTN}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
}}
>
<Folder className="mr-2 h-4 w-4" />
No project
<MoreHorizontal className="h-4 w-4" strokeWidth={ICON_STROKE} />
</button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add accessible names to icon-only overflow menu buttons.

These triggers are icon-only and currently lack aria-label, making row actions ambiguous for screen-reader users.

♿ Suggested patch
                      <button
+                      type="button"
+                      aria-label={`Open actions for ${title}`}
                       className={SIDEBAR_ELLIPSIS_BTN}
                       onClick={(event) => {
                         event.preventDefault();
                         event.stopPropagation();
                       }}
                     >
                          <button
+                            type="button"
+                            aria-label={`Open actions for project ${project.name}`}
                             className={SIDEBAR_ELLIPSIS_BTN}
                             onClick={(event) => {
                               event.preventDefault();
                               event.stopPropagation();
                             }}
                           >
                              <button
+                                type="button"
+                                aria-label={`Open actions for ${chat.title}`}
                                 className={SIDEBAR_ELLIPSIS_BTN}
                                 onClick={(e) => {
                                   e.preventDefault();
                                   e.stopPropagation();
                                 }}
                               >

Also applies to: 1407-1415, 1530-1538

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/ChatHistoryList.tsx` around lines 1257 - 1265, Add
accessible names to the icon-only overflow menu buttons in ChatHistoryList.tsx
by adding an explicit aria-label (and optionally title) to the button elements
that use SIDEBAR_ELLIPSIS_BTN and render the <MoreHorizontal ... /> icon (e.g.,
the button with onClick that calls
event.preventDefault()/event.stopPropagation()); update each occurrence
(including the other instances using MoreHorizontal at the other noted spots) to
include a descriptive aria-label like "Open row menu" or "More options for this
chat" so screen readers can identify the control.

Comment on lines +50 to +53
function toPlanNameLabel(rawPlanName: string | undefined): string {
const cleaned = (rawPlanName ?? "Pro").trim();
const hasPlanSuffix = /\bplan\b/i.test(cleaned);
return hasPlanSuffix ? cleaned : `${cleaned} Plan`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fall back when the plan name is empty.

If rawPlanName is blank or whitespace, this helper returns " Plan", which will surface as a broken badge label. Defaulting to "Pro" after trimming would avoid the bad UI.

Suggested fix
 function toPlanNameLabel(rawPlanName: string | undefined): string {
-  const cleaned = (rawPlanName ?? "Pro").trim();
+  const cleaned = (rawPlanName ?? "Pro").trim() || "Pro";
   const hasPlanSuffix = /\bplan\b/i.test(cleaned);
   return hasPlanSuffix ? cleaned : `${cleaned} Plan`;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/CreditUsage.tsx` around lines 50 - 53, The
toPlanNameLabel helper returns " Plan" when rawPlanName is blank/whitespace;
change it to default to "Pro" after trimming by first normalizing rawPlanName to
an empty string, trimming, then using a fallback: const cleaned = (rawPlanName
?? "").trim() || "Pro"; then detect hasPlanSuffix and return cleaned or
`${cleaned} Plan`; update within the toPlanNameLabel function.

Comment on lines +127 to +153
export function CreditUsage({ mockScenario }: { mockScenario?: MockScenario }) {
const { billingStatus } = useLocalState();

const totalLive = billingStatus?.total_tokens;
const usedLive = billingStatus?.used_tokens;
const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null && usedLive > 0;

const mockFlag = readMockScenario();
const useMock = !hasRealUsage && import.meta.env.DEV && mockFlag !== null && mockFlag !== "off";
const forcedMock = import.meta.env.DEV ? mockScenario : undefined;
const scenario = forcedMock ?? (mockFlag !== null && mockFlag !== "off" ? mockFlag : null);
const useMock = !hasRealUsage && import.meta.env.DEV && scenario !== null;

if (!hasRealUsage && !useMock) {
return null;
}

const mock = useMock ? mockPreset(mockFlag as MockScenario) : null;
const mock = useMock ? mockPreset(scenario as MockScenario) : null;
const total = hasRealUsage ? totalLive! : mock!.total_tokens;
const used = hasRealUsage ? usedLive! : mock!.used_tokens;
const productName = hasRealUsage ? billingStatus?.product_name : "Pro";
const usageResetDate = hasRealUsage ? billingStatus!.usage_reset_date : mockUsageResetIso();
const apiBalance = hasRealUsage ? billingStatus!.api_credit_balance : mock?.api_credit_balance;

const percentUsed = Math.min(100, Math.max(0, (used / total) * 100));
const roundedPercent = Math.round(percentUsed);
const tone = usageTone(percentUsed);
const barColor = toneColor(tone);
const percentRemaining = Math.max(0, 100 - percentUsed);
const roundedRemaining = Math.round(percentRemaining);
const tokensRemaining = Math.max(0, total - used);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Treat zero used tokens as a real billing state.

hasRealUsage still requires usedLive > 0, so a freshly reset account with 0 used tokens falls through to the mock/null path and the card disappears. That also lets the DEV mock preview mask a real zero-usage account.

Suggested fix
-  const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null && usedLive > 0;
+  const hasRealUsage = totalLive != null && totalLive > 0 && usedLive != null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/CreditUsage.tsx` around lines 127 - 153, The
component CreditUsage treats a zero used token state as "no real usage" because
hasRealUsage checks usedLive > 0; change the condition to treat any non-null
usedLive (including 0) as real usage when totalLive > 0 (e.g., hasRealUsage
should be totalLive != null && totalLive > 0 && usedLive != null), so the
real-zero state shows the billing card and prevents DEV mock from overriding it;
update the dependent logic (useMock,
total/used/productName/usageResetDate/apiBalance) to rely on this corrected
hasRealUsage so mockPreset/scenario only apply when no real billing data exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants