-
-
Notifications
You must be signed in to change notification settings - Fork 7
Jules 8488824498232079115 26d4e4cd #476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Restored the branch to the expected head at commit 488b47c. This recovers several missing features and architectural improvements: - Integrated HistoryToggleProvider and HistorySidebar. - Integrated UsageToggleProvider and the new UsageView component. - Removed legacy usage-sidebar.tsx. - Restored pricing and feature updates in PurchaseCreditsPopup. - Fixed layout structure in app/layout.tsx to support these new global state providers. Resolved previous merge conflicts and incorrect force-push state. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…c380 Restore Branch Head to Commit 488b47c
- Reset branch HEAD to historical recovery point 488b47c. - Applied latest code fixes from orphan commit 166aee9, including Mapbox rendering optimizations and GeoJSON streaming. - Improved type safety in app/actions.tsx by removing 'as any' casts and properly typing message arrays. - Refined getModel utility to support vision-aware model fallback. - Documented non-blocking background task pattern in server actions. - Updated feature/billing-integration branch with the restored state. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reset branch HEAD to historical recovery point 488b47c. - Applied latest code fixes from orphan commit 166aee9. - Resolved TypeScript build error in app/actions.tsx by casting GeoJSON data to FeatureCollection. - Improved type safety for AIState message filtering and content handling. - Implemented background processing for resolution search with immediate UI streaming. - Optimized chat history fetching to trigger only when the sidebar is open. - Ensured Mapbox style loading is robust against re-renders. - Cleaned up dead code and improved documentation in server actions. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reset branch HEAD to historical recovery point 488b47c. - Applied latest code fixes from orphan commit 166aee9. - Resolved TypeScript build error in app/actions.tsx by casting GeoJSON data to FeatureCollection. - Improved type safety for AIState message filtering and content handling. - Implemented background processing for resolution search with immediate UI streaming. - Re-enabled auto-opening of the pricing popup in components/header.tsx. - Optimized chat history fetching to trigger only when the sidebar is open. - Ensured Mapbox style loading is robust against re-renders. - Cleaned up dead code and improved documentation in server actions. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Restored historical state from 488b47c and merged latest changes. - Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx to improve response time. - Re-enabled auto-opening pricing popup in components/header.tsx. - Resolved all TypeScript build errors in app/actions.tsx. - Restored Grok model support for vision tasks in lib/utils/index.ts. - Optimized chat history loading in components/sidebar/chat-history-client.tsx. - Improved Mapbox style loading robustness in components/map/mapbox-map.tsx. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized branch with origin/main, prioritizing main's code structure and latest features. - Bridged the history with historical recovery point 488b47c. - Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx to resolve performance issues. - Restored the auto-opening Pricing Popup and Usage View in the Header component. - Integrated the Timezone Clock and time context into the restored resolution search logic. - Resolved TypeScript build errors with proper type casting and fixed a missing 'use client' directive in components/history.tsx. - Ensured all required providers (History, Usage, etc.) are correctly wrapped in the root layout. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized branch with origin/main, prioritizing main's code structure and latest features. - Bridged the history with historical recovery point 488b47c. - Integrated UsageView and billing UI into the Chat component, toggled by the tent tree icon. - Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx for better performance. - Restored the auto-opening Pricing Popup in the Header component. - Improved type safety across server actions and Mapbox components. - Ensured mutual exclusion between Settings, Usage, and Map views. - Fixed a missing 'use client' directive in components/history.tsx. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Integrated UsageView into the main Chat component for both mobile and desktop. - Ensured mutual exclusion between Settings, Usage, and Map views in the UI panel. - Updated ConditionalLottie to hide the loading animation when the Usage View is open. - Synchronized with origin/main while prioritizing its code structure. - Maintained historical recovery and performance optimizations for resolution search. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized with origin/main, prioritizing main branch code and features. - Fully restored historical context and missing changes from commit 488b47c. - Integrated Usage and Billing UI (UsageView) into the Chat component. - Implemented streaming for resolution search analysis to improve perceived performance. - Re-enabled auto-opening pricing popup in components/header.tsx. - Refined ConditionalLottie visibility to avoid overlaps with the Usage UI. - Ensured mutual exclusion between Settings, Usage, and Map views in the side panel. - Improved type safety across server actions and Mapbox components. - Resolved build failures related to missing client directives and type mismatches. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…ability - Recovered historical state from commit 488b47c and synchronized with main. - Optimized resolution search by refactoring to stream partial summaries. - Fixed Mapbox memory leaks by ensuring all event listeners are removed on cleanup. - Improved StreamableValue stability by initializing with default values. - Integrated Usage View with mutual exclusion logic and Lottie player visibility fixes. - Refined model selection for Grok vision and Gemini 1.5 Pro. - Integrated timezone-aware analysis using tz-lookup. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Fixed Type error in `app/actions.tsx` by casting `content` to `string` in `createStreamableValue`. - Addressed ESLint warnings in `components/map/mapbox-map.tsx` and `components/chat-panel.tsx` by adding missing dependencies to `useEffect` and `useCallback` hooks. - Ensured `relatedQueries` streamable value is initialized with an empty state for stability. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Optimized resolution search with streaming. - Improved timezone handling and AI context. - Fixed UI mutual exclusion and loading state logic. - Stabilized Mapbox cleanup and event listeners. - Resolved build errors and ESLint warnings. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…head features - Reverted branch to commit 6acfbe5. - Merged changes from main (e95a25b). - Preserved Tentree Icon (UsageView logic), History layout (HistoryContainer), and PurchaseCreditsPopup from 6acfbe5 as requested. - Updated Stripe checkout URL in PurchaseCreditsPopup to the official one (14A3cv7K72TR3go14Nasg02). - Re-applied bug fixes from 6acfbe5 (type casting in app/actions.tsx, ESLint dependencies in components/map/mapbox-map.tsx and components/chat-panel.tsx, and relatedQueries initialization). - Verified build and synchronization with main branch features (e.g., resolution search enhancements). Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…8' into jules-8488824498232079115-26d4e4cd
…ranch head features - Reverted branch to commit 6acfbe5 and merged with main (e95a25b). - Preserved Tentree Icon (Usage View), history layout, and PurchaseCreditsPopup from 6acfbe5. - Restored branch-specific UI components: Header, History button, Profile toggle, and Usage integration in Chat. - Synchronized all other logic with main, including resolution search enhancements. - Fixed an infinite re-render loop in Mapbox map by optimizing useEffect dependencies (removed cameraState from initialization effect). - Re-applied critical bug fixes from 6acfbe5: - Type casting in app/actions.tsx (getUIStateFromAIState). - Streamable value initialization for stability. - setSuggestions dependency in ChatPanel. - Updated Stripe checkout URL in PurchaseCreditsPopup to the official link. - Verified successful build with 'bun run build'. Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
WalkthroughThis PR introduces a new purchase flow and usage tracking dashboard. It adds context providers for history and usage state management, creates new UI components for purchase credits and usage display, refactors server-side streamable value initialization, and integrates toggle controls throughout the header and layout. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Header
participant UsageToggle as UsageToggle<br/>Context
participant ProfileToggle as ProfileToggle<br/>Context
participant Chat as Chat<br/>Component
participant UsageView
participant PurchasePopup as PurchaseCredits<br/>Popup
User->>Header: Click Usage Button
activate Header
Header->>UsageToggle: handleUsageToggle()
activate UsageToggle
UsageToggle->>ProfileToggle: closeProfileView()
activate ProfileToggle
ProfileToggle->>ProfileToggle: Set activeView = null
deactivate ProfileToggle
UsageToggle->>UsageToggle: toggleUsage()
UsageToggle->>Chat: isUsageOpen = true
deactivate UsageToggle
deactivate Header
activate Chat
Chat->>Chat: Render UsageView<br/>(instead of MapProvider)
deactivate Chat
activate UsageView
UsageView->>User: Display usage dashboard
User->>UsageView: Click Upgrade
deactivate UsageView
activate Header
Header->>PurchasePopup: Open on mount
activate PurchasePopup
PurchasePopup->>User: Show purchase dialog
User->>PurchasePopup: Click "Pay Now"
PurchasePopup->>PurchasePopup: Open Stripe URL
PurchasePopup->>Header: onClose()
deactivate PurchasePopup
deactivate Header
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (1)📓 Common learnings🧬 Code graph analysis (1)components/chat-panel.tsx (3)
🔇 Additional comments (1)
✏️ Tip: You can disable this entire section by setting 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. Comment |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/actions.tsx (1)
671-696:⚠️ Potential issue | 🟡 MinorWrap switch case declarations in blocks to prevent scope leakage.
The static analyzer correctly identifies that
const answer(line 672) andconst relatedQueries(line 685) are declared without block scope. These declarations can be erroneously accessed from other switch clauses if fall-through occurs.🛡️ Proposed fix to wrap declarations in blocks
case 'response': + { + const answer = createStreamableValue(content as string) + answer.done(content as string) return { id, component: ( <Section title="response"> <BotMessage content={answer.value} /> </Section> ) } - case 'related': - const relatedQueries = createStreamableValue<RelatedQueries>({ - items: [] - }) + } + case 'related': + { + const relatedQueries = createStreamableValue<RelatedQueries>({ + items: [] + }) relatedQueries.done(JSON.parse(content as string)) return { id, component: ( <Section title="Related" separator={true}> <SearchRelated relatedQueries={relatedQueries.value} /> </Section> ) } + }components/profile-toggle.tsx (1)
15-35:⚠️ Potential issue | 🟡 MinorRedundant conditional branches — both set the same value.
Lines 19-23 set
alignValueto"start"in both theifandelsebranches, making the conditional pointless. Additionally, the comments say "Right align" but"start"typically aligns to the left.🔧 Proposed fix
If the intent is always
"start", simplify:const handleResize = () => { const mobile = window.innerWidth < 768 setIsMobile(mobile) - if (mobile) { - setAlignValue("start") // Right align on mobile too - } else { - setAlignValue("start") // Right align on desktop - } + setAlignValue("start") }Or if different alignment was intended, clarify the logic and update comments.
🤖 Fix all issues with AI agents
In `@components/chat.tsx`:
- Line 113: Duplicate ternary rendering of activeView ? <SettingsView /> :
isUsageOpen ? <UsageView /> : <MapProvider /> should be extracted into a small
helper component (e.g., MainContentView) that accepts props activeView and
isUsageOpen (and optional position) and returns SettingsView if activeView,
UsageView if isUsageOpen, otherwise MapProvider; replace the inline ternaries in
both the mobile and desktop layouts with <MainContentView
activeView={activeView} isUsageOpen={isUsageOpen} position={...} /> to remove
duplication and improve readability while keeping existing component names
(SettingsView, UsageView, MapProvider).
In `@components/header.tsx`:
- Around line 81-83: The usage toggle Button(s) (the desktop one rendering
TentTree and the mobile variant rendered later) are missing accessible labels;
update the Button elements that call handleUsageToggle to include a descriptive
title (e.g., title="Open Usage") and an aria-label (e.g., aria-label="Open
Usage") so screen readers and tooltips match other header toggles; locate the
Button components wrapping TentTree (and the corresponding mobile Button at the
later occurrence) and add both attributes.
- Around line 39-42: The current useEffect unconditionally calls
setIsPurchaseOpen(true) causing the PurchaseCreditsPopup to show on every mount;
change it to only open after the user is authenticated and when a 7-day cooldown
has expired: read the authenticated state from your auth context (or a new hook
like useAuth) and check a persisted timestamp (e.g. localStorage key like
purchase_popup_last_shown) before calling setIsPurchaseOpen(true), updating that
timestamp when the popup is shown; consider extracting the logic into a
dedicated hook (e.g. usePurchasePopup) that returns whether to show and
encapsulates the auth check and 7-day cooldown calculation.
In `@components/purchase-credits-popup.tsx`:
- Around line 35-36: The Dialog currently passes onOpenChange={onClose} but
onOpenChange receives a boolean; update the handler to explicitly handle the
boolean state: use the Dialog's onOpenChange prop (e.g., onOpenChange={(open) =>
{ if (!open) onClose(); }}) or replace onClose with a new function (e.g.,
handleDialogOpenChange) that accepts the boolean and invokes onClose only when
open is false; locate the Dialog usage and the isOpen/onClose props in
purchase-credits-popup.tsx to implement this controlled open-state handler.
In `@components/sidebar/chat-history-client.tsx`:
- Around line 137-148: The current credits panel rendered when isCreditsVisible
shows hardcoded values; replace this static markup with the app's CreditsDisplay
component and feed it real state/props (e.g., userCredits, maxCredits,
creditsPercentage) or call the credits API/store selector to obtain those values
before render; locate the conditional using isCreditsVisible and swap the static
div for <CreditsDisplay credits={userCredits} maxCredits={maxCredits}
percent={creditsPercentage} /> (or equivalent prop names used in your codebase),
ensuring you import CreditsDisplay and derive userCredits/creditsPercentage from
your auth/user store or the existing credits-fetching hook.
- Around line 65-69: The effect watching isHistoryOpen always calls fetchChats()
on open, causing redundant network calls; modify the useEffect that depends on
isHistoryOpen so it checks whether chats (the state holding loaded chat list) is
already populated before calling fetchChats(), e.g., only call fetchChats() when
isHistoryOpen is true AND chats is empty (or when a separate forceRefresh flag
is set), or implement a stale-while-revalidate approach by returning cached
chats and triggering a background refresh via a refreshChats/forceRefresh
mechanism tied to a button or pull-to-refresh; update references to
isHistoryOpen, fetchChats, chats, and any refresh flag accordingly.
In `@components/usage-view.tsx`:
- Around line 10-15: The usage data in the usage-view component is hardcoded and
list items are rendered using the array index as a key; update the usage state
to either fetch real data or mark it as a placeholder with a clear TODO (replace
the const [usage] initialization) and add a stable unique id to each usage item
(e.g., include an id property for entries currently in the usage array and for
future API responses). Then change the list rendering to use that unique id (not
key={i}) wherever usage is mapped (referencing the usage state and the map that
currently uses key={i} around lines ~83-89) and leave credits state as-is if
it’s intentional. Ensure new ids are stable across reorders/filters so React
keys remain consistent.
- Line 3: The import statement in components/usage-view.tsx currently imports
useEffect but it is unused; remove useEffect from the import list so the line
reads import React, { useState } from 'react' (or drop the named imports
entirely if useState is also unused), ensuring only used symbols (React,
useState) remain to eliminate the unused import.
- Line 35: The Stripe checkout URL is hardcoded in the Button onClick handler;
replace the literal URL by reading process.env.NEXT_PUBLIC_STRIPE_CHECKOUT_URL
(or use a safe fallback/guard) and update the onClick in the Button component to
call window.open(checkoutUrl, '_blank') where checkoutUrl is the env var, and
add NEXT_PUBLIC_STRIPE_CHECKOUT_URL to your .env files per environment; ensure
the code uses the client-exposed NEXT_PUBLIC_ prefix so the value is available
in the browser.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
CC BY-NC 4.0.docxis excluded by!**/*.docx
📒 Files selected for processing (16)
app/actions.tsxapp/layout.tsxcomponents/chat-panel.tsxcomponents/chat.tsxcomponents/conditional-lottie.tsxcomponents/header.tsxcomponents/history-sidebar.tsxcomponents/history-toggle-context.tsxcomponents/history.tsxcomponents/mobile-icons-bar.tsxcomponents/profile-toggle-context.tsxcomponents/profile-toggle.tsxcomponents/purchase-credits-popup.tsxcomponents/sidebar/chat-history-client.tsxcomponents/usage-toggle-context.tsxcomponents/usage-view.tsx
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ngoiyaeric
Repo: QueueLab/QCX PR: 0
File: :0-0
Timestamp: 2026-01-20T10:04:04.963Z
Learning: The application has a comprehensive credits and payment UI system with: (1) PurchaseCreditsPopup that shows after user authentication with a 7-day cooldown, (2) History panel on the left side containing CreditsDisplay at the top and ChatHistoryClient below, (3) TentTree icon in header that opens UsageSidebar on the right side showing usage history and billing options. All these components are coordinated through RootLayout and only render for authenticated users.
📚 Learning: 2026-01-20T10:04:04.963Z
Learnt from: ngoiyaeric
Repo: QueueLab/QCX PR: 0
File: :0-0
Timestamp: 2026-01-20T10:04:04.963Z
Learning: The application has a comprehensive credits and payment UI system with: (1) PurchaseCreditsPopup that shows after user authentication with a 7-day cooldown, (2) History panel on the left side containing CreditsDisplay at the top and ChatHistoryClient below, (3) TentTree icon in header that opens UsageSidebar on the right side showing usage history and billing options. All these components are coordinated through RootLayout and only render for authenticated users.
Applied to files:
components/usage-view.tsxcomponents/sidebar/chat-history-client.tsxcomponents/header.tsxcomponents/purchase-credits-popup.tsx
🧬 Code graph analysis (12)
components/usage-view.tsx (1)
components/usage-toggle-context.tsx (1)
useUsageToggle(26-30)
components/history.tsx (1)
components/history-toggle-context.tsx (1)
useHistoryToggle(26-30)
components/conditional-lottie.tsx (4)
components/map-loading-context.tsx (1)
useMapLoading(20-26)components/profile-toggle-context.tsx (1)
useProfileToggle(43-49)components/usage-toggle-context.tsx (1)
useUsageToggle(26-30)components/ui/lottie-player.tsx (2)
isVisible(10-20)LottiePlayerProps(6-8)
components/chat-panel.tsx (2)
lib/actions/suggest.ts (1)
getSuggestions(9-46)components/suggestions-dropdown.tsx (3)
suggestionItems(31-61)suggestionItems(64-79)suggestions(26-26)
components/history-sidebar.tsx (4)
components/history-toggle-context.tsx (1)
useHistoryToggle(26-30)components/ui/sheet.tsx (4)
Sheet(130-130)SheetContent(135-135)SheetHeader(136-136)SheetTitle(138-138)components/history-skelton.tsx (1)
HistorySkeleton(4-12)components/sidebar/chat-history-client.tsx (1)
ChatHistoryClient(30-197)
components/history-toggle-context.tsx (2)
components/calendar-toggle-context.tsx (3)
children(20-35)context(12-18)CalendarToggleContextType(5-8)components/history-container.tsx (1)
div(8-14)
components/chat.tsx (6)
components/usage-toggle-context.tsx (1)
useUsageToggle(26-30)components/usage-view.tsx (1)
UsageView(9-96)components/map/map-provider.tsx (1)
MapProvider(16-28)lib/store/settings.ts (1)
MapProvider(3-3)components/map/map-context.tsx (1)
MapProvider(14-22)components/map/google-map.tsx (2)
apiKey(20-29)GoogleMapComponent(12-86)
components/profile-toggle-context.tsx (1)
components/settings/settings-view.tsx (1)
activeView(12-16)
app/actions.tsx (2)
lib/agents/inquire.tsx (1)
inquire(12-54)lib/agents/query-suggestor.tsx (1)
querySuggestor(8-50)
components/header.tsx (6)
components/calendar-toggle-context.tsx (1)
useCalendarToggle(12-18)components/usage-toggle-context.tsx (1)
useUsageToggle(26-30)components/profile-toggle-context.tsx (1)
useProfileToggle(43-49)components/history-toggle-context.tsx (1)
useHistoryToggle(26-30)components/purchase-credits-popup.tsx (1)
PurchaseCreditsPopup(20-73)components/settings/settings-view.tsx (1)
SettingsView(8-35)
components/profile-toggle.tsx (2)
components/profile-toggle-context.tsx (1)
useProfileToggle(43-49)components/usage-toggle-context.tsx (1)
useUsageToggle(26-30)
components/purchase-credits-popup.tsx (1)
components/ui/dialog.tsx (6)
Dialog(112-112)props(35-53)props(20-29)props(70-81)props(87-96)props(102-108)
🪛 Biome (2.3.13)
app/actions.tsx
[error] 672-672: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 685-687: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🔇 Additional comments (17)
components/mobile-icons-bar.tsx (1)
51-55: LGTM - Stripe URL updated consistently.The Stripe checkout URL update aligns with the same URL used in
PurchaseCreditsPopupand other components in this PR.components/chat-panel.tsx (1)
133-157: LGTM - Correct dependency array fix.Adding
setSuggestionsto the dependency array is the right fix. ThedebouncedGetSuggestionscallback referencessetSuggestions, so it should be listed as a dependency to ensure the callback always captures the current reference.components/conditional-lottie.tsx (1)
6-14: LGTM - Usage toggle integration is correct.The visibility logic now correctly hides the Lottie loading animation when the usage panel is open, consistent with the existing pattern for
activeView. This ensures the animation doesn't overlay on the usage panel.components/purchase-credits-popup.tsx (1)
20-72: Overall implementation looks good.The component structure, feature list, and Stripe integration are well-implemented. The dialog UI follows the established patterns from the codebase's Dialog primitives.
app/actions.tsx (2)
672-673: Streamable value initialization pattern looks correct.Initializing with the content value and immediately marking as
done()ensures consumers receive the final value synchronously when hydrating from AI state. This is the correct pattern for static/completed content.
740-743: Streamable value initialization for tool results is correct.Initializing
searchResultswithJSON.stringify(toolOutput)and marking done with the same value ensures the component receives the data immediately during hydration.components/history-toggle-context.tsx (1)
1-30: LGTM - Clean context implementation.The context provider follows established patterns in the codebase (similar to
CalendarToggleContext). Exposing bothtoggleHistoryandsetHistoryOpenprovides flexibility for consumers that need explicit control vs. simple toggling.components/history.tsx (1)
11-25: LGTM - Clean refactor to context-based toggle.The component is now a focused trigger button that delegates state management to the context. The Sheet content has been moved to
HistorySidebar, maintaining separation of concerns. This aligns well with the coordinated UI system described in the learnings where History panel components work together through shared state.components/history-sidebar.tsx (2)
15-34: LGTM!Clean implementation of the history sidebar using Sheet with Suspense boundary. The component correctly integrates with the history toggle context and provides a proper loading state via HistorySkeleton fallback.
12-12: The import path is correct. The filehistory-skelton.tsxexists in the components directory and matches the import statement, so no build error will occur.Likely an incorrect or invalid review comment.
app/layout.tsx (1)
75-103: LGTM!The provider hierarchy is well-structured with toggle providers at outer levels and theme/map contexts closer to the content. HistorySidebar is appropriately placed alongside other global UI elements.
components/profile-toggle-context.tsx (1)
32-37: LGTM!The
closeProfileViewaddition provides a cleaner API for closing the profile view without requiring knowledge of the current active section. This aligns well with thecloseUsagepattern in usage-toggle-context.tsx for consistency across toggle contexts.components/usage-toggle-context.tsx (1)
1-30: LGTM!Clean implementation of the usage toggle context following established patterns in the codebase. The API is consistent with other toggle contexts (history, profile) and includes proper error handling for usage outside the provider.
components/chat.tsx (1)
17-19: LGTM!The usage toggle integration is clean and follows the established pattern for other toggles. The mutual exclusion logic (Settings > Usage > Map) aligns with the PR objectives for UI panel coordination.
Also applies to: 36-36
components/profile-toggle.tsx (1)
37-43: LGTM — Mutual exclusion logic is correctly implemented.The
handleSectionTogglefunction properly closes the usage panel before opening a profile section when both conditions are met (activeView !== sectionensures we're about to open/switch, not close). This integrates well with the coordinated toggle system.components/header.tsx (2)
31-37: LGTM — Mutual exclusion between usage and profile views.The
handleUsageTogglecorrectly closes the profile view before opening usage when both would otherwise be visible simultaneously. This complements the inverse logic inprofile-toggle.tsx.
55-63: LGTM — History toggle on logo aligns with the UI system.The logo button now triggers the history panel, which is consistent with the coordinated toggle architecture where the history panel appears on the left side.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| <div className="mobile-layout-container"> | ||
| <div className="mobile-map-section"> | ||
| {activeView ? <SettingsView /> : <MapProvider />} | ||
| {activeView ? <SettingsView /> : isUsageOpen ? <UsageView /> : <MapProvider />} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider extracting conditional view logic for readability.
The ternary chain activeView ? <SettingsView /> : isUsageOpen ? <UsageView /> : <MapProvider /> is duplicated in both mobile (line 113) and desktop (line 224) layouts. Consider extracting this to a helper component or function to reduce duplication and improve maintainability.
♻️ Suggested extraction
// Add above the Chat component or as a separate file
function MainContentView({ activeView, isUsageOpen, position }: {
activeView: ProfileToggleEnum | null;
isUsageOpen: boolean;
position?: { latitude: number; longitude: number; };
}) {
if (activeView) return <SettingsView />;
if (isUsageOpen) return <UsageView />;
return <MapProvider position={position} />;
}
// Then in both layouts:
<MainContentView activeView={activeView} isUsageOpen={isUsageOpen} />Also applies to: 224-224
🤖 Prompt for AI Agents
In `@components/chat.tsx` at line 113, Duplicate ternary rendering of activeView ?
<SettingsView /> : isUsageOpen ? <UsageView /> : <MapProvider /> should be
extracted into a small helper component (e.g., MainContentView) that accepts
props activeView and isUsageOpen (and optional position) and returns
SettingsView if activeView, UsageView if isUsageOpen, otherwise MapProvider;
replace the inline ternaries in both the mobile and desktop layouts with
<MainContentView activeView={activeView} isUsageOpen={isUsageOpen}
position={...} /> to remove duplication and improve readability while keeping
existing component names (SettingsView, UsageView, MapProvider).
| useEffect(() => { | ||
| // Open payment popup as soon as application opens | ||
| setIsPurchaseOpen(true) | ||
| }, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing authentication check and 7-day cooldown for purchase popup.
The popup opens unconditionally on every component mount, which will annoy users with repeated prompts on each page load. Based on learnings, the PurchaseCreditsPopup should only appear after user authentication and respect a 7-day cooldown period.
🛠️ Suggested approach
useEffect(() => {
- // Open payment popup as soon as application opens
- setIsPurchaseOpen(true)
+ // Only show popup for authenticated users who haven't seen it in 7 days
+ const lastShown = localStorage.getItem('purchasePopupLastShown')
+ const sevenDaysAgo = Date.now() - (7 * 24 * 60 * 60 * 1000)
+
+ // TODO: Add authentication check (e.g., from session/auth context)
+ const isAuthenticated = true // Replace with actual auth check
+
+ if (isAuthenticated && (!lastShown || parseInt(lastShown) < sevenDaysAgo)) {
+ setIsPurchaseOpen(true)
+ localStorage.setItem('purchasePopupLastShown', Date.now().toString())
+ }
}, [])Consider moving this logic to a dedicated hook or integrating with your auth context.
Based on learnings: "PurchaseCreditsPopup that shows after user authentication with a 7-day cooldown."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| // Open payment popup as soon as application opens | |
| setIsPurchaseOpen(true) | |
| }, []) | |
| useEffect(() => { | |
| // Only show popup for authenticated users who haven't seen it in 7 days | |
| const lastShown = localStorage.getItem('purchasePopupLastShown') | |
| const sevenDaysAgo = Date.now() - (7 * 24 * 60 * 60 * 1000) | |
| // TODO: Add authentication check (e.g., from session/auth context) | |
| const isAuthenticated = true // Replace with actual auth check | |
| if (isAuthenticated && (!lastShown || parseInt(lastShown) < sevenDaysAgo)) { | |
| setIsPurchaseOpen(true) | |
| localStorage.setItem('purchasePopupLastShown', Date.now().toString()) | |
| } | |
| }, []) |
🤖 Prompt for AI Agents
In `@components/header.tsx` around lines 39 - 42, The current useEffect
unconditionally calls setIsPurchaseOpen(true) causing the PurchaseCreditsPopup
to show on every mount; change it to only open after the user is authenticated
and when a 7-day cooldown has expired: read the authenticated state from your
auth context (or a new hook like useAuth) and check a persisted timestamp (e.g.
localStorage key like purchase_popup_last_shown) before calling
setIsPurchaseOpen(true), updating that timestamp when the popup is shown;
consider extracting the logic into a dedicated hook (e.g. usePurchasePopup) that
returns whether to show and encapsulates the auth check and 7-day cooldown
calculation.
| <Button variant="ghost" size="icon" onClick={handleUsageToggle}> | ||
| <TentTree className="h-[1.2rem] w-[1.2rem]" /> | ||
| </Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add accessibility attributes to usage toggle buttons.
Other header buttons include title attributes (e.g., calendar toggle has title="Open Calendar"), but the usage toggle buttons lack them. Add title and consider aria-label for screen reader support.
♿ Proposed fix
- <Button variant="ghost" size="icon" onClick={handleUsageToggle}>
+ <Button variant="ghost" size="icon" onClick={handleUsageToggle} title="Toggle Usage" aria-label="Toggle usage view">
<TentTree className="h-[1.2rem] w-[1.2rem]" />
</Button>Apply the same fix to the mobile version at line 95.
Also applies to: 95-97
🤖 Prompt for AI Agents
In `@components/header.tsx` around lines 81 - 83, The usage toggle Button(s) (the
desktop one rendering TentTree and the mobile variant rendered later) are
missing accessible labels; update the Button elements that call
handleUsageToggle to include a descriptive title (e.g., title="Open Usage") and
an aria-label (e.g., aria-label="Open Usage") so screen readers and tooltips
match other header toggles; locate the Button components wrapping TentTree (and
the corresponding mobile Button at the later occurrence) and add both
attributes.
| return ( | ||
| <Dialog open={isOpen} onOpenChange={onClose}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider using a controlled open state handler.
onOpenChange receives a boolean argument indicating the new open state, but onClose is a void function. While this works when the dialog closes (since onClose() ignores the false argument), it may cause unexpected behavior if the Dialog ever triggers onOpenChange(true).
♻️ Suggested fix for explicit open state handling
- <Dialog open={isOpen} onOpenChange={onClose}>
+ <Dialog open={isOpen} onOpenChange={(open) => { if (!open) onClose(); }}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return ( | |
| <Dialog open={isOpen} onOpenChange={onClose}> | |
| return ( | |
| <Dialog open={isOpen} onOpenChange={(open) => { if (!open) onClose(); }}> |
🤖 Prompt for AI Agents
In `@components/purchase-credits-popup.tsx` around lines 35 - 36, The Dialog
currently passes onOpenChange={onClose} but onOpenChange receives a boolean;
update the handler to explicitly handle the boolean state: use the Dialog's
onOpenChange prop (e.g., onOpenChange={(open) => { if (!open) onClose(); }}) or
replace onClose with a new function (e.g., handleDialogOpenChange) that accepts
the boolean and invokes onClose only when open is false; locate the Dialog usage
and the isOpen/onClose props in purchase-credits-popup.tsx to implement this
controlled open-state handler.
|
|
||
| if (isHistoryOpen) { | ||
| fetchChats(); | ||
| } | ||
| }, [isHistoryOpen]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider caching to avoid redundant fetches on toggle.
The effect re-fetches chats every time isHistoryOpen transitions to true, even if data was already loaded. Consider adding a flag to skip re-fetching when chats is already populated, or use a stale-while-revalidate pattern.
♻️ Proposed optimization
useEffect(() => {
+ // Skip if already loaded and not stale
+ if (chats.length > 0) return;
+
if (isHistoryOpen) {
fetchChats();
}
- }, [isHistoryOpen]);
+ }, [isHistoryOpen, chats.length]);Alternatively, add a dedicated refresh mechanism (e.g., pull-to-refresh or a refresh button) for explicit reloads.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (isHistoryOpen) { | |
| fetchChats(); | |
| } | |
| }, [isHistoryOpen]); | |
| // Skip if already loaded and not stale | |
| if (chats.length > 0) return; | |
| if (isHistoryOpen) { | |
| fetchChats(); | |
| } | |
| }, [isHistoryOpen, chats.length]); |
🤖 Prompt for AI Agents
In `@components/sidebar/chat-history-client.tsx` around lines 65 - 69, The effect
watching isHistoryOpen always calls fetchChats() on open, causing redundant
network calls; modify the useEffect that depends on isHistoryOpen so it checks
whether chats (the state holding loaded chat list) is already populated before
calling fetchChats(), e.g., only call fetchChats() when isHistoryOpen is true
AND chats is empty (or when a separate forceRefresh flag is set), or implement a
stale-while-revalidate approach by returning cached chats and triggering a
background refresh via a refreshChats/forceRefresh mechanism tied to a button or
pull-to-refresh; update references to isHistoryOpen, fetchChats, chats, and any
refresh flag accordingly.
| {isCreditsVisible && ( | ||
| <div className="mt-2 p-3 rounded-lg bg-muted/50 border border-border/50 space-y-2"> | ||
| <div className="flex justify-between items-center text-xs"> | ||
| <span>Available Credits</span> | ||
| <span className="font-bold">0</span> | ||
| </div> | ||
| <div className="w-full bg-secondary h-1.5 rounded-full overflow-hidden"> | ||
| <div className="bg-yellow-500 h-full w-[0%]" /> | ||
| </div> | ||
| <p className="text-[10px] text-muted-foreground">Upgrade to get more credits</p> | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Credits Preview displays static placeholder data.
The credits display shows hardcoded values (0 credits, 0% progress bar) rather than actual user data. Per the retrieved learnings, the application has a comprehensive credits UI system with CreditsDisplay component. Consider wiring this to actual user credits state or API data.
Do you want me to help implement the integration with actual credits data, or is this intentionally a placeholder for a future iteration?
🤖 Prompt for AI Agents
In `@components/sidebar/chat-history-client.tsx` around lines 137 - 148, The
current credits panel rendered when isCreditsVisible shows hardcoded values;
replace this static markup with the app's CreditsDisplay component and feed it
real state/props (e.g., userCredits, maxCredits, creditsPercentage) or call the
credits API/store selector to obtain those values before render; locate the
conditional using isCreditsVisible and swap the static div for <CreditsDisplay
credits={userCredits} maxCredits={maxCredits} percent={creditsPercentage} /> (or
equivalent prop names used in your codebase), ensuring you import CreditsDisplay
and derive userCredits/creditsPercentage from your auth/user store or the
existing credits-fetching hook.
| @@ -0,0 +1,96 @@ | |||
| 'use client' | |||
|
|
|||
| import React, { useEffect, useState } from 'react' | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Remove unused import.
useEffect is imported but not used in this component.
🧹 Remove unused import
-import React, { useEffect, useState } from 'react'
+import React, { useState } from 'react'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import React, { useEffect, useState } from 'react' | |
| import React, { useState } from 'react' |
🤖 Prompt for AI Agents
In `@components/usage-view.tsx` at line 3, The import statement in
components/usage-view.tsx currently imports useEffect but it is unused; remove
useEffect from the import list so the line reads import React, { useState } from
'react' (or drop the named imports entirely if useState is also unused),
ensuring only used symbols (React, useState) remain to eliminate the unused
import.
| const [usage] = useState([ | ||
| { details: 'Efficiently Fix Pull Request ...', date: '2026-01-17 08:05', change: -418 }, | ||
| { details: 'Fix Build and Add Parallel S...', date: '2026-01-16 06:10', change: -482 }, | ||
| { details: 'How to Add a Feature to a ...', date: '2026-01-14 10:42', change: -300 }, | ||
| ]) | ||
| const [credits] = useState(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Usage data is static and uses array index as key.
Two observations:
- The usage data is hardcoded with sample entries. If this is a placeholder, consider adding a TODO comment or connecting to actual usage API.
- Using array index as React key (
key={i}) can cause rendering issues if the list is reordered or filtered. Consider using a unique identifier from the data.
♻️ Suggested improvement for key
-{usage.map((item, i) => (
- <TableRow key={i}>
+{usage.map((item) => (
+ <TableRow key={`${item.date}-${item.details}`}>Also applies to: 83-89
🤖 Prompt for AI Agents
In `@components/usage-view.tsx` around lines 10 - 15, The usage data in the
usage-view component is hardcoded and list items are rendered using the array
index as a key; update the usage state to either fetch real data or mark it as a
placeholder with a clear TODO (replace the const [usage] initialization) and add
a stable unique id to each usage item (e.g., include an id property for entries
currently in the usage array and for future API responses). Then change the list
rendering to use that unique id (not key={i}) wherever usage is mapped
(referencing the usage state and the map that currently uses key={i} around
lines ~83-89) and leave credits state as-is if it’s intentional. Ensure new ids
are stable across reorders/filters so React keys remain consistent.
| <div className="p-4 border rounded-xl space-y-4"> | ||
| <div className="flex justify-between items-center"> | ||
| <span className="italic font-medium text-lg">Free</span> | ||
| <Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank')}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract Stripe URL to environment variable.
Hardcoding the Stripe checkout URL directly in the component makes it difficult to manage across environments (dev/staging/prod) and poses a maintenance risk. Consider moving this to an environment variable.
🔧 Suggested approach
-<Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank')}>
+<Button size="sm" className="rounded-full px-4" onClick={() => window.open(process.env.NEXT_PUBLIC_STRIPE_CHECKOUT_URL, '_blank')}>Then add to .env:
NEXT_PUBLIC_STRIPE_CHECKOUT_URL=https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank')}> | |
| <Button size="sm" className="rounded-full px-4" onClick={() => window.open(process.env.NEXT_PUBLIC_STRIPE_CHECKOUT_URL, '_blank')}> |
🤖 Prompt for AI Agents
In `@components/usage-view.tsx` at line 35, The Stripe checkout URL is hardcoded
in the Button onClick handler; replace the literal URL by reading
process.env.NEXT_PUBLIC_STRIPE_CHECKOUT_URL (or use a safe fallback/guard) and
update the onClick in the Button component to call window.open(checkoutUrl,
'_blank') where checkoutUrl is the env var, and add
NEXT_PUBLIC_STRIPE_CHECKOUT_URL to your .env files per environment; ensure the
code uses the client-exposed NEXT_PUBLIC_ prefix so the value is available in
the browser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest correctness issue is in PurchaseCreditsPopup: onOpenChange={onClose} can cause the dialog to close immediately or behave unpredictably. Auto-opening the purchase popup on every app load in components/header.tsx is an intrusive UX and should be gated by real credit state and/or persisted dismissal. Mobile/desktop behavior for the TentTree action is inconsistent (Stripe link vs usage toggle), and ChatHistoryClient would benefit from abort/cancel handling to avoid stale updates when the history sheet closes.
Additional notes (3)
- Maintainability |
components/mobile-icons-bar.tsx:48-54
The mobile TentTree button still links directly to Stripe, while desktop header now uses TentTree to toggle the Usage panel. This creates inconsistent behavior across breakpoints (and conflicts with the new “UsageView” concept). Users will see different actions for the same icon.
Given the new UsageToggleProvider, the mobile icon should likely call toggleUsage() (or open the same purchase popup) instead of navigating away.
- Maintainability |
components/mobile-icons-bar.tsx:48-54
The mobile “TentTree” button still links directly to Stripe (<a href=...>) instead of toggling the in-appUsageView, while desktop header now toggles usage. This creates inconsistent behavior across breakpoints (mobile opens Stripe, desktop opens usage panel). IfUsageViewis the intended destination, mobile should trigger the same toggle.
Separately, there are now two different Stripe URLs in the codebase (here vs PurchaseCreditsPopup / UsageView), which is a maintainability risk and easy to regress.
- Readability |
components/sidebar/chat-history-client.tsx:36-36
ChatHistoryClientnow only fetches whenisHistoryOpenis true, but it doesn’t reset state on close. If the user opens history, sees an error, closes, then reopens, the component may flash stale error/loading state depending on timing.
Also, this pattern should guard against state updates after close (fetch in-flight) to avoid showing results for a panel that is no longer open.
Summary of changes
What changed
-
Added global UI state providers in
app/layout.tsx:- Wrapped the app with new
HistoryToggleProviderandUsageToggleProvider. - Rendered a new
HistorySidebaralongside the existingSidebar.
- Wrapped the app with new
-
Introduced History side panel as a global sheet:
- New
components/history-toggle-context.tsxmanages open/close state. - New
components/history-sidebar.tsxrenders theSheet+ChatHistoryClient. - Updated
components/history.tsxto be a simple toggle button (onClick={toggleHistory}), delegating the actual sheet toHistorySidebar.
- New
-
Integrated Usage UI:
- New
components/usage-toggle-context.tsxfor toggling usage view. - New
components/usage-view.tsx(static mock data) and integrated it intocomponents/chat.tsx(desktop and mobile panel selection). - Updated
components/conditional-lottie.tsxto hide the loading Lottie when usage is open.
- New
-
Billing / purchase flow updates:
- New
components/purchase-credits-popup.tsxand header now auto-opens it on initial mount. - Header tent-tree icon now toggles Usage instead of linking directly to Stripe.
- Mobile icons bar Stripe link updated to a new checkout URL.
- New
-
Server/UI streaming stability tweaks in
app/actions.tsx:- Initialized
createStreamableValue(...)with default values for several streams (answer,relatedQueries,isCollapsed,searchResults).
- Initialized
-
Chat history fetch behavior change:
ChatHistoryClientnow fetches only when the history sheet is open and adds a “Credits Preview” collapsible UI section.
-
Profile/usage mutual exclusion:
ProfileToggleContextaddscloseProfileView().ProfileTogglenow closes usage before opening a profile section.Headercloses profile before opening usage.
| return ( | ||
| <Dialog open={isOpen} onOpenChange={onClose}> | ||
| <DialogContent className="sm:max-w-[425px]"> | ||
| <DialogHeader> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PurchaseCreditsPopup is configured with onOpenChange={onClose} but Dialog’s onOpenChange typically passes the next open boolean. With the current wiring, any open-change (including opening) will call onClose() and can cause the dialog to immediately close or behave inconsistently (depending on the dialog implementation).
Suggestion
Update the handler to accept the boolean and only call onClose() when it transitions to false.
export function PurchaseCreditsPopup({ isOpen, onClose }: PurchaseCreditsPopupProps) {
return (
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) onClose()
}}
>
{/* ... */}
</Dialog>
)
}Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.
| useEffect(() => { | ||
| // Open payment popup as soon as application opens | ||
| setIsPurchaseOpen(true) | ||
| }, []) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-opening the purchase dialog on every app load (setIsPurchaseOpen(true) in a mount effect) is a high-friction UX and will likely break flows where the user is not actually out of credits. It can also cause repeated popups across navigations in SPA mode (layout persists) and makes automated tests flaky unless they always account for the dialog.
This should be driven by a real condition (e.g., credits === 0, a server flag, or a query param), and ideally persisted so users who click “Later” aren’t repeatedly interrupted.
Suggestion
Gate the auto-open behind a real signal and persist dismissal.
Example (client-only, minimal):
useEffect(() => {
const dismissed = localStorage.getItem('purchase-popup-dismissed') === '1'
const shouldOpen = !dismissed /* && credits <= 0 */
if (shouldOpen) setIsPurchaseOpen(true)
}, [])
const handleClose = () => {
localStorage.setItem('purchase-popup-dismissed', '1')
setIsPurchaseOpen(false)
}
<PurchaseCreditsPopup isOpen={isPurchaseOpen} onClose={handleClose} />Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.
| export function UsageView() { | ||
| const [usage] = useState([ | ||
| { details: 'Efficiently Fix Pull Request ...', date: '2026-01-17 08:05', change: -418 }, | ||
| { details: 'Fix Build and Add Parallel S...', date: '2026-01-16 06:10', change: -482 }, | ||
| { details: 'How to Add a Feature to a ...', date: '2026-01-14 10:42', change: -300 }, | ||
| ]) | ||
| const [credits] = useState(0) | ||
| const { toggleUsage } = useUsageToggle() | ||
|
|
||
| return ( | ||
| <div className="container py-8 h-full overflow-y-auto"> | ||
| <div className="flex justify-between items-center mb-8"> | ||
| <div> | ||
| <h1 className="text-3xl font-bold tracking-tight">Usage</h1> | ||
| <p className="text-muted-foreground">Track your credits and usage history</p> | ||
| </div> | ||
| <Button variant="ghost" size="icon" onClick={toggleUsage}> | ||
| <Minus className="h-6 w-6" /> | ||
| <span className="sr-only">Close usage</span> | ||
| </Button> | ||
| </div> | ||
|
|
||
| <div className="space-y-6"> | ||
| <div className="p-4 border rounded-xl space-y-4"> | ||
| <div className="flex justify-between items-center"> | ||
| <span className="italic font-medium text-lg">Free</span> | ||
| <Button size="sm" className="rounded-full px-4" onClick={() => window.open('https://buy.stripe.com/3cIaEX3tRcur9EM7tbasg00', '_blank')}> | ||
| Upgrade | ||
| </Button> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UsageView is hard-coded with mock usage rows and credits = 0, plus it opens Stripe via window.open inline. Shipping this as-is will mislead users and makes it harder to evolve (no data contract).
If this is intended as a placeholder, it should be clearly isolated (e.g., behind a feature flag) or wired to real data sources (same credits value used for gating the purchase popup / history preview).
Suggestion
Replace mock state with props or a real fetch hook, and centralize the Stripe URL.
Example shape:
type UsageEntry = { details: string; date: string; change: number }
export function UsageView({ credits, usage }: { credits: number; usage: UsageEntry[] }) {
// render only
}And move the checkout URL to a single constant (e.g., lib/constants/billing.ts). Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion.
| const relatedQueries = createStreamableValue<RelatedQueries>({ | ||
| items: [] | ||
| }) | ||
| relatedQueries.done(JSON.parse(content as string)) | ||
| return { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getUIStateFromAIState now initializes streamables with defaults, which is good, but relatedQueries.done(JSON.parse(content as string)) still assumes content is valid JSON for the related type. If malformed data arrives, this will throw and break rendering of the whole UI state mapping.
Because this is in a UI-state conversion function, a single bad message should degrade gracefully (e.g., show an error section or skip the related block) rather than crash the whole mapping.
Suggestion
Wrap the JSON parse for related in a try/catch and fall back to an empty { items: [] }.
const relatedQueries = createStreamableValue<RelatedQueries>({ items: [] })
try {
relatedQueries.done(JSON.parse(content as string))
} catch {
relatedQueries.done({ items: [] })
}Reply with "@CharlieHelps yes please" if you’d like me to add a commit with this guard.
PR Type
Enhancement
Description
Integrate billing popup, usage sidebar, and credit preview toggle
Add history toggle provider and sidebar for chat history management
Improve type safety in streamable values with proper initialization
Refactor profile and usage views with mutual exclusivity logic
Update Stripe payment links and add credits preview in history panel
Diagram Walkthrough
File Walkthrough
2 files
Improve type safety in streamable value initializationFix dependency array in useCallback hook13 files
Add history and usage toggle providers to layoutIntegrate usage view with conditional renderingAdd usage toggle check to visibility logicAdd billing popup and usage toggle functionalityCreate new history sidebar component with toggleCreate history toggle context providerRefactor to use history toggle contextAdd closeProfileView method to contextAdd mutual exclusivity between profile and usage viewsCreate billing popup with upgrade featuresAdd credits preview toggle and history fetch optimizationCreate usage toggle context providerCreate usage view component with credits display1 files
Update Stripe payment link to new URL1 files
Add license document fileSummary by CodeRabbit
Release Notes
New Features
UI/UX Improvements