Repository navigation
fix: replace mobile navbar crown button with AI quota display - #134
Conversation
Remove the billing crown button from mobile navbar and show the UsageCounter component on all screen sizes instead.
- Only show quota when PageSpace provider is selected - Show Standard quota only when Standard model (glm-4.5-air) is selected - Show Pro quota only when Pro model (glm-4.6) is selected - Hide quota entirely for external providers (OpenAI, Anthropic, etc.)
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughUsageCounter now loads assistant settings to detect PageSpace provider and model (Standard/Pro), then conditionally fetches and displays model-specific quotas with near-limit indicators. Main header replaces the billing/settings button with an unconditional UsageCounter. Changes
Sequence Diagram(s)sequenceDiagram
participant Header as MainHeader (UI)
participant Counter as UsageCounter (UI)
participant Store as AssistantSettingsStore
participant API as Usage API (SWR fetch)
Header->>Counter: Render UsageCounter
Counter->>Store: loadSettings() (on mount)
Store-->>Counter: settings (provider, model, access)
alt provider == PageSpace
Counter->>API: fetch usage (SWR) with model context
API-->>Counter: usage data / error
Counter->>Counter: compute near-limit flags (Standard/Pro)
Counter-->>Header: render quota badges (Standard/Pro) or loading/error
else not PageSpace
Counter-->>Header: render minimal/hidden usage UI
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (6)**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.tsx📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{tsx,css}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
apps/web/src/components/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (5)📚 Learning: 2025-12-18T05:22:42.263ZApplied to files:
📚 Learning: 2025-12-14T14:54:45.713ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.955ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.955ZApplied to files:
📚 Learning: 2025-12-23T18:49:41.955ZApplied to files:
🧬 Code graph analysis (1)apps/web/src/components/billing/UsageCounter.tsx (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (4)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/web/src/components/billing/UsageCounter.tsx (1)
19-21: Consider extracting model constants to a shared location.These model identifiers (
'glm-4.5-air'and'glm-4.6') are hardcoded in 40+ places across the codebase. They already exist inapps/web/src/lib/ai/core/ai-providers-config.tsas part of theAI_PROVIDERSconfiguration. Instead of duplicating them locally, reference the centralized config to reduce fragility if these model IDs change.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/components/billing/UsageCounter.tsxapps/web/src/components/layout/main-header/index.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Use camelCase for variable and function names
Use UPPER_SNAKE_CASE for constants
Use PascalCase for type and enum names
Use kebab-case for filenames, except React hooks (camelCase withuseprefix), Zustand stores (camelCase withuseprefix), and React components (PascalCase)
Lint with Next/ESLint as configured inapps/web/eslint.config.mjs
Message content should always use the message parts structure with{ parts: [{ type: 'text', text: '...' }] }
Use centralized permission functions from@pagespace/lib/permissions(e.g.,getUserAccessLevel,canUserEditPage) instead of implementing permission logic locally
Always use Drizzle client from@pagespace/dbpackage for database access
Use ESM modules throughout the codebase
**/*.{ts,tsx}: Never useanytypes - always use proper TypeScript types
Write code that is explicit over implicit and self-documenting
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: React component files should use PascalCase (e.g.,UserProfile.tsx)
Use @dnd-kit for drag-and-drop functionality
Use Zustand for client state management
Use SWR for server state management and caching
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Format code with Prettier
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Tailwind CSS and shadcn/ui components for styling and UI
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/**/*.{ts,tsx}: Use message parts structure for message content:{ parts: [{ type: 'text', text: '...' }] }
For database access, always use Drizzle client from@pagespace/db:import { db, pages } from '@pagespace/db';
Use centralized Drizzle ORM with PostgreSQL for all database operations - no direct SQL or other ORMs
Use Socket.IO for real-time collaboration features - imported from the realtime service at port 3001
Use Vercel AI SDK with async/await for all AI operations and streaming
Use Next.js 15 App Router and TypeScript for all routes and components
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
apps/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/src/components/**/*.{ts,tsx}: When document editing, register editing state withuseEditingStore.getState().startEditing()to prevent UI refreshes, and clean up in return statement
When AI is streaming, register streaming state withuseEditingStore.getState().startStreaming()to prevent UI refreshes, and clean up in return statement
For SWR data fetching with editing protection, useisPaused: () => hasLoadedRef.current && isEditingActive()to allow initial fetch and only pause after, withrevalidateOnFocus: false
Use Zustand for client-side state management as the primary state solution
Use SWR for server state and caching with proper configuration includingrevalidateOnFocus: falsefor editing protection
Use TipTap rich text editor with markdown support for document editing
Use Monaco Editor for code editing features
Use @dnd-kit for drag-and-drop functionality instead of other libraries
Use Tailwind CSS with shadcn/ui components for all UI styling and components
Files:
apps/web/src/components/layout/main-header/index.tsxapps/web/src/components/billing/UsageCounter.tsx
🧠 Learnings (5)
📚 Learning: 2025-12-14T14:54:45.713Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T14:54:45.713Z
Learning: Applies to app/**/*.{ts,tsx} : Import and use `getUserAccessLevel()` and `canUserEditPage()` from `pagespace/lib/permissions` for centralized permission logic
Applied to files:
apps/web/src/components/billing/UsageCounter.tsx
📚 Learning: 2025-12-18T05:22:42.263Z
Learnt from: 2witstudios
Repo: 2witstudios/PageSpace PR: 96
File: apps/web/src/components/layout/right-sidebar/ai-assistant/SidebarChatTab.tsx:641-657
Timestamp: 2025-12-18T05:22:42.263Z
Learning: In apps/web/src/components/layout/right-sidebar/ai-assistant/SidebarChatTab.tsx, the provider/model selector buttons are intentionally non-functional placeholders in the compact sidebar view. The `hideModelSelector={true}` prop is passed to ChatInput to hide the full ProviderModelSelector. Users are expected to use the full GlobalAssistantView for model selection. A settings link may be added in a future iteration.
Applied to files:
apps/web/src/components/billing/UsageCounter.tsx
📚 Learning: 2025-12-23T18:49:41.955Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.955Z
Learning: Applies to apps/web/src/components/**/*.{ts,tsx} : When AI is streaming, register streaming state with `useEditingStore.getState().startStreaming()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/billing/UsageCounter.tsx
📚 Learning: 2025-12-23T18:49:41.955Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.955Z
Learning: Applies to apps/web/src/components/**/*.{ts,tsx} : For SWR data fetching with editing protection, use `isPaused: () => hasLoadedRef.current && isEditingActive()` to allow initial fetch and only pause after, with `revalidateOnFocus: false`
Applied to files:
apps/web/src/components/billing/UsageCounter.tsx
📚 Learning: 2025-12-23T18:49:41.955Z
Learnt from: CR
Repo: 2witstudios/PageSpace PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-23T18:49:41.955Z
Learning: Applies to apps/web/src/components/**/*.{ts,tsx} : When document editing, register editing state with `useEditingStore.getState().startEditing()` to prevent UI refreshes, and clean up in return statement
Applied to files:
apps/web/src/components/billing/UsageCounter.tsx
🧬 Code graph analysis (2)
apps/web/src/components/layout/main-header/index.tsx (1)
apps/web/src/components/billing/UsageCounter.tsx (1)
UsageCounter(45-204)
apps/web/src/components/billing/UsageCounter.tsx (2)
apps/web/src/stores/useAssistantSettingsStore.ts (1)
useAssistantSettingsStore(52-168)apps/web/src/components/ui/badge.tsx (1)
Badge(46-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Unit Tests
🔇 Additional comments (7)
apps/web/src/components/layout/main-header/index.tsx (2)
5-5: LGTM!Clean removal of the unused
Crownicon import. The remaining icons (Home,PanelLeft,PanelRight,Search) are all still in use within the component.
71-72: LGTM!Good approach placing
UsageCounterunconditionally in the right-side cluster. SinceUsageCounternow handles its own visibility logic (returningnullfor non-PageSpace providers), the header remains clean and delegates the display decision appropriately.apps/web/src/components/billing/UsageCounter.tsx (5)
52-59: LGTM!Good use of Zustand selector pattern to subscribe only to the specific state fields needed. The derived booleans for provider/model checks are straightforward and efficient.
71-73: LGTM!The near-limit detection logic is sound. The
limit > 0guard correctly handles edge cases where the limit might be zero or unset.
122-125: LGTM!Correct placement of the early return after all hooks but before the loading/error UI. This ensures hooks are always called (React rules) while hiding the component for non-PageSpace providers.
145-148: Consider handling unknown PageSpace models.If
currentModelisnull,undefined, or a model ID not matching either constant (e.g., a future model), bothshowProQuotaandshowStandardQuotawill befalse. The component will render only the billing button with no quota display.Is this the intended behavior, or should there be a fallback (e.g., show Standard quota by default)?
152-180: LGTM!Clean implementation of model-specific quota displays. The responsive design appropriately hides labels on smaller screens while keeping the essential badge visible. The near-limit visual feedback using the
destructivevariant provides clear UX for users approaching their quota.
- Load assistant settings on mount to ensure provider/model are available - Always render the billing/upgrade button for navigation - Only conditionally show quota badges based on provider and model - Show loading state only when PageSpace provider is selected - Fixes regression where billing navigation was missing on direct page loads
Remove the billing crown button from mobile navbar and show the
UsageCounter component on all screen sizes instead.
Summary by CodeRabbit
New Features
User Interface
✏️ Tip: You can customize this high-level summary in your review settings.