Conversation
* update * fix: update * update * update * update * update * fix: opening threads * fix: rm threads dropdwon & added back link to bot page thread view page * fix: rm threads dropdwon & added back link to bot page thread view page * fix: update * fix: added back to profile page * fix: added sticky and color
…ock & clipboard hook (#425) * fix: codeblock ctas * fix: ts build
…426) * fix: css handleCLick condition * fix: get latest search params, continuous thread * fix(impr): all messages sorting * perf(impr): sign in & up redirection tweak * perf(impr): mobile chat css
…ck (#432) * refactor: use chat and continue generation * fix: uniq slug and id gen (#433) * fix: uniq thread + msg slug gen * style: formatting * fix: thread user attachments state upt * perf: impr thread component at all pages + mobile tweaks * refactor: thread-component card * chore: restore continue generation v1 * feat(impr): thread component card * fix: admin panel n actions * fix: fetch getThreads * chore: continue conversation v1.2 * chore: continue and update thread content * chore: add ui control continue generation state * chore: fix infinity loop * chore(impr): enable upt msg table permission * fix: seo thread fetch * chore: style formating * fix(impr): continued thread title + thread component reusability * chore: refactor loadings + extending sonners --------- Co-authored-by: bran18 <andreyfdez18@gmail.com> --------- Co-authored-by: Roberto Lucas <andler@bitcash.org>
* feat: add gemini provider * chore: update icons
* feat(wip): impr continuing thread tags + accordion first msg toggle * feat(impr): continuing thread tags + accordion at first message + header mobile tweak * style(impr): mobile thread-component x-axis space * perf(style): coderabbitai feedbacks * fix: css typo * perf: sendMessageFromResponse clicked guard + continued thread tags label tweak * chore: user thread panel clean up * fix: user-thread-panel infinite loader * perf: impr shared accordion animation and ux * style: defaultAccordionState comments loc * fix: record type warning, hasura updateMessage * fix: getThread user data, shared-accordion
…bels, parent thread guard
* update * fix: update * update * update * update * update * refactor: profile page threads pop up * fix: update config * fix: update * fix: update * fix: make profile page scroll on hero * fix: bot make popup and scroll * fix: make profile page sidebar scroll independently * fix: make profile page sidebar scroll independently * fix: check the category along the chatbot when it's not checked * fix: check the category along the chatbot when it's not checked --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> Co-authored-by: Roberto Lucas <andler@bitcash.org>
* feat-add-models * feat-add-models * feat-add-models * chore: add model * fix: typo * chore: add toggler color
… seeds (#447) * feat(wip): thread llm context, prev questions * fix: previousQuestionsString slice * fix: clickedContentId in followingQuestionsPrompt * feat: isContinued + model type in message table * fix: ts typo + sendMessageFromResponse callback call * fix: ts typo
* fix(wip): bot profile thread list * style: formatting
* fix: new chat state reset * fix: genql gen + share link check * fix: og img * fix: duplicate role permission in msg table
* chore: restore base version * chore: add new logic and hooks * chore: fix providers file * chore: improve continuation prompt * chore: add exlucision flag * chore: add better handler * chore: updated flow + experimental delay * chore: extended time * chore(impr): streamDelayMs experimental feat flag * style: formatting --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com>
* fix: profile sidebar cat opt render * chore: clean-up
…ess and type support (#456) * fix: slugify fn * chore: devMode logs
* fix: slugify first request delay incr + genql ts, seeds & model migration upt * fix: create thread & msg ts
* update * fix: update * update * update * update * update * fix: use the user avatar or robohash * fix: added avater to user menu * fix: user avatar * fix: reset search input when filter by category or chatbot * fix: personal chat browse provider + username chk in sign up * chore: clean duplicated if condition signup --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com>
* impr: continuation logic flow * impr: continuation logic flow * chore: update createImprovementPrompt * chore: upt logs --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com>
…gic (#462) * feat: models table * style: formatting * fix: continuation accordion content * fix: sql + metadata typo
* chore: enable twitter pixel track * perf(impr): twitter ads availability + dynamic config
* fix(wip): subscriptions page render * feat(impr): profile navigation + page ui tweaks * style: lintin + formatting * style(css): nav links px on mob * fix: goToProfile in mob prof sidebar * fix: build * fix: thread popup opening at nav * chore: enable preferences nav on prod
* feat: add image generation support - gemini provider * chore: add mineType * chore: add conditional checks
* chore: hasura, set icl seeds chunks * chore: track backup icl seed loc to lfs * chore(seeds): uncomment phase 3 topics & add new chatbots + icl metadata rel * chore: upt phase 3 init config seeds, adding rel * fix: example seeds integrity * test: incr hasura max req body * revert: cloudbuild og config * chore: restore skipped seed lines
* fix: thread list render states * chore: linting & format * fix: thread pop-up on refresh * fix: user table selection
Reviewer's GuideThis PR implements end-to-end user deletion flows, refactors profile sidebar and routing, centralizes thread-popup logic, enhances the thread visibility hook, integrates account-deletion checks in sign-in, adds AI image generation support, streamlines subscription components, and updates service methods, configuration, and migrations accordingly. Sequence Diagram: User Account Deletion Request ProcesssequenceDiagram
actor User
participant PrefSection as PreferenceSection
participant AlertDialog as Confirmation Dialog
participant HasuraSVC as Hasura Service
participant NextAuth
User->>PrefSection: Clicks "Delete Account"
PrefSection->>PrefSection: executeButton("delete_account")
PrefSection->>AlertDialog: Opens confirmation
AlertDialog-->>User: Shows "Are you sure?" message
User->>AlertDialog: Clicks "Delete"
AlertDialog->>PrefSection: handleDelete()
PrefSection->>PrefSection: requestUserAccountDelete()
PrefSection->>HasuraSVC: updateUserDeletionRequest(userId, jwt)
HasuraSVC->>HasuraSVC: Update user.deletionRequestedAt = now()
HasuraSVC-->>PrefSection: Success
PrefSection->>NextAuth: signOut({ callbackUrl: '/' })
NextAuth-->>User: User signed out, redirected
Sequence Diagram: Sign-In Process with Account Deletion ChecksequenceDiagram
actor User
participant SignInFormComp as SignInForm
participant NextAuthSVC as NextAuth.signIn
participant HasuraSVC as Hasura Service
participant DeletionDialog as DeletionRequest Dialog
participant Router
User->>SignInFormComp: Submits email and password
SignInFormComp->>NextAuthSVC: signIn('credentials', {email, password})
alt Authentication Fails
NextAuthSVC-->>SignInFormComp: Error
SignInFormComp-->>User: Shows error message
else Authentication Succeeds
NextAuthSVC-->>SignInFormComp: Success (session created)
SignInFormComp->>HasuraSVC: getUserByEmail(email)
HasuraSVC-->>SignInFormComp: User data (including deletionRequestedAt)
alt User.deletionRequestedAt is set
SignInFormComp->>DeletionDialog: Opens, shows deletion info and remaining days
DeletionDialog-->>User: Displays options (Cancel Request / Go Back)
else User.deletionRequestedAt is null
SignInFormComp->>Router: router.push('/c')
Router-->>User: Redirected to dashboard
end
end
Sequence Diagram: AI Image Generation and DisplaysequenceDiagram
actor User
participant ChatInput
participant MBChatProvider
participant AIService as AI Service (e.g., Gemini)
participant ChatMessageComp as ChatMessage
participant GeneratedImageComp as GeneratedImage
User->>ChatInput: Enters prompt for image generation (or uses ImageGeneratorDialog)
ChatInput->>MBChatProvider: appendWithMbContextPrompts(message, {files: [...]})
note right of MBChatProvider: If ImageGeneratorDialog used, prompt is already formatted for image gen.
MBChatProvider->>AIService: createResponseStream(prompt, model with IMAGE modality)
AIService-->>MBChatProvider: Streamed response (text part, image part with base64 data)
MBChatProvider->>MBChatProvider: saveMessagesToDB (message with content and image parts)
MBChatProvider-->>ChatMessageComp: Renders new message
ChatMessageComp->>ChatMessageComp: Calls ImagesSection()
ChatMessageComp->>ai_helpers: hasImageGeneration(message)
ai_helpers-->>ChatMessageComp: true
ChatMessageComp->>ai_helpers: extractImageContent(message)
ai_helpers-->>ChatMessageComp: Image data parts
ChatMessageComp->>GeneratedImageComp: Renders each image
GeneratedImageComp-->>User: Displays generated image(s)
ER Diagram: Updates to User Table for Deletion FeatureerDiagram
User {
string userId PK
string email
string name
string role
string slug
timestamp date_joined
timestamp last_login
timestamp deletionRequestedAt "Nullable - NEW"
}
note for User "Added 'deletionRequestedAt' to track account deletion requests."
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis update introduces new features, refactors user and thread management, enhances UI components, and restructures database seed and migration scripts. Key changes include improved admin and subscription flows, image generation and rendering in chat, expanded user deletion logic, and streamlined sidebar/profile navigation. Several database seed files are replaced or reorganized, and new cron jobs and redirect rules are added. Changes
Sequence Diagram(s)Account Deletion Cron Job FlowsequenceDiagram
participant Cron as Cron Scheduler
participant API as /api/cron/delete-requested-accounts
participant Hasura as Hasura Client
Cron->>API: Trigger GET /api/cron/delete-requested-accounts
API->>Hasura: Query users with deletionRequestedAt <= 30 days ago
Hasura-->>API: Return user IDs
alt No users found
API-->>Cron: 200 OK (no users to delete)
else Users found
API->>Hasura: Delete threads and users for found IDs
Hasura-->>API: Return affected rows
API-->>Cron: 200 OK (deleted users and threads count)
end
User-Initiated Account Deletion (Preferences)sequenceDiagram
participant User
participant UI as PreferenceSection
participant Hasura as Hasura Service
participant Auth as Auth System
User->>UI: Click "Delete Account"
UI->>UI: Show confirmation dialog
User->>UI: Confirm deletion
UI->>Hasura: updateUserDeletionRequest (set deletionRequestedAt)
Hasura-->>UI: Success/Failure
alt Success
UI->>Auth: Sign out and redirect
else Failure
UI->>User: Show error notification
end
Sign-In With Deletion Request HandlingsequenceDiagram
participant User
participant SignInForm
participant Hasura
participant UI as DeletionRequest Modal
User->>SignInForm: Submit credentials
SignInForm->>Hasura: getUserByEmail
Hasura-->>SignInForm: Return user data
alt User not found
SignInForm-->>User: Show "Sign up" error
else Deletion requested
SignInForm-->>UI: Show DeletionRequest modal
else Normal user
SignInForm-->>User: Redirect to dashboard
end
Image Generation in ChatsequenceDiagram
participant User
participant ImageGenDialog
participant Chat as useMBChat
participant UI as ChatMessage
User->>ImageGenDialog: Open dialog, input description/style/detail
ImageGenDialog->>Chat: Append image generation prompt
Chat->>UI: Render chat message with generated images
UI->>User: Show images, allow download
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
apps/masterbots.ai/app/api/chat/models/models.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct. The config "next/core-web-vitals" was referenced from the config file in "/apps/masterbots.ai/.eslintrc.json". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. apps/masterbots.ai/app/actions/ai-main-call.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct. The config "next/core-web-vitals" was referenced from the config file in "/apps/masterbots.ai/.eslintrc.json". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. apps/masterbots.ai/app/api/cron/delete-requested-accounts/route.tsOops! Something went wrong! :( ESLint: 8.57.1 ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct. The config "next/core-web-vitals" was referenced from the config file in "/apps/masterbots.ai/.eslintrc.json". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
@coderabbitai review |
There was a problem hiding this comment.
Pull Request Overview
This PR cleans up several seed files by removing outdated Git LFS metadata, adds a new column (deletion_requested_at) to the public.user table, updates permissions accordingly, and introduces new model definitions in the migrations.
- Removed Git LFS pointer metadata from various seed SQL files.
- Updated seed file hashes and sizes where applicable.
- Added a new column to public.user with corresponding permission updates and introduced new model variants in migrations.
Reviewed Changes
Copilot reviewed 106 out of 106 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| apps/hasura/seeds/masterbots/*.sql | Removed Git LFS metadata lines from seed files. |
| apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/up.sql | Added the deletion_requested_at column to the public.user table. |
| apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/down.sql | Contains a placeholder for a down migration requiring review. |
| apps/hasura/migrations/masterbots/1745471202166_create_table_public_models/up.sql | Updated model insertions to include a new model definition. |
| apps/hasura/migrations/masterbots/1718416395664_create_table_models_enum/up.sql | Added a new model enum tuple for the gemini-2.0-flash-exp model. |
| apps/hasura/metadata/databases/masterbots/tables/public_user.yaml | Updated select_permissions to include the new deletion_requested_at column. |
...s/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/down.sql
Show resolved
Hide resolved
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 21
🔭 Outside diff range comments (8)
apps/hasura/metadata/databases/masterbots/tables/public_user.yaml (1)
162-199:⚠️ Potential issueMissing update permission for deletion_requested_at
The update permissions for both moderator and user roles don't include the new
deletion_requested_atcolumn, which means users won't be able to cancel their deletion requests, and moderators won't be able to manage them.Add the
deletion_requested_atcolumn to the update permissions for both roles:- role: moderator permission: columns: - bio - date_joined - email - favourite_topic - get_free_month - is_blocked - is_verified - last_login + - deletion_requested_at - pro_user_subscription_id - profile_picture - role - slug - user_id - usernameAnd similarly for the user role:
- role: user permission: columns: - bio - favourite_topic - get_free_month - last_login - password + - deletion_requested_at - pro_user_subscription_id - profile_picture - role - slug - usernameapps/masterbots.ai/components/routes/thread/thread-list.tsx (1)
72-84:⚠️ Potential issueLoading flag is ineffective – the flag is reset synchronously
activateThreadPopupsetsloadingThreadtotrue, immediately flips it tofalsein the same tick, so the skeleton never appears.
Either make the functionasyncand await a real asynchronous task, or drop the loading flag entirely.-const activateThreadPopup = (thread: Thread) => { - try { - setLoadingThread(true) - setActiveThread(thread) - setIsOpenPopup(true) - } catch (error) { - ... - } finally { - setLoadingThread(false) - } -} +const activateThreadPopup = (thread: Thread) => { + setActiveThread(thread) + setIsOpenPopup(true) +}apps/masterbots.ai/components/layout/header/user-menu.tsx (1)
78-86:⚠️ Potential issueGuard against empty image
srcto avoid Next.js runtime errorWhen
data?.profilePictureis falsy you fall back to an empty string.
<Image>throws ifsrcis an empty string, so the component will crash while the user data is loading.- <Image … src={data?.profilePicture ? data.profilePicture : ''} … /> + {data?.profilePicture ? ( + <Image … src={data.profilePicture} … /> + ) : ( + /* fallback avatar (initials) or a blurred placeholder */ + )}Alternatively, move the
user?.imagecondition inside and only render<Image>whendata?.profilePictureis truthy.apps/masterbots.ai/components/layout/sidebar/profile-sidebar.tsx (1)
57-65:⚠️ Potential issueGuard against missing
user.slugto avoid malformed routes
goToProfileblindly interpolatesuser.sluginto the URL.
Ifslugisundefined(possible when the auth provider hasn’t populated the field yet, or the type definition doesn’t include it), the app will navigate to/u/undefined/t, breaking the profile page.- router.push(`/u/${user.slug}/t`) + if (!user.slug) { + console.error('User slug is missing – aborting navigation') + return + } + router.push(`/u/${user.slug}/t`)apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx (1)
115-122:⚠️ Potential issuePotential runtime error:
getThreadsresult shape differs from state shape
getThreadspreviously returnedThread[]; the new state expects{ threads, count }.
Passing the array directly tosetThreadsStatewill break rendering or TypeScript compilation.Ensure the service returns the new shape or adapt the setter:
-const fetchedThreads = await getThreads({ … }) -if (fetchedThreads) { - setThreadsState(fetchedThreads) -} +const fetchedThreads = await getThreads({ … }) +if (fetchedThreads) { + setThreadsState({ + threads: fetchedThreads.threads ?? fetchedThreads, // fallback for old shape + count: fetchedThreads.count ?? fetchedThreads.length, + }) +}apps/masterbots.ai/services/hasura/hasura.service.ts (3)
274-303: 🛠️ Refactor suggestion
⚠️ Potential issuePrivate / un-approved threads can slip through &
domainfilter silently ignoredThe new
baseThreadsArgumentsno longer appendsisPublic/isApprovedconstraints when the caller is not filtering byuserId.
As a consequence, a public browse page that supplies onlychatbotName,categoryId, ordomainwill now return all threads for that bot/category – including drafts and content awaiting moderation.In addition, when the caller passes only
domain, thewhereclause is not produced because the outer conditionchatbotName || categoryIdevaluates tofalse, so thedomainfilter is dropped entirely.const baseThreadsArguments = { - ...(chatbotName || categoryId + ...(chatbotName || categoryId || domain // keep domain-only queries ? { where: { chatbot: { @@ ...(userId ? { userId: { _eq: userId } } : {}), + // apply default visibility rules for anonymous/non-admin users + ...(!userId && { + isPublic: { _eq: true }, + isApproved: { _eq: true }, + }), }, } - : userId - ? { where: { userId: { _eq: userId } } } - : {}), + : userId // personal dashboard + ? { where: { userId: { _eq: userId } } } + : { + where: { // generic browse + isPublic: { _eq: true }, + isApproved: { _eq: true }, + }, + }), }This preserves the old safety net while still allowing admins (or the owner) to bypass it explicitly.
Please adjust accompanying unit / integration tests accordingly.Also applies to: 356-366
760-768:⚠️ Potential issue
isAdminModeexposes unapproved threads without authentication & lacks default
isAdminModecan be set totruefrom the browser while the client is instantiated withoutjwt/adminSecret, effectively requesting un-approved data as an anonymous user. Unless Hasura row-level-permissions block it, this is a privilege escalation vector.- The parameter is currently required. Mark it as optional (
isAdminMode = false) to avoidundefined→ falsey bugs and improve DX.-export async function getBrowseThreads({ +export async function getBrowseThreads({ @@ - isAdminMode, + isAdminMode = false,When
isAdminModeis true, enforce proper credentials:if (isAdminMode && !jwt) { throw new Error('Admin mode requires authentication'); } const client = getHasuraClient({ jwt });Finally, remember to update the type definition in
hasura.service.type.ts.Also applies to: 820-827
1159-1175: 💡 Verification agent🧩 Analysis chain
Empty JWT token & broad return shape introduce security / DX issues
Using
getHasuraClient({ jwt: '' })sends an empty bearer token header (Authorization: Bearer).
– This is equivalent to anonymous access but confuses observability & cache layers.
– Simply omit the field:getHasuraClient({}).Function name implies a single record, but you return
{ users: User[] }.
Either rename togetUsersByEmailor returnuser[0](with null-safety).Suggested minimal patch:
-const client = getHasuraClient({ jwt: '' }) +const client = getHasuraClient({}) // … -return { users: user as User[] } +return { user: user[0] as User | null }Also consider guarding the request with
adminSecret(or appropriate role) because email look-ups can reveal account existence to unauthorised callers.
The repository files aren’t available to inspect right now—let’s load the full
getUserByEmailimplementation to confirm how it returns values. Please run:
🏁 Script executed:
#!/bin/bash # Show the full getUserByEmail function (with 20 lines of context after start) rg -n -A20 "export async function getUserByEmail" apps/masterbots.ai/services/hasura/hasura.service.tsLength of output: 670
Let’s verify how
getHasuraClientis defined—specifically whether itsjwtoption is optional and how headers are set. Please run:
🏁 Script executed:
#!/bin/bash # Find its definition and inspect parameter defaults rg -n -C5 "export function getHasuraClient" -g "*.ts" rg -n -C5 "export const getHasuraClient" -g "*.ts"Length of output: 817
To inspect how
getHasuraClienthandles its parameters and headers, dump its full definition:
🏁 Script executed:
#!/bin/bash # Print getHasuraClient implementation sed -n -e '/export function getHasuraClient/,/^}/p' packages/mb-lib/src/hasura/hasura.lib.tsLength of output: 1150
Remove JWT override & tighten return shape
The
getHasuraClientfunction no longer accepts ajwtparameter—calling it with an object is ignored (or will error). To use the configured admin secret, invoke it without arguments. Also,getUserByEmailreturns a list (users: User[]) but its name implies a single user. Align these by either renaming the function or returning only the first match.• File: apps/masterbots.ai/services/hasura/hasura.service.ts
• Lines: 1159–1177Suggested patch:
- const client = getHasuraClient({ jwt: '' }) + const client = getHasuraClient() // … - return { users: user as User[] } + return { user: (user[0] as User) || null }Consider adding service-level authorization checks to prevent unauthorised email enumeration.
♻️ Duplicate comments (1)
apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/down.sql (1)
1-4: Incomplete down migration scriptThe down migration script contains only comments and doesn't implement the actual SQL command to drop the column.
Implement a proper down migration to drop the 'deletion_requested_at' column:
-- Could not auto-generate a down migration. -- Please write an appropriate down migration for the SQL below: -- alter table "public"."user" add column "deletion_requested_at" timestamptz -- null; +ALTER TABLE "public"."user" DROP COLUMN IF EXISTS "deletion_requested_at";
🧹 Nitpick comments (30)
apps/masterbots.ai/package.json (1)
110-111: Pin @types/bun to a specific version for reproducible builds
The"latest"tag can unexpectedly introduce breaking changes when new type definitions are published. Consider aligning this with the monorepo’s TypeScript version (e.g.^5.8.2) or another fixed version to ensure consistency across environments.packages/mb-genql/package.json (1)
25-25: Ensure consistency across GenQL-related packages
You’ve pinnedgenqlto^2.0.1but left@genql/cliand@genql/runtimeat"latest". This mismatch can lead to runtime or CLI incompatibilities. Consider aligning all three to the same major version range (e.g.^2.0.1) to guarantee compatibility.package.json (1)
27-27: Align root GenQL devDependency with workspace packages
The mainpackage.jsonnow pins"genql": "^2.0.1". To maintain version harmony, update@genql/cliand@genql/runtimein this file (and across other workspaces) to the same semver range, avoiding potential discrepancies during CI or local development.apps/masterbots.ai/components/routes/profile/user-thread-list.tsx (1)
15-15: Extra blank line after early return.
The inserted blank line afterif (!user) return nullis an unnecessary formatting change that may disrupt consistency with surrounding components. Consider removing it to adhere to the established style.apps/masterbots.ai/lib/models.tsx (1)
26-30: Consider adding braces to the multi-lineiffor clarity
While the current single-statementifis valid, wrapping thereturnin braces improves readability and consistency:-if ( - model.startsWith('openai') || - model.startsWith('gpt') || - model.startsWith('o4-mini') -) - return <IconOpenAI /> +if ( + model.startsWith('openai') || + model.startsWith('gpt') || + model.startsWith('o4-mini') +) { + return <IconOpenAI /> +}apps/masterbots.ai/components/layout/sidebar/sidebar.tsx (2)
43-43: Unify Tailwind class for min-height inheritance
Other components usemin-h-inheritrather than the bracketedmin-h-[inherit]. For consistency, consider:- 'min-h-[inherit] h-full flex flex-col z-40', + 'min-h-inherit h-full flex flex-col z-40',
50-52: Enhance accessibility by adding an aria-label to the<nav>
The<nav>wrapper currently has no accessible name. Recommend:-<nav className="pt-4 pb-20 size-full scrollbar"> +<nav aria-label="Sidebar categories" className="pt-4 pb-20 size-full scrollbar">This provides screen readers with context about the navigation region.
apps/masterbots.ai/app/u/[userSlug]/s/subs/page.tsx (1)
1-5: Function name doesn't match component responsibilityThe function is named
PreferencePagebut it renders subscription content via theSubscriptionPageComponent. Consider renaming this function toSubscriptionPageto better reflect its purpose and maintain consistency between component names and their responsibilities.-export default async function PreferencePage() { +export default async function SubscriptionPage() { return <SubscriptionPageComponent /> }apps/masterbots.ai/components/routes/subscription/payment-information.tsx (1)
28-29: Add error handling for potentially undefined session user.The component now correctly uses session-based authentication instead of getting user data from the payment hook. However, there's no protection against a potentially undefined session when accessing the user email in the Stripe confirmation token creation.
Consider adding a null check before using the user email:
-const user = session?.user as User +const user = session?.user as User | undefined const handlePaymentSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault() handleSetLoading(true) if (!stripe || !elements) { handleSetLoading(false) handleSetError('Stripe.js and Element has not loaded') return } + if (!user?.email) { + handleSetLoading(false) + handleSetError('User email is required') + return + }Also applies to: 37-40
apps/masterbots.ai/components/routes/preferences/preferences.tsx (1)
8-14: Consider refactoring the filtering logic for better readability.While the filtering logic works correctly, the conditional expression is complex and could be clearer. Consider separating it into more readable conditions or using constants for the section titles to reduce the risk of errors if preference titles change.
-const filteredPreferences = preferences.filter( - (section) => - ((section.title === 'General' || - section.title === 'Thread Preferences') && - appConfig.features.devMode) || - section.title === 'Danger Zone', -) +const DEV_ONLY_SECTIONS = ['General', 'Thread Preferences'] +const ALWAYS_VISIBLE_SECTIONS = ['Danger Zone'] + +const filteredPreferences = preferences.filter((section) => + (DEV_ONLY_SECTIONS.includes(section.title) && appConfig.features.devMode) || + ALWAYS_VISIBLE_SECTIONS.includes(section.title) +)apps/masterbots.ai/components/routes/subscription/plans.tsx (1)
73-73: Add null check for session dataWhile you've provided empty default values for email and name, the functions that use this data might expect valid user information. Consider adding validation before calling these functions with potentially empty values.
- const del = await handleDeleteCustomer(email) + if (email) { + const del = await handleDeleteCustomer(email) + if (del) return router.push('/c') + } else { + return router.push('/c') + } - if (del) return router.push('/c')Similarly, for the handleSubscription call:
const data = { planId: paymentPlan?.id, trialPeriodDays: paymentPlan?.recurring?.trial_period_days || 0, automatic_payment_methods: { enabled: true, }, - email, - name: name as string, + email: email || '', + name: name || '', }Also applies to: 121-123
apps/masterbots.ai/components/routes/subscription/subscription-page.tsx (2)
13-16: Remove stale commented-out code or convert to a TODODead code tends to linger and confuses future maintainers. If you really need to keep the alternate redirect flow, capture it in a proper
TODO:comment with context; otherwise delete lines 13-15.
10-12:handleOpenSubscriptionStepstoggles but recreates on every renderThe handler is re-created on each render which can cause unnecessary re-renders downstream (e.g., if passed to memoised children). It’s cheap to wrap it in
useCallback.-import { useState } from 'react' +import { useState, useCallback } from 'react' -const handleOpenSubscriptionSteps = () => { - setOpenSubscriptionSteps(!openSubscriptionSteps) -} +const handleOpenSubscriptionSteps = useCallback( + () => setOpenSubscriptionSteps((prev) => !prev), + [], +)Also applies to: 33-41
apps/masterbots.ai/components/auth/deletion-request.tsx (1)
58-60: Dialog is permanently open & cannot be dismissed
open={true}with anonOpenChangethat only logs prevents any way to close the modal (e.g., Escape key or clicking outside).
If the intent is to force the user to decide, route them away after cancellation or sign-out; otherwise make the dialog controllable:-<Dialog open={true} onOpenChange={() => console.log('Dialog closed')}> +<Dialog open onOpenChange={() => { /* optional redirect */ }}>Consider removing the prop altogether and letting the component caller decide the open state.
apps/masterbots.ai/lib/helpers/ai-helpers.ts (1)
302-312: Replaceanywith a typed helper & narrow return payloadThe helper currently suppresses type-checking (
// biome-ignore … noExplicitAny) and exposes the rest of the codebase to silent type errors.-// biome-ignore lint/suspicious/noExplicitAny: <explanation> -export function extractImageFiles(files: any[] | undefined) { +interface RawFile { + mimeType?: string; + base64: string; + uint8Array: Uint8Array; +} + +export function extractImageFiles(files?: RawFile[]): { + base64: string; + uint8Array: Uint8Array; + mimeType: string; +}[] { if (!files || !Array.isArray(files)) return []Typing the argument/return value prevents accidental misuse (e.g. passing a single object or a string).
apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx (1)
239-246: Consider addingisAdminModeto the dependency array
threadVisibilityStateis derived fromisAdminMode. WhenisAdminModetoggles, butthreadVisibilityStatehas not yet updated, this effect may miss the latest change. Adding it ensures state stays in sync:-}, [threadVisibilityState]) +}, [threadVisibilityState, isAdminMode])This is a minor resilience improvement; ignore if
threadVisibilityStatealready captures everyisAdminModetransition internally.apps/masterbots.ai/components/layout/profile/profile-page-sidebar.tsx (4)
26-35: Shadowed variable name reduces clarity
const { user, error } = await getUserInfo(...)re-uses the identifieruserthat will later become the value returned from theuseAsync. Although legal, the shadowing (inner and outeruser) is easy to mis-read and complicates debugging.- const { user, error } = await getUserInfo(userSlug as string) + const { user: fetchedUser, error } = await getUserInfo(userSlug as string) ... - return user + return fetchedUser
37-42:sameUserreferenced before initialisation
handleToggleThreadscloses oversameUser, but the constant is declared after the function. At runtime this works (the binding exists) yet the value is stillundefineduntil the next render, making the guard ineffective on first mount. Move thesameUserdeclaration above the handler or compute it inside the callback.
60-65: Key check for SPACE is incorrect
KeyboardEvent.keyfor the space bar is' '(single space) or historically'Spacebar', not'Space'. The guard currently never triggers, so the sidebar can’t be toggled with the space bar.-if (e.key === 'Enter' || e.key === 'Space') { +if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') {
92-101: UseLinkinstead of raw<a>for client-side navigation
Within a Next.js app router context,<Link>preserves SPA behaviour and pre-fetching. Swapping to<Link href=...>prevents full page reloads and maintains correct routing state.apps/masterbots.ai/lib/threads.ts (2)
128-137: EmptythreadSlugleads to inefficient query
When none of the route branches setsthreadSlug,getThread({ threadSlug: '' })still fires a network request that will always returnnull. Add an early return to save a round-trip.if (!threadSlug) return
153-158: Remove strayconsole.logbefore production
Leaving debugging logs in bundled code bloats the console and may leak PII (the slug). Please delete or guard withif (process.env.NODE_ENV === 'development').apps/masterbots.ai/lib/constants/preferences.ts (2)
24-25: Consider removing redundant type assertions
itemsis already typed asPreferenceItemType[]by virtue of the parent object’s structure, and the finalas constcast is enough to keep literal types. Keeping the extraas PreferenceItemType[]casts is harmless but adds noise and can sometimes mask missing required keys because the cast overrides structural checks.- ] as PreferenceItemType[], + ],Same applies to the other sections.
If you rely onas constto preserve literal buttonId strings for discriminated unions, consider casting only the outer array:export const preferences = [ /* … */ ] as const satisfies readonly { /* explicit shape here if needed */ }Also applies to: 41-42, 113-113
100-110: EnsurebuttonIdstrings remain unique & strongly-typed
'delete_account'and'delete_threads'look fine now, but because they are plain strings there’s no compiler guarantee against accidental reuse or typos in callers (e.g.'delete_threds').
You could extract them to aconst enumor a string-literal union:export const enum DangerButtonId { DeleteAccount = 'delete_account', DeleteThreads = 'delete_threads', } buttonId: DangerButtonId.DeleteAccountand reference the same union in the consuming component to get full type-safety.
apps/masterbots.ai/components/layout/header/user-menu.tsx (2)
130-147: Disable unavailable links instead of preventing defaultRendering an anchor and then
preventDefault()whendevModeis off still lets screen-readers announce it as an active link and breaks expected keyboard behaviour.Consider:
- <Link href={appConfig.features.devMode ? … : '#'} … onClick={…}> + {appConfig.features.devMode ? ( + <Link href={`/u/${user.slug}/s/pref`} …> + Preferences <SettingsIcon …/> + </Link> + ) : ( + <span className="flex w-full gap-4 px-0 text-sm opacity-50 cursor-not-allowed"> + Preferences <SettingsIcon …/> + </span> + )}This keeps semantics correct and avoids unnecessary
preventDefaultlogic.
48-65: Abort stale fetch requests to avoid memory leaksIf the component unmounts before
getUserInfoFromBrowseresolves,setDatawill try to set state on an unmounted component. Wrap the fetch in an abortable controller or track a mounted flag:React.useEffect(() => { if (!user?.slug) return let cancelled = false ;(async () => { try { const userData = await getUserInfoFromBrowse(user.slug!) if (!cancelled) setData(userData as User) } catch (e) { /* … */ } })() return () => { cancelled = true } }, [user?.slug])apps/masterbots.ai/components/routes/preferences/preference-section.tsx (2)
90-124: Duplicate deletion logic could be consolidated
requestUserAccountDeleteandhandleDeleteThreadsshare nearly identical JWT / error-handling scaffolding. Extract a generic helper to DRY up the component and make future maintenance easier:async function callDeletion<T>( fn: (args: {userId: string; jwt: string}) => Promise<T>, successMsg: string ) { … }Then invoke with the specific mutation.
This keeps the component lean and reduces the risk of inconsistencies (e.g. different Sonner messages, typo in “deletion successfully.”).
158-166: Provide clearer destructive action affordancesWhile the spinner disables the button, users can still close the dialog with the
Cancelbutton, potentially leavingisRemovePendingstuck if the mutation races.
Either:
- Disable the whole dialog while pending, or
- Keep the dialog open until the promise resolves and show a success / error state inside.
This improves feedback and prevents confusing intermediate UI states.
apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx (2)
64-71: State setter name and shape mismatch hinder readability
setThreadsnow manages an object ({ threads, count }), but the setter is still named as if it sets an array. Renaming improves clarity and prevents accidental misuse.-const [threadsState, setThreads] = useState<{ … }>(…) +const [threadsState, setThreadsState] = useState<{ … }>(…)(remember to update all calls).
193-198:awaiton synchronous constant is unnecessary
botNamesis a plainMap, not a promise. Usingawaitadds pointless micro-tasks and misleads readers.-const botSlugs = await botNames +const botSlugs = botNames
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
⛔ Files ignored due to path filters (4)
bun.lockis excluded by!**/*.lockpackages/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 (99)
apps/hasura/metadata/databases/masterbots/tables/public_user.yaml(3 hunks)apps/hasura/migrations/masterbots/1718416395664_create_table_models_enum/up.sql(1 hunks)apps/hasura/migrations/masterbots/1745471202166_create_table_public_models/up.sql(1 hunks)apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/down.sql(1 hunks)apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/up.sql(1 hunks)apps/hasura/seeds/masterbots/1724269974513_init_config_seeds.sql(1 hunks)apps/hasura/seeds/masterbots/1724270512560_init_users_seeds.sql(1 hunks)apps/hasura/seeds/masterbots/1740386118928_init_domain_enum.sql(0 hunks)apps/hasura/seeds/masterbots/1740386119320_init_domain_enum.sql(1 hunks)apps/hasura/seeds/masterbots/1740386119321_init_chatbot_metadata_seeds.sql(1 hunks)apps/hasura/seeds/masterbots/1740386128297_init_category_enum.sql(0 hunks)apps/hasura/seeds/masterbots/1740386133107_init_subcategory_enum.sql(0 hunks)apps/hasura/seeds/masterbots/1740386141151_init_tag_enum.sql(0 hunks)apps/hasura/seeds/masterbots/1740386174715_init_example_pt_1.sql(0 hunks)apps/hasura/seeds/masterbots/1740386174815_init_example_pt_2.sql(0 hunks)apps/hasura/seeds/masterbots/1740386174915_init_example_pt_3.sql(0 hunks)apps/hasura/seeds/masterbots/1740386175015_init_example_pt_4.sql(0 hunks)apps/hasura/seeds/masterbots/1740386175115_init_example_pt_5.sql(0 hunks)apps/hasura/seeds/masterbots/1740386175215_init_example_pt_6.sql(0 hunks)apps/hasura/seeds/masterbots/1740386175315_init_example_pt_7.sql(0 hunks)apps/hasura/seeds/masterbots/1740386175415_init_example_pt_8.sql(0 hunks)apps/hasura/seeds/masterbots/1746466168385_init_category_enum.sql(1 hunks)apps/hasura/seeds/masterbots/1746466170867_init_subcategory_enum.sql(1 hunks)apps/hasura/seeds/masterbots/1746466178152_init_tag_enum_pt_1.sql(1 hunks)apps/hasura/seeds/masterbots/1746466178153_init_tag_enum_pt_2.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541637_init_example_pt_1.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541638_init_example_pt_2.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541639_init_example_pt_3.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541640_init_example_pt_4.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541641_init_example_pt_5.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541642_init_example_pt_6.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541643_init_example_pt_7.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541644_init_example_pt_8.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541645_init_example_pt_9.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541646_init_example_pt_10.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541647_init_example_pt_11.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541648_init_example_pt_12.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541649_init_example_pt_13.sql(1 hunks)apps/hasura/seeds/masterbots/1746466541650_init_example_pt_14.sql(1 hunks)apps/masterbots.ai/app/actions/ai-main-call.ts(1 hunks)apps/masterbots.ai/app/actions/subscriptions.ts(0 hunks)apps/masterbots.ai/app/api/chat/models/models.ts(1 hunks)apps/masterbots.ai/app/api/cron/delete-requested-accounts/route.ts(1 hunks)apps/masterbots.ai/app/api/cron/unverified-users/route.ts(0 hunks)apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/[threadSlug]/[threadQuestionSlug]/page.tsx(3 hunks)apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/[threadSlug]/page.tsx(3 hunks)apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/page.tsx(3 hunks)apps/masterbots.ai/app/c/p/page.tsx(1 hunks)apps/masterbots.ai/app/c/page.tsx(1 hunks)apps/masterbots.ai/app/layout.tsx(2 hunks)apps/masterbots.ai/app/u/[userSlug]/page.tsx(1 hunks)apps/masterbots.ai/app/u/[userSlug]/s/page.tsx(1 hunks)apps/masterbots.ai/app/u/[userSlug]/s/subs/page.tsx(1 hunks)apps/masterbots.ai/app/u/page.tsx(1 hunks)apps/masterbots.ai/auth.ts(2 hunks)apps/masterbots.ai/components/auth/deletion-request.tsx(1 hunks)apps/masterbots.ai/components/auth/signin-form.tsx(2 hunks)apps/masterbots.ai/components/layout/header/user-menu.tsx(4 hunks)apps/masterbots.ai/components/layout/profile/profile-page-sidebar.tsx(3 hunks)apps/masterbots.ai/components/layout/sidebar/profile-sidebar.tsx(5 hunks)apps/masterbots.ai/components/layout/sidebar/sidebar-category-general.tsx(1 hunks)apps/masterbots.ai/components/layout/sidebar/sidebar.tsx(1 hunks)apps/masterbots.ai/components/routes/browse/browse-list.tsx(2 hunks)apps/masterbots.ai/components/routes/chat/chat-message.tsx(5 hunks)apps/masterbots.ai/components/routes/chat/chat-panel.tsx(1 hunks)apps/masterbots.ai/components/routes/preferences/preference-section.tsx(1 hunks)apps/masterbots.ai/components/routes/preferences/preferences.tsx(1 hunks)apps/masterbots.ai/components/routes/profile/user-thread-list.tsx(1 hunks)apps/masterbots.ai/components/routes/subscription/checkout.tsx(3 hunks)apps/masterbots.ai/components/routes/subscription/payment-information.tsx(1 hunks)apps/masterbots.ai/components/routes/subscription/plans.tsx(4 hunks)apps/masterbots.ai/components/routes/subscription/subscription-page.tsx(1 hunks)apps/masterbots.ai/components/routes/subscription/subscription.tsx(2 hunks)apps/masterbots.ai/components/routes/subscription/succes-content.tsx(2 hunks)apps/masterbots.ai/components/routes/thread/thread-component.tsx(0 hunks)apps/masterbots.ai/components/routes/thread/thread-list.tsx(3 hunks)apps/masterbots.ai/components/routes/thread/thread-panel.tsx(2 hunks)apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx(10 hunks)apps/masterbots.ai/components/shared/generated-image.tsx(1 hunks)apps/masterbots.ai/components/shared/image-generator-dialog.tsx(1 hunks)apps/masterbots.ai/components/shared/theme-toggle.tsx(1 hunks)apps/masterbots.ai/components/ui/button.tsx(1 hunks)apps/masterbots.ai/lib/constants/preferences.ts(5 hunks)apps/masterbots.ai/lib/constants/prompts.ts(1 hunks)apps/masterbots.ai/lib/helpers/ai-helpers.ts(1 hunks)apps/masterbots.ai/lib/hooks/use-mb-chat.tsx(2 hunks)apps/masterbots.ai/lib/hooks/use-payment.tsx(0 hunks)apps/masterbots.ai/lib/hooks/use-sidebar.tsx(0 hunks)apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx(7 hunks)apps/masterbots.ai/lib/models.tsx(1 hunks)apps/masterbots.ai/lib/threads.ts(2 hunks)apps/masterbots.ai/package.json(1 hunks)apps/masterbots.ai/services/hasura/hasura.service.ts(9 hunks)apps/masterbots.ai/services/hasura/hasura.service.type.ts(1 hunks)apps/masterbots.ai/types/types.ts(1 hunks)apps/masterbots.ai/vercel.json(1 hunks)package.json(1 hunks)packages/mb-env/src/config.env.ts(1 hunks)packages/mb-genql/package.json(1 hunks)
💤 Files with no reviewable changes (17)
- apps/masterbots.ai/components/routes/thread/thread-component.tsx
- apps/masterbots.ai/lib/hooks/use-sidebar.tsx
- apps/masterbots.ai/app/api/cron/unverified-users/route.ts
- apps/hasura/seeds/masterbots/1740386175415_init_example_pt_8.sql
- apps/hasura/seeds/masterbots/1740386174715_init_example_pt_1.sql
- apps/hasura/seeds/masterbots/1740386175215_init_example_pt_6.sql
- apps/hasura/seeds/masterbots/1740386175115_init_example_pt_5.sql
- apps/masterbots.ai/app/actions/subscriptions.ts
- apps/hasura/seeds/masterbots/1740386174915_init_example_pt_3.sql
- apps/hasura/seeds/masterbots/1740386174815_init_example_pt_2.sql
- apps/hasura/seeds/masterbots/1740386141151_init_tag_enum.sql
- apps/hasura/seeds/masterbots/1740386118928_init_domain_enum.sql
- apps/hasura/seeds/masterbots/1740386128297_init_category_enum.sql
- apps/hasura/seeds/masterbots/1740386175015_init_example_pt_4.sql
- apps/hasura/seeds/masterbots/1740386133107_init_subcategory_enum.sql
- apps/masterbots.ai/lib/hooks/use-payment.tsx
- apps/hasura/seeds/masterbots/1740386175315_init_example_pt_7.sql
🧰 Additional context used
🧬 Code Graph Analysis (23)
apps/masterbots.ai/app/c/p/page.tsx (1)
apps/masterbots.ai/components/routes/subscription/subscription.tsx (1)
Subscription(44-81)
apps/masterbots.ai/components/shared/theme-toggle.tsx (1)
apps/masterbots.ai/lib/utils.ts (1)
cn(9-11)
apps/masterbots.ai/components/layout/sidebar/sidebar.tsx (2)
apps/masterbots.ai/components/layout/sidebar/sidebar-header.tsx (1)
SidebarHeader(6-12)apps/masterbots.ai/components/layout/sidebar/sidebar-category-general.tsx (1)
SidebarCategoryGeneral(6-28)
apps/masterbots.ai/components/routes/preferences/preferences.tsx (2)
apps/masterbots.ai/lib/constants/preferences.ts (1)
preferences(4-113)packages/mb-env/src/config.env.ts (1)
appConfig(2-51)
apps/masterbots.ai/components/layout/sidebar/sidebar-category-general.tsx (1)
apps/masterbots.ai/lib/memoized-markdown-components.tsx (1)
ul(132-136)
apps/masterbots.ai/app/u/[userSlug]/s/subs/page.tsx (2)
apps/masterbots.ai/app/u/[userSlug]/s/pref/page.tsx (1)
PreferencePage(3-9)apps/masterbots.ai/components/routes/subscription/subscription-page.tsx (1)
SubscriptionPageComponent(7-44)
apps/masterbots.ai/app/layout.tsx (1)
packages/mb-env/src/config.env.ts (1)
appConfig(2-51)
apps/masterbots.ai/lib/hooks/use-mb-chat.tsx (1)
packages/mb-env/src/config.env.ts (1)
appConfig(2-51)
apps/masterbots.ai/components/routes/subscription/payment-information.tsx (3)
apps/masterbots.ai/components/ui/wizard/index.tsx (1)
WizardStepProps(13-20)apps/masterbots.ai/auth.ts (1)
session(171-186)apps/masterbots.ai/lib/hooks/use-payment.tsx (1)
usePayment(53-59)
apps/masterbots.ai/components/routes/subscription/subscription-page.tsx (3)
apps/masterbots.ai/lib/memoized-markdown-components.tsx (2)
h1(71-86)p(62-68)apps/masterbots.ai/components/ui/button.tsx (1)
Button(71-71)apps/masterbots.ai/components/routes/subscription/subscription.tsx (1)
Subscription(44-81)
apps/masterbots.ai/app/u/[userSlug]/page.tsx (2)
apps/masterbots.ai/app/u/[userSlug]/s/page.tsx (1)
ProfilePageDefaultRedirect(4-8)apps/masterbots.ai/types/types.ts (1)
PageProps(276-286)
apps/masterbots.ai/auth.ts (1)
apps/masterbots.ai/services/hasura/hasura.service.ts (1)
getUserByEmail(1159-1182)
apps/masterbots.ai/app/u/[userSlug]/s/page.tsx (1)
apps/masterbots.ai/types/types.ts (1)
PageProps(276-286)
apps/masterbots.ai/app/c/page.tsx (2)
apps/masterbots.ai/components/routes/thread/thread-panel.tsx (1)
ThreadPanel(24-44)apps/masterbots.ai/lib/utils.ts (1)
isAdminOrModeratorRole(229-231)
apps/masterbots.ai/components/shared/image-generator-dialog.tsx (7)
apps/masterbots.ai/lib/hooks/use-mb-chat.tsx (1)
useMBChat(72-78)apps/masterbots.ai/lib/constants/prompts.ts (1)
createImageGenerationPrompt(232-240)apps/masterbots.ai/components/ui/dialog.tsx (5)
Dialog(115-115)DialogTrigger(124-124)DialogContent(117-117)DialogHeader(120-120)DialogTitle(123-123)apps/masterbots.ai/components/ui/button.tsx (1)
Button(71-71)apps/masterbots.ai/components/ui/label.tsx (1)
Label(38-38)apps/masterbots.ai/components/ui/input.tsx (1)
Input(25-25)apps/masterbots.ai/components/ui/select.tsx (5)
Select(111-111)SelectTrigger(117-117)SelectValue(118-118)SelectContent(112-112)SelectItem(114-114)
apps/masterbots.ai/components/routes/subscription/plans.tsx (1)
apps/masterbots.ai/auth.ts (1)
session(171-186)
apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/[threadSlug]/page.tsx (3)
apps/masterbots.ai/auth.ts (1)
session(171-186)apps/masterbots.ai/lib/utils.ts (2)
RoleTypes(227-227)isAdminOrModeratorRole(229-231)apps/masterbots.ai/components/routes/thread/thread-panel.tsx (1)
ThreadPanel(24-44)
apps/masterbots.ai/components/routes/subscription/checkout.tsx (1)
apps/masterbots.ai/auth.ts (1)
session(171-186)
apps/masterbots.ai/components/routes/subscription/succes-content.tsx (3)
apps/masterbots.ai/components/ui/wizard/index.tsx (1)
WizardStepProps(13-20)apps/masterbots.ai/lib/hooks/use-payment.tsx (1)
usePayment(53-59)apps/masterbots.ai/auth.ts (1)
session(171-186)
apps/masterbots.ai/components/routes/browse/browse-list.tsx (1)
apps/masterbots.ai/lib/threads.ts (1)
getOpeningActiveThreadHelper(53-162)
apps/masterbots.ai/lib/helpers/ai-helpers.ts (1)
packages/mb-genql/generated/schema.ts (1)
Message(906-934)
apps/masterbots.ai/lib/threads.ts (4)
packages/mb-genql/generated/schema.ts (1)
Thread(2206-2236)apps/masterbots.ai/lib/hooks/useSonner.tsx (1)
useSonner(42-130)apps/masterbots.ai/lib/utils.ts (1)
getRouteType(310-341)apps/masterbots.ai/services/hasura/hasura.service.ts (1)
getThread(381-486)
apps/masterbots.ai/lib/constants/preferences.ts (1)
apps/masterbots.ai/types/types.ts (1)
PreferenceItemType(399-409)
🔇 Additional comments (76)
apps/masterbots.ai/app/layout.tsx (2)
12-12: Twitter Ads tracking script implementation looks good.The implementation correctly uses the Next.js
Scriptcomponent to load the Twitter Ads pixel dynamically when enabled. The script is conditionally rendered based on the config flag and properly injects the campaign ID from the configuration.Also applies to: 18-27
65-65: Metadata base URL change improves configuration consistency.Changing from
VERCEL_URLtoBASE_URLaligns with standard environment variable naming conventions and likely provides better flexibility for different deployment environments.packages/mb-env/src/config.env.ts (2)
41-50: The new ads configuration section is well-structured.The implementation follows the existing pattern in the configuration file, with environment variables and appropriate defaults. This structure provides a clean way to manage ad-related settings.
47-47: Consider if a default campaign ID is appropriate.The Twitter Ads campaign ID has a hardcoded default of 'pngjn', unlike most other configuration values that default to empty strings. Verify if this is intentional or if it should follow the pattern of other configuration values.
apps/masterbots.ai/components/routes/chat/chat-panel.tsx (1)
128-128: Improved z-index value for proper UI layeringThe change from
z-[2]toz-20ensures the chat panel appears at the appropriate level in the UI stack, preventing potential overlap issues with other components.apps/hasura/migrations/masterbots/1745923775527_alter_table_public_user_add_column_deletion_requested_at/up.sql (1)
1-2:Details
✅ Verification successful
LGTM: Good addition for user deletion flow
The nullable
deletion_requested_attimestamp column is well-designed for tracking when users request account deletion, which will support the account deletion workflow.Run this script to verify this column is being properly used in relevant queries:
🏁 Script executed:
#!/bin/bash # Check how the deletion_requested_at column is used in queries rg -A 5 "deletion_requested_at" --glob "*.{ts,tsx,js,jsx,graphql,gql}"Length of output: 533
deletion_requested_at usage verified
The
deletion_requested_atcolumn is properly referenced in the user deletion flow. In particular:
- apps/masterbots.ai/services/hasura/hasura.service.ts:
updateUserDeletionRequestsets or clears this timestamp as expected.LGTM—good to merge.
apps/hasura/seeds/masterbots/1724270512560_init_users_seeds.sql (1)
2-3:Details
❓ Verification inconclusive
Verify updated LFS pointer integrity
The Git LFS pointer has been updated with a new SHA-256 hash and file size. Ensure the updated seed file content is properly synced and contains the expected data.
Run this script to check LFS status and verify the file is properly tracked:
🏁 Script executed:
#!/bin/bash # Check the status of LFS-tracked files git lfs status # List all LFS files in the repository git lfs ls-files | grep users_seedsLength of output: 224
🏁 Script executed:
#!/bin/bash # Locate the seed file in the repository FILE=$(fd 1724270512560_init_users_seeds.sql) if [[ -z "$FILE" ]]; then echo "Seed file not found." exit 1 fi echo "Located file: $FILE" echo "---- First 5 lines (LFS pointer header) ----" head -n 5 "$FILE" echo "---- Last 5 lines (size hash) ----" tail -n 5 "$FILE"Length of output: 939
Verify updated LFS pointer integrity
I’ve confirmed that the pointer header in
apps/hasura/seeds/masterbots/1724270512560_init_users_seeds.sql
matches the new SHA-256 and size. Please perform the following to ensure the true seed data is in place:
- Confirm
.gitattributesincludes an LFS filter for.sqlfiles (or this specific path).- Run
git lfs pull(orgit lfs fetch && git lfs checkout) to retrieve the real file.- Inspect the fetched content, for example:
and verify it contains the expected SQL seed statements rather than a pointer.git show HEAD:apps/hasura/seeds/masterbots/1724270512560_init_users_seeds.sql | head -n 20apps/masterbots.ai/types/types.ts (1)
400-400:Details
✅ Verification successful
Good addition for specific button identification
Adding the optional
buttonIdproperty toPreferenceItemTypeenables identifying specific dangerous operations like account deletion in the preferences UI.Let's check where this new property is being used:
🏁 Script executed:
#!/bin/bash # Find where buttonId is being referenced in the codebase rg -A 3 "buttonId" --glob "*.{ts,tsx}" # Look specifically for implementation in preference-related files rg -A 5 "buttonId.*delete" --glob "*.{ts,tsx}"Length of output: 2167
buttonId property correctly integrated
I’ve verified that the new optional
buttonIdonPreferenceItemTypeis being used in:
- apps/masterbots.ai/components/routes/preferences/preference-section.tsx for calling
executeButton(item.buttonId ?? '')- apps/masterbots.ai/lib/constants/preferences.ts where each dangerous-action preference (e.g.
delete_account,delete_threads) is assigned itsbuttonIdNo further changes needed.
apps/masterbots.ai/app/c/p/page.tsx (1)
32-32: Improved component encapsulation by removing prop drillingThe removal of props from the
Subscriptioncomponent is a good refactoring decision. The component now retrieves user data directly from the session usinguseSession()hook, which reduces prop drilling and centralizes user session management.apps/hasura/seeds/masterbots/1746466541650_init_example_pt_14.sql (1)
1-3: Appropriate use of Git LFS for large seed fileUsing Git LFS for managing this large seed file (~7.36 MB) is a good practice. This keeps the repository size manageable while still tracking the seed data in version control.
apps/hasura/seeds/masterbots/1740386119320_init_domain_enum.sql (1)
1-3: Consistent approach to enum seed file managementThe addition of this domain enum seed file using Git LFS maintains consistency with the project's approach to managing seed data. The systematic naming convention with timestamps helps track the evolution of seed data over time.
apps/hasura/seeds/masterbots/1746466541637_init_example_pt_1.sql (1)
1-3: Well-structured approach to large seed data managementThe addition of this large seed file (~26.2 MB) using Git LFS and breaking the overall dataset into multiple parts (pt_1 through pt_14) demonstrates good data management practices. This approach makes the seed data more manageable while keeping it under version control.
apps/masterbots.ai/components/routes/profile/user-thread-list.tsx (1)
17-17: Verify removal of vertical padding (pb-10).
Thepb-10class was dropped from the outer<div>, which may affect the vertical spacing on the profile thread list. Please confirm that the layout and responsive design remain as intended, or provide alternative spacing adjustments if needed.apps/hasura/seeds/masterbots/1746466541648_init_example_pt_12.sql (1)
1-4: LFS pointer file, no SQL content to review.
This file is a Git LFS pointer for large seed data; it contains no SQL statements in the diff.apps/hasura/seeds/masterbots/1746466541645_init_example_pt_9.sql (1)
1-4: LFS pointer file, no SQL content to review.
This file is a Git LFS pointer for large seed data; it contains no SQL statements in the diff.apps/hasura/seeds/masterbots/1746466541639_init_example_pt_3.sql (1)
1-4: LFS pointer file, no SQL content to review.
This file is a Git LFS pointer for large seed data; it contains no SQL statements in the diff.apps/hasura/seeds/masterbots/1746466541644_init_example_pt_8.sql (1)
1-4: LFS pointer file, no SQL content to review.
This file is a Git LFS pointer for large seed data; it contains no SQL statements in the diff.apps/hasura/seeds/masterbots/1746466170867_init_subcategory_enum.sql (1)
1-3: Verify Git LFS pointer metadata
This seed file is tracked as a Git LFS pointer (oid and size). Please confirm that the actual SQL content is correctly stored in LFS, available in CI/local clones, and matches the intended subcategory enum initialization.apps/hasura/seeds/masterbots/1746466541641_init_example_pt_5.sql (1)
1-3: Verify Git LFS pointer metadata
This example seed is a Git LFS pointer. Ensure the underlying SQL is present in LFS, resolves properly in build environments, and contains the expected example data for part 5.apps/hasura/seeds/masterbots/1746466168385_init_category_enum.sql (1)
1-3: Verify Git LFS pointer metadata
The new category enum seed is stored via Git LFS. Confirm that the actual SQL file is correctly tracked, accessible in CI, and accurately represents the category enumeration changes.apps/hasura/seeds/masterbots/1746466541643_init_example_pt_7.sql (1)
1-3: Verify Git LFS pointer metadata
This example seed (part 7) is an LFS pointer file. Please validate that the SQL content is properly checked into LFS, available during migrations, and contains the correct data.apps/hasura/seeds/masterbots/1746466541642_init_example_pt_6.sql (1)
1-3: Verify Git LFS pointer metadata
The seed file for example pt 6 is tracked via Git LFS. Ensure the actual SQL payload is present, resolves in CI/builds, and aligns with the intended seed data.apps/hasura/seeds/masterbots/1746466541649_init_example_pt_13.sql (1)
1-3: LFS pointer file only – no SQL content to review.
This file is a Git LFS pointer to a large seed script. Ensure the actual SQL is properly stored in LFS and included in your seed execution process.apps/hasura/seeds/masterbots/1746466541647_init_example_pt_11.sql (1)
1-3: LFS pointer file only – no SQL content to review.
This is a Git LFS pointer. Confirm that the corresponding SQL file is present in LFS and that your deployment pipeline applies it in the correct sequence.apps/hasura/seeds/masterbots/1746466541638_init_example_pt_2.sql (1)
1-3: LFS pointer file only – no SQL content to review.
Ensure that the referenced SQL file is committed to LFS and referenced correctly by your seeding mechanism.apps/hasura/seeds/masterbots/1746466541646_init_example_pt_10.sql (1)
1-3: LFS pointer file only – no SQL content to review.
Verify that this seed file is tracked in LFS and loaded properly alongside the otherinit_example_ptfiles.apps/hasura/seeds/masterbots/1724269974513_init_config_seeds.sql (1)
1-3: LFS pointer update – verify alignment with schema migrations.
This pointer reflects a major update toinit_config_seeds.sql. Please confirm that the new seed populates recently added schema elements (e.g.,deletion_requested_at, new enum values) introduced in your migrations.apps/masterbots.ai/components/ui/button.tsx (1)
23-24: Well-aligned hover styles forsideBarProfilevariant
The addition ofhover:bg-mutedandhover:text-muted-foregroundbrings interactive feedback in line with other variants. LGTM!apps/hasura/seeds/masterbots/1746466178152_init_tag_enum_pt_1.sql (1)
1-3: Skip seed file pointer metadata review
This file contains only Git LFS pointer metadata. The actual SQL content should be reviewed separately if needed.apps/hasura/seeds/masterbots/1746466541640_init_example_pt_4.sql (1)
1-3: Skip seed file pointer metadata review
As with other LFS-tracked seed files, this pointer is formatted correctly. Ensure the SQL it references is valid.apps/masterbots.ai/app/actions/ai-main-call.ts (1)
462-467: Good implementation of Gemini 2.0 Flash image response capabilities.The conditional configuration for the 'gemini-2.0-flash-exp' model looks correct, specifically setting the response modalities to include both text and images. This aligns well with the broader changes mentioned in the PR summary regarding image generation and rendering.
apps/masterbots.ai/app/u/page.tsx (1)
1-6: LGTM: Proper implementation of profile default redirect.This simple redirect implementation serves as a sensible fallback for the '/u' route, directing users to the homepage when no specific user profile is requested. It aligns with the broader routing improvements in the PR.
apps/hasura/seeds/masterbots/1746466178153_init_tag_enum_pt_2.sql (1)
1-3: LGTM: Proper use of Git LFS for large data file.Using Git LFS for managing large SQL seed files is appropriate. This approach prevents bloating the main repository with large binary files while still allowing version control of the data.
apps/hasura/migrations/masterbots/1718416395664_create_table_models_enum/up.sql (1)
19-20: LGTM: New Gemini model properly added to database enum.The addition of the 'Gemini__2_0__Flash' entry with value 'gemini-2.0-flash-exp' is consistent with the model handling added in the ai-main-call.ts file. The ON CONFLICT clause properly handles potential duplicate entries.
apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/page.tsx (3)
7-7: LGTM: Added proper import for role-based utilities.The addition of the RoleTypes type and isAdminOrModeratorRole utility function import is appropriate for the new role-based admin mode functionality.
43-43: LGTM: Added role extraction from session.Properly casting the session.user.role as RoleTypes to ensure type safety when using the role value.
53-57: LGTM: ThreadPanel now receives isAdminMode prop based on user role.The isAdminOrModeratorRole utility is correctly used to determine if the current user has admin privileges, and this boolean value is properly passed to the ThreadPanel component via the isAdminMode prop.
apps/hasura/seeds/masterbots/1740386119321_init_chatbot_metadata_seeds.sql (1)
2-3: Updated seed file metadata with new versionThe Git LFS pointer has been updated to reference a new version of the chatbot metadata seeds file, with an increased size (from 17,251 bytes to 32,262 bytes). This indicates significant additions to the seed data.
apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/[threadSlug]/[threadQuestionSlug]/page.tsx (3)
6-6: Added role-based access control importsThe import of
RoleTypestype andisAdminOrModeratorRoleutility function will help identify admin/moderator users for conditional UI rendering.
43-43: Role extraction and typecasting from user sessionGood approach to extract and properly type-cast the user role from the session object.
53-57: Added admin mode toggle to ThreadPanelThe ThreadPanel component now receives an
isAdminModeprop based on the user's role, which will enable admin-specific UI elements and functionality.apps/hasura/metadata/databases/masterbots/tables/public_user.yaml (3)
104-104: Added deletion_requested_at to anonymous role permissionsThe new column has been properly added to the select permissions for the anonymous role.
122-122: Added deletion_requested_at to moderator role permissionsThe new column has been properly added to the select permissions for the moderator role.
143-143: Added deletion_requested_at to user role permissionsThe new column has been properly added to the select permissions for the user role.
apps/masterbots.ai/app/u/[userSlug]/s/subs/page.tsx (1)
4-4: Cleaner component implementationGood simplification by delegating all subscription-related UI and logic to the
SubscriptionPageComponent. This makes the page component cleaner and follows proper component composition patterns.apps/masterbots.ai/components/layout/sidebar/sidebar-category-general.tsx (2)
11-13: Consistent height styling added to "no matches" viewThe addition of
min-h-inheritclass improves layout consistency when no categories are found.
16-16: Consistent height styling for category listThe addition of
min-h-inheritclass to the<ul>element ensures consistent height behavior whether categories are found or not, maintaining visual stability during filtering.apps/masterbots.ai/services/hasura/hasura.service.type.ts (1)
72-72: Admin mode filter moved to proper interfaceGood refactoring of the
isAdminModeflag fromGetThreadsParamstoGetBrowseThreadsParams. This change centralizes admin mode filtering logic to the browse threads query, which is a more appropriate location based on the changes in the implementation.apps/masterbots.ai/auth.ts (2)
24-24: Enhanced user data retrieval with deletion tracking supportThe import has been updated from
getUserRoleByEmailtogetUserByEmail, supporting the expanded user data model that includes account deletion request tracking.
106-106: Updated function call for enhanced user data retrievalUpdated the function call to use
getUserByEmailwhich now fetches additional user data fields includingdeletionRequestedAttimestamp androleandslug. This supports the account deletion request tracking feature.apps/masterbots.ai/app/u/[userSlug]/s/page.tsx (1)
1-8: Clean and straightforward redirect implementation.This new page component effectively handles redirecting users from
/u/[userSlug]/sto/u/[userSlug]/t, consistent with the application's routing patterns. The implementation correctly awaits the Promise-based params and uses Next.js's redirect function.apps/hasura/migrations/masterbots/1745471202166_create_table_public_models/up.sql (1)
29-30: Successfully added new model entries to the database.The migration correctly adds two new models to the
public.modelstable:
llama-3-sonar-large-32k-online(disabled, paid)gemini-2.0-flash-exp(enabled, paid)Both follow the established pattern for model entries and properly use the
ON CONFLICTclause to handle potential duplicates.apps/masterbots.ai/components/routes/preferences/preferences.tsx (2)
1-4: LGTM: Client directive and imports properly configured.The addition of the 'use client' directive is necessary since this component uses client-side features. The imports for preferences and appConfig are correctly defined.
17-23: Correctly implemented the filtered preferences rendering.The component now properly renders only the preferences sections that pass the filtering conditions, which aligns with the conditional display requirements based on the devMode feature flag.
apps/masterbots.ai/lib/hooks/use-mb-chat.tsx (2)
272-294: Image file handling added to enhance chat responses with generated images.The implementation properly maps generated image files to message parts with appropriate metadata (base64, Uint8Array, mimeType, fileName) and includes a dev-mode notification. This is a well-structured addition that enables AI-generated image support.
438-441: Prepare for backend integration of image files.The commented code and TODO indicate upcoming backend integration for generated image files. Make sure to track this task to ensure it's completed when the backend is ready.
Are there any tracking tickets/issues for this backend integration work? Consider adding the ticket number to the TODO comment to improve traceability.
apps/masterbots.ai/app/api/chat/models/models.ts (1)
13-14: AI model nomenclature updated for consistency and new model added.The change standardizes the Gemini model naming convention using hyphens instead of underscores and adds the new Gemini Flash Pro model, properly aligning with the backend database migrations.
apps/masterbots.ai/app/c/[category]/[domain]/[chatbot]/[threadSlug]/page.tsx (3)
6-6: Import utility for role-based access control.Good addition of the role type and utility function for admin/moderator role checking.
43-43: Extract and type-cast user role from session.Correctly extracts the user role from the session and casts it to the proper
RoleTypestype.
53-57: Add admin mode conditional rendering based on user role.Properly passes the
isAdminModeprop to the ThreadPanel component based on the user's role, enabling role-specific UI elements.apps/masterbots.ai/app/u/[userSlug]/page.tsx (1)
1-8: Implement default redirect for user profile routes.This component properly extracts the userSlug parameter and redirects to the threads view, simplifying URL structure and providing consistent navigation for user profiles.
apps/masterbots.ai/components/routes/thread/thread-panel.tsx (3)
2-2: Nice work adding the AdminModeToggle import.The addition of this import enables the conditional rendering of admin functionality.
27-27: Good addition of the isAdminMode prop.The boolean prop allows for conditional rendering of admin functionality while maintaining clear interface documentation.
Also applies to: 31-31
35-40: Consider improving the sticky behavior.The implementation of the admin toggle in a sticky container looks good, but there's a TODO comment noting a limitation with the sticky behavior when scrolling beyond 100vh.
You might want to address this sticky positioning limitation in a future update. Consider using a fixed position with appropriate z-index, or investigate if CSS position: sticky with a different container structure would solve the issue.
apps/masterbots.ai/components/routes/subscription/succes-content.tsx (1)
26-26: Good implementation of session-based user data.Using the
useSessionhook to access user data is appropriate and aligns with authentication best practices.Also applies to: 31-31
apps/masterbots.ai/app/c/page.tsx (1)
32-36: Good centralization of admin mode logic.The refactoring to pass
isAdminModeas a prop to the ThreadPanel component simplifies the page-level JSX and centralizes the admin UI control logic. This is a clean approach.apps/masterbots.ai/components/routes/subscription/checkout.tsx (1)
35-35: Good implementation of session-based user identification.Using the
useSessionhook to access authenticated user data is appropriate and aligns with authentication best practices.Also applies to: 46-46
apps/masterbots.ai/lib/constants/prompts.ts (1)
228-240: Good implementation of the image generation prompt templateThe template and helper function provide a clear structure for generating image prompts with placeholders for description, style, and details. This aligns well with the image generation features being added in this PR.
Consider adding parameter validation to handle edge cases like null or undefined inputs, though this may not be critical for this straightforward use case.
apps/masterbots.ai/components/shared/theme-toggle.tsx (1)
8-38: Great improvement to the ThemeToggle componentThe refactoring enhances the component's reusability by:
- Accepting standard button props (className, onClick)
- Properly handling theme transitions
- Correctly merging classNames using the
cnutility- Using a more appropriate text size (sm instead of xs)
The handling of the onClick event inside the startTransition callback is particularly well done, ensuring the theme toggle happens first before any external click handlers.
apps/masterbots.ai/components/routes/subscription/plans.tsx (1)
32-33: Good migration to using authenticated session dataThis change correctly transitions from using usePayment hook's user data to the authenticated session data by importing and using useSession from next-auth/react.
Also applies to: 52-56
apps/masterbots.ai/components/routes/chat/chat-message.tsx (2)
109-127: Well-implemented image rendering for chat messagesThe ImagesSection component correctly:
- Checks if the message contains image generation data
- Extracts image content using the helper functions
- Renders each image with proper properties
- Includes download capability through the GeneratedImage component
This implementation neatly integrates with the existing message rendering flow.
147-147: Good placement of the ImagesSection componentThe ImagesSection is appropriately placed after the markdown content but before the actions and references sections, providing a logical content flow in the UI.
apps/masterbots.ai/components/routes/subscription/subscription.tsx (1)
61-68: Avoid calling customer-deletion endpoint with an empty email
handleCloseWizardwill happily invokehandleDeleteCustomer('')when the session has not hydrated yet.
Add a safeguard:-const del = await handleDeleteCustomer(email) +if (!email) return router.push('/c') // nothing to delete +const del = await handleDeleteCustomer(email)apps/masterbots.ai/components/routes/browse/browse-list.tsx (1)
33-35:getOpeningActiveThreadHelperimport looks goodCentralising the logic is a solid refactor and removes a sizeable chunk of duplicate code from this component.
apps/masterbots.ai/app/api/cron/delete-requested-accounts/route.ts (1)
14-23:Details
❓ Verification inconclusive
GraphQL field casing may not exist (
uservsusers)
Hasura’s generated root field for querying a table calleduseris normallyuseronly if singularization has been customised. By default it isusers. Double-check the schema; if it is stillusers, this query will returnundefined, propagating to an emptyuserIdsarray and silently skipping deletions.
🏁 Script executed:
#!/bin/bash set -e echo "Searching for GraphQL schema files (.graphql, .gql)..." fd --type f --exclude node_modules -e graphql -e gqlLength of output: 262
🏁 Script executed:
#!/bin/bash set -e echo "== Query type snippet ==" rg -n -A 30 "type Query" packages/mb-genql/generated/schema.graphql echo "" echo "== 'users(' occurrences ==" rg -n "users(" packages/mb-genql/generated/schema.graphql echo "" echo "== 'user(' occurrences ==" rg -n "user(" packages/mb-genql/generated/schema.graphqlLength of output: 137
🏁 Script executed:
#!/bin/bash set -e echo "== Query root definition and fields ==" rg -n -A 200 "type query_root" packages/mb-genql/generated/schema.graphql || echo "No query_root found" echo "" echo "== Roots named 'users(' ==" rg -n "users(" -C 3 packages/mb-genql/generated/schema.graphql || echo "No 'users(' occurrences" echo "" echo "== Roots named 'user(' ==" rg -n "user(" -C 3 packages/mb-genql/generated/schema.graphql || echo "No 'user(' occurrences"Length of output: 5444
#!/bin/bash set -e echo "=== Fetch doc for 'user' table ===" rg -n -A 5 'fetch data from the table: "user"' packages/mb-genql/generated/schema.graphql || echo "No doc for 'user' table found" echo "" echo "=== Root fields for 'user' ===" rg -n -F 'user(' -C 2 packages/mb-genql/generated/schema.graphql || echo "No literal 'user(' occurrences" echo "" echo "=== Root fields for 'users' ===" rg -n -F 'users(' -C 2 packages/mb-genql/generated/schema.graphql || echo "No literal 'users(' occurrences"
#!/bin/bash set -e echo "== Locate 'table: \"user\"' occurrences ==" rg -n 'table: "user"' -C 2 packages/mb-genql/generated/schema.graphql || echo "No 'table: \"user\"' found" echo echo "== Literal root field 'user(' ==" rg -n -F 'user(' -C 2 packages/mb-genql/generated/schema.graphql || echo "No literal 'user(' occurrences" echo echo "== Literal root field 'users(' ==" rg -n -F 'users(' -C 2 packages/mb-genql/generated/schema.graphql || echo "No literal 'users(' occurrences"
Double-check Hasura root query field for
usertable
I wasn’t able to find either auser(orusers(root in the generated schema (packages/mb-genql/generated/schema.graphql). By default, a table nameduserin Hasura exposes ausersfield unless you’ve customized singularization. If your root isusers, the currentuserquery will returnundefined, producing an emptyuserIdsarray and silently skipping deletions.• Verify in
packages/mb-genql/generated/schema.graphqlwhether the root isusersoruser.
• If it’s the defaultusers, update the query in
apps/masterbots.ai/app/api/cron/delete-requested-accounts/route.ts(lines 14–23) to:const userQuery = await client.query({ - user: { + users: { userId: true, __args: { where: { deletionRequestedAt: { _lte: thirtyDaysAgo } }, }, }, })Please verify your Hasura schema and adjust this field name to avoid silent failures.
apps/masterbots.ai/components/layout/sidebar/profile-sidebar.tsx (1)
39-45: Re-evaluate the sidebar-reset logic inhandleNavigationEvery navigation click (including Theme toggle) resets
activeCategoryandactiveChatbot.
This may be surprising when the user simply changes the theme or visits another page inside the same category. Consider decoupling the “close drawer” concern from the “reset filters” concern, or make the reset conditional (e.g. only when navigating to/c).[ suggest_optional_refactor ]
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| href={`/u/s/subs/${paymentIntent.id}`} | ||
| href={`/u/${session?.user.slug}/s/subs/${paymentIntent.id}`} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider adding a fallback for the session user slug.
The dynamic URL construction using session?.user.slug lacks a fallback if the session is not available or the slug is missing.
-href={`/u/${session?.user.slug}/s/subs/${paymentIntent.id}`}
+href={`/u/${session?.user.slug || 'profile'}/s/subs/${paymentIntent.id}`}🤖 Prompt for AI Agents
In apps/masterbots.ai/components/routes/subscription/succes-content.tsx at line
54, the URL uses session?.user.slug without a fallback, which can cause issues
if session or slug is undefined. Add a fallback value for the slug, such as an
empty string or a default placeholder, to ensure the URL is always valid even
when session data is missing.
| window.history.pushState( | ||
| {}, | ||
| '', | ||
| `/u/${session?.user.slug}/s/subs/${paymentIntent.id}`, | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add fallback for missing session slug when constructing the URL.
The history pushState call uses session?.user.slug without handling the case where session may be null or slug may be missing.
window.history.pushState(
{},
'',
- `/u/${session?.user.slug}/s/subs/${paymentIntent.id}`,
+ `/u/${session?.user.slug || 'profile'}/s/subs/${paymentIntent.id}`,
)This ensures that navigation won't break if the session hasn't fully loaded or if the slug is missing for any reason.
📝 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.
| window.history.pushState( | |
| {}, | |
| '', | |
| `/u/${session?.user.slug}/s/subs/${paymentIntent.id}`, | |
| ) | |
| window.history.pushState( | |
| {}, | |
| '', | |
| `/u/${session?.user.slug || 'profile'}/s/subs/${paymentIntent.id}`, | |
| ) |
🤖 Prompt for AI Agents
In apps/masterbots.ai/components/routes/subscription/checkout.tsx around lines
83 to 87, the code uses session?.user.slug directly in the URL without handling
cases where session or slug might be null or undefined. To fix this, add a
fallback value (like an empty string or a placeholder) for the slug when
constructing the URL in window.history.pushState to prevent navigation errors if
session or slug is missing.
| const { data: session } = useSession() | ||
| const { email } = (session?.user as Session['user']) || { | ||
| email: '', | ||
| } | ||
| const { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard against undefined session & avoid unsafe type-casts
(session?.user as Session['user']) assumes session.user is always shape-compatible with Session['user'].
If session is still loading, email becomes an empty string which then propagates to the subsequent API calls, causing useless requests and potential 400/404 noise on the server.
Consider early-returning until the session is ready, and drop the brittle type-cast:
-const { email } = (session?.user as Session['user']) || { email: '' }
+if (!session?.user?.email) return null // or render a loader
+const { email } = session.user📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const { data: session } = useSession() | |
| const { email } = (session?.user as Session['user']) || { | |
| email: '', | |
| } | |
| const { | |
| const { data: session } = useSession() | |
| - const { email } = (session?.user as Session['user']) || { | |
| - email: '', | |
| - } | |
| + if (!session?.user?.email) return null // or render a loader | |
| + const { email } = session.user | |
| const { |
🤖 Prompt for AI Agents
In apps/masterbots.ai/components/routes/subscription/subscription.tsx around
lines 46 to 50, the code uses an unsafe type-cast on session.user and assigns an
empty string to email if session is undefined, which can cause invalid API
calls. To fix this, remove the type-cast and add an early return or conditional
rendering to wait until the session is fully loaded before accessing
session.user and email, preventing unnecessary requests with invalid data.
| const { value: openDialog } = useAsync( | ||
| async () => await checkIfCustomerHasActiveSub(user.email), | ||
| async () => await checkIfCustomerHasActiveSub(email), | ||
| ) |
There was a problem hiding this comment.
useAsync never re-runs when the email arrives – add dependency & null-check
useAsync without a deps array only fires once (on mount).
On first render email === ''; once the real email arrives the check is never repeated, so users with a cold page load are shown the wrong dialog state.
-const { value: openDialog } = useAsync(
- async () => await checkIfCustomerHasActiveSub(email),
-)
+const { value: openDialog } = useAsync(
+ async () => {
+ if (!email) return false // skip until we know who the user is
+ return checkIfCustomerHasActiveSub(email)
+ },
+ [email], // <- rerun when session resolves
+)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const { value: openDialog } = useAsync( | |
| async () => await checkIfCustomerHasActiveSub(user.email), | |
| async () => await checkIfCustomerHasActiveSub(email), | |
| ) | |
| const { value: openDialog } = useAsync( | |
| async () => { | |
| if (!email) return false // skip until we know who the user is | |
| return checkIfCustomerHasActiveSub(email) | |
| }, | |
| [email], // <- rerun when session resolves | |
| ) |
🤖 Prompt for AI Agents
In apps/masterbots.ai/components/routes/subscription/subscription.tsx around
lines 57 to 59, the useAsync hook is called without a dependency array, causing
it to run only once on mount and not re-run when the email value changes. To fix
this, add the email variable to the dependency array of useAsync so it
re-executes whenever email updates. Also, add a null or empty string check to
avoid running the async function when email is not yet available.
| const [, getOpeningActiveThread] = useAsyncFn( | ||
| () => | ||
| getOpeningActiveThreadHelper( | ||
| activeThread, | ||
| customSonner, | ||
| activateThreadPopup, | ||
| ), | ||
| [activeThread, window.location.pathname], | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Avoid window.location inside dependency array – use usePathname
Referencing window directly breaks during pre-render / storybook and hinders testing. Next-auth provides usePathname() which is reactive and SSR-safe.
-import { useEffect, useState } from 'react'
+import { useEffect, useState } from 'react'
+import { usePathname } from 'next/navigation'
+const pathname = usePathname()
const [, getOpeningActiveThread] = useAsyncFn(
() =>
getOpeningActiveThreadHelper(
activeThread,
customSonner,
activateThreadPopup,
),
- [activeThread, window.location.pathname],
+ [activeThread, pathname],
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [, getOpeningActiveThread] = useAsyncFn( | |
| () => | |
| getOpeningActiveThreadHelper( | |
| activeThread, | |
| customSonner, | |
| activateThreadPopup, | |
| ), | |
| [activeThread, window.location.pathname], | |
| ) | |
| // at the top of the file | |
| import { useEffect, useState } from 'react' | |
| import { usePathname } from 'next/navigation' | |
| export function ThreadList(/* … */) { | |
| // usePathname is SSR-safe and reactive | |
| const pathname = usePathname() | |
| const [, getOpeningActiveThread] = useAsyncFn( | |
| () => | |
| getOpeningActiveThreadHelper( | |
| activeThread, | |
| customSonner, | |
| activateThreadPopup, | |
| ), | |
| [activeThread, pathname], | |
| ) | |
| // … | |
| } |
🤖 Prompt for AI Agents
In apps/masterbots.ai/components/routes/thread/thread-list.tsx around lines 86
to 94, replace the direct use of window.location.pathname in the dependency
array with the Next.js hook usePathname() to ensure the code is reactive,
SSR-safe, and compatible with pre-rendering and testing environments. Import
usePathname from 'next/navigation' and use it to get the current path, then
include that value in the dependency array instead of window.location.pathname.
| { "source": "/user/:path*", "destination": "/u/:path*", "permanent": true }, | ||
| { | ||
| "source": "/profile/:path*", | ||
| "destination": "/u/:path*", | ||
| "permanent": true | ||
| }, | ||
| { | ||
| "source": "/author/:path*", | ||
| "destination": "/u/:path*", | ||
| "permanent": true | ||
| }, |
There was a problem hiding this comment.
Specific redirects are shadow-ed by the broader /user/:path* rule
Vercel evaluates redirects top-to-bottom.
Because the catch-all rule /user/:path* → /u/:path* comes before the more specific preferences/subscriptions rules, requests like /user/john/preferences will match the first rule and be redirected to /u/john/preferences, never reaching /u/john/s/pref.
Move the three catch-all rules to the bottom or place the specific rules above them.
- { "source": "/user/:path*", "destination": "/u/:path*", "permanent": true },
+ // … specific /user/:userSlug/preferences & /subscriptions rules first …
+ { "source": "/user/:path*", "destination": "/u/:path*", "permanent": true },Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/masterbots.ai/vercel.json around lines 13 to 23, the broad redirect rule
for "/user/:path*" is placed before more specific rules like "/profile/:path*"
and "/author/:path*", causing the specific redirects to be shadowed. To fix
this, reorder the redirect rules by moving the broad "/user/:path*" catch-all
rule to the bottom of the list or placing the more specific rules above it,
ensuring specific paths are matched before the general catch-all.
| interface ThreadVisibilityContextProps { | ||
| isPublic: boolean | ||
| toggleVisibility: (newIsPublic: boolean, threadId: string) => Promise<void> | ||
| threads: Thread[] | ||
| threadsState: { | ||
| threads: Thread[] | ||
| count: number | ||
| } | ||
| isAdminMode: boolean | ||
| isContinuousThread: boolean | ||
| isSameUser: (thread: Thread) => boolean | ||
| toggleVisibility: (newIsPublic: boolean, threadId: string) => Promise<void> | ||
| adminApproveThread: (threadId: string) => void | ||
| initiateDeleteThread: (threadId: string) => Promise<DeleteThreadResponse> |
There was a problem hiding this comment.
adminApproveThread type is incorrect – returning a Promise but declared void
The async implementation (lines 216-233) returns Promise<void>, which is not assignable to the declared (threadId: string) => void.
Consumers expecting void will silently ignore rejections.
- adminApproveThread: (threadId: string) => void
+ adminApproveThread: (threadId: string) => Promise<void>📝 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.
| interface ThreadVisibilityContextProps { | |
| isPublic: boolean | |
| toggleVisibility: (newIsPublic: boolean, threadId: string) => Promise<void> | |
| threads: Thread[] | |
| threadsState: { | |
| threads: Thread[] | |
| count: number | |
| } | |
| isAdminMode: boolean | |
| isContinuousThread: boolean | |
| isSameUser: (thread: Thread) => boolean | |
| toggleVisibility: (newIsPublic: boolean, threadId: string) => Promise<void> | |
| adminApproveThread: (threadId: string) => void | |
| initiateDeleteThread: (threadId: string) => Promise<DeleteThreadResponse> | |
| interface ThreadVisibilityContextProps { | |
| isPublic: boolean | |
| threadsState: { | |
| threads: Thread[] | |
| count: number | |
| } | |
| isAdminMode: boolean | |
| isContinuousThread: boolean | |
| isSameUser: (thread: Thread) => boolean | |
| toggleVisibility: (newIsPublic: boolean, threadId: string) => Promise<void> | |
| adminApproveThread: (threadId: string) => Promise<void> | |
| initiateDeleteThread: (threadId: string) => Promise<DeleteThreadResponse> | |
| } |
🤖 Prompt for AI Agents
In apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx around lines 25 to 36,
the adminApproveThread function is declared to return void but its
implementation returns Promise<void>. Update the type declaration of
adminApproveThread to return Promise<void> to match the async implementation and
ensure consumers handle the promise correctly.
| // a function to delete all users messages and threads | ||
| export async function deleteUserMessagesAndThreads({ | ||
| userId, | ||
| jwt, | ||
| }: { | ||
| userId: string | ||
| jwt: string | ||
| }): Promise<{ success: boolean; error?: string }> { | ||
| try { | ||
| if (!jwt) { | ||
| throw new Error( | ||
| 'Authentication required to delete user messages and threads', | ||
| ) | ||
| } | ||
|
|
||
| const client = getHasuraClient({ jwt }) | ||
|
|
||
| // First, delete all messages associated with the user's threads | ||
| // Then, delete all the user's threads | ||
| const whereArgDeleteObject = { | ||
| thread: { | ||
| userId: { _eq: userId }, | ||
| isPublic: { _eq: true }, | ||
| isApproved: { _eq: true }, | ||
| }, | ||
| } | ||
| await client.mutation({ | ||
| deleteMessage: { | ||
| __args: { | ||
| where: whereArgDeleteObject, | ||
| }, | ||
| affectedRows: true, | ||
| }, | ||
| deleteThread: { | ||
| __args: { | ||
| where: whereArgDeleteObject, | ||
| }, | ||
| affectedRows: true, | ||
| }, | ||
| }) | ||
|
|
||
| return { success: true } | ||
| } catch (error) { | ||
| console.error('Error deleting user messages and threads:', error) | ||
| return { success: false, error: (error as Error).message } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Thread deletion helper uses invalid where shape & misses private content
deleteThreadexpects columns of thread, but you pass a nestedthreadobject ({ thread: { … } }) – this will raise a GraphQL validation error.- The current predicate deletes only public & approved content, leaving drafts/private threads and their messages behind, which defeats account-deletion requirements.
- Two separate deletions are issued in a single mutation; use Postgres
ON DELETE CASCADEor wrap them in a transaction to avoid orphaned rows on partial failure.
Proposed fix (simplified):
-const whereArgDeleteObject = {
- thread: {
- userId: { _eq: userId },
- isPublic: { _eq: true },
- isApproved: { _eq: true },
- },
-}
+const threadWhere = { userId: { _eq: userId } } // delete **all** threads
+const messageWhere = { thread: threadWhere } // messages linked to those threads
@@
deleteMessage: { __args: { where: messageWhere }, affectedRows: true },
deleteThread: { __args: { where: threadWhere }, affectedRows: true },Add a follow-up verification to ensure the number of deleted rows matches expectations.
if (result.deleteThread.affectedRows === 0) {
return { success:false, error:'No threads deleted – check userId.' }
}🤖 Prompt for AI Agents
In apps/masterbots.ai/services/hasura/hasura.service.ts around lines 1794 to
1840, the deleteUserMessagesAndThreads function incorrectly uses a nested
`thread` object in the `where` clause for deleting threads, which causes GraphQL
validation errors. Fix this by passing the correct shape with direct thread
columns for `deleteThread`. Also, remove the filters limiting deletion to only
public and approved threads to ensure all user threads and messages, including
private and drafts, are deleted. To prevent orphaned rows, either rely on
Postgres ON DELETE CASCADE or wrap deletions in a transaction. Finally, add a
verification step after deletion to check if any threads were deleted and return
an error if none were affected.
| const client = getHasuraClient({ jwt }) | ||
| await client.mutation({ | ||
| const result = await client.mutation({ | ||
| deleteThread: { | ||
| __args: { | ||
| where: { threadId: { _eq: threadId }, userId: { _eq: userId } }, | ||
| }, | ||
| returning: { | ||
| threadId: true, | ||
| where: { | ||
| threadId: { _eq: threadId }, | ||
| userId: { _eq: userId }, | ||
| }, | ||
| }, | ||
| affectedRows: true, | ||
| }, | ||
| }) | ||
|
|
||
| return { success: true } | ||
| if ((result.deleteThread?.affectedRows ?? 0) > 0) { | ||
| return { success: true } | ||
| } | ||
| return { success: false } | ||
| } catch (error) { |
There was a problem hiding this comment.
Deletion check trusts caller-supplied userId – verify against JWT
The where clause now matches both threadId and userId, which is good, but userId is supplied as a parameter and not validated against jwt claims.
A malicious client could therefore delete another user’s thread by passing that user’s id.
Add a quick guard:
const claimsUserId = parseJwt(jwt).['x-hasura-user-id']
if (claimsUserId !== userId) {
throw new Error('UserId mismatch – forbidden')
}(or simply drop userId from the API and read it exclusively from JWT claims).
Minor: on failure you return only { success:false }; include error for observability consistency.
🤖 Prompt for AI Agents
In apps/masterbots.ai/services/hasura/hasura.service.ts around lines 1198 to
1215, the deletion logic uses a caller-supplied userId without verifying it
against the JWT claims, which risks unauthorized deletions. Fix this by
extracting the userId from the JWT using a parseJwt function and comparing it to
the supplied userId; if they differ, throw an error to prevent unauthorized
access. Alternatively, remove the userId parameter entirely and rely solely on
the JWT userId. Also, enhance the failure response to include the error details
alongside success:false for better observability.
| // update user deletion_requested_at with the current date | ||
| export async function updateUserDeletionRequest({ | ||
| userId, | ||
| jwt, | ||
| reset = false, | ||
| }: { | ||
| userId: string | ||
| jwt: string | ||
| reset?: boolean | ||
| }): Promise<{ success: boolean; error?: string }> { | ||
| try { | ||
| if (!jwt) { | ||
| throw new Error('Authentication required to update user deletion request') | ||
| } | ||
|
|
||
| const client = getHasuraClient({ jwt }) | ||
| await client.mutation({ | ||
| updateUserByPk: { | ||
| __args: { | ||
| pkColumns: { userId }, | ||
| _set: { | ||
| deletionRequestedAt: reset ? null : new Date().toISOString(), | ||
| }, | ||
| }, | ||
| userId: true, | ||
| }, | ||
| }) | ||
|
|
||
| return { success: true } | ||
| } catch (error) { | ||
| console.error('Error updating user deletion request:', error) | ||
| return { success: false, error: (error as Error).message } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Prefer database timestamp for deletionRequestedAt
new Date().toISOString() is generated on the frontend server, which may differ from the DB clock or be susceptible to manual tampering in tests.
Hasura (Postgres) already exposes now(). You can set it with x-hasura-update:
- _set: { deletionRequestedAt: reset ? null : new Date().toISOString() }
+ _set: { deletionRequestedAt: reset ? null : 'now()' }This guarantees a consistent, timezone-aware value.
Also, when reset === true the mutation still requires authentication. Consider letting admins reset without JWT by accepting adminSecret.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/masterbots.ai/services/hasura/hasura.service.ts around lines 1759 to
1792, replace the client-side timestamp new Date().toISOString() for
deletionRequestedAt with the database server timestamp by using Hasura's
x-hasura-update or equivalent to set deletionRequestedAt to now() in the
mutation. Additionally, modify the function to allow resetting
deletionRequestedAt without a JWT by accepting an adminSecret parameter and
using it for authentication when reset is true, enabling admins to perform the
reset securely without a user JWT.
# Add features, refactor user and thread management, update UI and database scripts * fix: change toggler wording + util hook (#424) * impr: makes threads open on profile page and profile tweaks (#421) * update * fix: update * update * update * update * update * fix: opening threads * fix: rm threads dropdwon & added back link to bot page thread view page * fix: rm threads dropdwon & added back link to bot page thread view page * fix: update * fix: added back to profile page * fix: added sticky and color * fix: codeblock ctas refactor markdown rendering, sidebar nav, code block & clipboard hook (#425) * fix: codeblock ctas * fix: ts build * fix: continue thread + allMessages sequence + mobile chat css tweak (#426) * fix: css handleCLick condition * fix: get latest search params, continuous thread * fix(impr): all messages sorting * perf(impr): sign in & up redirection tweak * perf(impr): mobile chat css * chore: next + react security ver upt (#427) * refactor: use chat and continue thread + continue conversation fallback (#432) * refactor: use chat and continue generation * fix: uniq slug and id gen (#433) * fix: uniq thread + msg slug gen * style: formatting * fix: thread user attachments state upt * perf: impr thread component at all pages + mobile tweaks * refactor: thread-component card * chore: restore continue generation v1 * feat(impr): thread component card * fix: admin panel n actions * fix: fetch getThreads * chore: continue conversation v1.2 * chore: continue and update thread content * chore: add ui control continue generation state * chore: fix infinity loop * chore(impr): enable upt msg table permission * fix: seo thread fetch * chore: style formating * fix(impr): continued thread title + thread component reusability * chore: refactor loadings + extending sonners --------- Co-authored-by: bran18 <andreyfdez18@gmail.com> --------- Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add gemini provider (#437) * feat: add gemini provider * chore: update icons * feat: impr continuing thread tags + accordion first msg toggle (#435) * feat(wip): impr continuing thread tags + accordion first msg toggle * feat(impr): continuing thread tags + accordion at first message + header mobile tweak * style(impr): mobile thread-component x-axis space * perf(style): coderabbitai feedbacks * fix: css typo * perf: sendMessageFromResponse clicked guard + continued thread tags label tweak * chore: user thread panel clean up * fix: user-thread-panel infinite loader * perf: impr shared accordion animation and ux * style: defaultAccordionState comments loc * fix: record type warning, hasura updateMessage * fix: getThread user data, shared-accordion * fix: coderabbitai observations * fix: impr file management per llm, multimodel feat flag, chat tool labels, parent thread guard * fix: tunningUserContent parentThread condition * fix: feature flag typo * feat: profile page thread popup feature flag and tweaks (#434) * update * fix: update * update * update * update * update * refactor: profile page threads pop up * fix: update config * fix: update * fix: update * fix: make profile page scroll on hero * fix: bot make popup and scroll * fix: make profile page sidebar scroll independently * fix: make profile page sidebar scroll independently * fix: check the category along the chatbot when it's not checked * fix: check the category along the chatbot when it's not checked --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add new llm models (#444) * feat-add-models * feat-add-models * feat-add-models * chore: add model * fix: typo * chore: add toggler color * perf(impr): thread llm context, last question & response + new models seeds (#447) * feat(wip): thread llm context, prev questions * fix: previousQuestionsString slice * fix: clickedContentId in followingQuestionsPrompt * feat: isContinued + model type in message table * fix: ts typo + sendMessageFromResponse callback call * fix: ts typo * fix: bot profile page view (#449) * fix(wip): bot profile thread list * style: formatting * fix: new chats and share + og img (#451) * fix: new chat state reset * fix: genql gen + share link check * fix: og img * fix: duplicate role permission in msg table * feat: initial continuation logic flow (#450) * chore: restore base version * chore: add new logic and hooks * chore: fix providers file * chore: improve continuation prompt * chore: add exlucision flag * chore: add better handler * chore: updated flow + experimental delay * chore: extended time * chore(impr): streamDelayMs experimental feat flag * style: formatting --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * fix: profile sidebar cat opt render (#453) * fix: profile sidebar cat opt render * chore: clean-up * [masterbots.ai] refactor: slug generation logic with improved uniqueness and type support (#456) * fix: slugify fn * chore: devMode logs * fix: uniq slug gen fn nanoid flag typo * feat: sentry logs in webapp (#457) * fix(impr): llm enum data, thread creation, ts, and log behavior (#458) * fix: slugify first request delay incr + genql ts, seeds & model migration upt * fix: create thread & msg ts * fix(impr): profile page bugs & tweaks v1 4/15/25 (#455) * update * fix: update * update * update * update * update * fix: use the user avatar or robohash * fix: added avater to user menu * fix: user avatar * fix: reset search input when filter by category or chatbot * fix: personal chat browse provider + username chk in sign up * chore: clean duplicated if condition signup --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * refactor: continuation flow (#460) * impr: continuation logic flow * impr: continuation logic flow * chore: update createImprovementPrompt * chore: upt logs --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * feat: models table, enum type, and refactor chat msg deduplication logic (#462) * feat: models table * style: formatting * fix: continuation accordion content * fix: sql + metadata typo * fix: db migrations and messages uniqby condition (#463) * fix: db migrations + messages uniqby condition * fix: typo * perf(impr): verify duplicate message return condition * chore: upt default available models * perf(impr): reassign continued prompt * chore: incr fn stream max duration * fix: mob prof sidebar + sign-up pw verif + username chk (#464) * fix: mob prof sidebar + sign-up pw verif + username chk * chore: upt genql gen * perf(impr): profile navigation * feat: model selector (#466) * wip: model selector query * wip: model selector query * chore: improve funtions * chore: add coderabbit suggestion * chore: add hasura permissions, models table * style: formatting * chore: fix get model client type * chore: add model --------- Co-authored-by: Roberto Romero Lucas <contact@andler.dev> * chore: impr models (#472) * chore: fix model name and condition (#473) * refactor: user fetching code (#471) * refactor: profile sidebar ui, upt styling, and disable prefetch (#470) * chore: remove prefetch on sidebar & profile navigation * perf: impr profile sidebar * fix: infinite scroll load more fetch * perf(impr): google sign-in * perf(impr): session loaders tweak * perf: impr categoriesId obtention * fix: tailwind typo * chore(impr): pro user guard in model selector * chore: category label upt to topic * chore: rm dev mode guard (#476) * feat: add reasoning compatibility (#480) * feat: add resoning stable * chore: add reasoning stable v * chore: activate reasoning * chore: activate reasoning * feat: pro users whitelist (#481) * feat(wip): whitelist pro users * chore: add whitelist pro users + page size fetch * perf(impr): following question impr prompt * fix: pro whitelist users clean up * feat: user account setting (#468) * update * fix: update * update * update * update * update * feat: imple account setting * feat: added dialog to delete button * feat: update user deletion func * fix: move back exmaples files * fix: update * fix: user account scheduling api * fix: user account deletion request function * refactor: account deletion request api * fix: user account request and thread deletion * fix: added permission and account deletion page * fix: update on permission * fix: enable new col permission * fix: profile side bar * fix: update * fix: function rerendering * fix: update route * chore(impr): preferences actions and ui tweaks --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * chore: enable twitter pixel track (#479) * chore: enable twitter pixel track * perf(impr): twitter ads availability + dynamic config * feat: impr profile navigation page (#478) * fix(wip): subscriptions page render * feat(impr): profile navigation + page ui tweaks * style: lintin + formatting * style(css): nav links px on mob * fix: goToProfile in mob prof sidebar * fix: build * fix: thread popup opening at nav * chore: enable preferences nav on prod * feat: image generation (#486) * feat: add image generation support - gemini provider * chore: add mineType * chore: add conditional checks * chore: upt model enums & list * chore: hasura, set icl seeds chunks (#484) * chore: hasura, set icl seeds chunks * chore: track backup icl seed loc to lfs * chore(seeds): uncomment phase 3 topics & add new chatbots + icl metadata rel * chore: upt phase 3 init config seeds, adding rel * fix: example seeds integrity * test: incr hasura max req body * revert: cloudbuild og config * chore: restore skipped seed lines * fix: thread rendering (#487) * fix: thread list render states * chore: linting & format * fix: thread pop-up on refresh * fix: user table selection --------- Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Jimoh sherifdeen <63134009+sheriffjimoh@users.noreply.github.com>
# Add features, refactor user and thread management, update UI and database scripts * fix: change toggler wording + util hook (#424) * impr: makes threads open on profile page and profile tweaks (#421) * update * fix: update * update * update * update * update * fix: opening threads * fix: rm threads dropdwon & added back link to bot page thread view page * fix: rm threads dropdwon & added back link to bot page thread view page * fix: update * fix: added back to profile page * fix: added sticky and color * fix: codeblock ctas refactor markdown rendering, sidebar nav, code block & clipboard hook (#425) * fix: codeblock ctas * fix: ts build * fix: continue thread + allMessages sequence + mobile chat css tweak (#426) * fix: css handleCLick condition * fix: get latest search params, continuous thread * fix(impr): all messages sorting * perf(impr): sign in & up redirection tweak * perf(impr): mobile chat css * chore: next + react security ver upt (#427) * refactor: use chat and continue thread + continue conversation fallback (#432) * refactor: use chat and continue generation * fix: uniq slug and id gen (#433) * fix: uniq thread + msg slug gen * style: formatting * fix: thread user attachments state upt * perf: impr thread component at all pages + mobile tweaks * refactor: thread-component card * chore: restore continue generation v1 * feat(impr): thread component card * fix: admin panel n actions * fix: fetch getThreads * chore: continue conversation v1.2 * chore: continue and update thread content * chore: add ui control continue generation state * chore: fix infinity loop * chore(impr): enable upt msg table permission * fix: seo thread fetch * chore: style formating * fix(impr): continued thread title + thread component reusability * chore: refactor loadings + extending sonners --------- Co-authored-by: bran18 <andreyfdez18@gmail.com> --------- Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add gemini provider (#437) * feat: add gemini provider * chore: update icons * feat: impr continuing thread tags + accordion first msg toggle (#435) * feat(wip): impr continuing thread tags + accordion first msg toggle * feat(impr): continuing thread tags + accordion at first message + header mobile tweak * style(impr): mobile thread-component x-axis space * perf(style): coderabbitai feedbacks * fix: css typo * perf: sendMessageFromResponse clicked guard + continued thread tags label tweak * chore: user thread panel clean up * fix: user-thread-panel infinite loader * perf: impr shared accordion animation and ux * style: defaultAccordionState comments loc * fix: record type warning, hasura updateMessage * fix: getThread user data, shared-accordion * fix: coderabbitai observations * fix: impr file management per llm, multimodel feat flag, chat tool labels, parent thread guard * fix: tunningUserContent parentThread condition * fix: feature flag typo * feat: profile page thread popup feature flag and tweaks (#434) * update * fix: update * update * update * update * update * refactor: profile page threads pop up * fix: update config * fix: update * fix: update * fix: make profile page scroll on hero * fix: bot make popup and scroll * fix: make profile page sidebar scroll independently * fix: make profile page sidebar scroll independently * fix: check the category along the chatbot when it's not checked * fix: check the category along the chatbot when it's not checked --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> Co-authored-by: Roberto Lucas <andler@bitcash.org> * feat: add new llm models (#444) * feat-add-models * feat-add-models * feat-add-models * chore: add model * fix: typo * chore: add toggler color * perf(impr): thread llm context, last question & response + new models seeds (#447) * feat(wip): thread llm context, prev questions * fix: previousQuestionsString slice * fix: clickedContentId in followingQuestionsPrompt * feat: isContinued + model type in message table * fix: ts typo + sendMessageFromResponse callback call * fix: ts typo * fix: bot profile page view (#449) * fix(wip): bot profile thread list * style: formatting * fix: new chats and share + og img (#451) * fix: new chat state reset * fix: genql gen + share link check * fix: og img * fix: duplicate role permission in msg table * feat: initial continuation logic flow (#450) * chore: restore base version * chore: add new logic and hooks * chore: fix providers file * chore: improve continuation prompt * chore: add exlucision flag * chore: add better handler * chore: updated flow + experimental delay * chore: extended time * chore(impr): streamDelayMs experimental feat flag * style: formatting --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * fix: profile sidebar cat opt render (#453) * fix: profile sidebar cat opt render * chore: clean-up * [masterbots.ai] refactor: slug generation logic with improved uniqueness and type support (#456) * fix: slugify fn * chore: devMode logs * fix: uniq slug gen fn nanoid flag typo * feat: sentry logs in webapp (#457) * fix(impr): llm enum data, thread creation, ts, and log behavior (#458) * fix: slugify first request delay incr + genql ts, seeds & model migration upt * fix: create thread & msg ts * fix(impr): profile page bugs & tweaks v1 4/15/25 (#455) * update * fix: update * update * update * update * update * fix: use the user avatar or robohash * fix: added avater to user menu * fix: user avatar * fix: reset search input when filter by category or chatbot * fix: personal chat browse provider + username chk in sign up * chore: clean duplicated if condition signup --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * refactor: continuation flow (#460) * impr: continuation logic flow * impr: continuation logic flow * chore: update createImprovementPrompt * chore: upt logs --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * feat: models table, enum type, and refactor chat msg deduplication logic (#462) * feat: models table * style: formatting * fix: continuation accordion content * fix: sql + metadata typo * fix: db migrations and messages uniqby condition (#463) * fix: db migrations + messages uniqby condition * fix: typo * perf(impr): verify duplicate message return condition * chore: upt default available models * perf(impr): reassign continued prompt * chore: incr fn stream max duration * fix: mob prof sidebar + sign-up pw verif + username chk (#464) * fix: mob prof sidebar + sign-up pw verif + username chk * chore: upt genql gen * perf(impr): profile navigation * feat: model selector (#466) * wip: model selector query * wip: model selector query * chore: improve funtions * chore: add coderabbit suggestion * chore: add hasura permissions, models table * style: formatting * chore: fix get model client type * chore: add model --------- Co-authored-by: Roberto Romero Lucas <contact@andler.dev> * chore: impr models (#472) * chore: fix model name and condition (#473) * refactor: user fetching code (#471) * refactor: profile sidebar ui, upt styling, and disable prefetch (#470) * chore: remove prefetch on sidebar & profile navigation * perf: impr profile sidebar * fix: infinite scroll load more fetch * perf(impr): google sign-in * perf(impr): session loaders tweak * perf: impr categoriesId obtention * fix: tailwind typo * chore(impr): pro user guard in model selector * chore: category label upt to topic * chore: rm dev mode guard (#476) * feat: add reasoning compatibility (#480) * feat: add resoning stable * chore: add reasoning stable v * chore: activate reasoning * chore: activate reasoning * feat: pro users whitelist (#481) * feat(wip): whitelist pro users * chore: add whitelist pro users + page size fetch * perf(impr): following question impr prompt * fix: pro whitelist users clean up * feat: user account setting (#468) * update * fix: update * update * update * update * update * feat: imple account setting * feat: added dialog to delete button * feat: update user deletion func * fix: move back exmaples files * fix: update * fix: user account scheduling api * fix: user account deletion request function * refactor: account deletion request api * fix: user account request and thread deletion * fix: added permission and account deletion page * fix: update on permission * fix: enable new col permission * fix: profile side bar * fix: update * fix: function rerendering * fix: update route * chore(impr): preferences actions and ui tweaks --------- Co-authored-by: Roberto Lucas <andler.dev@gmail.com> * chore: enable twitter pixel track (#479) * chore: enable twitter pixel track * perf(impr): twitter ads availability + dynamic config * feat: impr profile navigation page (#478) * fix(wip): subscriptions page render * feat(impr): profile navigation + page ui tweaks * style: lintin + formatting * style(css): nav links px on mob * fix: goToProfile in mob prof sidebar * fix: build * fix: thread popup opening at nav * chore: enable preferences nav on prod * feat: image generation (#486) * feat: add image generation support - gemini provider * chore: add mineType * chore: add conditional checks * chore: upt model enums & list * chore: hasura, set icl seeds chunks (#484) * chore: hasura, set icl seeds chunks * chore: track backup icl seed loc to lfs * chore(seeds): uncomment phase 3 topics & add new chatbots + icl metadata rel * chore: upt phase 3 init config seeds, adding rel * fix: example seeds integrity * test: incr hasura max req body * revert: cloudbuild og config * chore: restore skipped seed lines * fix: thread rendering (#487) * fix: thread list render states * chore: linting & format * fix: thread pop-up on refresh * fix: user table selection --------- Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Jimoh sherifdeen <63134009+sheriffjimoh@users.noreply.github.com>
Summary by Sourcery
Implement account and thread deletion, image generation, and UI enhancements across the application.
New Features:
Bug Fixes:
Enhancements:
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Refactor
Chores