-
Notifications
You must be signed in to change notification settings - Fork 1
[pro-web] feat: implement brand kit wizard with multi-step creation flow #597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
Reviewer's GuideImplements a multi-step Brand Kit creation wizard in the Media Tab, backed by a new reusable WorkspaceDialog shell and a full persistence path (React state, localStorage, IndexedDB, Hasura/PG brand_kit JSONB) so users can configure vibes, fonts, and colors, review them on a checkpoint step, and resume progress per organization. Sequence diagram for saving Brand Kit from CheckpointStepsequenceDiagram
actor User
participant MediaSidebar
participant BrandKitDialog
participant BrandKitWizard
participant CheckpointStep
participant useWorkspaceMedia
participant saveBrandKitMutation
participant ApiOrganizationsId as Api_organizations_id
participant Hasura
participant Postgres
participant IndexedDB
participant ReactQuery as TanStack_Query
User->>MediaSidebar: click BrandKit button
MediaSidebar->>useWorkspaceMedia: openBrandKit()
useWorkspaceMedia-->>MediaSidebar: set showBrandKit true
MediaSidebar->>BrandKitDialog: open=true
BrandKitDialog->>BrandKitWizard: render wizard
loop Wizard navigation
User->>BrandKitWizard: navigate steps (Vibe, Fonts, Colors)
BrandKitWizard->>useWorkspaceMedia: setSelectedVibes / setSelectedFonts / setSelectedPalette
BrandKitWizard->>useWorkspaceMedia: saveBrandKitStep(currentStep, organizationId)
useWorkspaceMedia->>LocalStorage: set brandkit_step_organizationId
end
User->>CheckpointStep: click Continue Later or Generate Logo
CheckpointStep->>useWorkspaceMedia: saveBrandKit(brandKitData, organizationId)
useWorkspaceMedia->>saveBrandKitMutation: mutateAsync(brandKitData, organizationId)
saveBrandKitMutation->>ApiOrganizationsId: PATCH /api/organizations/:id { brandKit }
ApiOrganizationsId->>Hasura: updateOrganizationByPk(brand_kit)
Hasura->>Postgres: update organization.brand_kit JSONB
Postgres-->>Hasura: updated row
Hasura-->>ApiOrganizationsId: organization with brand_kit
ApiOrganizationsId-->>saveBrandKitMutation: response json
saveBrandKitMutation->>IndexedDB: getItem(WORKSPACE_STRUCTURE_KEY)
IndexedDB-->>saveBrandKitMutation: workspaceStructure
saveBrandKitMutation->>IndexedDB: updateItem(WORKSPACE_STRUCTURE_KEY, updatedWorkspace)
saveBrandKitMutation->>ReactQuery: invalidateQueries(workspace userId structure)
ReactQuery->>ApiOrganizationsId: refetch organizations with brandKit
ApiOrganizationsId-->>ReactQuery: latest organization data
ReactQuery-->>useWorkspaceMedia: updated cache merged via useWorkspaceStructure
alt Continue Later
CheckpointStep->>BrandKitDialog: close()
BrandKitDialog-->>MediaSidebar: onOpenChange(false)
useWorkspaceMedia->>useWorkspaceMedia: brandKitCurrentStep remains at Checkpoint
else Generate Logo
CheckpointStep->>useWorkspaceMedia: clearBrandKitStep(organizationId)
useWorkspaceMedia->>LocalStorage: remove brandkit_step_organizationId
CheckpointStep->>BrandKitWizard: next() to logo flow
end
ER diagram for organization brand_kit integrationerDiagram
user {
uuid userId PK
text email
text name
}
organization {
uuid organizationId PK
text name
uuid userId FK
jsonb brand_kit
}
organization_chatbot {
uuid id PK
uuid organizationId FK
integer chatbotId
boolean isActive
}
user ||--o{ organization : owns
organization ||--o{ organization_chatbot : has
Class diagram for Brand Kit wizard components and stateclassDiagram
class WorkspaceDialog {
+boolean open
+function onOpenChange(open boolean)
+string title
+string subtitle
+ReactNode children
+ReactNode footer
+string maxWidth
}
class BrandKitDialog {
+boolean open
+function onOpenChange(open boolean)
-BrandKitView currentView
-function handleNewBrand()
-function handleImportBrand()
-function handleWizardFinish()
-function handleWizardCancel()
}
class BrandKitEntry {
+function onNewBrand()
+function onImportBrand()
}
class BrandKitWizard {
+function onFinish()
+function onCancel()
-number currentStep
-boolean isInitialized
-function handleNext()
-function handleClose()
}
class WizardStep {
+string name
+ReactComponent component
}
class WizardStepper {
+string[] steps
+number currentStep
+function onStepClick(index number)
}
class VibeStep {
+function next()
+function prev()
+function close()
}
class FontsStep {
+function next()
+function prev()
}
class ColorsStep {
+function next()
+function prev()
}
class CheckpointStep {
+function next()
+function close()
-function buildBrandKitData()
-function handleContinueLater()
-function handleGenerateLogo()
-function handleSwitchFonts()
}
class BrandKitData {
+string[] vibes
+BrandKitFonts fonts
+BrandKitPalette palette
+BrandKitLogo logo
+string createdAt
+string updatedAt
}
class BrandKitFonts {
+string primary
+string secondary
}
class BrandKitPalette {
+string name
+string category
+string primary
+string accent
+string bg
+string text
}
class BrandKitLogo {
+string generatedImageUrl
+string[] variations
}
class SelectedFont {
+string family
+string role
}
class Palette {
+string name
+string category
+string primary
+string accent
+string bg
+string text
}
class OrganizationData {
+string id
+string name
+OrganizationChatbot[] chatbots
+BrandKitData brandKit
}
class useWorkspaceMedia {
+string[] selectedVibes
+SelectedFont[] selectedFonts
+Palette selectedPalette
+number brandKitCurrentStep
+boolean isSavingBrandKit
+boolean showBrandKit
+function openBrandKit()
+function setSelectedVibes(vibes string[])
+function setSelectedFonts(fonts SelectedFont[])
+function setSelectedPalette(palette Palette)
+function saveBrandKit(brandKitData BrandKitData, organizationId string)
+function saveBrandKitStep(step number, organizationId string)
+function loadBrandKitStep(organizationId string) number
+function clearBrandKitStep(organizationId string)
}
class useWorkspace {
+string activeOrganization
+WorkspaceInitialState initialState
}
class WorkspaceInitialState {
+OrganizationData[] organizationData
}
WorkspaceDialog <|-- BrandKitDialog
BrandKitDialog o-- BrandKitEntry
BrandKitDialog o-- BrandKitWizard
BrandKitWizard o-- WizardStepper
BrandKitWizard o-- VibeStep
BrandKitWizard o-- FontsStep
BrandKitWizard o-- ColorsStep
BrandKitWizard o-- CheckpointStep
BrandKitData o-- BrandKitFonts
BrandKitData o-- BrandKitPalette
BrandKitData o-- BrandKitLogo
useWorkspaceMedia o-- SelectedFont
useWorkspaceMedia o-- Palette
useWorkspaceMedia o-- BrandKitData
OrganizationData o-- BrandKitData
useWorkspace o-- WorkspaceInitialState
WorkspaceInitialState o-- OrganizationData
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdd Brand Kit: DB column and Hasura permissions, server API support, types, client fetching/merge, workspace media hook state and persistence (IDB/localStorage), Google Fonts support, a multi-step Brand Kit wizard/dialog UI, and Drizzle schema/relations updates. (34 words) Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as BrandKit UI
participant Hook as WorkspaceMedia Hook
participant IDB as IndexedDB
participant API as Server API
participant DB as Database
Note over User,UI: Open Brand Kit
User->>UI: open dialog
UI->>Hook: init/load step for org
Hook->>IDB: read cached brandKit & step
IDB-->>Hook: cached data
Hook-->>UI: populate wizard state
loop Wizard steps
User->>UI: select vibes / fonts / colors
UI->>Hook: update in-memory state
Hook->>IDB: persist step & selections
IDB-->>Hook: ack
end
User->>UI: Finish / Save
UI->>Hook: saveBrandKit(brandKitData)
Hook->>API: PATCH organization.brand_kit
API->>DB: persist brand_kit column
DB-->>API: confirm
API-->>Hook: return updated org
Hook->>IDB: update local workspace cache
Hook-->>UI: success
UI->>User: show summary / close
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
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 |
- Add dynamic subtitle showing org name + "Logo & Style" in wizard mode - Implement sticky wizard stepper and navigation buttons layout - Create VibeStep with 12 brand vibes, 2-selection limit, and color preview - Add proper scroll container for wizard content with fixed header/footer - Style BadgeCheck icon and color dots with proper borders for dark mode - Update wizard container to use viewport-based height for proper layout
- Add FontsStep with primary/secondary font selection - Create Google Fonts integration with 70+ font families - Implement vibe-based font recommendations system - Add role badges (primary/secondary) for selected fonts - Include font preview with multiple samples - Update Brand Kit state management in useWorkspaceMedia hook - Adjust wizard and dialog padding for better spacing - Fix VibeStep to use shared state from context
… scroll optimization - Add sticky bar showing selected fonts with removal capability - Implement vertical scroll snap carousel for font grid - Update font state management with role-based structure - Optimize scroll behavior in VibeStep and wizard stepper - Remove border from stepper for cleaner visual separation
…e preview - Add ColorsStep with 8 curated color palettes across multiple categories - Implement live preview card with selected fonts and organization name - Add AA contrast ratio validation with gentle auto-adjustment - Create shuffle functionality for random palette selection - Build carousel navigation for palette browsing - Display color strips with primary, accent, bg, and text tokens - Add palette state management to useWorkspaceMedia hook - Integrate selected fonts from previous step into color preview
…d responsive design
…s and improve contrast handling
- Create CheckpointStep component to review selected brand elements - Display color scheme with palette circles and category information - Show font family preview with primary and secondary fonts - Add font switching functionality between primary and secondary roles - Integrate organization name and vibe label in checkpoint UI - Replace placeholder LogoStep with functional CheckpointStep - Add flag icon to final step in wizard stepper for visual clarity
d98b66d to
0e113d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/pro-web/lib/constants/google-fonts.ts (1)
76-410: Consider supporting multiple font weights for typography flexibility.All fonts are configured with a single weight (
'400'), which limits typographic hierarchy for brand kits. Brand identity typically requires multiple weights (e.g.,400,600,700) for headers, body text, and emphasis. Consider enabling multiple weights or variable fonts where supported.Example: Supporting multiple weights
export const inter = Inter({ subsets: ['latin'], display: 'swap', weight: ['400', '600', '700'], // Regular, semi-bold, bold }) // Or for variable fonts: export const inter = Inter({ subsets: ['latin'], display: 'swap', variable: true, // Enable CSS variable })As per coding guidelines.
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
33-48: Add defensive check for emptyselectedFontsarray.The
buildBrandKitDatafunction accessesselectedFonts[0].familywithout verifying the array has at least one element. While the wizard flow should enforce font selection, adding a defensive check improves robustness and prevents potential runtime errors.🔎 Suggested fix
const buildBrandKitData = (): BrandKitData => { if (!selectedPalette) { throw new Error('Palette is required') } + if (selectedFonts.length === 0) { + throw new Error('At least one font is required') + } return { vibes: selectedVibes, fonts: { primary: selectedFonts[0].family, secondary: selectedFonts[1]?.family, }, palette: selectedPalette, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), } }
🧹 Nitpick comments (7)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsx (1)
31-40: Extract inline arrow function to stable handler reference.The inline arrow function in the
onClickprop violates the coding guideline to use regular function references for event handlers. Extract to a stable handler or memoize to avoid unnecessary re-renders.🔎 Proposed refactor
<button type="button" - onClick={() => isClickable && onStepClick(index)} + onClick={isClickable ? () => onStepClick(index) : undefined} disabled={!isClickable} className={cn( 'flex flex-col items-center transition-all', isClickable && 'cursor-pointer', !isClickable && 'cursor-not-allowed', )} >Or better yet, extract to a handler function:
+const handleStepClick = (stepIndex: number) => { + if (onStepClick && stepIndex <= currentStep) { + onStepClick(stepIndex) + } +} + return ( <div className="sticky top-0 z-10 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 flex flex-col items-center w-full gap-3 pb-6 pt-2"> {/* Steps row */} <div className="flex items-center justify-center w-full max-w-3xl"> {steps.map((step, index) => { const isActive = index === currentStep const isCompleted = index < currentStep const isFuture = index > currentStep const isClickable = onStepClick && index <= currentStep return ( <React.Fragment key={step}> {/* Step circle + label */} <button type="button" - onClick={() => isClickable && onStepClick(index)} + onClick={() => handleStepClick(index)} disabled={!isClickable}As per coding guidelines.
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
51-98: Improve error handling with user feedback.Both
handleContinueLaterandhandleGenerateLogosilently swallow errors after logging to console. Users won't know if the save operation failed. Consider adding toast notifications or error UI to inform users of save failures.Example enhancement
import { toast } from '@/components/ui/use-toast' // or your toast system const handleContinueLater = async () => { if (!currentOrg?.id) { close() return } setIsSaving(true) try { const brandKitData = buildBrandKitData() await saveBrandKit(brandKitData, currentOrg.id) toast({ title: 'Success', description: 'Brand Kit saved successfully', }) close() } catch (error) { console.error('❌ Failed to save brand kit:', error) toast({ title: 'Error', description: 'Failed to save Brand Kit. Please try again.', variant: 'destructive', }) // Don't close on error - let user retry } finally { setIsSaving(false) } }apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsx (1)
134-144: Consider extracting the inline arrow function to avoid re-renders.The inline arrow function
onClick={() => handleVibeClick(vibe.name)}creates a new function on every render. While not critical, consider using a data attribute pattern or useCallback for better performance.🔎 Alternative approach using data attributes
+ const handleVibeButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => { + const vibeName = e.currentTarget.dataset.vibeName + if (vibeName) handleVibeClick(vibeName) + } + return ( <button key={vibe.name} type="button" - onClick={() => handleVibeClick(vibe.name)} + onClick={handleVibeButtonClick} + data-vibe-name={vibe.name} className={cn(apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsx (1)
57-57: Remove debug console.log statements or replace with proper logging.Multiple console.log statements are present for debugging purposes. These should be removed before production or replaced with a proper logging service for better observability and log management.
Also applies to: 62-62, 88-88, 119-119
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (1)
36-36: Remove debug console.log statements.Console.log statements in handlers should be removed before production or replaced with proper logging for production observability.
Also applies to: 41-41
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsx (1)
296-305: Consider stable function references for palette selection.The inline arrow function in the onClick handler creates a new function instance on each render. For better performance, consider using data attributes or event delegation.
🔎 Alternative approach
+ const handlePaletteButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => { + const paletteName = e.currentTarget.dataset.paletteName + const palette = PALETTES.find(p => p.name === paletteName) + if (palette) setSelectedPalette(palette) + } + <button type="button" - onClick={() => handlePaletteClick(palette)} + onClick={handlePaletteButtonClick} + data-palette-name={palette.name} className={cn(apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (1)
104-115: Consider stable function reference for font selection.The inline arrow function
onClick={() => onFontClick(font.family)}is recreated on every render. Consider using data attributes for better performance across all font cards.🔎 Alternative approach
+ const handleFontButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => { + const fontFamily = e.currentTarget.dataset.fontFamily + if (fontFamily) onFontClick(fontFamily) + } + <button key={font.family} type="button" - onClick={() => onFontClick(font.family)} + onClick={handleFontButtonClick} + data-font-family={font.family} className={cn(
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
packages/mb-genql/generated/schema.graphqlis excluded by!**/generated/**packages/mb-genql/generated/schema.tsis excluded by!**/generated/**packages/mb-genql/generated/types.tsis excluded by!**/generated/**
📒 Files selected for processing (25)
apps/hasura/metadata/databases/masterbots/tables/public_organization.yamlapps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sqlapps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/up.sqlapps/pro-web/app/actions/thread.actions.tsapps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/app/api/organizations/route.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/components/routes/workspace/media-tab/wizards/version-history-dialog.tsxapps/pro-web/components/ui/workspace-dialog/index.tsxapps/pro-web/lib/constants/google-fonts.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/types/media.types.tsapps/pro-web/types/thread.types.tspackages/mb-drizzle/src/drizzle/relations.tspackages/mb-drizzle/src/drizzle/schema.ts
🚧 Files skipped from review as they are similar to previous changes (9)
- apps/pro-web/app/actions/thread.actions.ts
- apps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/up.sql
- apps/pro-web/components/ui/workspace-dialog/index.tsx
- apps/pro-web/components/routes/workspace/media-tab/wizards/version-history-dialog.tsx
- apps/pro-web/lib/hooks/use-workspace-media.tsx
- apps/pro-web/app/api/organizations/route.ts
- apps/pro-web/lib/queries/use-workspace-structure.ts
- apps/pro-web/app/api/organizations/[id]/route.ts
- packages/mb-drizzle/src/drizzle/schema.ts
🧰 Additional context used
📓 Path-based instructions (10)
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/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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/workspace/media-tab/wizards/media-wizards.tsxpackages/mb-drizzle/src/drizzle/relations.tsapps/pro-web/types/media.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/types/thread.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/lib/constants/google-fonts.ts
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/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/types/media.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/types/thread.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/lib/constants/google-fonts.ts
**/*
📄 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/workspace/media-tab/wizards/media-wizards.tsxpackages/mb-drizzle/src/drizzle/relations.tsapps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sqlapps/pro-web/types/media.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/hasura/metadata/databases/masterbots/tables/public_organization.yamlapps/pro-web/types/thread.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/lib/constants/google-fonts.ts
**/*.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/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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/workspace/media-tab/wizards/media-wizards.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsx
apps/hasura/migrations/masterbots/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Store and manage Hasura migrations under apps/hasura/migrations/masterbots/
Store Hasura-managed migrations in timestamped folders under apps/hasura/migrations/masterbots/
Keep Hasura-managed database migrations in timestamped folders under apps/hasura/migrations/masterbots/
Files:
apps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sql
apps/{web,pro-web}/types/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Place shared TypeScript definitions under types/
Keep TypeScript type definitions under types/
Files:
apps/pro-web/types/media.types.tsapps/pro-web/types/thread.types.ts
apps/{web,pro-web}/types/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place shared TypeScript types under types/
Files:
apps/pro-web/types/media.types.tsapps/pro-web/types/thread.types.ts
🧠 Learnings (23)
📓 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.
📚 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/hasura/migrations/masterbots/** : Keep Hasura-managed database migrations in timestamped folders under apps/hasura/migrations/masterbots/
Applied to files:
apps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sql
📚 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:
apps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sql
📚 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/pro-web/types/media.types.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/types/thread.types.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}/types/** : Place shared TypeScript definitions under types/
Applied to files:
apps/pro-web/types/media.types.tsapps/pro-web/types/thread.types.tsapps/pro-web/lib/constants/google-fonts.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 apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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}/**/*.tsx : Order React component files: imports, constants, component, styled components, types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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 : Order component files: imports → constants → component → styled components → types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/lib/constants/google-fonts.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 apps/{web,pro-web}/components/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsxapps/pro-web/lib/constants/google-fonts.ts
📚 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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/lib/constants/google-fonts.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 apps/{web,pro-web}/**/*.{ts,tsx} : Follow Next.js file conventions as per documentation
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/lib/constants/google-fonts.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/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.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/workspace/media-tab/ui/sidebar/media-sidebar.tsxapps/pro-web/types/thread.types.ts
📚 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/routes/workspace/media-tab/ui/sidebar/media-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/routes/workspace/media-tab/ui/sidebar/media-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}/types/**/*.ts : Place shared TypeScript types under types/
Applied to files:
apps/pro-web/types/thread.types.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}/types/** : Keep TypeScript type definitions under types/
Applied to files:
apps/pro-web/types/thread.types.ts
📚 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/types/thread.types.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 **/*.{ts,tsx} : Use meaningful names; prefix booleans with is/has/does/should (e.g., isDisabled)
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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 meaningful variable names; prefix booleans with is/has/does/should
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsx
🧬 Code graph analysis (9)
packages/mb-drizzle/src/drizzle/relations.ts (1)
packages/mb-drizzle/src/drizzle/schema.ts (4)
prompt(43-61)promptTypeEnum(63-65)promptChatbot(463-489)promptUser(491-517)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsx (5)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStep(23-26)apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/components/ui/wizard/hook/useWizard.tsx (1)
useWizard(18-83)apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsx (1)
WizardStepper(13-82)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (6)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)apps/pro-web/lib/utils.ts (1)
cn(9-11)
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx (1)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)
apps/pro-web/types/thread.types.ts (1)
apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsx (3)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)apps/pro-web/lib/utils.ts (1)
cn(9-11)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (4)
apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/components/ui/workspace-dialog/index.tsx (1)
WorkspaceDialog(23-67)apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsx (1)
BrandKitEntry(11-53)apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsx (1)
BrandKitWizard(27-193)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/colors-step.tsx (7)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)apps/pro-web/lib/hooks/use-workspace-media.tsx (2)
useWorkspaceMedia(496-504)Palette(65-72)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/components/ui/carousel.tsx (2)
CarouselApi(257-257)Carousel(258-258)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)apps/pro-web/lib/memoized-markdown-components.tsx (1)
p(62-68)apps/pro-web/lib/utils.ts (1)
cn(9-11)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/wizard-stepper.tsx (1)
apps/pro-web/lib/utils.ts (1)
cn(9-11)
🔇 Additional comments (7)
apps/pro-web/components/routes/workspace/media-tab/ui/sidebar/media-sidebar.tsx (1)
11-11: LGTM! Clean integration of Brand Kit feature.The changes correctly wire the Brand Kit button to the
openBrandKithandler fromuseWorkspaceMedia, following the established pattern used by the Templates button. The import updates (removingPalette) align with the feature changes, and the implementation follows all coding guidelines:
- Uses function reference for
onClick(not inline arrow)- Maintains consistent styling and tooltip structure
- Properly extracts the handler from the custom hook
Also applies to: 14-14, 43-43
apps/hasura/migrations/masterbots/1766505347896_alter_table_public_organization_add_column_brand_kit/down.sql (1)
1-2: LGTM! Down migration correctly reverts the brand_kit column addition.The migration properly drops the brand_kit column to revert the schema change, following Hasura migration conventions.
apps/pro-web/types/thread.types.ts (1)
2-2: LGTM! Type extension properly integrates BrandKitData.The addition of the optional
brandKitfield toOrganizationDatafollows TypeScript best practices with type-only import and proper optional/nullable typing.Also applies to: 21-21
apps/pro-web/components/routes/workspace/media-tab/wizards/media-wizards.tsx (1)
9-9: LGTM! Clean integration of BrandKitDialog.The BrandKitDialog integration follows the existing pattern used for other dialogs (VersionHistoryDialog) and properly wires up state management from the useWorkspaceMedia hook.
Also applies to: 25-26, 114-115
apps/hasura/metadata/databases/masterbots/tables/public_organization.yaml (1)
30-30: LGTM! Hasura permissions correctly expose brand_kit column.The metadata updates properly grant insert, select, and update permissions for the
brand_kitcolumn to both moderator and user roles, following the existing permission patterns for the organization table.Also applies to: 40-40, 48-48, 57-57, 69-69, 77-77
apps/pro-web/types/media.types.ts (1)
51-95: LGTM! Well-structured and documented BrandKitData interface.The interface is comprehensive with clear JSDoc comments for each field. The type structure properly represents brand identity data with appropriate optionality and nesting.
Optional: Consider hex color validation
For stricter type safety, you could define a branded type for hex colors:
type HexColor = `#${string}` export interface BrandKitData { // ... palette: { name: string category: string primary: HexColor accent: HexColor bg: HexColor text: HexColor } // ... }However, this is optional and the current string typing is acceptable.
packages/mb-drizzle/src/drizzle/relations.ts (1)
36-50: No changes to remove. These relation definitions at lines 36-50 were not modified in this PR; the file remains unchanged according to git. Remove this review comment.Likely an incorrect or invalid review comment.
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (5)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
380-386: Previous review comment addressed.The hardcoded query key
['workspace', userId, 'structure']from previous review has been correctly replaced withworkspaceKeys.structure(userId)at line 384.apps/pro-web/app/api/organizations/[id]/route.ts (1)
70-79: Previous null validation issue addressed.The validation now correctly handles
nullwith the explicit checkbody.brandKit === null. This preventsnullfrom passing validation sincetypeof null === 'object'in JavaScript.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
33-52: Previous review comment addressed with defensive check.The
buildBrandKitDatafunction now includes the defensive check for emptyselectedFontsarray at lines 38-40, throwing a clear error message.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (1)
286-288: Previous grammar issue addressed.The heading text has been corrected from "Which font family you look for?" to "Which font family are you looking for?"
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (1)
20-27: Previous possessive apostrophe issue addressed.The subtitle now correctly handles possessives with the logic at lines 23-24, using just an apostrophe for names ending in 's' and "'s" otherwise.
🧹 Nitpick comments (6)
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
30-33: Consider consolidatingPalettetype withBrandKitData.palette.The
Paletteinterface (lines 65-72) duplicates the palette shape defined inBrandKitData(fromapps/pro-web/types/media.types.ts). Consider importing and reusingBrandKitData['palette']to avoid drift between the two definitions.🔎 Suggested approach
+import type { BrandKitData, ReferenceImagePayload } from '@/types/media.types' + +export type Palette = BrandKitData['palette'] export interface SelectedFont { family: string role: 'primary' | 'secondary' } - -export interface Palette { - name: string - category: string - primary: string - accent: string - bg: string - text: string -}Also applies to: 65-72
apps/pro-web/app/api/organizations/[id]/route.ts (1)
179-191: Consider adding schema validation forbrandKitstructure.The API accepts any object as
brandKitwithout validating required fields (vibes,fonts,palette,createdAt,updatedAt). While TypeScript provides compile-time safety on the client, malformed data from other sources could be persisted.For production robustness, consider using Zod or similar to validate the
BrandKitDatashape:import { z } from 'zod' const brandKitSchema = z.object({ vibes: z.array(z.string()), fonts: z.object({ primary: z.string(), secondary: z.string().optional(), }), palette: z.object({ name: z.string(), category: z.string(), primary: z.string(), accent: z.string(), bg: z.string(), text: z.string(), }), createdAt: z.string(), updatedAt: z.string(), })apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
182-202: Addaria-labelfor screen reader accessibility on color swatches.The color swatch divs have
titleattributes for hover tooltips, but screen readers don't announcetitle. Consider addingaria-labelandrole="img"for better accessibility.🔎 Suggested improvement
<div className="w-12 h-12 rounded-full border-2 border-border shadow-sm" style={{ backgroundColor: selectedPalette.primary }} title="Primary" + role="img" + aria-label={`Primary color: ${selectedPalette.primary}`} />apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (2)
211-242: Potential unnecessary re-runs due tosetSelectedFontsin dependencies.The
setSelectedFontsfunction comes from context state and should be stable, but including it in the dependency array could cause unnecessary effect re-runs if the context provider re-renders. Consider wrapping the effect logic more defensively or using a ref for the setter.The current implementation is functionally correct since line 235 prevents infinite loops. This is a minor optimization consideration.
327-430: Consider extracting font data to a separate constants file.The
Vibetype,FontOptioninterface, and font dictionaries (PRIMARY_FONTS,SECONDARY_FONTS) are substantial data definitions (~190 lines). Extracting them to a dedicated file (e.g.,lib/constants/brand-kit-fonts.ts) would improve maintainability and keep the component focused on rendering logic.This also allows reuse of font mappings if needed elsewhere in the Brand Kit feature.
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (1)
33-43: Placeholder handlers and missing summary view noted.The
handleImportBrandandhandleWizardFinishhandlers are placeholders. SettingcurrentViewto'summary'will render nothing since the summary view isn't implemented yet (line 71). Ensure these are tracked for completion.Would you like me to open an issue to track the implementation of the Brand Kit summary view and import flow?
Also applies to: 70-71
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/lib/queries/use-workspace-structure.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsx
🧰 Additional context used
📓 Path-based instructions (10)
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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/api/organizations/[id]/route.ts
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-media.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-media.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.
📚 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/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx
📚 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/pro-web/lib/queries/use-workspace-structure.ts
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.
Applied to files:
apps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.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/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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 : Order component files: imports → constants → component → styled components → types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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/**/*.tsx : Order component files: imports → constants → component → styled components → types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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} : Follow Next.js file conventions as per documentation
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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}/**/*.tsx : Order React component files: imports, constants, component, styled components, types/interfaces
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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/app/api/organizations/[id]/route.tsapps/pro-web/lib/hooks/use-workspace-media.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/lib/hooks/use-workspace-media.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-media.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/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-11-14T19:14:07.243Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Applied to files:
apps/pro-web/lib/hooks/use-workspace-media.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/lib/hooks/use-workspace-media.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/pro-web/lib/hooks/use-workspace-media.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/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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 meaningful variable names; prefix booleans with is/has/does/should
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx
🧬 Code graph analysis (4)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (5)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (4)
apps/pro-web/lib/hooks/use-workspace-media.tsx (2)
SelectedFont(30-33)useWorkspaceMedia(496-504)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)apps/pro-web/lib/utils.ts (1)
cn(9-11)apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)
apps/pro-web/app/api/organizations/[id]/route.ts (1)
apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)
apps/pro-web/lib/hooks/use-workspace-media.tsx (8)
apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)apps/pro-web/lib/query-client.ts (1)
queryClient(12-28)apps/pro-web/lib/hooks/use-indexed-db.ts (1)
getUserIndexedDBKeys(35-40)apps/pro-web/lib/constants/workspace.ts (1)
WORKSPACE_STRUCTURE_KEY(27-27)apps/pro-web/lib/queries/use-workspace-structure.ts (1)
WorkspaceStructure(22-38)apps/pro-web/types/thread.types.ts (1)
OrganizationData(17-22)apps/pro-web/lib/queries/use-workspace-mutations.ts (1)
structureToIDBPayload(912-918)apps/pro-web/lib/queries/workspace-keys.ts (1)
workspaceKeys(16-38)
🔇 Additional comments (6)
apps/pro-web/lib/hooks/use-workspace-media.tsx (2)
340-390: Well-structured mutation with proper persistence flow.The
saveBrandKitMutationcorrectly implements the server-first, then IDB sync pattern. The query invalidation on success ensures the cache stays fresh.
409-415: No action needed. TheloadBrandKitStepfunction is in a'use client'component, which means it only executes in the browser and is not subject to SSR hydration cycles. localStorage access in client-only components has no hydration risk. Additionally, the actual usage shows the function is called within a useEffect (based on the conditional organization change pattern), which is the correct timing for localStorage operations.Likely an incorrect or invalid review comment.
apps/pro-web/app/api/organizations/[id]/route.ts (1)
193-225: Clean integration ofbrandKitin query and response.The
brandKitfield is properly fetched from Hasura and included in the transformed response, maintaining consistency with the existing response structure.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
109-127: Font handling and switch logic looks correct.The fallback of
secondaryFonttoprimaryFontwhen only one font is selected provides visual consistency. The switch button is appropriately disabled when fewer than 2 fonts are selected.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (1)
172-173: Clean wizard step implementation.The component properly destructures only the needed props (
next,prev) fromWizardStepPropsand disables navigation appropriately based on selection state.Also applies to: 314-322
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (1)
16-18: View state persists across dialog open/close cycles.When the dialog closes and reopens,
currentViewretains its previous value (e.g., staying on 'wizard' instead of resetting to 'entry'). Verify this is the intended UX behavior. If users expect a fresh start on reopen, add a reset effect.🔎 Potential fix if reset is desired
+import { useEffect, useMemo, useState } from 'react' export function BrandKitDialog({ open, onOpenChange }: BrandKitDialogProps) { const [currentView, setCurrentView] = useState<BrandKitView>('entry') + + // Reset view when dialog closes + useEffect(() => { + if (!open) { + setCurrentView('entry') + } + }, [open])Also applies to: 49-73
| } catch (error) { | ||
| console.error('❌ Failed to save brand kit:', error) | ||
| close() | ||
| } finally { | ||
| setIsSaving(false) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silent failure could cause data loss without user feedback.
Both handleContinueLater and handleGenerateLogo catch errors but proceed with navigation (close() / next()) without notifying the user. If the save fails, the user may believe their brand kit was saved when it wasn't.
🔎 Suggested improvement
Consider adding user feedback on failure:
} catch (error) {
console.error('❌ Failed to save brand kit:', error)
- close()
+ // Show error toast before closing
+ toast.error('Failed to save brand kit. Please try again.')
+ // Optionally: don't close on failure so user can retry
} finally {Also applies to: 96-102
1e883e4 to
49a7027
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/pro-web/lib/queries/use-workspace-structure.ts (1)
243-261: Name-based deduplication looks correct now.The switch to name-based organization lookup resolves the previous ID mismatch issue during anonymous→user migration. The merge logic now correctly finds existing orgs by name and updates their
brandKitandchatbotsfields.One minor note from the previous review still applies: the
||fallback on lines 258-259 means explicitly settingbrandKittonull(to clear it) won't take effect. If clearing brand kit is a supported use case, consider using'brandKit' in orgData ? orgData.brandKit : existingOrg.brandKitinstead.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
70-76: Silent failure could cause data loss without user feedback.Both error handlers log the error but proceed with navigation (
close()/next()). If the save fails, the user may believe their brand kit was saved when it wasn't.Consider adding a toast notification on failure, or keeping the dialog open so the user can retry:
} catch (error) { console.error('❌ Failed to save brand kit:', error) - close() + // Show error toast and optionally keep dialog open for retry + toast.error('Failed to save brand kit. Please try again.') } finally {Also applies to: 96-102
🧹 Nitpick comments (2)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (1)
159-164: Possessive apostrophe logic could be extracted.The pattern for handling possessive apostrophes (
activeOrganization?.endsWith('s') ? "'" : "'s") appears here and inbrand-kit-dialog.tsx. Consider extracting a small helper function for consistency.🔎 Optional helper extraction
// In a shared utils file export function possessive(name: string | null | undefined): string { if (!name) return '' return name.endsWith('s') ? `${name}'` : `${name}'s` }apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
340-390: Brand Kit persistence follows the correct pattern.The mutation properly:
- Saves to server first (source of truth)
- Updates IDB for offline access
- Invalidates queries to trigger refetch
Minor concern: if the IDB update (lines 361-376) fails after successful server save, there's no error handling. The next page load will sync from server anyway, but a console warning would help debugging.
🔎 Optional: Add IDB error handling
// 2. Update workspace IDB after successful server save +try { const workspaceData = await getItem(WORKSPACE_STRUCTURE_KEY) if (workspaceData && typeof workspaceData === 'object') { // ... existing logic await updateItem(WORKSPACE_STRUCTURE_KEY, payload) } +} catch (idbError) { + console.warn('IDB update failed, will sync on next load:', idbError) +}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/lib/queries/use-workspace-structure.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/pro-web/app/api/organizations/[id]/route.ts
- apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsx
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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/pro-web/lib/hooks/use-workspace-media.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-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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-media.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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-media.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx
🧠 Learnings (15)
📓 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.
📚 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/pro-web/lib/queries/use-workspace-structure.ts
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.
Applied to files:
apps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-11-07T18:41:56.562Z
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).
Applied to files:
apps/pro-web/lib/queries/use-workspace-structure.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 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-media.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/lib/hooks/use-workspace-media.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-media.tsx
📚 Learning: 2025-11-14T19:14:07.243Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Applied to files:
apps/pro-web/lib/hooks/use-workspace-media.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/lib/hooks/use-workspace-media.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/pro-web/lib/hooks/use-workspace-media.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx
🧬 Code graph analysis (2)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (4)
apps/pro-web/lib/hooks/use-workspace-media.tsx (2)
SelectedFont(30-33)useWorkspaceMedia(496-504)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)apps/pro-web/lib/utils.ts (1)
cn(9-11)apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (7)
apps/pro-web/components/ui/wizard/index.tsx (1)
WizardStepProps(14-21)apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
useWorkspaceMedia(496-504)apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/types/media.types.ts (1)
BrandKitData(55-95)apps/pro-web/lib/constants/google-fonts.ts (2)
getGoogleFontClass(488-490)FontFamily(486-486)apps/pro-web/lib/memoized-markdown-components.tsx (3)
h2(88-103)p(62-68)h3(105-120)apps/pro-web/lib/utils.ts (1)
cn(9-11)
🔇 Additional comments (11)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx (2)
33-52: Defensive validation looks good.The
buildBrandKitDatafunction now properly validates bothselectedPaletteandselectedFontsbefore building the payload. This prevents runtime errors if the wizard state is somehow incomplete.
119-127: Font switching logic is correct.The swap only triggers when exactly two fonts are selected, and roles are explicitly reassigned. The button is also correctly disabled when
selectedFonts.length < 2.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx (3)
19-56: SelectedFontsBar implementation is clean.The component correctly handles the empty state, renders chips with role badges, and provides accessible removal buttons with proper
aria-label. Good use of Tailwind utilities for styling.
244-276: Font selection handlers are well-implemented.Both
handleFontClickandhandleRemoveFontcorrectly:
- Use functional setState to avoid stale closures
- Reassign roles deterministically after any change
- Enforce the 2-font maximum
327-430: Font dictionaries are well-curated.The
Vibetype covers a good range of brand personalities, and the font pairings are professionally chosen. The overlap of fonts across vibes (e.g.,Interappearing in Modern, Bold, Techy) is appropriate since some fonts are versatile.apps/pro-web/lib/hooks/use-workspace-media.tsx (3)
30-72: New Brand Kit types are well-defined.
SelectedFontandPaletteinterfaces provide clear type safety for the wizard state. The structure aligns withBrandKitDatainmedia.types.ts.
447-484: Context provider exposes Brand Kit state and actions correctly.The new state fields and actions are properly wired into the context value, following the existing patterns. The
isSavingBrandKit: saveBrandKitMutation.isPendingderivation is clean.
399-421: localStorage usage for wizard step tracking is appropriate and safe as implemented.This pattern for non-critical UI state is solid. Since the functions are only invoked from
useEffecthooks (which run exclusively on the client) and the component is marked'use client', SSR hydration issues won't occur. The implementation is safe without explicit guards, as evidenced by similar patterns inuse-sidebar.tsx.apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (3)
20-27: Possessive apostrophe handling is correct.The fix properly handles organization names ending in 's' (e.g., "Dynamics'" vs "Acme's"). Good use of
useMemoto avoid recalculating on every render.
29-47: View state transitions are straightforward.The handlers correctly manage the
entry → wizard → summaryflow. The TODO placeholders for import functionality are acceptable for this PR scope.
49-73: Dialog composition is clean.The conditional rendering based on
currentViewis clear and maintainable. TheWorkspaceDialogwrapper provides consistent styling. The TODO comment for summary view appropriately marks future work.
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx
Show resolved
Hide resolved
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx
Outdated
Show resolved
Hide resolved
49a7027 to
6037eb6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
apps/pro-web/lib/queries/use-workspace-structure.ts (1)
258-259: Clarify or adjust merge semantics for explicit clearing.This was flagged in a previous review but remains unresolved. The
||operator prevents intentional clearing ofbrandKitorchatbots. If clearing is a supported use case, consider using an explicit check:if (existingOrg) { - existingOrg.brandKit = orgData.brandKit || existingOrg.brandKit - existingOrg.chatbots = orgData.chatbots || existingOrg.chatbots + existingOrg.brandKit = orgData.brandKit !== undefined ? orgData.brandKit : existingOrg.brandKit + existingOrg.chatbots = orgData.chatbots !== undefined ? orgData.chatbots : existingOrg.chatbots }If this behavior is intentional (to prevent accidental data loss), update the comment to reflect it.
🧹 Nitpick comments (3)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (2)
33-37: Remove debug console.log statements before merging.The
console.log('Importing brand...')is a debug artifact that should be removed or replaced with proper logging/toast notification when the import flow is implemented.
39-43: Remove debug console.log statement.Similar to the import handler, this debug log should be removed.
apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
30-33: Consider moving shared types totypes/media.types.ts.
SelectedFontandPaletteare exported from this hook file but could be co-located withBrandKitDataintypes/media.types.tsfor better discoverability and reuse across the codebase. This aligns with the coding guideline for organizing type definitions.Also applies to: 65-72
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/pro-web/app/api/organizations/[id]/route.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsxapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsxapps/pro-web/lib/hooks/use-workspace-media.tsxapps/pro-web/lib/queries/use-workspace-structure.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/pro-web/app/api/organizations/[id]/route.ts
- apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/fonts-step.tsx
- apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx
- apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/vibe-step.tsx
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/lib/hooks/use-workspace-media.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/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/lib/hooks/use-workspace-media.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/queries/use-workspace-structure.tsapps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/lib/hooks/use-workspace-media.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/lib/hooks/use-workspace-media.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/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsxapps/pro-web/lib/hooks/use-workspace-media.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/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/lib/hooks/use-workspace-media.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-media.tsx
🧠 Learnings (13)
📓 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.
📚 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/pro-web/lib/queries/use-workspace-structure.ts
📚 Learning: 2025-06-13T08:55:45.217Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 508
File: apps/masterbots.ai/lib/helpers/ai-helpers.ts:280-283
Timestamp: 2025-06-13T08:55:45.217Z
Learning: In `apps/masterbots.ai/lib/helpers/ai-helpers.ts` the `verifyDuplicateMessage` function should:
• Use `message.content` as the sole de-duplication key so provisional (no-slug) and persisted (slugged) messages merge properly.
• Return the full `message` object (not just a string key) for the continuation prompts (`CONTINUE_GENERATION_PROMPT`, `CONTINUE_GENERATION_PROMPT_2`) because their content repeats and they must remain distinct.
• No explicit `!message.content` guard is needed; `return message.content` already yields `undefined` when content is missing.
Applied to files:
apps/pro-web/lib/queries/use-workspace-structure.tsapps/pro-web/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-11-07T18:41:56.562Z
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).
Applied to files:
apps/pro-web/lib/queries/use-workspace-structure.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 apps/{web,pro-web}/components/shared/**/*.{ts,tsx} : Store reusable UI elements in components/shared/
Applied to files:
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.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/lib/hooks/use-workspace-media.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/lib/hooks/use-workspace-media.tsx
📚 Learning: 2025-11-14T19:14:07.243Z
Learnt from: AndlerRL
Repo: bitcashorg/masterbots PR: 584
File: apps/pro-web/app/api/generate-images/route.ts:86-107
Timestamp: 2025-11-14T19:14:07.243Z
Learning: In apps/pro-web/app/api/generate-images/route.ts, the hardcoded 'image/png' MIME type for Gemini previousImage is intentional—LLM-generated images are PNG by default. When the library/template features are added (allowing user-uploaded reference images), the architecture should use Next.js server actions with checksum-based caching (computeChecksum fn) to handle files larger than the 2.5-3MB API route limit, rather than detecting MIME types in the API route directly.
Applied to files:
apps/pro-web/lib/hooks/use-workspace-media.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/lib/hooks/use-workspace-media.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-media.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/pro-web/lib/hooks/use-workspace-media.tsx
🧬 Code graph analysis (2)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (4)
apps/pro-web/lib/hooks/use-workspace.tsx (1)
useWorkspace(668-674)apps/pro-web/components/ui/workspace-dialog/index.tsx (1)
WorkspaceDialog(23-67)apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-entry.tsx (1)
BrandKitEntry(11-53)apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/brand-kit-wizard.tsx (1)
BrandKitWizard(27-193)
apps/pro-web/lib/hooks/use-workspace-media.tsx (7)
apps/pro-web/lib/query-client.ts (1)
queryClient(12-28)apps/pro-web/lib/hooks/use-indexed-db.ts (1)
getUserIndexedDBKeys(35-40)apps/pro-web/lib/constants/workspace.ts (1)
WORKSPACE_STRUCTURE_KEY(27-27)apps/pro-web/lib/queries/use-workspace-structure.ts (1)
WorkspaceStructure(22-38)apps/pro-web/types/thread.types.ts (1)
OrganizationData(17-22)apps/pro-web/lib/queries/use-workspace-mutations.ts (1)
structureToIDBPayload(912-918)apps/pro-web/lib/queries/workspace-keys.ts (1)
workspaceKeys(16-38)
🔇 Additional comments (4)
apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/brand-kit-dialog.tsx (2)
16-18: Consider resetting view state when dialog closes.When the dialog is closed and reopened,
currentViewretains its previous value. If a user closes the dialog mid-wizard and reopens it, they'll see the wizard instead of the entry screen. Depending on UX requirements, you may want to reset to 'entry' whenopenbecomesfalse.🔎 Potential fix if reset is desired
export function BrandKitDialog({ open, onOpenChange }: BrandKitDialogProps) { const [currentView, setCurrentView] = useState<BrandKitView>('entry') const { activeOrganization } = useWorkspace() + + // Reset view when dialog closes + const handleOpenChange = (isOpen: boolean) => { + if (!isOpen) { + setCurrentView('entry') + } + onOpenChange(isOpen) + }Then pass
handleOpenChangetoWorkspaceDialoginstead ofonOpenChange.
49-73: LGTM!The component structure follows guidelines: functional component with
functionkeyword, named export, props typed with interface, stable handler references, and proper use ofuseMemofor the computed subtitle. The possessive apostrophe handling (line 23-24) correctly distinguishes names ending in 's'.apps/pro-web/lib/queries/use-workspace-structure.ts (1)
243-261: LGTM! The name-based deduplication fix is correct.The merge logic now correctly uses organization name for both existence check and lookup, resolving the previous mismatch issue. The map is keyed by
org.name(line 244), and the lookup usesorgData.name(line 255), ensuring consistent behavior during anonymous-to-user migration.apps/pro-web/lib/hooks/use-workspace-media.tsx (1)
129-134: LGTM! Session integration and query invalidation are correctly implemented.The provider correctly retrieves the session to derive user-specific IDB keys, and the mutation's
onSuccessproperly invalidates the workspace structure query usingworkspaceKeys.structure(userId)as per the past review feedback.Also applies to: 380-386
| // Brand Kit persistence mutation | ||
| const saveBrandKitMutation = useMutation({ | ||
| mutationFn: async ({ | ||
| brandKitData, | ||
| organizationId, | ||
| }: { | ||
| brandKitData: BrandKitData | ||
| organizationId: string | ||
| }) => { | ||
| // 1. Save to server first | ||
| const response = await fetch(`/api/organizations/${organizationId}`, { | ||
| method: 'PATCH', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ brandKit: brandKitData }), | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error('Failed to save brand kit to server') | ||
| } | ||
|
|
||
| // 2. Update workspace IDB after successful server save | ||
| const workspaceData = await getItem(WORKSPACE_STRUCTURE_KEY) | ||
| if (workspaceData && typeof workspaceData === 'object') { | ||
| const workspace = workspaceData as unknown as WorkspaceStructure | ||
| const updatedWorkspace: WorkspaceStructure = { | ||
| ...workspace, | ||
| organizationData: workspace.organizationData.map( | ||
| (org: OrganizationData) => | ||
| org.id === organizationId | ||
| ? { ...org, brandKit: brandKitData } | ||
| : org, | ||
| ), | ||
| } | ||
|
|
||
| const payload = structureToIDBPayload(updatedWorkspace) | ||
| await updateItem(WORKSPACE_STRUCTURE_KEY, payload) | ||
| } | ||
|
|
||
| return await response.json() | ||
| }, | ||
| onSuccess: () => { | ||
| // Invalidate and refetch - merge will prioritize IDB data (most recent updatedAt) | ||
| const userId = session?.user?.id || 'anonymous' | ||
| queryClient.invalidateQueries({ | ||
| queryKey: workspaceKeys.structure(userId), | ||
| }) | ||
| }, | ||
| onError: (error) => { | ||
| console.error('Failed to save brand kit:', error) | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find where saveBrandKitMutation is called
rg -n "saveBrandKit" apps/pro-web --type ts --type tsx -A 3 -B 2Repository: bitcashorg/masterbots
Length of output: 92
🏁 Script executed:
# Check the component file structure and context
fd "use-workspace-media" apps/pro-web -type fRepository: bitcashorg/masterbots
Length of output: 235
🏁 Script executed:
# Look at the full file to understand the context better
wc -l apps/pro-web/lib/hooks/use-workspace-media.tsxRepository: bitcashorg/masterbots
Length of output: 115
🏁 Script executed:
# Read the full hook file to understand context
cat -n apps/pro-web/lib/hooks/use-workspace-media.tsxRepository: bitcashorg/masterbots
Length of output: 18422
🏁 Script executed:
# Find where saveBrandKit is called
rg -n "saveBrandKit" apps/pro-web --type-listRepository: bitcashorg/masterbots
Length of output: 454
🏁 Script executed:
# Search for saveBrandKit calls in components
rg "saveBrandKit" apps/pro-web -A 3 -B 2Repository: bitcashorg/masterbots
Length of output: 7107
🏁 Script executed:
# Find Brand Kit related components
fd -e tsx -e ts "brand-kit" apps/pro-webRepository: bitcashorg/masterbots
Length of output: 325
🏁 Script executed:
# Read the checkpoint-step.tsx to see the full context of saveBrandKit calls
cat -n apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx | head -100Repository: bitcashorg/masterbots
Length of output: 3254
🏁 Script executed:
# See the full checkpoint-step.tsx
wc -l apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsxRepository: bitcashorg/masterbots
Length of output: 165
🏁 Script executed:
# Check the full checkpoint-step.tsx to see if there are more guards
cat -n apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx | tail -300Repository: bitcashorg/masterbots
Length of output: 12110
🏁 Script executed:
# Check useWorkspace hook to understand initialState source
grep -n "initialState" apps/pro-web/lib/hooks/use-workspace.ts -A 5 -B 5Repository: bitcashorg/masterbots
Length of output: 137
🏁 Script executed:
# Find the use-workspace hook
fd "use-workspace" apps/pro-web/lib/hooks -type fRepository: bitcashorg/masterbots
Length of output: 235
🏁 Script executed:
# Also check how currentOrg is determined - it's from initialState.organizationData
# Let's search for where initialState comes from
rg "initialState" apps/pro-web/lib/hooks -A 2 -B 2Repository: bitcashorg/masterbots
Length of output: 2412
🏁 Script executed:
# Check how initialState is passed to WorkspaceProvider - look for where it's created
rg "WorkspaceProvider" apps/pro-web --context 5 -m 3Repository: bitcashorg/masterbots
Length of output: 4010
🏁 Script executed:
# Look at the mutation onError to see if it handles this scenario
cat -n apps/pro-web/lib/hooks/use-workspace-media.tsx | sed -n '340,390p'Repository: bitcashorg/masterbots
Length of output: 1972
🏁 Script executed:
# Check if there's any logging or error handling for when org is not found
rg "organizationData.*map" apps/pro-web -B 5 -A 5Repository: bitcashorg/masterbots
Length of output: 5730
🏁 Script executed:
# Look at the complete checkpoint-step to see all guards
cat -n apps/pro-web/components/routes/workspace/media-tab/ui/brand-kit/wizard/steps/checkpoint-step.tsx | grep -A 15 "const currentOrg"Repository: bitcashorg/masterbots
Length of output: 566
Add explicit validation when updating the organization in IDB.
If organizationId doesn't match any organization in the cached workspace structure (e.g., due to stale IDB data), the map() silently leaves the data unchanged after a successful server save. This creates a divergence between server and local state. Either validate that the organization exists before updating, log a warning if not found, or throw an error to surface the inconsistency instead of silently skipping the IDB update.
🤖 Prompt for AI Agents
In apps/pro-web/lib/hooks/use-workspace-media.tsx around lines 340-390, the code
updates organizationData with map() but doesn’t check whether any org matched
organizationId, so a stale IDB may remain unchanged and diverge from the server;
fix by detecting whether the map produced a change (e.g., compare lengths of
filtered matches or use a flag during mapping), and if no organization was
found, do not silently skip — either log a clear warning (console.warn) and
invalidate/refetch the workspace
(queryClient.invalidateQueries(workspaceKeys.structure(userId))) to reconcile
local state, or throw an error to surface the inconsistency; if you choose to
update IDB anyway, explicitly insert the organization data returned by the
server into organizationData before calling updateItem.
| // 2. Update workspace IDB after successful server save | ||
| const workspaceData = await getItem(WORKSPACE_STRUCTURE_KEY) | ||
| if (workspaceData && typeof workspaceData === 'object') { | ||
| const workspace = workspaceData as unknown as WorkspaceStructure | ||
| const updatedWorkspace: WorkspaceStructure = { | ||
| ...workspace, | ||
| organizationData: workspace.organizationData.map( | ||
| (org: OrganizationData) => | ||
| org.id === organizationId | ||
| ? { ...org, brandKit: brandKitData } | ||
| : org, | ||
| ), | ||
| } | ||
|
|
||
| const payload = structureToIDBPayload(updatedWorkspace) | ||
| await updateItem(WORKSPACE_STRUCTURE_KEY, payload) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDB update omits updatedAt timestamp, which may affect merge priority.
The merge logic in use-workspace-structure.ts uses updatedAt to determine which source takes priority (line 225-227: sourcesToMerge.sort((a, b) => b.updatedAt - a.updatedAt)). The IDB update here doesn't set a new updatedAt, so the cached workspace structure may not be recognized as the most recent during subsequent merges.
🔎 Suggested fix
const updatedWorkspace: WorkspaceStructure = {
...workspace,
organizationData: workspace.organizationData.map(
(org: OrganizationData) =>
org.id === organizationId
? { ...org, brandKit: brandKitData }
: org,
),
+ updatedAt: Date.now(),
}📝 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.
| // 2. Update workspace IDB after successful server save | |
| const workspaceData = await getItem(WORKSPACE_STRUCTURE_KEY) | |
| if (workspaceData && typeof workspaceData === 'object') { | |
| const workspace = workspaceData as unknown as WorkspaceStructure | |
| const updatedWorkspace: WorkspaceStructure = { | |
| ...workspace, | |
| organizationData: workspace.organizationData.map( | |
| (org: OrganizationData) => | |
| org.id === organizationId | |
| ? { ...org, brandKit: brandKitData } | |
| : org, | |
| ), | |
| } | |
| const payload = structureToIDBPayload(updatedWorkspace) | |
| await updateItem(WORKSPACE_STRUCTURE_KEY, payload) | |
| } | |
| // 2. Update workspace IDB after successful server save | |
| const workspaceData = await getItem(WORKSPACE_STRUCTURE_KEY) | |
| if (workspaceData && typeof workspaceData === 'object') { | |
| const workspace = workspaceData as unknown as WorkspaceStructure | |
| const updatedWorkspace: WorkspaceStructure = { | |
| ...workspace, | |
| organizationData: workspace.organizationData.map( | |
| (org: OrganizationData) => | |
| org.id === organizationId | |
| ? { ...org, brandKit: brandKitData } | |
| : org, | |
| ), | |
| updatedAt: Date.now(), | |
| } | |
| const payload = structureToIDBPayload(updatedWorkspace) | |
| await updateItem(WORKSPACE_STRUCTURE_KEY, payload) | |
| } |
🤖 Prompt for AI Agents
In apps/pro-web/lib/hooks/use-workspace-media.tsx around lines 360 to 376, the
code updates the workspace in IDB but doesn't set a new updatedAt timestamp so
the merge logic may treat the cached workspace as older; update the workspace
structure or the payload to include an updatedAt (e.g., Date.now()) before
calling structureToIDBPayload/updateItem, ensuring the field type matches
WorkspaceStructure and the payload includes the new timestamp so subsequent
merges correctly prioritize this update.
| const saveBrandKitStep = useCallback( | ||
| (step: number, organizationId: string) => { | ||
| setBrandKitCurrentStep(step) | ||
| // Also persist to localStorage for reliability | ||
| const key = `brandkit_step_${organizationId}` | ||
| localStorage.setItem(key, String(step)) | ||
| }, | ||
| [], | ||
| ) | ||
|
|
||
| const loadBrandKitStep = useCallback((organizationId: string) => { | ||
| const key = `brandkit_step_${organizationId}` | ||
| const savedStep = localStorage.getItem(key) | ||
| const step = savedStep ? Number.parseInt(savedStep, 10) : 0 | ||
| setBrandKitCurrentStep(step) | ||
| return step | ||
| }, []) | ||
|
|
||
| const clearBrandKitStep = useCallback((organizationId: string) => { | ||
| setBrandKitCurrentStep(0) | ||
| const key = `brandkit_step_${organizationId}` | ||
| localStorage.removeItem(key) | ||
| }, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap localStorage access in try-catch for SSR and storage-disabled scenarios.
localStorage access can throw in SSR environments or when storage is disabled (e.g., private browsing in some browsers). Since this is a 'use client' component, SSR is less of a concern, but storage quota/disabled scenarios should be handled.
🔎 Suggested fix
const saveBrandKitStep = useCallback(
(step: number, organizationId: string) => {
setBrandKitCurrentStep(step)
- // Also persist to localStorage for reliability
- const key = `brandkit_step_${organizationId}`
- localStorage.setItem(key, String(step))
+ try {
+ const key = `brandkit_step_${organizationId}`
+ localStorage.setItem(key, String(step))
+ } catch {
+ // localStorage unavailable or quota exceeded
+ }
},
[],
)
const loadBrandKitStep = useCallback((organizationId: string) => {
const key = `brandkit_step_${organizationId}`
- const savedStep = localStorage.getItem(key)
+ let savedStep: string | null = null
+ try {
+ savedStep = localStorage.getItem(key)
+ } catch {
+ // localStorage unavailable
+ }
const step = savedStep ? Number.parseInt(savedStep, 10) : 0
setBrandKitCurrentStep(step)
return step
}, [])
const clearBrandKitStep = useCallback((organizationId: string) => {
setBrandKitCurrentStep(0)
- const key = `brandkit_step_${organizationId}`
- localStorage.removeItem(key)
+ try {
+ const key = `brandkit_step_${organizationId}`
+ localStorage.removeItem(key)
+ } catch {
+ // localStorage unavailable
+ }
}, [])🤖 Prompt for AI Agents
In apps/pro-web/lib/hooks/use-workspace-media.tsx around lines 399-421, wrap all
localStorage access in try-catch blocks to avoid exceptions in storage-disabled
or restricted environments: in saveBrandKitStep catch errors from
localStorage.setItem and fall back to a no-op (but still call
setBrandKitCurrentStep), in loadBrandKitStep catch errors from
localStorage.getItem and return/assign a safe default (0) after calling
setBrandKitCurrentStep, and in clearBrandKitStep catch errors from
localStorage.removeItem and perform a no-op (still call
setBrandKitCurrentStep(0)); optionally check typeof window !== 'undefined'
before touching localStorage but ensure functions never throw and always update
state.
📖 Description
Implements a comprehensive Brand Kit creation wizard for the Media Tab, enabling users to configure their brand identity through a guided multi-step process. This PR introduces a reusable dialog component architecture, establishes the foundation for brand customization features, fully integrates the Brand Kit functionality into the Media Tab workflow with functional vibe, fonts, and colors selection steps, implements a checkpoint review screen, and adds complete persistence layer with IndexedDB caching and server synchronization.
✅ Changes Made
Component Architecture & Foundation:
WorkspaceDialogreusable component for standardized dialog structure across media tab wizardsversion-history-dialogto use newWorkspaceDialogcomponent (reducing 192 lines of duplicate code)BrandKitEntrycomponent with "New Brand" and "Import Brand" options for better code organizationBrandKitWizardwith multi-step navigation flow using custom wizard hookWizardSteppercomponent for visual step progress indication with animationsBrandKitDialogwithMediaWizardsandMediaSidebarfor seamless user accessMediaSidebarto open dialogVibe Step (Brand Personality):
VibeStepwith 12 brand vibes, 2-selection limit, and color preview badgesBadgeCheckicon and color dots with proper borders for dark mode compatibilityFonts Step (Typography):
FontsStepwith vibe-based font recommendations systemSelectedFonttype)Colors Step (Palette Selection):
ColorsStepwith 8 curated color palettes across multiple categories (Minimal Neutrals, Cool Tech, Bold Saturated, Warm & Friendly, Fresh Greens, Vintage/Retro, Elegant Monochrome)useWorkspaceMediahookCheckpoint Step (Review & Save):
CheckpointStepcomponent (265 lines) to review selected brand elementsFlagTriangleRight) to final step in wizard stepper for visual clarityLogoStepwith functionalCheckpointStepDatabase Schema & Hasura Integration:
brand_kitJSONB column toorganizationtable in PostgreSQLpublic_organization.yaml) with brand_kit fieldbrandKitfield definitionPersistence Layer & API Integration:
saveBrandKitmutation inuseWorkspaceMediausing TanStack QuerysaveBrandKitStepfunction to track wizard progress in LocalStorage per organizationclearBrandKitStepfunction to reset progress after wizard completionBrandKitWizardon mount:useRefto prevent unnecessary re-renders from brandKit changes/api/organizations/[id]route (PATCH):/api/organizationsroute (GET):getUserOrganizationsserver actionuse-workspace-structure.ts)Type Definitions:
BrandKitDatainterface inmedia.types.ts:vibes: string[]- Brand personality descriptorsfonts: { primary: string, secondary?: string }- Typography selectionpalette: { name, category, primary, accent, bg, text }- Color configurationlogo?: { generatedImageUrl, variations }- Generated logo assets (future)createdAtandupdatedAttimestampsbrandKit?: BrandKitData | nulltoOrganizationDatainterfaceBrandKitDatafrom main types indexState Management:
useWorkspaceMediahook:selectedVibes,selectedFonts,selectedPalette- Wizard selectionsbrandKitCurrentStep- Current wizard step numberisSavingBrandKit- Loading state for save operationsshowBrandKit,openBrandKit- UI visibility controlsuseWorkspaceMedia:setSelectedVibes,setSelectedFonts,setSelectedPalette- State setterssaveBrandKit(brandKitData, organizationId)- Persist to server + IDBsaveBrandKitStep(step, organizationId)- Track wizard progressclearBrandKitStep(organizationId)- Reset wizard progressData Flow Architecture:
Code Quality & Polish:
useReffor brandKit tracking🖼️ Media (screenshots/videos)
https://www.loom.com/share/486914fdb4ba4f30a6151589a2632abe
Summary by Sourcery
Introduce a multi-step Brand Kit creation wizard to the media tab and standardize media dialogs with a reusable workspace dialog layout.
New Features:
Enhancements:
Summary by Sourcery
Introduce a multi-step Brand Kit wizard for the media workspace and persist brand configuration on organizations, while standardizing media dialogs with a reusable workspace dialog layout.
New Features:
Enhancements:
Build:
Chores:
Summary by CodeRabbit
New Features
Chores
Refactor
UI
✏️ Tip: You can customize this high-level summary in your review settings.