Fix: Dashboard category popup issues(web-pro) & Profile Page Bugs - October Release#590
Fix: Dashboard category popup issues(web-pro) & Profile Page Bugs - October Release#590
Conversation
…to fix-new-popup-issues
…to fix-new-popup-issues
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Reviewer's GuideThis PR resolves various dashboard popup and profile page bugs across web and pro-web by refining Hasura service methods, enhancing session-based profile management, improving NextAuth callbacks, syncing session updates in the preferences flow, adding “Select All” functionality in category popups, cleaning up Hasura permissions, unifying empty state messages, and applying UI styling tweaks. Sequence diagram for session-based profile update flowsequenceDiagram
actor User
participant "PreferenceSection"
participant "ProfileProvider"
participant "HasuraService"
participant "NextAuth Session"
participant "Router"
User->>PreferenceSection: Update profile (username/email)
PreferenceSection->>ProfileProvider: updateUserDetails(email, username, slug)
ProfileProvider->>HasuraService: updateUser(...)
HasuraService-->>ProfileProvider: User updated
PreferenceSection->>ProfileProvider: updateSessionUser({ ...session.user, slug, name })
PreferenceSection->>Router: router.push(`/u/${slug}/s/pref`)
PreferenceSection->>User: Show success message
Class diagram for updated ProfileProvider context and session userclassDiagram
class ProfileProvider {
- currentUser: User | null
- sessionUser: Session['user'] | null
+ getUserInfo(username: string): Promise<any>
+ updateUserDetails(email: string | null, name: string | null, slug: string | null): void
+ updateSessionUser(user: Session['user'] | null): void
}
class User {
+ userId: string
+ username: string
+ email: string
+ slug: string
+ profilePicture: string
+ role: string
}
ProfileProvider --> User : manages
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Caution Review failedThe pull request is closed. WalkthroughPR introduces user preferences system (language, font-size) with database persistence via new Hasura migrations and service APIs. Adds PreferencesProvider/usePreferences hook for client state management, updates auth flows to handle session updates, refactors workspace state management for departments, and includes UI/CSS adjustments for overlays and Google Translate hiding. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser as Browser<br/>(React App)
participant Hook as usePreferences<br/>Hook
participant Service as Hasura<br/>Service
participant Hasura as Hasura<br/>Backend
participant Storage as Local<br/>Storage & DOM
User->>Browser: Visit app / Mount component
Browser->>Hook: Mount PreferencesProvider
Hook->>Storage: Read fontSize from localStorage
Hook->>Storage: Apply to DOM (data-font-size)
rect rgb(200, 220, 240)
Note over Hook,Hasura: If user authenticated (session.user.id + jwt)
Hook->>Service: fetchUserPreferences(userId, jwt)
Service->>Hasura: Query user preferences (lang, font_size)
Hasura-->>Service: Return preferences
Service-->>Hook: { lang, fontSize }
end
Hook->>Storage: Update localStorage with fetched prefs
Hook->>Storage: Apply fontSize to DOM
Hook->>Storage: Set googtrans cookie for language
User->>Browser: Change font size / language
Browser->>Hook: setPreferences({ fontSize, lang })
rect rgb(220, 240, 200)
Note over Hook,Storage: Update UI immediately (optimistic)
Hook->>Storage: Update in-memory state
Hook->>Storage: Update localStorage
Hook->>Storage: Update DOM (data-font-size)
Hook->>Storage: Update googtrans cookie
end
rect rgb(240, 220, 200)
Note over Hook,Service: Persist to DB (if authenticated)
Hook->>Service: savePreferences(userId, jwt, prefs)
Service->>Hasura: Update/Insert preference record
Hasura-->>Service: Confirm update/insert
Service-->>Hook: Return { lang, fontSize, preferenceId }
end
alt DB Sync Success
Hook->>Browser: Sync complete (no action)
else DB Sync Failure
Hook->>Browser: Log error (user sees optimistic update)
end
sequenceDiagram
participant User
participant App as Pro-Web App
participant Auth as Auth Layer<br/>(NextAuth)
participant Session as Session<br/>Provider
participant Profile as Profile<br/>Component
User->>App: Login with credentials
App->>Auth: Authenticate (email, password)
Auth->>Auth: Validate password (enabled)
Auth->>Auth: Generate JWT with user/account
Auth-->>Session: Return token + user info
rect rgb(200, 220, 240)
Note over Auth,Session: JWT Callback - Initial Sign-in
Auth->>Auth: jwt({ token, user, account })
Auth->>Session: Return token with user.id, name, slug, email
end
Session->>Profile: Provide session context
Profile->>Profile: Render authenticated UI
rect rgb(220, 240, 200)
Note over User,Auth: User updates profile (name/email)
User->>Profile: Submit profile update form
Profile->>Profile: Call updateUserDetails API
Profile->>Profile: Push to /u/{newSlug}/s/pref
end
rect rgb(240, 220, 200)
Note over Auth,Session: JWT Callback - Session Update Trigger
Auth->>Auth: jwt({ token, user, account, trigger, session })
alt trigger === 'update' && session exists
Auth->>Auth: Update token.name, token.slug, token.email from session
Auth-->>Session: Return refreshed token
end
end
Session->>Profile: Session refreshed with new values
Profile->>Profile: Re-render with updated user info
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (6)
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 |
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- This PR spans multiple domains (profile page, category popup, permissions, CSS) — consider splitting into smaller, domain-focused PRs for better maintainability and reviewability.
- Remove or replace temporary console.log/debug statements (especially in auth.ts and service methods) with a proper logging mechanism before merging.
- The select-all logic is repeated across several components; consider extracting it into a shared hook or utility to reduce duplication.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- This PR spans multiple domains (profile page, category popup, permissions, CSS) — consider splitting into smaller, domain-focused PRs for better maintainability and reviewability.
- Remove or replace temporary console.log/debug statements (especially in auth.ts and service methods) with a proper logging mechanism before merging.
- The select-all logic is repeated across several components; consider extracting it into a shared hook or utility to reduce duplication.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
apps/web/components/routes/thread/user-thread-panel.tsx (1)
487-487: Consider omitting the description prop instead of passing an empty string.The title change from "No Threads Available" to "No public threads" is clearer and more accurate for the profile context. However, passing
description={''}is unnecessary—consider either omitting the prop entirely or providing a helpful message to guide users.Apply this diff to omit the description prop:
-<EmptyState title="No public threads" description={''} /> +<EmptyState title="No public threads" />Alternatively, if you want to provide context, consider:
-<EmptyState title="No public threads" description={''} /> +<EmptyState title="No public threads" description="This user hasn't shared any public threads yet" />apps/pro-web/components/routes/thread/user-thread-panel.tsx (1)
486-486: Consider omitting the description prop instead of passing an empty string.The title change to "No public threads" improves clarity. However, passing
description={''}is unnecessary—consider either omitting the prop entirely or providing helpful guidance for users viewing an empty profile.Apply this diff to omit the description prop:
-<EmptyState title="No public threads" description={''} /> +<EmptyState title="No public threads" />Alternatively, provide context:
-<EmptyState title="No public threads" description={''} /> +<EmptyState title="No public threads" description="This user hasn't shared any public threads yet" />apps/pro-web/components/routes/chat/chat-layout-section.tsx (1)
27-27: Consider using a more reasonable z-index value.The z-index value of
9999is extremely high and could cause future layering conflicts or mask underlying z-index organization issues. Unless there's a specific requirement for this value, consider using a more maintainable approach likez-[100]or defining semantic z-index values in your design system.Additionally, there's an extra space after
"inset-0"in the className string that should be removed for consistency.Apply this diff to use a more reasonable z-index and clean up the spacing:
- <div className="flex fixed inset-0 z-[9999] justify-center items-center backdrop-blur-sm bg-black/50"> + <div className="flex fixed inset-0 z-[100] justify-center items-center backdrop-blur-sm bg-black/50">apps/web/auth.ts (1)
111-121: Consider validation and JWT refresh for session updates.The update trigger handling updates token fields directly from the session payload without validation. This has a few implications:
No validation: Fields from
sessionare assigned totokenwithout checking if they're valid or if the user has permission to change them.JWT not refreshed: The
hasuraJwtis not regenerated when user details change. While this might be intentional for performance, it means the JWT claims won't reflect the updated username/slug until the next full sign-in.Incomplete sync: Only
name,slug, andimagefield is not synced, which might cause inconsistencies if profile pictures are updated.Consider adding validation and deciding on JWT refresh policy:
if (trigger === 'update' && session) { console.log( 'JWT callback → handling update trigger, session payload:', session, ) + + // Validate session updates have required fields + if (!session.name || !session.slug) { + console.error('Invalid session update: missing required fields') + return token + } + token.name = session.name ?? token.name token.slug = session.slug ?? token.slug token.email = session.email ?? token.email - // If you want to refresh hasuraJwt on update, do it here (carefully, with try/catch). + token.image = session.image ?? token.image + + // Consider: Should we regenerate hasuraJwt with updated claims? + // Pro: JWT claims stay in sync with user data + // Con: Performance overhead, requires secret validation + return token }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
seed.logis excluded by!**/*.log
📒 Files selected for processing (21)
Taskfile.yml(1 hunks)apps/hasura/metadata/databases/masterbots/tables/public_thread.yaml(0 hunks)apps/hasura/seeds/masterbots/1738186795715_init_chatbot_metadata_seeds.sql(0 hunks)apps/pro-web/app/globals.css(1 hunks)apps/pro-web/components/layout/profile/hero.tsx(1 hunks)apps/pro-web/components/routes/chat/chat-layout-section.tsx(1 hunks)apps/pro-web/components/routes/thread/user-thread-panel.tsx(1 hunks)apps/pro-web/components/shared/category-dashboard.tsx(2 hunks)apps/pro-web/components/shared/onboarding-section.tsx(2 hunks)apps/web/app/globals.css(1 hunks)apps/web/auth.ts(2 hunks)apps/web/components/auth/user-login.tsx(3 hunks)apps/web/components/layout/header/user-menu.tsx(1 hunks)apps/web/components/layout/profile/hero.tsx(1 hunks)apps/web/components/routes/browse/browse-chatbot-desktop-details.tsx(1 hunks)apps/web/components/routes/preferences/preference-section.tsx(3 hunks)apps/web/components/routes/thread/user-thread-panel.tsx(1 hunks)apps/web/components/shared/category-dashboard.tsx(2 hunks)apps/web/lib/hooks/use-profile.tsx(4 hunks)apps/web/lib/url.ts(1 hunks)apps/web/services/hasura/hasura.service.ts(1 hunks)
💤 Files with no reviewable changes (2)
- apps/hasura/metadata/databases/masterbots/tables/public_thread.yaml
- apps/hasura/seeds/masterbots/1738186795715_init_chatbot_metadata_seeds.sql
🧰 Additional context used
📓 Path-based instructions (14)
apps/{web,pro-web}/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders
apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/shared/onboarding-section.tsxapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/shared/onboarding-section.tsxapps/web/auth.tsapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/lib/url.tsapps/web/services/hasura/hasura.service.tsapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
apps/{web,pro-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components
apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers
apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/shared/onboarding-section.tsxapps/web/auth.tsapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/lib/url.tsapps/web/services/hasura/hasura.service.tsapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/app/globals.cssapps/pro-web/components/shared/onboarding-section.tsxTaskfile.ymlapps/web/auth.tsapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/app/globals.cssapps/web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/lib/url.tsapps/web/services/hasura/hasura.service.tsapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/shared/onboarding-section.tsxapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
apps/{web,pro-web}/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Order component files: imports → constants → component → styled components → types/interfaces
Files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/layout/header/user-menu.tsxapps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/shared/onboarding-section.tsxapps/pro-web/components/shared/category-dashboard.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/shared/category-dashboard.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/components/auth/user-login.tsxapps/web/components/layout/profile/hero.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
apps/{web,pro-web}/components/routes/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place page-specific components under components/routes/[feature]/
Organize page-specific components under components/routes/
Files:
apps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
apps/{web,pro-web}/app/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/app/**: Prefer Next.js Server Components; use 'use client' only when necessary
Leverage Streaming and Suspense for responsiveness in Next.js 15
Follow Next.js file conventions in the App Router
apps/{web,pro-web}/app/**: Leverage Server Components by default; use the use client directive only when client-side features are needed
Implement Nested Layouts using the App Router
Use Streaming and Suspense features in Next.js 14/15 where appropriate
Follow Next.js file conventions for routing and layout in the App Router
Optimize data fetching: fetch on the server, fetch where needed, and use preload patterns to avoid waterfalls
Files:
apps/pro-web/app/globals.cssapps/web/app/globals.css
apps/{web,pro-web}/components/shared/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place reusable UI under components/shared/
Place reusable UI elements under components/shared/
Files:
apps/pro-web/components/shared/onboarding-section.tsxapps/pro-web/components/shared/category-dashboard.tsxapps/web/components/shared/category-dashboard.tsx
apps/{web,pro-web}/components/shared/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Store reusable UI elements in components/shared/
Files:
apps/pro-web/components/shared/onboarding-section.tsxapps/pro-web/components/shared/category-dashboard.tsxapps/web/components/shared/category-dashboard.tsx
apps/{web,pro-web}/lib/hooks/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logicStore custom React hooks under lib/hooks/
Files:
apps/web/lib/hooks/use-profile.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place custom React hooks in lib/hooks/
Files:
apps/web/lib/hooks/use-profile.tsx
apps/{web,pro-web}/services/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place external API integrations under services/
Files:
apps/web/services/hasura/hasura.service.ts
apps/{web,pro-web}/services/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RORO (Receive an object, Return an object) for functions, especially when calling external services
Place external API integrations under services/
Files:
apps/web/services/hasura/hasura.service.ts
🧠 Learnings (36)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
📚 Learning: 2025-08-29T20:34:24.433Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: The UserCard component in apps/web/components/routes/profile/user-card.tsx accepts a loading prop to show skeleton/loading states. This should be used when user data is not yet available rather than passing null or using type assertions.
Applied to files:
apps/pro-web/components/layout/profile/hero.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsxapps/web/components/layout/profile/hero.tsx
📚 Learning: 2024-11-07T20:08:13.609Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 301
File: apps/masterbots.ai/components/routes/browse/browse-user-details.tsx:65-67
Timestamp: 2024-11-07T20:08:13.609Z
Learning: In the `BrowseUserDetails` component (`browse-user-details.tsx`), when displaying usernames, truncate and display ellipsis only on large screens (LG/XL) without creating custom reactive hooks. On smaller screens, do not include ellipsis for responsive reasons.
Applied to files:
apps/web/components/layout/header/user-menu.tsxapps/web/components/auth/user-login.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.
Applied to files:
apps/pro-web/components/routes/chat/chat-layout-section.tsxapps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
📚 Learning: 2024-10-23T19:11:47.520Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:39-45
Timestamp: 2024-10-23T19:11:47.520Z
Learning: In the `UserThreadPanel` component (`apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx`), the `count` state variable is used in the `loadMore` function and depends on `finalThreads.length`, so updating `count` in the `useEffect` is necessary.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsx
📚 Learning: 2024-12-11T19:40:37.103Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 324
File: apps/masterbots.ai/components/routes/browse/browse-chatbot-mobile-details.tsx:145-146
Timestamp: 2024-12-11T19:40:37.103Z
Learning: In `apps/masterbots.ai/components/routes/browse/browse-chatbot-mobile-details.tsx`, the follower and following counts are currently hardcoded as these features are being developed in other PRs.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component is redundant as thread-list.tsx has been developed to support all the same functionality including public pages. The codebase should be cleaned up to remove browse-list.tsx and related components in the browse directory, along with the BrowseProvider context.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsx
📚 Learning: 2024-11-23T02:41:45.884Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2024-11-23T02:41:45.884Z
Learning: In the application, both chat routing and profile routing should use shallow redirection instead of full page reloads to maintain consistent UI/UX. The profile thread list interaction must be the same as the browse page, ensuring that navigation within the profile does not disrupt the application's state.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-11-07T14:40:39.595Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 301
File: apps/masterbots.ai/components/routes/chat/chat-combobox.tsx:33-33
Timestamp: 2024-11-07T14:40:39.595Z
Learning: In `apps/masterbots.ai/components/routes/chat/chat-combobox.tsx`, the 'MB' logo is temporarily represented by the string `'MB'` until the custom MB icon is created.
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
📚 Learning: 2025-10-24T20:40:56.510Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 573
File: apps/pro-web/components/routes/pro/pro.tsx:49-49
Timestamp: 2025-10-24T20:40:56.510Z
Learning: In apps/pro-web/lib/hooks/use-mb-chat.tsx, the useMBChat() hook returns a tuple [MBChatHookState, MBChatHookActions], not a direct object. Use array destructuring to access state (index 0) and actions (index 1), e.g., const [state, actions] = useMBChat() or const [{ isLoading }] = useMBChat().
Applied to files:
apps/web/components/routes/thread/user-thread-panel.tsxapps/web/components/auth/user-login.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Run backend first (task boot) before frontend; use Hasura console for schema changes
Applied to files:
Taskfile.yml
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Perform database schema changes via Hasura console (task console), then migrations (task migrate)
Applied to files:
Taskfile.yml
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Use Hasura console (task console) for schema modifications
Applied to files:
Taskfile.yml
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/hasura/migrations/masterbots/** : Store and manage Hasura migrations under apps/hasura/migrations/masterbots/
Applied to files:
Taskfile.yml
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Run backend with task boot before frontend development
Applied to files:
Taskfile.yml
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Use NextAuth.js with custom user management; JWT for API auth; roles/subscriptions for access control
Applied to files:
apps/web/auth.tsapps/web/lib/hooks/use-profile.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Applied to files:
apps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/lib/hooks/use-profile.tsxapps/web/components/auth/user-login.tsx
📚 Learning: 2024-10-14T18:40:46.645Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 283
File: apps/masterbots.ai/components/routes/chat/admin-mode-approve.tsx:11-15
Timestamp: 2024-10-14T18:40:46.645Z
Learning: In the project, the `adminApproveThread` function within the `useThread` hook manages error handling and loading state, so components using it don't need to implement additional error handling unless they introduce side effects.
Applied to files:
apps/pro-web/components/routes/thread/user-thread-panel.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-08-29T20:34:37.023Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-08-29T20:34:37.023Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-12T20:30:40.360Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 561
File: apps/web/components/layout/profile/layout.tsx:28-31
Timestamp: 2025-09-12T20:30:40.360Z
Learning: Created a centralized normalizeUserSlug utility function in apps/web/lib/utils.ts and apps/pro-web/lib/utils.ts that safely handles undefined parameter values, trims whitespace, and converts to lowercase. This should be used consistently across all userSlug parameter extractions to prevent crashes and ensure database query consistency.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2024-11-28T06:49:04.598Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/components/layout/profile/profile-page-sidebar.tsx:33-37
Timestamp: 2024-11-28T06:49:04.598Z
Learning: When updating the URL in Next.js, prefer using `router.push` or `router.replace` from the Next.js `useRouter` hook instead of directly manipulating `window.history` to maintain consistency and leverage Next.js features.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-11-28T07:10:40.413Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/lib/hooks/use-sidebar.tsx:218-227
Timestamp: 2024-11-28T07:10:40.413Z
Learning: In the profile page `u/{username}/t`, when navigating between categories and chatbots, we should use shallow routing to enhance navigation performance.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-11-28T18:35:38.503Z
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/lib/hooks/use-sidebar.tsx:218-227
Timestamp: 2024-11-28T18:35:38.503Z
Learning: In Next.js App Router, shallow routing is not supported with `useRouter` from `next/navigation`, so `window.history.pushState` should be used for shallow navigation between routes.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-12-05T01:14:50.365Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2024-12-05T01:14:50.365Z
Learning: The masterbots.ai project follows Next.js 14 App Router conventions with server components as default and client components marked explicitly with 'use client' directive when needed.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-12T20:30:40.360Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 561
File: apps/web/components/layout/profile/layout.tsx:28-31
Timestamp: 2025-09-12T20:30:40.360Z
Learning: A centralized normalizeUserSlug utility function should be used for all user slug parameter extraction to ensure consistent handling of undefined values, whitespace trimming, and lowercase conversion. This prevents runtime crashes and ensures database query consistency.
Applied to files:
apps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface
Applied to files:
apps/web/components/auth/user-login.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use Streaming and Suspense in Next.js 14/15 where appropriate
Applied to files:
apps/web/components/auth/user-login.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Use functional components and hooks instead of class components
Applied to files:
apps/web/components/auth/user-login.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.
Applied to files:
apps/web/components/auth/user-login.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/services/hasura.service.ts : Use hasura.service.ts as the single interaction point for GraphQL operations with Hasura
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to **/services/hasura.service.ts : Use hasura.service.ts as the single point for all GraphQL interactions
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use hasura.service.ts for all GraphQL operations from UI layers
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-11-07T18:38:42.273Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 579
File: apps/pro-web/app/api/auth/signup/route.ts:151-157
Timestamp: 2025-11-07T18:38:42.273Z
Learning: In apps/pro-web/app/actions/admin.actions.ts, the insertUserOrganizations function should use Drizzle DB transactions to ensure atomicity when inserting organizations and their associated chatbots, preventing partial persistence issues.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2024-10-03T20:10:44.311Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 276
File: apps/masterbots.ai/app/wordware/layout.tsx:12-19
Timestamp: 2024-10-03T20:10:44.311Z
Learning: In `apps/masterbots.ai/app/wordware/layout.tsx`, the current layout is intentional to prevent layout issues such as unwanted gaps and sidebar design problems. A similar design is used in `apps/c/layout`.
Applied to files:
apps/web/components/routes/browse/browse-chatbot-desktop-details.tsx
🧬 Code graph analysis (6)
apps/web/auth.ts (1)
packages/mb-drizzle/src/drizzle/schema.ts (1)
user(171-214)
apps/web/components/shared/category-dashboard.tsx (1)
packages/mb-drizzle/src/drizzle/schema.ts (1)
category(220-228)
apps/web/components/routes/preferences/preference-section.tsx (4)
apps/web/lib/hooks/use-profile.tsx (1)
useProfile(41-47)apps/web/lib/hooks/use-accessibility.tsx (1)
useAccessibility(39-47)packages/mb-lib/src/text/text.lib.ts (1)
toSlug(12-44)apps/web/auth.ts (1)
session(195-210)
apps/web/lib/hooks/use-profile.tsx (2)
apps/web/auth.ts (1)
session(195-210)apps/web/services/hasura/hasura.service.ts (1)
getUserByID(2012-2053)
apps/web/components/auth/user-login.tsx (2)
apps/web/lib/hooks/use-profile.tsx (1)
useProfile(41-47)apps/web/components/layout/header/user-menu.tsx (1)
UserMenu(48-182)
apps/web/services/hasura/hasura.service.ts (2)
packages/mb-lib/src/hasura/hasura.lib.ts (1)
getHasuraClient(19-54)packages/mb-drizzle/src/drizzle/schema.ts (1)
user(171-214)
🔇 Additional comments (16)
Taskfile.yml (1)
38-40: Helpful debugging guidance added.The commented alternative command and logging tip are useful additions for developers who need to debug seed operations. The hasura CLI syntax and shell redirection are correct.
These comments align well with the project's documented workflow (boot → migrate → seed) and provide practical alternatives when working with specific databases or troubleshooting seed issues. As per learnings, ensure developers are aware that schema changes should still go through the Hasura console first before applying migrations and seeds.
apps/web/components/routes/browse/browse-chatbot-desktop-details.tsx (1)
34-34: LGTM! Vertical padding enhancement improves layout.The addition of
py-5provides consistent vertical spacing for the hero section container, aligning with similar padding improvements across other components in this PR.apps/web/lib/url.ts (1)
320-320: LGTM! Formatting improvement for readability.The blank line separates the declaration of
pathPartsfrom its subsequent mutation, improving code readability without any functional impact.apps/pro-web/components/layout/profile/hero.tsx (1)
9-9: LGTM! Vertical padding enhancement improves layout consistency.The addition of
py-5provides consistent vertical spacing for the hero section, aligning with the parallel change in the web app version.apps/web/components/layout/profile/hero.tsx (1)
9-9: LGTM! Vertical padding enhancement improves layout consistency.The addition of
py-5provides consistent vertical spacing for the hero section, matching the parallel change in the pro-web app version.apps/web/components/layout/header/user-menu.tsx (1)
128-128: LGTM! Improves consistency across menu items.The updated className for
ThemeTogglenow matches the styling pattern used by other dropdown menu items (px-2 text-sm py-3 h-11), ensuring uniform height and text size across the menu.apps/web/components/shared/category-dashboard.tsx (2)
92-95: LGTM! Useful feature addition for bulk category selection.The
handleSelectAllfunction correctly collects all category IDs and updates the local selection state, providing a convenient way for users to select all categories at once.
173-179: LGTM! Select All button enhances UX.The new "Select All" button provides a convenient way for users to quickly select all categories, complementing the existing "Clear All" functionality. The styling is consistent with other action buttons.
apps/pro-web/components/shared/category-dashboard.tsx (2)
92-95: LGTM! Useful feature addition for bulk category selection.The
handleSelectAllfunction correctly collects all category IDs and updates the local selection state, matching the implementation in the web app version for consistency.
173-179: LGTM! Select All button enhances UX.The new "Select All" button provides a convenient way for users to quickly select all categories, maintaining consistency with the web app version. The styling is appropriate and consistent with other action buttons.
apps/pro-web/components/shared/onboarding-section.tsx (2)
57-60: LGTM! Clean implementation of "Select All" functionality.The
handleSelectAllfunction correctly collects all category IDs fromallCategoriesand updates the local state, mirroring the established pattern used elsewhere in the codebase.
107-113: LGTM! Button implementation is consistent.The "Select All" button follows the same styling and structure as the existing "Clear All" button, maintaining UI consistency.
apps/web/app/globals.css (1)
864-864: LGTM! Background image addition for profile hero.The background-image property complements the existing background properties for the profile hero section.
apps/pro-web/app/globals.css (1)
864-864: LGTM! Consistent background image addition.This change mirrors the same update in the web app, maintaining UI consistency across both applications.
apps/web/auth.ts (1)
71-74: LGTM! Password validation re-enabled.Good security practice to validate passwords. The error message is appropriately generic to avoid information leakage.
apps/web/services/hasura/hasura.service.ts (1)
2012-2053: Verify whether this architectural pattern aligns with your security requirements.The concern is valid:
getUserByIDis called from a client component (use-profile.tsx, line 64) and uses admin privileges viagetHasuraClient({})without JWT. However, the specific usage is safe—it only fetches the current user's own data (session.user.id). This pattern is widespread throughout the codebase (e.g.,getCategory,getModels,getChatbots,getUserByEmailare similarly called from client components). If this is intentional, document it; otherwise, consider moving to server actions (which exist inapps/pro-web/app/actions/) for better separation of concerns and explicit authentication handling.
apps/web/lib/hooks/use-profile.tsx
Outdated
| useEffect(() => { | ||
| const loadUser = async () => { | ||
| if (!session?.user?.id) return | ||
|
|
||
| const { user } = await getUserByID(session.user.id) | ||
| if (user) { | ||
| setSessionUser({ | ||
| id: user.userId, | ||
| name: user.username, | ||
| email: user.email, | ||
| image: user.profilePicture, | ||
| slug: user.slug, | ||
| role: user.role, | ||
| hasuraJwt: session.user.hasuraJwt, | ||
| }) | ||
| } | ||
| } | ||
| loadUser() | ||
| }, [session]) |
There was a problem hiding this comment.
Missing error handling and loading state for sessionUser fetch.
The useEffect that fetches user data via getUserByID has several issues:
-
No error handling: If
getUserByIDfails or returns an error, the error is silently ignored andsessionUserremainsnull, causing UI components to show skeleton states indefinitely. -
No loading state: There's no way for consuming components to distinguish between "not loaded yet" and "load failed" or "user not found".
-
Silent failures: The
{ user }destructuring will throw if the response shape is unexpected, with no try/catch to handle it.
Add proper error handling and consider exposing loading state:
+const [sessionUserLoading, setSessionUserLoading] = React.useState(false)
+const [sessionUserError, setSessionUserError] = React.useState<string | null>(null)
useEffect(() => {
const loadUser = async () => {
if (!session?.user?.id) return
+
+ setSessionUserLoading(true)
+ setSessionUserError(null)
- const { user } = await getUserByID(session.user.id)
- if (user) {
- setSessionUser({
- id: user.userId,
- name: user.username,
- email: user.email,
- image: user.profilePicture,
- slug: user.slug,
- role: user.role,
- hasuraJwt: session.user.hasuraJwt,
- })
- }
+ try {
+ const { user, error } = await getUserByID(session.user.id)
+
+ if (error || !user) {
+ console.error('Failed to load session user:', error)
+ setSessionUserError(error || 'User not found')
+ setSessionUser(null)
+ return
+ }
+
+ setSessionUser({
+ id: user.userId,
+ name: user.username,
+ email: user.email,
+ image: user.profilePicture,
+ slug: user.slug,
+ role: user.role,
+ hasuraJwt: session.user.hasuraJwt,
+ })
+ } catch (err) {
+ console.error('Exception loading session user:', err)
+ setSessionUserError(err instanceof Error ? err.message : 'Unknown error')
+ setSessionUser(null)
+ } finally {
+ setSessionUserLoading(false)
+ }
}
loadUser()
}, [session])
Also expose the loading/error state in the context:
interface profileContextProps {
// ... existing props ...
sessionUser: sessionUserType
updateSessionUser: (user: sessionUserType) => void
+ sessionUserLoading: boolean
+ sessionUserError: string | null
}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web/lib/hooks/use-profile.tsx around lines 60 to 78, the effect that
calls getUserByID lacks try/catch, loading and error state and assumes the
response shape; wrap the async loadUser in a try/catch and add a local loading
flag (set loading true before fetch and false in finally) and an error state
(set on catch), guard the response access (check the returned object and user
property before destructuring), handle the "no user found" case explicitly (set
sessionUser to null and set an appropriate error or notFound flag), and expose
loading and error (or notFound) from the hook so consumers can render skeletons,
errors, or fallback UI; ensure you still clear loading/error on cleanup or when
session changes.
There was a problem hiding this comment.
@coderabbitai We should avoid getting the user data on client side. The only exception is when the user has updated their data, in that case we refresh the user data with the new one and we should even refresh the JWT token to update the user data there and reflect it among the other components.
cc - @sheriffjimoh
There was a problem hiding this comment.
@AndlerRL Thank you for the clarification on the architecture! You're absolutely right—the current implementation is fetching user data from Hasura on the client side unnecessarily.
The correct approach should be:
-
Session as the source of truth: The
sessionUsershould be populated directly fromsession.user(which comes from the JWT), not by fetching from Hasura on mount. -
Remove the
useEffectfetch: The entireuseEffectblock that callsgetUserByIDshould be removed since it's doing unnecessary client-side database queries. -
Initialize from session: Instead,
sessionUsershould be synchronized withsession.user:
const [sessionUser, setSessionUser] = React.useState<sessionUserType>(null)
useEffect(() => {
if (session?.user) {
setSessionUser(session.user)
} else {
setSessionUser(null)
}
}, [session])- Update flow: When a user updates their profile (as in
preference-section.tsx):- Update the database via the mutation
- Call
update()fromuseSession()to trigger the JWT refresh (which I see is already handled inauth.tswith thetrigger === 'update'flow) - The session update will automatically propagate the new data to
sessionUservia the effect above
This approach:
- ✅ Avoids unnecessary Hasura queries on every session change
- ✅ Keeps the JWT as the single source of truth
- ✅ Only hits the database when the user explicitly updates their profile
- ✅ Properly refreshes the JWT to keep all components in sync
✏️ Learnings added
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-21T18:00:08.403Z
Learning: In apps/web/lib/hooks/use-profile.tsx: The sessionUser state should be populated directly from session.user (JWT) and not by fetching from Hasura on the client side. The useEffect should only synchronize sessionUser with session.user. Client-side Hasura fetches for user data should be avoided; user data comes from the JWT/session. Only when users update their profile should we refresh both the database and JWT token (via NextAuth session update trigger).
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: The UserCard component in apps/web/components/routes/profile/user-card.tsx accepts a loading prop to show skeleton/loading states. This should be used when user data is not yet available rather than passing null or using type assertions.
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 283
File: apps/masterbots.ai/components/routes/chat/admin-mode-approve.tsx:11-15
Timestamp: 2024-10-14T18:40:46.645Z
Learning: In the project, the `adminApproveThread` function within the `useThread` hook manages error handling and loading state, so components using it don't need to implement additional error handling unless they introduce side effects.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
There was a problem hiding this comment.
@coderabbitai, @AndlerRL - I have tried this approaches initially but the session doesn’t seesm to reload new data. i will revert to it.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if preference-section.tsx is calling session.update()
echo "=== Checking for session.update() calls in preference-section.tsx ==="
rg -n "update\(\)" apps/web/components/routes/preferences/preference-section.tsx
echo -e "\n=== Checking for useSession import and usage ==="
rg -n "useSession" apps/web/components/routes/preferences/preference-section.tsx
echo -e "\n=== Getting the handleUpdateProfile function ==="
ast-grep --pattern $'const handleUpdateProfile = async ($$$) => {
$$$
}' apps/web/components/routes/preferences/preference-section.tsx
Length of output: 269
🏁 Script executed:
#!/bin/bash
# Get the complete handleUpdateProfile implementation
echo "=== Searching for handleUpdateProfile function ==="
rg -n -A 30 "handleUpdateProfile" apps/web/components/routes/preferences/preference-section.tsx | head -50
echo -e "\n=== Check how updateSessionUser is being called ==="
rg -n -B 2 -A 5 "updateSessionUser" apps/web/components/routes/preferences/preference-section.tsx
Length of output: 2277
@sheriffjimoh I found the issue! The session isn't reloading because you're not calling session.update() to trigger NextAuth's JWT refresh.
Looking at preference-section.tsx, here's what's happening:
Current flow (doesn't work):
await updateUserDetails(email, username, slug) // ✅ Updates DB
await updateSessionUser({ ...session.user, slug, name: username }) // ❌ Only updates local state
// Missing: session.update() call!The updateSessionUser function only updates the local React state in ProfileProvider. It doesn't trigger NextAuth's JWT callback where you have the trigger === 'update' logic in auth.ts.
Here's the fix:
// In preference-section.tsx, update the useSession destructuring:
const { data: session, update } = useSession() // Add 'update'
// In handleUpdateProfile:
async function handleUpdateProfile() {
// ... existing validation ...
try {
const { username } = inputValue
const slug = toSlug(username)
const email = currentUser?.email
// 1. Update the database
await updateUserDetails(email ?? null, username ?? null, slug ?? null)
// 2. Trigger NextAuth session update (this calls JWT callback with trigger='update')
await update({
name: username,
slug: slug,
})
// 3. Remove the manual updateSessionUser call - it's now handled by session refresh
// The useEffect in use-profile.tsx will automatically sync sessionUser from session.user
customSonner({ type: 'success', text: 'Profile updated successfully' })
router.push(`/u/${slug}/s/pref`)
} catch (error) {
// ... error handling ...
}
}How it works:
session.update({ name, slug })triggers the JWT callback inauth.tswithtrigger === 'update'- The JWT callback updates the token with the new values
- NextAuth automatically refreshes the session with the updated JWT
- The
useEffectinuse-profile.tsxpicks up the session change and syncssessionUser
This way you avoid the client-side Hasura fetch entirely and let NextAuth handle the session refresh properly! 🎯
✏️ Learnings added
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-28T03:44:16.369Z
Learning: In apps/web/components/routes/preferences/preference-section.tsx: After updating user profile in the database via updateUserDetails, must call session.update() (from useSession hook) with the updated fields to trigger NextAuth's JWT callback with trigger='update'. This refreshes the JWT token and session automatically. Do not manually call updateSessionUser; the useEffect in use-profile.tsx will sync sessionUser from the refreshed session.user.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-21T18:00:08.455Z
Learning: In apps/web/lib/hooks/use-profile.tsx: The sessionUser state should be populated directly from session.user (JWT) and not by fetching from Hasura on the client side. The useEffect should only synchronize sessionUser with session.user. Client-side Hasura fetches for user data should be avoided; user data comes from the JWT/session. Only when users update their profile should we refresh both the database and JWT token (via NextAuth session update trigger).
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: The UserCard component in apps/web/components/routes/profile/user-card.tsx accepts a loading prop to show skeleton/loading states. This should be used when user data is not yet available rather than passing null or using type assertions.
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-21T19:47:50.195Z
Learning: For repo bitcashorg/masterbots (apps/pro-web), AndlerRL prefers integrating TanStack Query into React Context Hooks wherever they fit to manage shared server state and side effects, with a longer-term plan to align broader state management with TanStack Query and potentially replace React Context hooks. Captured from PR #584 discussion on Nov 21, 2025.
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
There was a problem hiding this comment.
@coderabbitai - yeah i have tried this approach, i called the update and all but the sessions was not updating, instead, it's clearing the login session and i have to re-login
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Get the complete JWT callback implementation from auth.ts
echo "=== JWT callback implementation in auth.ts ==="
rg -n -A 50 "async jwt\(" apps/web/auth.ts | head -80
echo -e "\n=== Check session callback implementation ==="
rg -n -A 20 "async session\(" apps/web/auth.ts
echo -e "\n=== Check what fields are in the user type from NextAuth ==="
rg -n "interface.*User" apps/web/auth.ts -A 10
Length of output: 2749
@sheriffjimoh I found the issue! 🎯 Looking at your auth.ts JWT callback, the problem is in the update trigger handler (lines 111-121).
The Problem
When you call session.update(), the JWT callback receives trigger === 'update' and does this:
if (trigger === 'update' && session) {
token.name = session.name ?? token.name
token.slug = session.slug ?? token.slug
token.email = session.email ?? token.email
return token // ❌ Returns early without ensuring critical fields exist!
}This assumes the token already has all required fields (id, hasuraJwt, role, etc.). But if the token is stale or those fields are missing, NextAuth sees an incomplete token and invalidates the session, forcing you to re-login.
The Fix
You need to ensure all required fields are preserved during the update. Here's the corrected implementation:
async jwt({ token, user, account, trigger, session }) {
console.log(
'JWT callback → trigger:',
trigger,
'session:',
session ? 'present' : 'none',
'user:',
user ? 'present' : 'none',
)
// Handle update trigger
if (trigger === 'update' && session) {
console.log('JWT callback → handling update trigger, session payload:', session)
// ✅ Validate that token has critical fields BEFORE updating
if (!token.id || !token.hasuraJwt) {
console.error('JWT callback → token missing critical fields during update:', {
hasId: !!token.id,
hasJwt: !!token.hasuraJwt,
hasRole: !!token.role
})
// Don't return here - let it fall through to regenerate the token
} else {
// ✅ Only update if we have a valid token
token.name = session.name ?? token.name
token.slug = session.slug ?? token.slug
token.email = session.email ?? token.email
console.log('JWT callback → token updated successfully:', {
id: token.id,
name: token.name,
slug: token.slug,
hasJwt: !!token.hasuraJwt
})
return token
}
}
// Rest of your existing JWT callback logic...
if (user) {
// ... (keep all existing code)
}
// ✅ At the end, ensure all required fields are present
if (!token.id || !token.hasuraJwt) {
console.error('JWT callback → token still incomplete at end of callback')
throw new Error('Failed to generate complete token')
}
return token
}Additional Debugging
Add this logging to your preference-section.tsx to see what's being sent:
async function handleUpdateProfile() {
// ... existing code ...
try {
const updatePayload = {
name: username,
slug: slug,
}
console.log('About to call session.update with:', updatePayload)
await update(updatePayload)
console.log('session.update completed successfully')
// Give NextAuth a moment to process
await new Promise(resolve => setTimeout(resolve, 100))
// Now check the session
const newSession = await getSession()
console.log('New session after update:', {
hasUser: !!newSession?.user,
userId: newSession?.user?.id,
slug: newSession?.user?.slug
})
} catch (error) {
console.error('session.update failed:', error)
throw error
}
}Root Cause Summary
The issue is that the update path was returning early without validating the token has all required fields. When NextAuth sees a token without id, hasuraJwt, or role, it treats it as invalid and clears the session.
The fix ensures:
- ✅ Critical fields are validated before returning during update
- ✅ If fields are missing, it falls through to regenerate the token
- ✅ Proper error logging to catch this issue in the future
Try this fix and let me know if the session still clears! 🚀
🧬 Code Graph Analysis Results
[apps/web/auth.ts:195-210]
Summary: JWT callback for NextAuth
- Purpose: Generate/verify Hasura JWT on login and on subsequent updates; attach JWT and user details to the token.
- Parameters: token, user, account, trigger, session
- Behavior:
- If trigger is 'update' and session exists, propagate session fields (name, slug, email, etc.) back to the token.
- If user exists (e.g., login with Google), fetch user role/slug and assign to token; otherwise use existing token values.
- Generate a Hasura JWT using a server-side secret, verify it, and store it in the token (hasuraJwt).
- Persist the Hasura JWT in a client cookie named 'token' with configured maxAge, httpOnly, secure, sameSite.
- Returns: token (with updated fields) for the next step in the flow.
- Errors: Logs errors and propagates error where applicable.
[apps/web/auth.ts:101-194]
Summary: JWT callback (full flow)
- Purpose: Populate token with user/session details at sign-in and handle updates.
- Parameters: token, user, account, trigger, session
- Behavior:
- Logs diagnostic information about trigger, session, user presence.
- On trigger 'update', copies relevant fields from session to token for refresh without full re-login.
- On initial sign-in with Google or other providers, enrich token with role/slug by querying user data as needed; set id, email, name, image, provider.
- Validate Hasura JWT secret; create and verify Hasura JWT; store JWT in cookie; ensure user preferences exist.
- Returns: enriched token to continue the sign-in/updates flow.
- Errors: Logs and rethrows to caller.
[apps/web/services/hasura/hasura.service.ts:1430-1538]
Summary: updateUserPersonality
- Purpose: Update user bio, topic (favouriteTopic), and profilePicture in Hasura via GraphQL mutation.
- Parameters:
- userId: string | undefined
- bio: string | null
- topic: string | null
- jwt: string | undefined
- profilePicture: string | null
- Behavior:
- Requires jwt; builds updateArgs with pkColumns { userId }.
- Sets only non-null fields: bio, favouriteTopic, profilePicture as provided.
- Executes updateUserByPk mutation; returns { success: true } on success.
- On error, logs and returns { success: false, error } with message.
- Returns: object { success: boolean, error?: string }.
- Errors: Returns structured error object instead of throwing.
[apps/web/services/hasura/hasura.service.ts:2197-2250]
Summary: updateUser
- Purpose: Update user basic fields (username, slug) and optionally email (commented out) for a user by userId.
- Parameters:
- userId: string | undefined
- email: string | null
- username: string | null
- slug: string | null
- jwt: string | undefined
- Behavior:
- Requires jwt; if username is provided, checks if already taken (isUsernameTaken) and errors if so.
- Builds updateArgs with pkColumns { userId } and sets non-null fields (username, slug).
- Executes updateUserByPk mutation; returns { success: true } on success.
- Returns: object { success: boolean } on success; throws on error.
- Errors: Logs error and rethrows.
[apps/web/services/hasura/hasura.service.ts:2030-2071]
Summary: getUserByID
- Purpose: Fetch a user by userId.
- Parameters:
- userId: string
- Behavior:
- Validates input; runs GraphQL query to retrieve userId, username, email, slug, profilePicture, role.
- Returns { user, error } with user data when found; error string on failure/not found.
- Returns: { user: UserInterface | null, error: string | null }.
- Errors: Logs error details and returns error message.
🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-21T18:00:08.455Z
Learning: In apps/web/lib/hooks/use-profile.tsx: The sessionUser state should be populated directly from session.user (JWT) and not by fetching from Hasura on the client side. The useEffect should only synchronize sessionUser with session.user. Client-side Hasura fetches for user data should be avoided; user data comes from the JWT/session. Only when users update their profile should we refresh both the database and JWT token (via NextAuth session update trigger).
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-28T03:44:16.369Z
Learning: In apps/web/components/routes/preferences/preference-section.tsx: After updating user profile in the database via updateUserDetails, must call session.update() (from useSession hook) with the updated fields to trigger NextAuth's JWT callback with trigger='update'. This refreshes the JWT token and session automatically. Do not manually call updateSessionUser; the useEffect in use-profile.tsx will sync sessionUser from the refreshed session.user.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: The UserCard component in apps/web/components/routes/profile/user-card.tsx accepts a loading prop to show skeleton/loading states. This should be used when user data is not yet available rather than passing null or using type assertions.
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
apps/web/lib/hooks/use-profile.tsx
Outdated
| const updateSessionUser = (user: sessionUserType) => { | ||
| setSessionUser(user) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
updateSessionUser doesn't sync with NextAuth session.
The updateSessionUser function only updates local React state but doesn't call NextAuth's update() function to persist the changes to the actual session. This means:
- The session will revert to old values on page refresh
- The JWT token won't reflect the updated user data
- Server-side session checks will still see old data
The function should likely call NextAuth's update() method. Verify if this is the intended behavior:
Based on the verification results, consider updating the function:
+import { useSession } from 'next-auth/react'
export function ProfileProvider({ children }: ProfileProviderProps) {
- const { data: session } = useSession()
+ const { data: session, update } = useSession()
// ... existing code ...
- const updateSessionUser = (user: sessionUserType) => {
+ const updateSessionUser = async (user: sessionUserType) => {
setSessionUser(user)
+
+ // Sync with NextAuth session
+ if (user) {
+ try {
+ await update({
+ name: user.name,
+ slug: user.slug,
+ email: user.email,
+ image: user.image,
+ })
+ } catch (error) {
+ console.error('Failed to update NextAuth session:', error)
+ throw error
+ }
+ }
}
🏁 Script executed:
#!/bin/bash
# Check if update() is called elsewhere when updateSessionUser is used
echo "=== Finding usages of updateSessionUser ==="
rg -n -C5 "updateSessionUser\(" --type=ts --type=tsx
echo -e "\n=== Checking if session.update() is called nearby ==="
rg -n -C5 "update\(\{" --type=ts --type=tsx -g "preference*.tsx"
Length of output: 154
📝 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.
| const updateSessionUser = (user: sessionUserType) => { | |
| setSessionUser(user) | |
| } | |
| const updateSessionUser = async (user: sessionUserType) => { | |
| setSessionUser(user) | |
| if (user) { | |
| try { | |
| await update({ | |
| name: user.name, | |
| slug: user.slug, | |
| email: user.email, | |
| image: user.image, | |
| }) | |
| } catch (error) { | |
| console.error('Failed to update NextAuth session:', error) | |
| throw error | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In apps/web/lib/hooks/use-profile.tsx around lines 34, 51 and 79-81: the current
updateSessionUser only updates local state and is synchronous, causing session
reversion and a type mismatch where callers await it. Change the
profileContextProps type at line 34 so updateSessionUser returns Promise<void>,
import the update function from useSession() at line 51, and make
updateSessionUser async (lines 79-81) so it calls setSessionUser(user) and then
awaits update({ user }) to persist the change to NextAuth; ensure proper error
handling (rethrow or log) so callers receive rejection if update fails.
There was a problem hiding this comment.
We should sync this state with the server session that we get from the server side. Setting it as the initial state is fine, so we can remove the useEffect code block.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check NextAuth configuration and session structure
echo "=== Checking auth.ts for session structure ==="
cat git/apps/web/auth.ts | grep -A 30 "session:"
echo -e "\n=== Checking what's in session.user type ==="
rg "session\?.user\." -n -C2 git/apps/web/
echo -e "\n=== Check JWT callback to see what's encoded ==="
cat git/apps/web/auth.ts | grep -A 50 "jwt({"
Length of output: 302
@AndlerRL Got it. I’ll remove the client refetch and take the server session as the source of truth for the initial state. I’ve also made updateSessionUser persist changes via NextAuth so it doesn’t drift on refresh.
Here’s the patch for apps/web/lib/hooks/use-profile.tsx:
diff --git a/apps/web/lib/hooks/use-profile.tsx b/apps/web/lib/hooks/use-profile.tsx
index 0000000..0000001 100644
--- a/apps/web/lib/hooks/use-profile.tsx
+++ b/apps/web/lib/hooks/use-profile.tsx
@@ -1,16 +1,16 @@
'use client'
import {
- getUserByID,
getUserBySlug,
updateUser,
updateUserPersonality,
} from '@/services/hasura'
import type { User } from 'mb-genql'
import type { Session } from 'next-auth'
import { useSession } from 'next-auth/react'
-import React, { useEffect } from 'react'
+import React from 'react'
import { useSonner } from './useSonner'
type sessionUserType = Session['user'] | null
interface profileContextProps {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
@@ -24,8 +24,8 @@ interface profileContextProps {
setCurrentUser: React.Dispatch<React.SetStateAction<User | null>>
updateUserDetails: (
email: string | null,
name: string | null,
slug: string | null,
) => void
sessionUser: sessionUserType
- updateSessionUser: (user: sessionUserType) => void
+ updateSessionUser: (user: sessionUserType) => Promise<void>
}
const profileContext = React.createContext<profileContextProps | undefined>(
undefined,
)
@@ -48,14 +48,25 @@ interface ProfileProviderProps {
}
export function ProfileProvider({ children }: ProfileProviderProps) {
- const { data: session } = useSession()
+ const { data: session, update } = useSession()
const [currentUser, setCurrentUser] = React.useState<User | null>(null)
- const [sessionUser, setSessionUser] = React.useState<sessionUserType>(null)
+ const [sessionUser, setSessionUser] = React.useState<sessionUserType>(() =>
+ session?.user
+ ? {
+ id: session.user.id,
+ name: session.user.name,
+ email: session.user.email,
+ image: session.user.image,
+ slug: session.user.slug,
+ role: session.user.role,
+ hasuraJwt: session.user.hasuraJwt,
+ }
+ : null,
+ )
const { customSonner } = useSonner()
- useEffect(() => {
- const loadUser = async () => {
- if (!session?.user?.id) return
- const { user } = await getUserByID(session.user.id)
- if (user) {
- setSessionUser({
- id: user.userId,
- name: user.username,
- email: user.email,
- image: user.profilePicture,
- slug: user.slug,
- role: user.role,
- hasuraJwt: session.user.hasuraJwt,
- })
- }
- }
- loadUser()
- }, [session])
- const updateSessionUser = (user: sessionUserType) => {
- setSessionUser(user)
- }
+ const updateSessionUser = async (user: sessionUserType) => {
+ setSessionUser(user)
+ if (user) {
+ try {
+ await update({
+ name: user.name,
+ email: user.email,
+ image: user.image,
+ slug: user.slug,
+ })
+ } catch (error) {
+ console.error('Failed to update NextAuth session:', error)
+ throw error
+ }
+ }
+ }
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const getUserInfo = async (slug: string): Promise<any> => {Notes:
- Removed the getUserByID import and the entire useEffect block that refetched the user by ID.
- Initialized sessionUser from the server-provided session (via SessionProvider’s initialSession).
- updateSessionUser is now async and persists to NextAuth via update(); callers that await it (e.g., preferences) won’t have a type mismatch.
- If you’d prefer to keep updateSessionUser as local-only and handle session.update() at call sites, I can revert that part.
If this looks good, I’ll proceed similarly for any mirrored hook in apps/pro-web if/when it adopts the sessionUser state.
🧬 Code Graph Analysis Results
[apps/pro-web/lib/hooks/use-profile.tsx: lines 35-41]
export function useProfile() {
const context = React.useContext(profileContext)
if (!context) {
throw new Error('useProfileContext must be used within a ProfileProvider')
}
return context
}
[apps/pro-web/lib/hooks/use-profile.tsx: lines 47-165]
export function ProfileProvider({ children }: ProfileProviderProps) {
const { data: session } = useSession()
const [currentUser, setCurrentUser] = React.useState<User | null>(null)
const { customSonner } = useSonner()
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const getUserInfo = async (slug: string): Promise<any> => {
if (!slug?.trim()) {
throw new Error('Slug is required')
}
try {
const sessionSlug = session?.user.slug
? session?.user.slug.toLowerCase()
: session?.user.name?.toLowerCase()
const userInfo = await getUserBySlug({
slug,
isSameUser: sessionSlug === slug,
})
if (!userInfo) {
throw new Error('User not found')
}
setCurrentUser(userInfo.user as User)
return userInfo
} catch (error) {
console.error('Failed to fetch user info:', error)
throw error
}
}
const isSameUser = (userId: string) => {
if (!userId?.trim() || !session?.user?.id) {
return false
}
return session?.user.id === userId
}
const updateUserInfo = async (
bio: string | null,
topic: string | null,
profilePicture: string | null,
) => {
try {
const jwt = session?.user?.hasuraJwt
if (!jwt || !session.user?.id) {
throw new Error('User not authenticated')
}
await updateUserPersonality({
userId: session?.user.id,
jwt: session?.user.hasuraJwt,
bio,
topic,
profilePicture,
})
setCurrentUser((prevUser) => {
if (!prevUser) return null
return {
...prevUser,
bio: bio || prevUser.bio || '',
profilePicture: profilePicture || prevUser.profilePicture,
}
})
} catch (error) {
console.error('Failed to update user info', error)
customSonner({ type: 'error', text: 'Failed to update user info' })
}
}
const updateUserDetails = async (
email: string | null,
username: string | null,
slug: string | null,
) => {
try {
const jwt = session?.user?.hasuraJwt
if (!jwt || !session.user?.id) {
throw new Error('User not authenticated')
}
const result = await updateUser({
userId: session.user.id,
jwt,
email,
username,
slug,
})
if (!result.success) {
throw new Error('An error occurred while updating user details')
}
setCurrentUser((prevUser) => {
if (!prevUser) return null
return {
...prevUser,
email: email || prevUser.email || '',
username: username || prevUser.username || '',
slug: slug || prevUser.slug || '',
}
})
} catch (error) {
console.error('Failed to update user details', error)
throw error
}
}
return (
<profileContext.Provider
value={{
getUserInfo,
isSameUser,
updateUserInfo,
currentUser,
setCurrentUser,
updateUserDetails,
}}
>
{children}
</profileContext.Provider>
)
}
[apps/web/lib/hooks/use-profile.tsx] Summary (relevant to the user comment)
- The file uses a client-side ProfileProvider with a useEffect that loads the current user from the server session (via session.user.id) and populates sessionUser/state accordingly. It also maintains currentUser and provides functions to fetch user info and update user details, syncing local state with server updates. You may want to remove any useEffect that rehydrates from session if you want to purely rely on server-side session data and initialize state from the server, as suggested in your comment. If removing useEffect, you would still need to ensure initial state (e.g., currentUser) aligns with the server session data and that updates propagate correctly.
✏️ Learnings added
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.613Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: The UserCard component in apps/web/components/routes/profile/user-card.tsx accepts a loading prop to show skeleton/loading states. This should be used when user data is not yet available rather than passing null or using type assertions.
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:39-45
Timestamp: 2024-10-23T19:11:47.520Z
Learning: In the `UserThreadPanel` component (`apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx`), the `count` state variable is used in the `loadMore` function and depends on `finalThreads.length`, so updating `count` in the `useEffect` is necessary.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:195-205
Timestamp: 2025-01-14T06:20:03.578Z
Learning: React's useState setters (setState functions) maintain referential stability between renders and don't need to be included in useEffect dependency arrays. Include only the state values that the effect actually needs to track.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/layout/profile/layout.tsx:67-68
Timestamp: 2025-08-29T20:34:24.433Z
Learning: AndlerRL prefers skeleton loading states over conditional rendering for better UX when components are waiting for data to load. Components should show loading indicators rather than blank spaces.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
AndlerRL
left a comment
There was a problem hiding this comment.
Hey @sheriffjimoh, I went through the changes that you did. I added comments so you can take them in consideration on the next updates.
Also, I made a few updates in the pro-web app. What I did is to copy/paste the profile navigation and components to the pro-web app, as well the subscriptions API routes and his related hooks. The update went well, but I caused a regression of showing the sidebar duplicate in the profile page. I can take care of that, so you can cover the rest of the feedbacks.
The changes are looking good 👍 anything, please let me know! We need to move on your next tasks with the N8N implementations. We are currently delayed on deliverables so, the sooner we have this, the better!
There was a problem hiding this comment.
Please restore this file. it is required for ICL system.
There was a problem hiding this comment.
Didn't we add this before? I have been using the "Select All" from previous PRs merged to prod, unless is a duplicate? 🤔
apps/web/lib/hooks/use-profile.tsx
Outdated
| const { customSonner } = useSonner() | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
Do not use useEffect to get the user data. There is a function getServerSession from next-auth package which can be used to get the user session data from there. We can use it to pass along the user data. Adding the validation like this would cause a flicker in the UI and you will need to add extra validations in order to be able to sync the user data. Please see this -> https://github.com/bitcashorg/masterbots/blob/develop/apps/pro-web/app/layout.tsx and apply it. If we need to add more user data, do it from here so the initial state gets loaded properly 👀
apps/web/lib/hooks/use-profile.tsx
Outdated
| useEffect(() => { | ||
| const loadUser = async () => { | ||
| if (!session?.user?.id) return | ||
|
|
||
| const { user } = await getUserByID(session.user.id) | ||
| if (user) { | ||
| setSessionUser({ | ||
| id: user.userId, | ||
| name: user.username, | ||
| email: user.email, | ||
| image: user.profilePicture, | ||
| slug: user.slug, | ||
| role: user.role, | ||
| hasuraJwt: session.user.hasuraJwt, | ||
| }) | ||
| } | ||
| } | ||
| loadUser() | ||
| }, [session]) |
There was a problem hiding this comment.
@coderabbitai We should avoid getting the user data on client side. The only exception is when the user has updated their data, in that case we refresh the user data with the new one and we should even refresh the JWT token to update the user data there and reflect it among the other components.
cc - @sheriffjimoh
apps/web/lib/hooks/use-profile.tsx
Outdated
| const updateSessionUser = (user: sessionUserType) => { | ||
| setSessionUser(user) | ||
| } |
There was a problem hiding this comment.
We should sync this state with the server session that we get from the server side. Setting it as the initial state is fine, so we can remove the useEffect code block.
| @@ -2027,6 +2009,49 @@ export async function isUsernameTaken(username: string, jwt?: string) { | |||
| return result.user.length > 0 | |||
| } | |||
|
|
|||
| export async function getUserByID(userId: string) { | |||
There was a problem hiding this comment.
We should do at this point refactor the function to get the user data. Instead, to have getUserBySlug, getUserBy, getUserInfoFromBrowse, and getUserByID we should have getUserData which will fetch depending on the obj props that we send as the function parameters. In that scenario is clearer and clean.
Taskfile.yml
Outdated
| cmds: | ||
| - hasura seeds apply --project apps/hasura --admin-secret ${HASURA_GRAPHQL_ADMIN_SECRET} | ||
|
|
||
| # - hasura seeds apply --project apps/hasura --database-name masterbots --admin-secret ${HASURA_GRAPHQL_ADMIN_SECRET} |
There was a problem hiding this comment.
Once you finished to debug, keep in mind to restore this 👀
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/package.json (1)
26-26: Version mismatch: Next.js upgraded but supporting packages not aligned.Line 71 updates
nextto 15.5.7, but@next/third-parties(line 26) remains at 15.2.2 andeslint-config-next(line 110) remains at 15.2.4. Per Next.js documentation,@next/third-partiesandeslint-config-nextshould be maintained at versions matching the installednextversion to avoid compatibility issues and ESLint rule incompatibilities.Update
@next/third-partiesandeslint-config-nextto versions compatible withnext@15.5.7. If compatible 15.5.7 releases are unavailable, upgrade all three to the latest available 15.x releases, or runnext lintto allow Next.js to install the appropriate ESLint configuration automatically.
🧹 Nitpick comments (3)
apps/pro-web/package.json (1)
28-28: Consider aligning @next/third-parties with next version for consistency.While
@next/third-parties@15.2.2satisfies the peerDependency requirement fornext@15.5.7(peerDependencies accept^15.0.0), it may be beneficial to update it to a 15.5.x release to maintain version consistency across the Next.js ecosystem. The same applies toeslint-config-next@15.2.4— consider updating to 15.5.7. This is a best-practice recommendation rather than a blocking concern, as the current versions are technically compatible.apps/pro-web/components/shared/onboarding-section.tsx (2)
27-27: RedundantisOpenguard can be simplified
if (!isOpen) return nullis present twice; with the early guard at Line 27, the later one at Line 64 is redundant. Keeping only a single early return reduces noise without changing behavior.Example adjustment:
- if (!isOpen) return null - - return ( + return (Also applies to: 64-64
155-254: Minor CategoryCard polish: share bgImage constant, harden avatar fallback, and ensure unique SVG idsA few small cleanups here would improve robustness and maintainability:
- DRY the background-image tailwind string
The same
bg-[url(/background-light.webp)] dark:bg-[url(/background.webp)]string is defined in bothOnboardingSectionandCategoryCard. Hoist this into a shared constant to keep it consistent:-import { useEffect, useState } from 'react' - -// ! Deactivated on PRO only. Currently not in product scope. +import { useEffect, useState } from 'react' + +const ONBOARDING_BG_IMAGE = + 'bg-[url(/background-light.webp)] dark:bg-[url(/background.webp)]' + +// ! Deactivated on PRO only. Currently not in product scope. @@ - const bgImage = - 'bg-[url(/background-light.webp)] dark:bg-[url(/background.webp)]' + const bgImage = ONBOARDING_BG_IMAGE @@ - const bgImage = - 'bg-[url(/background-light.webp)] dark:bg-[url(/background.webp)]' + const bgImage = ONBOARDING_BG_IMAGE
- Avoid potential SVG id collisions
If the same chatbot ever appeared in more than one card in the same DOM tree,
id={avatar-${firstBot.chatbotId}}could be duplicated. Including the category id makes the pattern id and itsfillreference unique per card:- <pattern - id={`avatar-${firstBot.chatbotId}`} + <pattern + id={`avatar-${category.categoryId}-${firstBot.chatbotId}`} @@ - fill={`url(#avatar-${firstBot.chatbotId})`} + fill={`url(#avatar-${category.categoryId}-${firstBot.chatbotId})`}
- Safer initial for empty/odd names
For the text fallback, using optional chaining and a default avoids issues if
firstBot.nameis empty:- {firstBot.name.charAt(0).toUpperCase()} + {(firstBot.name?.[0] ?? '?').toUpperCase()}These are all incremental cleanups; behavior stays the same in normal cases but the code becomes slightly more robust and easier to maintain. As per coding guidelines, this keeps shared UI components DRY and resilient.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/pro-web/components/shared/onboarding-section.tsx(1 hunks)apps/pro-web/package.json(1 hunks)apps/pro-web/types/index.ts(1 hunks)apps/web/package.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/pro-web/types/index.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs
Files:
apps/pro-web/package.jsonapps/web/package.jsonapps/pro-web/components/shared/onboarding-section.tsx
apps/{web,pro-web}/components/shared/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place reusable UI under components/shared/
Place reusable UI elements under components/shared/
Files:
apps/pro-web/components/shared/onboarding-section.tsx
apps/{web,pro-web}/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders
apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes
Files:
apps/pro-web/components/shared/onboarding-section.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...
Files:
apps/pro-web/components/shared/onboarding-section.tsx
apps/{web,pro-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components
apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers
apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates
Files:
apps/pro-web/components/shared/onboarding-section.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces
Files:
apps/pro-web/components/shared/onboarding-section.tsx
apps/{web,pro-web}/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Order component files: imports → constants → component → styled components → types/interfaces
Files:
apps/pro-web/components/shared/onboarding-section.tsx
apps/{web,pro-web}/components/shared/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Store reusable UI elements in components/shared/
Files:
apps/pro-web/components/shared/onboarding-section.tsx
🧠 Learnings (14)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/app/** : Leverage Streaming and Suspense for responsiveness in Next.js 15
Applied to files:
apps/pro-web/package.json
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Follow Next.js file conventions as per documentation
Applied to files:
apps/pro-web/package.jsonapps/web/package.json
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use Streaming and Suspense in Next.js 14/15 where appropriate
Applied to files:
apps/pro-web/package.jsonapps/web/package.json
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/app/** : Use Streaming and Suspense features in Next.js 14/15 where appropriate
Applied to files:
apps/pro-web/package.json
📚 Learning: 2024-12-05T01:08:50.085Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2024-12-05T01:08:50.085Z
Learning: The project is a monorepo using Turborepo with Next.js frontend (apps/masterbots.ai), Hasura backend (apps/hasura), and shared packages for types, GraphQL operations, and utilities.
Applied to files:
apps/pro-web/package.jsonapps/web/package.json
📚 Learning: 2025-01-28T19:42:19.327Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: packages/mb-genql/package.json:23-25
Timestamp: 2025-01-28T19:42:19.327Z
Learning: The genql dependencies (genql/cli, genql/runtime, genql) in packages/mb-genql/package.json are used primarily for TypeScript generation, and using "latest" versions is acceptable due to their stability and limited impact on the build process.
Applied to files:
apps/pro-web/package.jsonapps/web/package.json
📚 Learning: 2025-08-26T06:40:51.075Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-08-26T06:40:51.075Z
Learning: In the masterbots project, the pro-web app is missing onboarding elements that exist in the main web app, and pro-web has Thread Pop-up layout improvements that should be shared with the web app.
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Separate presentation from business logic and compose small components
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2024-11-28T07:00:08.096Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 313
File: apps/masterbots.ai/lib/hooks/use-sidebar.tsx:218-227
Timestamp: 2024-11-28T07:00:08.096Z
Learning: When navigating between categories and chatbots routes, we should use shallow push state with Next.js. For transitions between main pages (e.g., from `/` to `/c`), we should perform full redirects.
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
📚 Learning: 2025-10-09T18:23:06.425Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 572
File: apps/web/components/shared/category-dashboard.tsx:47-85
Timestamp: 2025-10-09T18:23:06.425Z
Learning: In the masterbots codebase, chatbots are designed to belong to only one category (topic) by product design, even though the data model technically supports multiple category associations. This means category deselection logic can safely remove all chatbots from a removed category without checking if they belong to other selected categories.
Applied to files:
apps/pro-web/components/shared/onboarding-section.tsx
🔇 Additional comments (2)
apps/pro-web/package.json (1)
50-50: Note: @sentry/nextjs version differs between apps.This file uses
@sentry/nextjs@9.15.0(line 50), whileapps/web/package.jsonuses9.13.0. This inconsistency is not changed by this PR but may warrant alignment if both apps should have consistent error reporting behavior.apps/pro-web/components/shared/onboarding-section.tsx (1)
1-9: Good alignment with shared-component and hook conventions
'use client', named export, PascalCase component names, typed props imports, and use ofuseSidebar/usePathnameall match the TSX and shared-components conventions forapps/{web,pro-web}. Placing this undercomponents/sharedis also consistent with the reuse guidance between web and pro-web. As per coding guidelines, this keeps shared UI and hook usage structured as expected.
| // ! Deactivated on PRO only. Currently not in product scope. | ||
| export function OnboardingSection({ isOpen, onClose }: OnboardingSectionProps) { | ||
| const { | ||
| // allCategories, | ||
| // setSelectedCategories, | ||
| setSelectedChatbots, | ||
| // selectedCategories, | ||
| } = useSidebar() | ||
| const routeType = getRouteType(usePathname()) | ||
| const [localSelectedCategories, setLocalSelectedCategories] = | ||
| // useState<number[]>(selectedCategories) | ||
| useState<number[]>([]) | ||
|
|
||
| // useEffect(() => { | ||
| // setLocalSelectedCategories(selectedCategories) | ||
| // }, [selectedCategories]) | ||
|
|
||
| if (!isOpen) return null | ||
|
|
||
| const bgImage = | ||
| 'bg-[url(/background-light.webp)] dark:bg-[url(/background.webp)]' | ||
|
|
||
| const handleCategoryToggle = (categoryId: number) => { | ||
| setLocalSelectedCategories((prev) => | ||
| prev.includes(categoryId) | ||
| ? prev.filter((id) => id !== categoryId) | ||
| : [...prev, categoryId], | ||
| ) | ||
| } | ||
|
|
||
| const handleApplySelection = () => { | ||
| // setSelectedCategories(localSelectedCategories) | ||
|
|
||
| // const selectedChatbots = allCategories | ||
| // .filter((category) => | ||
| // localSelectedCategories.includes(category.categoryId), | ||
| // ) | ||
| // .flatMap((category) => | ||
| // category.chatbots.map((chatbot) => chatbot.chatbot.chatbotId), | ||
| // ) | ||
|
|
||
| // setSelectedChatbots(selectedChatbots) | ||
| onClose() | ||
| } | ||
|
|
||
| const handleClearAll = () => { | ||
| // setLocalSelectedCategories([]) | ||
| } | ||
|
|
||
| const handleSelectAll = () => { | ||
| // const allCategoryIds = allCategories.map((category) => category.categoryId) | ||
| // setLocalSelectedCategories(allCategoryIds) | ||
| } | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/pro-web/components/shared/onboarding-section.tsxRepository: bitcashorg/masterbots
Length of output: 9839
🏁 Script executed:
rg "OnboardingSection" apps/pro-web --type tsx --type ts -B 2 -A 2Repository: bitcashorg/masterbots
Length of output: 92
🏁 Script executed:
rg "OnboardingSection" apps/pro-web -B 2 -A 2Repository: bitcashorg/masterbots
Length of output: 1266
🏁 Script executed:
rg "from.*onboarding-section" apps/pro-webRepository: bitcashorg/masterbots
Length of output: 47
🏁 Script executed:
rg "onboarding-section" apps/webRepository: bitcashorg/masterbots
Length of output: 310
🏁 Script executed:
rg "export.*onboarding-section\|from.*shared.*onboarding" apps/pro-webRepository: bitcashorg/masterbots
Length of output: 47
🏁 Script executed:
cat -n apps/web/components/shared/onboarding-section.tsx | head -100Repository: bitcashorg/masterbots
Length of output: 3942
🏁 Script executed:
rg "useCategorySelections" apps/pro-webRepository: bitcashorg/masterbots
Length of output: 445
🏁 Script executed:
grep -A 5 -B 5 "OnboardingSection" apps/web/components/routes/home/home-page.tsx | head -20Repository: bitcashorg/masterbots
Length of output: 628
OnboardingSection UI renders but all selection logic is disabled, creating a broken modal if accidentally used
The component has all core wiring commented out:
allCategories,selectedCategories,setSelectedCategorieshooks are commenteduseEffectsync is commentedhandleClearAllandhandleSelectAllhave empty bodies- Categories grid render is commented
This means localSelectedCategories stays [], "Clear All"/"Select All" buttons are no-ops, and "Get Started" remains permanently disabled—users cannot interact with or dismiss the modal.
While currently unused in pro-web, exporting a non-functional UI component creates latent risk. If any future code imports and renders this component, it will trap the user with a broken modal. The web app version has full implementation (with proper state syncing, deduplication, and category management), showing this can work.
Either guard this component behind a feature flag to prevent accidental use, or implement it fully by uncommenting the sidebar wiring, re-enabling the useEffect sync, and the categories grid mapping.
🤖 Prompt for AI Agents
In apps/pro-web/components/shared/onboarding-section.tsx around lines 10 to 63,
the component has all category state wiring and UI mapping commented out which
leaves it non-functional and able to produce a trapped modal if accidentally
rendered; fix by either (A) guarding the component behind a feature flag/prop so
it returns null or a safe placeholder when PRO mode is active (prevent
accidental use), or (B) fully restore the original behavior: uncomment and
rewire allCategories, selectedCategories, setSelectedCategories and
setSelectedChatbots from useSidebar, re-enable the useEffect to sync
selectedCategories -> localSelectedCategories, restore the categories grid
rendering, implement handleSelectAll to set all category IDs, handleClearAll to
clear localSelectedCategories, and ensure handleApplySelection derives and
deduplicates selectedChatbots from allCategories before calling
setSelectedChatbots and onClose so the "Get Started" button and clear/select all
behave correctly.
| <div className="flex justify-between items-center mb-6 sm:mb-8"> | ||
| <div className="flex-1"> | ||
| <h1 className="mb-3 text-2xl font-bold text-green-500 sm:mb-4 sm:text-3xl"> | ||
| Welcome to Masterbots.ai | ||
| </h1> | ||
| <div className="text-base text-zinc-700 dark:text-zinc-300"> | ||
| <p>Choose 1-3 topics that matter to you to start</p> | ||
| <p> | ||
| We'll show you the most relevant chatbots and resources | ||
| </p> | ||
| <p>You can update your selections anytime</p> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and read the onboarding-section.tsx file
fd "onboarding-section.tsx" -t fRepository: bitcashorg/masterbots
Length of output: 168
🏁 Script executed:
# Read the onboarding-section.tsx file in pro-web
cat -n apps/pro-web/components/shared/onboarding-section.tsxRepository: bitcashorg/masterbots
Length of output: 9839
🏁 Script executed:
# Search for any references to the maximum selection limit in the onboarding-related files
rg "max.*3|limit.*3|1.*3.*topic" apps/pro-web/components/shared/onboarding-section.tsx -i
rg "handleCategoryToggle" apps/pro-web -t tsx -A 5 -B 2Repository: bitcashorg/masterbots
Length of output: 171
🏁 Script executed:
# Search for max selection or limit logic related to categories
rg "max.*select|select.*limit|localSelectedCategories.length.*3" apps/pro-web/ -i -A 2 -B 2Repository: bitcashorg/masterbots
Length of output: 47
🏁 Script executed:
# Check the types file to see if there's any constraint at the type level
rg "OnboardingSectionProps|CategoryCardProps" apps/pro-web/types -A 5Repository: bitcashorg/masterbots
Length of output: 638
Copy says "Choose 1–3 topics" but selection logic does not enforce a max
The header text instructs users to "Choose 1–3 topics", but handleCategoryToggle has no upper bound check; users can select an unlimited number of topics without validation. Note that this feature is currently deactivated (marked "not in product scope" on PRO), but when enabled, either enforce a maximum of 3 in handleCategoryToggle (with optional feedback at the limit) or relax the copy to "Choose your topics" if no strict limit applies.
🤖 Prompt for AI Agents
In apps/pro-web/components/shared/onboarding-section.tsx around lines 80 to 92,
the copy instructs users to "Choose 1–3 topics" but the selection handler does
not enforce a maximum; update the code so selection count cannot exceed 3.
Modify handleCategoryToggle to check the current selected count and, if already
3 and the user is trying to add another, prevent adding (and optionally return
early or show a small toast/inline message); ensure deselecting still works
normally. Alternatively, if you intend no limit, change the copy text to "Choose
your topics" to avoid misleading users.
…masterbots into fix-new-popup-issues
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/pro-web/components/layout/sidebar/sidebar-link.tsx (3)
93-100: Type mismatch insetActiveDepartmentcallback.The callback compares
prevDepartmentdirectly withdepartment.departmentId(a number), butWorkspaceContextTypedeclaresactiveDepartmentas[string, number] | null(a tuple), notnumber | null.The comparison on line 95 will always be false since a tuple cannot equal a number:
department.departmentId === prevDepartment // tuple !== numberEither update the comparison to use the tuple index:
setActiveDepartment((prevDepartment) => { const newDepartmentId = - department.departmentId === prevDepartment + department.departmentId === prevDepartment?.[1] ? null - : department.departmentId + : [department.name, department.departmentId] - return newDepartmentId + return newDepartmentId as [string, number] | null })Or verify if
activeDepartmentinSidebarLinkshould be typed differently from the workspace context.
141-141: Type mismatch inisActivecalculation.Same issue as above:
activeDepartmentis typed as[string, number] | nullbut is compared directly todepartment.departmentId(a number). This comparison will always befalse.-const isActive = activeDepartment === department.departmentId +const isActive = activeDepartment?.[1] === department.departmentId
196-196: Type mismatch in URL calculation.Same pattern: comparing
department.departmentId(number) withactiveDepartment(tuple). This will always betrue, causing unnecessary URL recalculations.-const isNewDepartment = department.departmentId !== activeDepartment +const isNewDepartment = department.departmentId !== activeDepartment?.[1]
🧹 Nitpick comments (1)
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml (1)
75-94: Consider standardizing column ordering across all roles.The select_permissions columns are listed in different orders across the anonymous, moderator, and user roles. While functionally equivalent, standardizing the order (e.g., alphabetically or by functional grouping) would improve consistency and maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml(3 hunks)apps/pro-web/components/layout/header/header.tsx(2 hunks)apps/pro-web/components/layout/profile/profile-page-sidebar.tsx(2 hunks)apps/pro-web/components/layout/sidebar/profile-sidebar.tsx(2 hunks)apps/pro-web/components/layout/sidebar/sidebar-link.tsx(2 hunks)apps/pro-web/lib/hooks/use-workspace.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/{web,pro-web}/lib/hooks/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logicStore custom React hooks under lib/hooks/
Files:
apps/pro-web/lib/hooks/use-workspace.tsx
apps/{web,pro-web}/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders
apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes
Files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...
Files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
apps/{web,pro-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components
apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers
apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates
Files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs
Files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/hasura/metadata/databases/masterbots/tables/public_chatbot.yamlapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces
Files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place custom React hooks in lib/hooks/
Files:
apps/pro-web/lib/hooks/use-workspace.tsx
apps/{web,pro-web}/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Order component files: imports → constants → component → styled components → types/interfaces
Files:
apps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
🧠 Learnings (21)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-28T03:44:16.389Z
Learning: In apps/web/components/routes/preferences/preference-section.tsx: After updating user profile in the database via updateUserDetails, must call session.update() (from useSession hook) with the updated fields to trigger NextAuth's JWT callback with trigger='update'. This refreshes the JWT token and session automatically. Do not manually call updateSessionUser; the useEffect in use-profile.tsx will sync sessionUser from the refreshed session.user.
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Applied to files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface
Applied to files:
apps/pro-web/lib/hooks/use-workspace.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component is redundant as thread-list.tsx has been developed to support all the same functionality including public pages. The codebase should be cleaned up to remove browse-list.tsx and related components in the browse directory, along with the BrowseProvider context.
Applied to files:
apps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.
Applied to files:
apps/pro-web/components/layout/header/header.tsxapps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2024-10-03T20:10:44.311Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 276
File: apps/masterbots.ai/app/wordware/layout.tsx:12-19
Timestamp: 2024-10-03T20:10:44.311Z
Learning: In `apps/masterbots.ai/app/wordware/layout.tsx`, the current layout is intentional to prevent layout issues such as unwanted gaps and sidebar design problems. A similar design is used in `apps/c/layout`.
Applied to files:
apps/pro-web/components/layout/header/header.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.
Applied to files:
apps/pro-web/components/layout/header/header.tsxapps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.
Applied to files:
apps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations
Applied to files:
apps/pro-web/components/layout/sidebar/profile-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-11-06T22:31:20.903Z
Learnt from: derianrddev
Repo: bitcashorg/masterbots PR: 579
File: apps/hasura/migrations/masterbots/1762286346002_alter_table_public_chatbot_add_column_department_id/up.sql:1-2
Timestamp: 2025-11-06T22:31:20.903Z
Learning: In the masterbots codebase, the `department_id` column in the `public.chatbot` table is intentionally nullable because not all chatbots are part of the onboarding flow. Only chatbots used in onboarding have an associated department.
Applied to files:
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml
📚 Learning: 2025-01-25T08:43:05.202Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 344
File: apps/masterbots.ai/services/hasura/hasura.service.ts:0-0
Timestamp: 2025-01-25T08:43:05.202Z
Learning: In the masterbots.ai database schema:
1. Previous "categories" are now called "topics"
2. Chatbots are now referred to as "domains"
3. Domains have context-dependent "categories" and "subcategories" based on user question context
4. Domains include "tags" that are used for filtering based on the user question context
Applied to files:
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml
📚 Learning: 2025-11-07T18:38:42.273Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 579
File: apps/pro-web/app/api/auth/signup/route.ts:151-157
Timestamp: 2025-11-07T18:38:42.273Z
Learning: In apps/pro-web/app/actions/admin.actions.ts, the insertUserOrganizations function should use Drizzle DB transactions to ensure atomicity when inserting organizations and their associated chatbots, preventing partial persistence issues.
Applied to files:
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml
📚 Learning: 2025-11-21T18:02:42.653Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-11-21T18:00:08.455Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-21T18:00:08.455Z
Learning: In apps/web/lib/hooks/use-profile.tsx: The sessionUser state should be populated directly from session.user (JWT) and not by fetching from Hasura on the client side. The useEffect should only synchronize sessionUser with session.user. Client-side Hasura fetches for user data should be avoided; user data comes from the JWT/session. Only when users update their profile should we refresh both the database and JWT token (via NextAuth session update trigger).
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-10-24T20:40:56.510Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 573
File: apps/pro-web/components/routes/pro/pro.tsx:49-49
Timestamp: 2025-10-24T20:40:56.510Z
Learning: In apps/pro-web/lib/hooks/use-mb-chat.tsx, the useMBChat() hook returns a tuple [MBChatHookState, MBChatHookActions], not a direct object. Use array destructuring to access state (index 0) and actions (index 1), e.g., const [state, actions] = useMBChat() or const [{ isLoading }] = useMBChat().
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx} : Place custom React hooks in lib/hooks/
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsxapps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Place custom React hooks under lib/hooks/
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Store custom React hooks under lib/hooks/
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2024-10-23T19:11:47.520Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:39-45
Timestamp: 2024-10-23T19:11:47.520Z
Learning: In the `UserThreadPanel` component (`apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx`), the `count` state variable is used in the `loadMore` function and depends on `finalThreads.length`, so updating `count` in the `useEffect` is necessary.
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2024-11-20T04:00:45.413Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 300
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:120-123
Timestamp: 2024-11-20T04:00:45.413Z
Learning: In React code, when reviewing `useEffect` dependencies, it's not always necessary to add functions like `handleThreadsChange` to the dependency array, as this may lead to unnecessary re-renders and performance issues. Only include dependencies that are essential and may change.
Applied to files:
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace system has identified performance bottlenecks in markdown parsing, AI streaming response handling, selection range management, Base64 document processing, and multiple debounced state operations that require optimization and better coordination.
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
🧬 Code graph analysis (2)
apps/pro-web/components/layout/header/header.tsx (1)
apps/pro-web/lib/hooks/use-sidebar.tsx (1)
useSidebar(61-67)
apps/pro-web/components/layout/profile/profile-page-sidebar.tsx (3)
apps/pro-web/lib/hooks/use-sidebar.tsx (1)
useSidebar(61-67)apps/web/lib/hooks/use-sidebar.tsx (1)
useSidebar(66-72)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(907-913)
🔇 Additional comments (5)
apps/hasura/metadata/databases/masterbots/tables/public_chatbot.yaml (1)
39-45: The Hasura metadata is correct; the typo exists at the database schema level.The
prompt_chatbottable in the database schema (migrations and Drizzle files) actually defines the column aschabot_id, notchatbot_id. The Hasura metadata files correctly reference the actual column name. The real issue is that the database column itself is misspelled at the schema level inpackages/mb-drizzle/src/drizzle/0000_pink_lionheart.sqlandapps/hasura/migrations/masterbots/1698804096149_init/up.sql. Fixing this would require updating both the database schema/migrations and then the Hasura metadata, not just the metadata alone.Likely an incorrect or invalid review comment.
apps/pro-web/components/layout/header/header.tsx (1)
78-92: LGTM!The migration of
setActiveDepartmentfromuseSidebartouseWorkspaceis correctly implemented. The separation of concerns is clear: chatbot state remains in the sidebar hook while department state is now centralized in the workspace context.apps/pro-web/components/layout/sidebar/profile-sidebar.tsx (1)
37-46: LGTM!Consistent with the migration pattern in
header.tsx. ThehandleNavigationfunction correctly sources department state from workspace and chatbot state from sidebar.apps/pro-web/components/layout/profile/profile-page-sidebar.tsx (1)
48-58: LGTM!The migration follows the established pattern.
handleToggleThreadscorrectly sourcessetActiveDepartmentfrom the workspace context while keepingsetActiveChatbotfrom the sidebar context.apps/pro-web/components/layout/sidebar/sidebar-link.tsx (1)
49-52: Inconsistent source forexpandedDepartments.
expandedDepartmentsandsetExpandedDepartmentsare still sourced fromuseSidebar(line 48-50), but theWorkspaceContextTypeinuse-workspace.tsxdeclares these as workspace state. This creates dual sources of truth.Either:
- Move
expandedDepartmentsto workspace (requires implementing the missing state inuse-workspace.tsxas noted in that file's review)- Or remove
expandedDepartmentsfromWorkspaceContextTypeif it should remain sidebar-scoped
| expandedDepartments: number[] | ||
| setExpandedDepartments: ( | ||
| departments: number[] | ((prev: number[]) => number[]), | ||
| ) => void | ||
| } |
There was a problem hiding this comment.
Missing implementation for expandedDepartments and setExpandedDepartments.
The interface declares these new members but they are never implemented in the provider:
expandedDepartmentsis not added toWorkspaceState(lines 141-145)- No
useStateor state initialization forexpandedDepartments contextValue(lines 723-770) does not spread these propertiesstableSetters(lines 558-591) does not includesetExpandedDepartments
Consumers calling useWorkspace().setExpandedDepartments(...) will encounter a runtime error since it will be undefined.
Add the implementation:
interface WorkspaceState {
isWorkspaceActive: boolean
// Add active action state
activeAction: string | null
+ expandedDepartments: number[]
}Then initialize and expose in the provider:
const [state, setState] = useSetState<WorkspaceState>({
isWorkspaceActive: false,
activeAction: null,
+ expandedDepartments: [],
})+const setExpandedDepartments = useCallback(
+ (departments: number[] | ((prev: number[]) => number[])) => {
+ setState((prev) => ({
+ expandedDepartments:
+ typeof departments === 'function'
+ ? departments(prev.expandedDepartments)
+ : departments,
+ }))
+ },
+ [setState],
+)Include in stableSetters and contextValue.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/pro-web/lib/hooks/use-workspace.tsx around lines 131-135 (and refer to
WorkspaceState at ~141-145, stableSetters at ~558-591, and contextValue at
~723-770), implement the missing expandedDepartments state: add
expandedDepartments: number[] to WorkspaceState, create a useState hook const
[expandedDepartments, setExpandedDepartments] = useState<number[]>([]) (or
appropriate initial value) in the provider, include setExpandedDepartments in
the stableSetters object, and spread both expandedDepartments and
setExpandedDepartments into the contextValue returned by the provider so
consumers calling useWorkspace().setExpandedDepartments(...) will be defined.
There was a problem hiding this comment.
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)
apps/pro-web/components/routes/preferences/google-translation.tsx (1)
174-174: Replace default export with named export.The coding guidelines specify: "Avoid default exports; prefer named exports" for consistency across the codebase.
Apply this diff:
-export default GoogleTranslate +export { GoogleTranslate }Then update import statements in consuming files from:
import GoogleTranslate from '@/components/routes/preferences/google-translation'to:
import { GoogleTranslate } from '@/components/routes/preferences/google-translation'apps/pro-web/components/routes/preferences/preference-section.tsx (1)
238-262: Blocker:updateInput()username validation is inverted / always returns early (username can’t become “valid”).
Right now, valid usernames hitconsole.error('Invalid username format')andreturn(Line 258-260), sosetErrorMessage({ inputId: '', message: '' })(Line 261) is never reached forusername. Also, the error text doesn’t mention spaces even though the regex allows spaces.function updateInput( inputId: string | undefined, e: React.ChangeEvent<HTMLInputElement>, ) { if (!inputId) return + // Prevent state tampering if the DOM readOnly flag is bypassed + if (inputId === 'email') return + const value = e.target.value setInputValue((prev) => ({ ...prev, [inputId]: value })) if (inputId === 'username') { const usernameRegex = /^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$/ if (value.length < 3 || value.length > 24 || !usernameRegex.test(value)) { setErrorMessage({ inputId, message: - 'Username must be 3-24 characters long and can only contain letters, numbers, and underscores.', + 'Username must be 3-24 characters long and can only contain letters, numbers, underscores, and single spaces between words.', }) return } - console.error('Invalid username format:', value) - return + setErrorMessage({ inputId: '', message: '' }) + return } - setErrorMessage({ inputId: '', message: '' }) + setErrorMessage({ inputId: '', message: '' }) }Based on learnings, guard email changes even if the input is “readOnly”.
♻️ Duplicate comments (6)
apps/pro-web/components/routes/preferences/google-translation.tsx (1)
63-64: UsepageLanguageinstead of hard-coded"en"in googtrans cookie.This issue was previously flagged but remains unresolved. The cookie uses a hard-coded source language "/en/" which will be incorrect when
pageLanguagediffers from "en".Apply this diff:
- document.cookie = `googtrans=/en/${langCode}; path=/` - document.cookie = `googtrans=/en/${langCode}; domain=${window.location.hostname}; path=/` + document.cookie = `googtrans=/${pageLanguage}/${langCode}; path=/` + document.cookie = `googtrans=/${pageLanguage}/${langCode}; domain=${window.location.hostname}; path=/`apps/web/services/hasura/hasura.service.ts (2)
2156-2194: Dead code with inconsistent mutation structure.
updateUserPreferencesduplicates functionality ofupdatePreferencesbut with an inconsistent GraphQL mutation structure (selects fields directly vs usingreturningblock). Per past review, this function is unused and should be removed or refactored as a thin wrapper aroundupdatePreferences.
719-720: Critical: Invalid GraphQL query -savePreferencesfunction reference in query.
savePreferencesat line 719 is a function imported from this service file, not a GraphQL field. Including it in thefollowersselection set will cause a GraphQL parse error at runtime.followers: { followerId: true, followeeIdChatbot: true, - savePreferences, },apps/web/components/routes/preferences/preference-section.tsx (1)
382-387: UnuseduserIdvariable in font-size handler.The
userIdvariable is extracted but never used. Remove it as flagged in past review.if (type === 'font-size') { const fontVal = value as FontSizeType - const userId = user?.id as string setPreferences({ lang: preferences.lang, fontSize: fontVal }) return }apps/hasura/metadata/databases/masterbots/tables/public_preference.yaml (1)
38-38: Overly permissive Hasura permissions remain unaddressed.The previous review correctly identified that
check: {}on insert (line 38) andfilter: {}on select (lines 66, 98) allow users to insert/read preferences for any user, not just their own. This is a security risk exposing user preference data.The
update_permissionsfor user role (lines 128-130) correctly enforcesuser_id: { _eq: X-Hasura-User-Id }, but this pattern should also apply to insert and select permissions.Also applies to: 66-66, 98-98
apps/web/lib/hooks/use-preferences.tsx (1)
12-15: LocalPreferencesinterface shadows exported type with different field naming.The local
Preferencesinterface usesfontSize(camelCase) while the exportedPreferencesfrom@/types/typesusesfont_size(snake_case). WhensavePreferencesis called at line 97, it passesupdatedPrefswithfontSize, butsavePreferencesexpects the snake_casefont_sizefield.This will cause the font size preference to not persist correctly to the database.
Either:
- Import and use
Preferencesfrom@/types/typesand map fields- Or update
savePreferencesto handle the camelCase variant+import type { Preferences as DbPreferences } from '@/types/types' + const setPreferences = async (prefs: Partial<Preferences>) => { const updatedPrefs = { ...preferences, ...prefs } setPreferencesState(updatedPrefs) const userId = session?.user?.id const jwt = session?.user?.hasuraJwt if (userId && jwt) { try { - await savePreferences(userId, jwt, updatedPrefs) + await savePreferences(userId, jwt, { + lang: updatedPrefs.lang, + font_size: updatedPrefs.fontSize, + } as DbPreferences) } catch (err) { console.error('Failed to save preferences:', err) } } }
🧹 Nitpick comments (13)
apps/pro-web/components/routes/preferences/google-translation.tsx (1)
58-60: AwaitsetPreferencesto prevent race condition.The preference update is not awaited before the page reload (line 71). This could result in preferences not being persisted if the reload happens before the async operation completes.
Apply this diff:
// Save user preference if (user?.id && user?.hasuraJwt) { - setPreferences({ lang: langCode }) + await setPreferences({ lang: langCode }) }apps/pro-web/components/routes/preferences/preference-section.tsx (4)
179-200: Harden auth preconditions intoggleMode: requireuser.idanduser.hasuraJwt, not justuser.
if (!user) throw ...(Line 181) still allowsuser?.id/user?.hasuraJwtto be undefined (Line 184-186), which can turn into opaque Hasura failures.- if (!user) throw new Error('No user session found. Aborting...') + if (!user?.id || !user?.hasuraJwt) { + throw new Error('User session missing id/jwt. Aborting...') + } const preferencesUpdate = await updatePreferences({ - jwt: user?.hasuraJwt, - userId: user?.id, + jwt: user.hasuraJwt, + userId: user.id, preferencesSet, })
264-303: Error message bug:!user.slugbranch prints “logged in as undefined”.
Ifuser.slugis falsy (Line 273), the message uses${user?.slug}(Line 276) which will likely beundefined. Consider a generic message or reference a stable identifier (email/id).
376-388: Remove dead code + avoid unsafe casts in font-size dropdown.
const userId = user?.id as string(Line 384) is unused. Alsovalue as FontSizeType(Line 383) is an unchecked cast—at minimum, drop the unuseduserId; ideally validate against an allowed list before casting.if (type === 'font-size') { const fontVal = value as FontSizeType - const userId = user?.id as string setPreferences({ lang: preferences.lang, fontSize: fontVal }) return }
460-474: Optional: avoid inline JSX handlers to match repo guideline (“stable function references”).
onChange={(e) => updateInput(...)}andonClick={() => handleUpdateProfile()}are inline and will create new functions each render.As per coding guidelines, prefer stable handler refs over inline arrows in JSX.
apps/web/components/routes/preferences/google-translation.tsx (3)
12-12: Unused import:savePreferencesis never called.
savePreferencesis imported (line 12) but the component usessetPreferencesfromusePreferenceshook (line 60) which internally handles DB persistence. Remove the unused import.import { usePreferences } from '@/lib/hooks/use-preferences' -import { savePreferences } from '@/services/hasura' import type { GoogleTranslateProps } from '@/types/types'
54-77: Language change handler has potential timing fragility.The 600ms
setTimeoutbefore page reload (lines 71-73) is arbitrary and may race with script loading on slower connections. Consider using a more reliable signal (e.g., scriptonloadevent) or at minimum, add a comment explaining the timing choice.Also,
setPreferences({ lang: langCode })at line 60 only updates thelangfield, which is correct for a partial update, but if the hook'ssetPreferencesdoesn't properly merge with existing preferences,fontSizecould be lost.
175-175: Prefer named export per coding guidelines.As per coding guidelines, prefer named exports over default exports.
-export default GoogleTranslate +export { GoogleTranslate }Then update the import in
preference-section.tsxaccordingly.apps/web/components/routes/preferences/preference-section.tsx (2)
53-54: DuplicateFontSizeTypedefinition.
FontSizeTypeis defined here and also asFontSizeinuse-preferences.tsx(line 10). Consider importing from a shared location to avoid drift.-type FontSizeType = 'normal' | 'large' | 'x-large' | 'small' | 'medium' +import type { FontSize as FontSizeType } from '@/lib/hooks/use-preferences'Or export from a shared types file.
395-397: Remove debugconsole.logstatement.Debug logging should be removed before merging:
- console.log({ - preferences, - })apps/web/lib/hooks/use-preferences.tsx (3)
47-71: Suppressed exhaustive dependencies warning may hide issues.The
biome-ignorecomment suppresses the exhaustive dependencies warning. While intentional to avoid re-fetch loops, consider documenting whylocalFontSizeis excluded or using a ref to track initialization state instead.
82-84: Cookie lacks explicit expiration.The
googtranscookie is set without amax-ageorexpiresattribute, making it a session cookie that expires when the browser closes. For persistent language preference across sessions, consider adding an expiration:-document.cookie = `googtrans=/en/${preferences.lang}; domain=${window.location.hostname}; path=/` +document.cookie = `googtrans=/en/${preferences.lang}; domain=${window.location.hostname}; path=/; max-age=31536000`
88-102:setPreferencesimplementation correctly handles stale closure.The function computes
updatedPrefsbefore callingsetPreferencesState, avoiding the stale closure issue flagged in past review. The async DB persistence with error handling is appropriate.Consider removing or reducing the log level of line 95 for production:
- console.log('Saving preferences to DB:', updatedPrefs)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/hasura/metadata/databases/masterbots/tables/public_preference.yaml(6 hunks)apps/pro-web/components/routes/preferences/google-translation.tsx(1 hunks)apps/pro-web/components/routes/preferences/preference-section.tsx(15 hunks)apps/pro-web/lib/constants/preferences.ts(1 hunks)apps/web/components/routes/preferences/google-translation.tsx(1 hunks)apps/web/components/routes/preferences/preference-section.tsx(14 hunks)apps/web/lib/constants/preferences.ts(2 hunks)apps/web/lib/hooks/use-preferences.tsx(1 hunks)apps/web/services/hasura/hasura.service.ts(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/lib/constants/preferences.ts
- apps/pro-web/lib/constants/preferences.ts
🧰 Additional context used
📓 Path-based instructions (11)
apps/{web,pro-web}/components/routes/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place page-specific components under components/routes/[feature]/
Organize page-specific components under components/routes/
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/components/routes/preferences/google-translation.tsx
apps/{web,pro-web}/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders
apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/components/routes/preferences/google-translation.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
apps/{web,pro-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components
apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers
apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsxapps/hasura/metadata/databases/masterbots/tables/public_preference.yaml
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/components/routes/preferences/google-translation.tsx
apps/{web,pro-web}/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Order component files: imports → constants → component → styled components → types/interfaces
Files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/components/routes/preferences/google-translation.tsx
apps/{web,pro-web}/lib/hooks/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/lib/hooks/**: Place custom React hooks under lib/hooks/
Encapsulate complex state in custom hooks and separate presentation from business logicStore custom React hooks under lib/hooks/
Files:
apps/web/lib/hooks/use-preferences.tsx
apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place custom React hooks in lib/hooks/
Files:
apps/web/lib/hooks/use-preferences.tsx
apps/{web,pro-web}/services/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place external API integrations under services/
Files:
apps/web/services/hasura/hasura.service.ts
apps/{web,pro-web}/services/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use RORO (Receive an object, Return an object) for functions, especially when calling external services
Place external API integrations under services/
Files:
apps/web/services/hasura/hasura.service.ts
🧠 Learnings (45)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-28T03:44:16.389Z
Learning: In apps/web/components/routes/preferences/preference-section.tsx: After updating user profile in the database via updateUserDetails, must call session.update() (from useSession hook) with the updated fields to trigger NextAuth's JWT callback with trigger='update'. This refreshes the JWT token and session automatically. Do not manually call updateSessionUser; the useEffect in use-profile.tsx will sync sessionUser from the refreshed session.user.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace features have complex performance considerations including markdown parsing optimization, AI streaming response handling, state persistence coordination, and selection range management that require careful monitoring and optimization.
📚 Learning: 2025-11-28T03:44:16.389Z
Learnt from: sheriffjimoh
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-28T03:44:16.389Z
Learning: In apps/web/components/routes/preferences/preference-section.tsx: After updating user profile in the database via updateUserDetails, must call session.update() (from useSession hook) with the updated fields to trigger NextAuth's JWT callback with trigger='update'. This refreshes the JWT token and session automatically. Do not manually call updateSessionUser; the useEffect in use-profile.tsx will sync sessionUser from the refreshed session.user.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-11-21T18:02:42.653Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:79-81
Timestamp: 2025-11-21T18:02:42.653Z
Learning: Preference: In apps/web/lib/hooks/use-profile.tsx, avoid client-side re-fetching the current user in ProfileProvider. Initialize sessionUser from the server-provided NextAuth session (initialSession) and treat it as the source of truth; remove the useEffect that calls getUserByID. Persist client edits via NextAuth’s session update when needed.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/pro-web/components/routes/preferences/google-translation.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-08-29T20:34:37.023Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-08-29T20:34:37.023Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 542
File: apps/web/components/routes/preferences/preference-section.tsx:228-249
Timestamp: 2025-08-29T20:34:37.023Z
Learning: In the preferences component (apps/web/components/routes/preferences/preference-section.tsx), email inputs are read-only and should not be changeable by users. Both updateInput and handleUpdateProfile functions need guards to prevent email changes even if users manipulate the DOM to remove the read-only attribute. The updateInput function should return early for email inputId, and handleUpdateProfile should always use currentUser?.email instead of inputValue.email.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-11-21T18:00:08.455Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 590
File: apps/web/lib/hooks/use-profile.tsx:60-78
Timestamp: 2025-11-21T18:00:08.455Z
Learning: In apps/web/lib/hooks/use-profile.tsx: The sessionUser state should be populated directly from session.user (JWT) and not by fetching from Hasura on the client side. The useEffect should only synchronize sessionUser with session.user. Client-side Hasura fetches for user data should be avoided; user data comes from the JWT/session. Only when users update their profile should we refresh both the database and JWT token (via NextAuth session update trigger).
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-02-17T16:51:19.102Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 376
File: apps/masterbots.ai/components/routes/chat/chat.tsx:92-102
Timestamp: 2025-02-17T16:51:19.102Z
Learning: For the Chat component in apps/masterbots.ai/components/routes/chat/chat.tsx, the developer prefers to verify potential optimizations through local testing before accepting suggestions, particularly for performance-related changes like useCallback usage in debounce implementations.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.tsapps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-10-24T20:40:56.510Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 573
File: apps/pro-web/components/routes/pro/pro.tsx:49-49
Timestamp: 2025-10-24T20:40:56.510Z
Learning: In apps/pro-web/lib/hooks/use-mb-chat.tsx, the useMBChat() hook returns a tuple [MBChatHookState, MBChatHookActions], not a direct object. Use array destructuring to access state (index 0) and actions (index 1), e.g., const [state, actions] = useMBChat() or const [{ isLoading }] = useMBChat().
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.tsx : Use functional components and hooks; type props with a TypeScript interface
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.tsx : Use functional components and hooks instead of class components
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/components/ui/**/*.{ts,tsx} : Follow Radix UI patterns under components/ui/
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-05-12T22:01:24.005Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 468
File: apps/masterbots.ai/app/api/cron/delete-requested-accounts/route.ts:44-44
Timestamp: 2025-05-12T22:01:24.005Z
Learning: When a user deletes their account, consider whether to delete all threads or only private threads, possibly keeping public threads with a [deleted] attribution similar to Reddit's approach.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-10-14T18:40:46.645Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 283
File: apps/masterbots.ai/components/routes/chat/admin-mode-approve.tsx:11-15
Timestamp: 2024-10-14T18:40:46.645Z
Learning: In the project, the `adminApproveThread` function within the `useThread` hook manages error handling and loading state, so components using it don't need to implement additional error handling unless they introduce side effects.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2024-12-04T22:22:16.749Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 320
File: apps/masterbots.ai/services/admin/admin.service.ts:6-11
Timestamp: 2024-12-04T22:22:16.749Z
Learning: In `apps/masterbots.ai/services/admin/admin.service.ts`, the `verifyAdmin` function uses email domain verification as an additional security layer, complementing the role-based security implemented via JWTs and the GraphQL API with user roles "users" and "moderators".
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2024-10-23T22:38:25.517Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 289
File: apps/masterbots.ai/components/auth/signup-form.tsx:75-96
Timestamp: 2024-10-23T22:38:25.517Z
Learning: In `signup-form.tsx`, we should not provide options for resending verification emails or editing emails to the user at this time.
Applied to files:
apps/pro-web/components/routes/preferences/preference-section.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx} : Place custom React hooks in lib/hooks/
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Store custom React hooks under lib/hooks/
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/** : Place custom React hooks under lib/hooks/
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use TypeScript to define React props types (interfaces for props)
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use IndexedDB for local caching to enable immediate UI updates
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.{ts,tsx} : Use meaningful variable names; prefix booleans with is/has/does/should
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to **/*.{ts,tsx} : Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to **/*.{ts,tsx} : Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.{ts,tsx} : Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to **/*.{ts,tsx} : Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.{ts,tsx} : Avoid using any; prefer precise types
Applied to files:
apps/web/lib/hooks/use-preferences.tsx
📚 Learning: 2025-09-12T20:29:24.733Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 561
File: apps/pro-web/lib/hooks/use-accessibility.tsx:7-7
Timestamp: 2025-09-12T20:29:24.733Z
Learning: When extending FontSize type in use-accessibility.tsx hooks, corresponding CSS rules must exist in globals.css for [data-font-size="value"] selectors, otherwise the unsupported font size values should be removed from the type definition to maintain consistency between TypeScript types and actual styling support.
Applied to files:
apps/web/lib/hooks/use-preferences.tsxapps/web/components/routes/preferences/preference-section.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to **/*.{ts,tsx} : Add explicit type annotations for function parameters and return values
Applied to files:
apps/web/lib/hooks/use-preferences.tsxapps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/services/hasura.service.ts : Use hasura.service.ts as the single interaction point for GraphQL operations with Hasura
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to **/services/hasura.service.ts : Use hasura.service.ts as the single point for all GraphQL interactions
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-12T20:30:40.360Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 561
File: apps/web/components/layout/profile/layout.tsx:28-31
Timestamp: 2025-09-12T20:30:40.360Z
Learning: A centralized normalizeUserSlug utility function should be used for all user slug parameter extraction to ensure consistent handling of undefined values, whitespace trimming, and lowercase conversion. This prevents runtime crashes and ensures database query consistency.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-12T20:30:40.360Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 561
File: apps/web/components/layout/profile/layout.tsx:28-31
Timestamp: 2025-09-12T20:30:40.360Z
Learning: Created a centralized normalizeUserSlug utility function in apps/web/lib/utils.ts and apps/pro-web/lib/utils.ts that safely handles undefined parameter values, trims whitespace, and converts to lowercase. This should be used consistently across all userSlug parameter extractions to prevent crashes and ensure database query consistency.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/**/services/hasura.service.ts : Use hasura.service.ts as the single point of GraphQL interaction in each app
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use hasura.service.ts for all GraphQL operations from UI layers
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to **/*.{ts,tsx} : Explicitly annotate function parameters and return types
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to **/*.{ts,tsx} : Leverage type inference where clear; annotate function params and return types
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2024-11-14T21:12:19.789Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 302
File: apps/masterbots.ai/lib/hooks/use-mb-chat.ts:0-0
Timestamp: 2024-11-14T21:12:19.789Z
Learning: In `apps/masterbots.ai/lib/hooks/use-mb-chat.ts`, for handling message ordering issues, prefer simple solutions like using `setTimeout` over adding sequence numbers to the message schema, to keep the codebase simple.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-10-09T18:23:06.425Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 572
File: apps/web/components/shared/category-dashboard.tsx:47-85
Timestamp: 2025-10-09T18:23:06.425Z
Learning: In the masterbots codebase, chatbots are designed to belong to only one category (topic) by product design, even though the data model technically supports multiple category associations. This means category deselection logic can safely remove all chatbots from a removed category without checking if they belong to other selected categories.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2024-12-11T19:40:37.103Z
Learnt from: Bran18
Repo: bitcashorg/masterbots PR: 324
File: apps/masterbots.ai/components/routes/browse/browse-chatbot-mobile-details.tsx:145-146
Timestamp: 2024-12-11T19:40:37.103Z
Learning: In `apps/masterbots.ai/components/routes/browse/browse-chatbot-mobile-details.tsx`, the follower and following counts are currently hardcoded as these features are being developed in other PRs.
Applied to files:
apps/web/services/hasura/hasura.service.ts
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: For React/State: minimize useEffect deps, use refs for non-reactive values, separate state vs DOM manipulation
Applied to files:
apps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-09-30T22:08:30.965Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-30T22:08:30.965Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Applied to files:
apps/web/components/routes/preferences/google-translation.tsx
📚 Learning: 2025-01-14T06:20:03.578Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 337
File: apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx:195-205
Timestamp: 2025-01-14T06:20:03.578Z
Learning: React's useState setters (setState functions) maintain referential stability between renders and don't need to be included in useEffect dependency arrays. Include only the state values that the effect actually needs to track.
Applied to files:
apps/web/components/routes/preferences/google-translation.tsx
🧬 Code graph analysis (4)
apps/web/lib/hooks/use-preferences.tsx (5)
apps/web/types/types.ts (1)
Preferences(676-679)packages/mb-lib/src/hooks/use-local-storage.ts (1)
useLocalStorage(5-79)apps/web/lib/constants/preferences.ts (1)
preferences(11-213)apps/web/auth.ts (2)
session(183-198)jwt(101-182)apps/web/services/hasura/hasura.service.ts (2)
getUserPreferences(2129-2154)savePreferences(2196-2230)
apps/pro-web/components/routes/preferences/google-translation.tsx (2)
apps/pro-web/types/index.ts (1)
GoogleTranslateProps(708-711)apps/web/lib/hooks/use-preferences.tsx (1)
usePreferences(111-116)
apps/web/services/hasura/hasura.service.ts (3)
packages/mb-lib/src/hasura/hasura.lib.ts (1)
getHasuraClient(19-54)apps/pro-web/types/index.ts (1)
Preferences(718-721)apps/web/types/types.ts (1)
Preferences(676-679)
apps/web/components/routes/preferences/google-translation.tsx (3)
apps/web/types/types.ts (1)
GoogleTranslateProps(671-674)apps/web/auth.ts (1)
session(183-198)apps/web/lib/hooks/use-preferences.tsx (1)
usePreferences(111-116)
🔇 Additional comments (9)
apps/pro-web/components/routes/preferences/google-translation.tsx (3)
16-25: LGTM! Clean integration of session and preferences.The component correctly initializes state, refs, and integrates with both NextAuth session and preferences context.
27-33: LGTM! Proper preferences initialization.The effect correctly guards against missing preferences and initializes the language state.
35-51: LGTM! Script reloading logic is sound.The helper correctly removes existing Google Translate script and widget before re-adding, ensuring clean re-initialization.
apps/hasura/metadata/databases/masterbots/tables/public_preference.yaml (1)
27-28: New preference columns added consistently.The
font_sizeandlangcolumns are correctly added across insert, select, and update permissions for all applicable roles. The column additions are consistent.Also applies to: 42-43
apps/web/services/hasura/hasura.service.ts (2)
1885-1890: Preference mutation return values updated correctly.The
returningblock now includeslang,fontSize, andpreferenceIdfields, aligning with the new preference schema. This is consistent betweenupdatePreferencesandinsertPreferencesByUserId.
2129-2154: Well-structured authenticated preferences query.
getUserPreferencescorrectly requires JWT authentication, follows the RORO pattern with{ data, error }return structure, and has proper error handling.apps/web/components/routes/preferences/google-translation.tsx (1)
28-34: Language initialization from preferences is correct.The effect properly initializes
currentLanguagefrompreferences.langwith a fallback to 'en'. The dependency onpreferencesensures re-initialization when preferences change.apps/web/components/routes/preferences/preference-section.tsx (1)
290-303: Session update flow follows established pattern.The implementation correctly calls
update()fromuseSessionafter updating the database, which triggers NextAuth's JWT callback. Navigation happens after the session update, with proper error handling. This aligns with the learned pattern.apps/web/lib/hooks/use-preferences.tsx (1)
111-116: Hook structure follows best practices.The
usePreferenceshook correctly throws if used outside the provider, follows naming conventions, and is properly located inlib/hooks/. Named exports are used as per guidelines.
| console.log({ | ||
| preferences, | ||
| }) | ||
|
|
There was a problem hiding this comment.
Remove console.log({ preferences }) before merge (log/PII hygiene).
This will spam prod logs and may expose user settings.
- console.log({
- preferences,
- })
📝 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.
| console.log({ | |
| preferences, | |
| }) |
🤖 Prompt for AI Agents
In apps/pro-web/components/routes/preferences/preference-section.tsx around
lines 395 to 398 there is a debug statement console.log({ preferences }) that
must be removed to avoid spamming production logs and potentially exposing user
data; delete that console.log line (or replace with a non-sensitive debug-only
logger gated by NODE_ENV === 'development' if you need local debugging) and
ensure no other temporary debug prints remain in this file before merging.
| const usernameRegex = /^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$/ | ||
|
|
||
| if (!usernameRegex.test(value)) { | ||
| setErrorMessage( | ||
| 'Username must be 3–24 characters and contain only letters, numbers, or underscores.', | ||
| ) | ||
| console.error('Invalid username format:', value) | ||
| if (value.length < 3 || value.length > 24 || !usernameRegex.test(value)) { | ||
| setErrorMessage({ | ||
| inputId, | ||
| message: | ||
| 'Username must be 3-24 characters long and can only contain letters, numbers, and underscores.', | ||
| }) | ||
| return | ||
| } | ||
| console.error('Invalid username format:', value) | ||
| return | ||
| } | ||
| setErrorMessage('') | ||
| setErrorMessage({ inputId: '', message: '' }) |
There was a problem hiding this comment.
Username validation logic has inverted flow.
The validation at lines 250-259 sets an error and returns early when the username is invalid, but then line 258 logs "Invalid username format" and line 259 returns unconditionally. This means:
- If validation fails (line 250), error is set and function returns at line 256
- Lines 258-259 are unreachable after a failed validation
- If validation passes, lines 258-259 execute, logging "Invalid username format" even for valid input
The logic appears inverted. Consider:
if (value.length < 3 || value.length > 24 || !usernameRegex.test(value)) {
setErrorMessage({
inputId,
message:
'Username must be 3-24 characters long and can only contain letters, numbers, and underscores.',
})
return
}
- console.error('Invalid username format:', value)
- return
+ setErrorMessage({ inputId: '', message: '' })
}
- setErrorMessage({ inputId: '', message: '' })🤖 Prompt for AI Agents
In apps/web/components/routes/preferences/preference-section.tsx around lines
248 to 261 the validation flow is inverted and contains unreachable code: the
branch that detects invalid usernames correctly sets setErrorMessage and
returns, but there is an unconditional console.error('Invalid username format:',
value) and return after the if-block which executes for valid usernames and
never for invalid ones; remove the stray console.error and return (or move the
console.error inside the invalid branch) so only invalid inputs log the error
and return, and ensure that after a successful validation you simply clear the
error with setErrorMessage({ inputId: '', message: '' }) without extra returns.
| export async function getUserByID(userId: string) { | ||
| if (!userId) throw new Error('userId is required') | ||
|
|
||
| try { | ||
| const client = getHasuraClient({}) | ||
|
|
||
| const { user } = await client.query({ | ||
| user: { | ||
| __args: { | ||
| where: { | ||
| userId: { _eq: userId }, | ||
| }, | ||
| }, | ||
| userId: true, | ||
| username: true, | ||
| email: true, | ||
| slug: true, | ||
| profilePicture: true, | ||
| role: true, | ||
| }, | ||
| } as const) | ||
|
|
||
| if (!user || user.length === 0) { | ||
| return { user: null, error: 'User not found' } | ||
| } | ||
|
|
||
| return { | ||
| user: user[0], | ||
| error: null, | ||
| } | ||
| } catch (error) { | ||
| console.error('Error fetching user by ID:', { | ||
| error, | ||
| userId, | ||
| timestamp: new Date().toISOString(), | ||
| }) | ||
| if (error instanceof Error) { | ||
| return { user: null, error: error.message } | ||
| } | ||
| return { user: null, error: 'Unexpected error while fetching user' } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all invocations of getUserByID in the codebase
echo "=== All getUserByID calls ==="
rg -n "getUserByID" apps/web --type ts --type tsx -B 2 -A 2
echo -e "\n=== Count by file ==="
rg -l "getUserByID" apps/web --type ts --type tsx | sort | uniq -cRepository: bitcashorg/masterbots
Length of output: 190
🏁 Script executed:
#!/bin/bash
# Find all invocations of getUserByID in apps/web
echo "=== All getUserByID calls ==="
rg "getUserByID" apps/web -B 2 -A 2
echo -e "\n=== Files containing getUserByID ==="
rg -l "getUserByID" apps/webRepository: bitcashorg/masterbots
Length of output: 498
🏁 Script executed:
#!/bin/bash
# Check use-profile.tsx implementation
cat -n apps/web/lib/hooks/use-profile.tsx | head -100Repository: bitcashorg/masterbots
Length of output: 3275
🏁 Script executed:
#!/bin/bash
# Search entire repository for getUserByID usage (not just apps/web)
echo "=== getUserByID in entire repository ==="
rg "getUserByID" --type-list | head -20
echo -e "\n=== getUserByID calls anywhere ==="
rg "getUserByID" . -B 2 -A 2 2>/dev/null | grep -v "node_modules"
echo -e "\n=== Check if it's exported from hasura service ==="
rg "export.*getUserByID" .Repository: bitcashorg/masterbots
Length of output: 1030
Remove the unused getUserByID export.
The function is no longer called anywhere in the codebase. The architectural pattern is correctly implemented: user data comes from session.user via the NextAuth session, and the hook no longer performs client-side Hasura refetches for user data. Delete this function from apps/web/services/hasura/hasura.service.ts (lines 2031-2072) to clean up orphaned code.
🤖 Prompt for AI Agents
In apps/web/services/hasura/hasura.service.ts around lines 2031 to 2072, remove
the unused exported function getUserByID entirely (delete the function
declaration and its export). After removal, run a project-wide search for
getUserByID to confirm there are no remaining references and remove any
now-unused imports or type declarations that only existed to support this
function.
| export async function savePreferences( | ||
| userId: string, | ||
| jwt: string, | ||
| preferences: Preferences, | ||
| ) { | ||
| try { | ||
| // 1️⃣ Try to update first | ||
| const updateResult = await updatePreferences({ | ||
| userId, | ||
| jwt, | ||
| preferencesSet: preferences, | ||
| }) | ||
|
|
||
| const affectedRows = updateResult?.data?.returning?.length || 0 | ||
| if (affectedRows > 0) { | ||
| console.log('Preferences updated:', updateResult.data) | ||
| return updateResult.data | ||
| } | ||
|
|
||
| // 2️⃣ If update changed nothing → insert new preference row | ||
| const insertResult = await insertPreferencesByUserId({ | ||
| jwt, | ||
| preferencesSet: { | ||
| userId: userId, // 🔥 correct field name | ||
| ...preferences, | ||
| }, | ||
| }) | ||
|
|
||
| console.log('Preferences inserted:', insertResult.data) | ||
| return insertResult.data | ||
| } catch (err) { | ||
| console.error('Failed to save preferences:', err) | ||
| throw err | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find Preferences type definition
rg -n "type Preferences|interface Preferences" --type ts -A 15 apps/webRepository: bitcashorg/masterbots
Length of output: 1531
🏁 Script executed:
# Find PreferenceSetInput and PreferenceInsertInput definitions
rg -n "PreferenceSetInput|PreferenceInsertInput" --type ts -A 10 apps/webRepository: bitcashorg/masterbots
Length of output: 5625
🏁 Script executed:
# Also check the hasura.service.ts file to see the full context
cat -n apps/web/services/hasura/hasura.service.ts | sed -n '2196,2230p'Repository: bitcashorg/masterbots
Length of output: 1132
🏁 Script executed:
# Check imports at the top of hasura.service.ts
head -n 50 apps/web/services/hasura/hasura.service.ts | grep -n "Preferences\|import"Repository: bitcashorg/masterbots
Length of output: 221
🏁 Script executed:
# Also check around line 2196 to see context and imports
sed -n '1,100p' apps/web/services/hasura/hasura.service.ts | grep -n "Preferences\|import"Repository: bitcashorg/masterbots
Length of output: 221
🏁 Script executed:
# Get the complete import statement for Preferences
sed -n '2,10p' apps/web/services/hasura/hasura.service.tsRepository: bitcashorg/masterbots
Length of output: 276
🏁 Script executed:
# Verify the structure by checking how PreferenceSetInput fields are defined in mb-genql
# Search for any transformation or mapping logic that might handle snake_case to camelCase
rg -n "font_size|fontSize" apps/web/services/hasura/hasura.service.ts -B 2 -A 2Repository: bitcashorg/masterbots
Length of output: 693
🏁 Script executed:
# Check if there's any type transformation in updatePreferences or insertPreferencesByUserId
sed -n '1867,1895p' apps/web/services/hasura/hasura.service.tsRepository: bitcashorg/masterbots
Length of output: 543
🏁 Script executed:
# Also check insertPreferencesByUserId function
sed -n '1913,1935p' apps/web/services/hasura/hasura.service.tsRepository: bitcashorg/masterbots
Length of output: 526
Add field mapping to align snake_case Preferences with camelCase Hasura input types.
savePreferences imports Preferences from @/types/types (with snake_case fields: lang, font_size), but passes it directly to updatePreferences and insertPreferencesByUserId which expect PreferenceSetInput/PreferenceInsertInput (camelCase: fontSize). This causes a field name mismatch in GraphQL mutations.
Transform the fields at lines 2206 and 2220:
const updateResult = await updatePreferences({
userId,
jwt,
- preferencesSet: preferences,
+ preferencesSet: {
+ lang: preferences.lang,
+ fontSize: preferences.font_size,
+ },
}) const insertResult = await insertPreferencesByUserId({
jwt,
preferencesSet: {
userId: userId,
+ lang: preferences.lang,
+ fontSize: preferences.font_size,
},
})🤖 Prompt for AI Agents
In apps/web/services/hasura/hasura.service.ts around lines 2196 to 2230, the
function passes a snake_case Preferences object (e.g., font_size) directly to
Hasura input types that expect camelCase (e.g., fontSize); update the payloads
at the updatePreferences call (around line 2206) and the
insertPreferencesByUserId call (around line 2220) to map snake_case to camelCase
explicitly (e.g., font_size -> fontSize, any other snake_case fields similarly)
and ensure the insert payload includes userId as the correct field name while
spreading/mapping the other preference fields into the camelCase input shape.
…to fix-new-popup-issues
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/pro-web/components/layout/sidebar/sidebar-link.tsx (1)
79-79: Remove or document the biome-ignore directive.The
biome-ignorecomment has a placeholder<explanation>instead of a meaningful reason. Either provide a proper explanation for why exhaustive dependencies are disabled, or remove the ignore and fix the dependency array.The callback uses several setter functions (
setSearchTerm,changeKeyword,setIsOpenPopup,setActiveThread,setActiveChatbot,setActiveDepartment,setExpandedDepartments) that should be stable references from hooks. If they are guaranteed stable, document that as the reason for the ignore.-// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation> +// biome-ignore lint/correctness/useExhaustiveDependencies: Setter functions from hooks are stable references
🧹 Nitpick comments (2)
apps/pro-web/components/layout/sidebar/sidebar-link.tsx (2)
145-145: Address the TODO: implement department state synchronization.The TODO suggests that direct navigation to a department URL may not properly initialize
activeDepartmentstate. This could cause incorrect active states and broken navigation when users bookmark or directly access department URLs.Do you want me to generate the
useEffectguard that fetches and syncs the department from URL params to theactiveDepartmentstate?
120-123: Remove debug console.log statements.These
console.logcalls appear to be debugging artifacts and should be removed from production code.const handleCheckboxChange = useCallback( async (checked: boolean) => { - console.log('handleCheckboxChange called', { - checked, - departmentId: department.departmentId, - }) if (checked) { // Add all chatbots from this department const botsToAdd = department.chatbots.map((cb) => cb.chatbotId) await setSelectedChatbots((prev) => { const uniqueBots = [...new Set([...prev, ...botsToAdd])] return uniqueBots }) } else { // Remove all chatbots from this department const botsToRemove = department.chatbots.map((cb) => cb.chatbotId) await setSelectedChatbots((prev) => prev.filter((id) => !botsToRemove.includes(id)), ) } - console.log('handleCheckboxChange completed') }, [department.departmentId, department.chatbots, setSelectedChatbots], )Also applies to: 140-140
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/pro-web/components/layout/sidebar/profile-sidebar.tsx(2 hunks)apps/pro-web/components/layout/sidebar/sidebar-link.tsx(2 hunks)apps/pro-web/lib/hooks/use-workspace.tsx(1 hunks)apps/pro-web/services/hasura/hasura.service.ts(2 hunks)apps/pro-web/types/index.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/pro-web/types/index.ts
- apps/pro-web/components/layout/sidebar/profile-sidebar.tsx
- apps/pro-web/lib/hooks/use-workspace.tsx
- apps/pro-web/services/hasura/hasura.service.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/{web,pro-web}/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.tsx: Declare React components with the function keyword
Name React components using PascalCase
Order component files: imports → constants → component → styled components → types/interfaces
Use functional components and hooks; type props with a TypeScript interface
Use regular function references (not inline arrows) for React event handlers to avoid extra re-renders
apps/{web,pro-web}/**/*.tsx: Use regular function references for event handlers instead of inline arrow functions in JSX
Declare React components with the function keyword (function ComponentName() {})
Use PascalCase for React component names
Order React component files: imports, constants, component, styled components, types/interfaces
Style components with Tailwind CSS utility classes
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use meaningful variable names; prefix booleans with is/has/does/should
Use interface for objects/classes; type for unions/tuples/aliases; enum for fixed sets; const for literals
Avoid any; prefer specific types
Leverage type inference where clear; annotate function params and return types
Prefer type assertions with 'as' over angle-bracket syntax
Use type guards to narrow types in conditionals
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Use modern JavaScript features with TypeScript across the codebase
Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Receive an object and return an object (RORO) for functions interfacing with external services
Type definitions: use interface for objects/classes; type for unions/tuples/aliases; const for literals; enum for fixed sets
Avoid any; prefer specific types
Leverage type inference; omit explicit annotations when obvious
Add explicit type annotations for function parameters and return values
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types within conditionals
Favor composition over inheritance in code structure
**/*.{ts,tsx}: Avoid default exports; prefer named exports
Prefer RORO (Receive an object, return an object) for function signatures, especially for external service interactions
Use interface for object shapes/classes; type for unions/tuples/aliases; const for literals; enum for fixed enumerations
Avoid using any; prefer precise types
Leverage type inference when clear; omit redundant annotations
Explicitly annotate function parameters and return types
Prefer type assertions with as over angle-bracket syntax
Use type guards to narrow types safely
Use meaningful variable names; prefix booleans with is/has/does/should
Favor composition over inheritance
Use lowercase dash-separated names for files and folders; use extensions like .config.ts, .test.ts, .context.tsx, .typ...
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
apps/{web,pro-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
apps/{web,pro-web}/**/*.{ts,tsx}: Use lowercase kebab-case for directories and filenames (components can omit extension)
Verify DOM operations and consider timing (RAF/delays) when manipulating the DOM in React
Use Tailwind CSS utility classes for styling React components
apps/{web,pro-web}/**/*.{ts,tsx}: Use TypeScript to define React props types (interfaces for props)
Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Separate presentation from business logic and compose small components
Use hasura.service.ts for all GraphQL operations from UI layers
apps/{web,pro-web}/**/*.{ts,tsx}: Prefer Server Components; use the use client directive only when client-side features are required
Implement Nested Layouts using the App Router
Use Streaming and Suspense in Next.js 14/15 where appropriate
Follow Next.js file conventions as per documentation
Use IndexedDB for local caching to enable immediate UI updates
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: Use lowercase with dash-separated directory and file names; use specific extensions: .config.ts, .test.ts, .context.tsx, .type.ts, .hook.ts; components may omit extension
Use Bun for package management and scripts instead of npm/yarn
Use Biome for formatting and linting via bun format-and-lint:fix; avoid Prettier/ESLint configs
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/*.tsx: Avoid inline arrow functions in JSX props; use stable function references for event handlers
Declare React components with the function keyword (functional components)
Use PascalCase for React component names
Use functional components and hooks instead of class components
Type component props with TypeScript interfaces
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
apps/{web,pro-web}/components/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Order component files: imports → constants → component → styled components → types/interfaces
Files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
🧠 Learnings (8)
📓 Common learnings
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: Successfully created comprehensive GitHub issue #555 consolidating performance feedback and edge-case management for pro-web workspace features, including prioritized action items, testing requirements, and specific file references for implementation.
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-11-07T18:41:56.562Z
Learning: Successfully created comprehensive GitHub issue #581 consolidating 16 unresolved observations from PR #579 review, including critical TDZ crash, migration bugs, transaction safety issues, and validation improvements, with specific file paths, line numbers, and action items organized by priority (4 critical, 8 major, 2 minor, 2 acknowledged for future PRs).
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace features have complex performance considerations including markdown parsing optimization, AI streaming response handling, state persistence coordination, and selection range management that require careful monitoring and optimization.
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component is redundant as thread-list.tsx has been developed to support all the same functionality including public pages. The codebase should be cleaned up to remove browse-list.tsx and related components in the browse directory, along with the BrowseProvider context.
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-04-26T10:58:44.341Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 465
File: apps/masterbots.ai/components/routes/browse/browse-list.tsx:1-1
Timestamp: 2025-04-26T10:58:44.341Z
Learning: The browse-list.tsx component and related components in the browse directory are redundant since thread-list.tsx has been developed to support all pages including public pages, and should be removed to simplify the codebase.
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Applies to apps/{web,pro-web}/**/*.{ts,tsx} : Use custom hooks (useMBChat, useThread, useSidebar, useModel) for domain-specific state and keep providers focused and composed hierarchically
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-04T21:31:18.830Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 0
File: :0-0
Timestamp: 2025-09-04T21:31:18.830Z
Learning: The pro-web workspace system has identified performance bottlenecks in markdown parsing, AI streaming response handling, selection range management, Base64 document processing, and multiple debounced state operations that require optimization and better coordination.
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2024-10-23T07:33:36.041Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 287
File: apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx:3-3
Timestamp: 2024-10-23T07:33:36.041Z
Learning: Always use explicit imports for React hooks to maintain consistency across the monorepo, and avoid using both named and default imports simultaneously.
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:09:37.969Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-30T22:09:37.969Z
Learning: Pro workspace editors: controlled/uncontrolled patterns, Markdown utilities, section state sync, and timed DOM operations
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
📚 Learning: 2025-09-30T22:11:18.270Z
Learnt from: CR
Repo: bitcashorg/masterbots PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-30T22:11:18.270Z
Learning: Applies to apps/{web,pro-web}/lib/hooks/**/*.{ts,tsx} : Place custom React hooks in lib/hooks/
Applied to files:
apps/pro-web/components/layout/sidebar/sidebar-link.tsx
🧬 Code graph analysis (1)
apps/pro-web/components/layout/sidebar/sidebar-link.tsx (2)
apps/pro-web/lib/hooks/use-sidebar.tsx (1)
useSidebar(63-69)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(684-690)
🔇 Additional comments (2)
apps/pro-web/components/layout/sidebar/sidebar-link.tsx (2)
193-221: LGTM: Well-structured URL building logic.The
departmentUrlmemo correctly:
- Determines if the department is newly selected
- Handles profile page URLs differently from workspace URLs
- Provides appropriate fallback URLs
- Uses
urlBuildersfor consistency- Includes all necessary dependencies
58-58: Verify workspace context performance impact.The migration of
activeDepartmentfrom sidebar-local to workspace-global state is architecturally sound and consistent with other components. However, this change means thatactiveDepartmentupdates will trigger re-renders in all components consumingWorkspaceContext.Ensure that:
WorkspaceProvideruses proper memoization for context values- Components consuming workspace context use appropriate optimizations (React.memo, useMemo, useCallback)
- The workspace context is structured to minimize unnecessary re-renders
As per coding guidelines, custom hooks (useWorkspace, useSidebar) should manage domain-specific state with focused, hierarchically-composed providers.
Also applies to: 99-106, 147-147
|
https://github.com/user-attachments/assets/39d6e2fd-b200-40f6-a01c-feaa81ac60dd |
AndlerRL
left a comment
There was a problem hiding this comment.
LGTM! Thanks for spreading the fixes to the pro site and to polish the preferences UI 💯 👍 I see now the UI and logic feedbacks were also addressed. More test will be running after the merge. For now, I have included a few fixes before the merge.
Summary by Sourcery
Fix various UI and backend integration issues on dashboard and profile pages, enrich profile context with fresh user data, streamline authentication flows, refine permissions and styles, and add category 'Select All' functionality
New Features:
Bug Fixes:
Enhancements:
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.