From 0038bbca49a273b9f4a78245cf888f09d19920ef Mon Sep 17 00:00:00 2001 From: Roberto Lucas Date: Tue, 10 Dec 2024 02:05:15 -0600 Subject: [PATCH] [hasura] fix: thread delete and user permissions duplicate (#331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * devops: force deploy * devops: trigger automated build * devops: trigger automated build * devops: trigger automated build * devops: trigger automated build * devops: trigger automated build * devops: trigger automated build * devops: trigger automated build * impr(masterbots.ai): add return to browse on bot thread page view (#204) * ✨ Added back button to thread details page * ⚡️ changed char to svg * feat: ai gen 404 image for custom 404 error page (#210) * ⚡️ added custom error page * ⚡️ clean up * fix(masterbots.ai): terms page visibility and access * feat(masterbots.ai): consistent og image style design and dynamic metadata (#215) * feat: added og api endpoint * feat: design og image for dark mode * fix: file formated * fix: amend og image to pick current theme color and adapt * feat: added custom metadata to thread page * feat: added custom metadata to bot page * fix: clean up * fix: move bg to a component * fix: move og-image design to a component * fix: use variable for URL * fix: to slug func * ⚡️ Move and clean up UrlToSlug * fix(masterbots.ai): zod dependecy * fix: type error * fix: type error for metadata * fix: clean and build fix --------- Co-authored-by: Roberto Lucas * fix(masterbots.ai): OG not redering (#224) * fix: og to render first letter of username if there's no avatar * fix: clean up * fix: clean up * fix(masterbots.ai): share function (#225) * feat: create action.ts * fix: upt share button * fix: add axios module * fix: add resend module * fix: update vercel env config * fix: split share function * fix: update share component * [coderabbitai] style: upt thread-user-actions condition Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat(hasura): update user db schema for pro users (#227) * feat: add get_free_month column to user table * feat: create referral table * feat: add is_blocked column to user table * feat: add pro_user_subscription_id column to user table * fix: upt metadata * fix: update relationship name * feat(hasura): add Ai Model Tracker To Threads (#229) * feat: create 'models' table AI models * fix: add 'model' column to 'thread' table with foreign key constraint * feat: add model_value into models * [masterbots.ai] feat: multi AI models integration (#228) * [masterbots.ai]feat:(multimodels-integration)add actions - helpers - routes * [masterbots.ai]feat:(multimodels-integration)add NextTopLoader * [masterbots.ai]feat:(multimodels-integration)add NextTopLoaders * [masterbots.ai]feat:(multimodels-integration)add new chat components * [masterbots.ai]chore:next version * [masterbots.ai]feat:(multimodels-integration)update use context * [masterbots.ai]feat:(multimodels-integration)icons update * [masterbots.ai]chore:command ui * [masterbots.ai]refactor:moving chat componets to folder * [masterbots.ai]feat:env checker * [masterbots.ai]feat:env guard * docs: site map diagram * [masterbots.ai] fix: multi AI models guard (#235) * fix-guards + dom warning * fix-rename env var - vercel name * chore(masterbots.ai): update payment terms & conditions (#233) * fix: update terms * fix: building error * fix: update terms content * fix: rm the older part at the bottom * feat(masterbots.ai): pro subscription payment + wizard (#226) * feat: added free card * feat: added animation to the plan card * feat: added more plan card and referral code link * fix: clean up * wip: wizard * feat: wizard & modal * feat: plan Design theme and modal Header and Footer * feat: plan clean up * update * clean up * fix: rm plan comp on browse page * fix: wizard clean up * feat: succes & error modal * feat: loading comp * feat: added checkout comp * feat: set up stripe and context * wip: implementing subscription * feat: implementing subscription * feat: payment reciept * fix: clean up receipt * fix: modal not showing & shallow routing * fix: small fix * fix: receipt comp * fix: clean up * fix: shallow rerouting * feat: check if user has an active subscription * fix: coderabbit ob * fix: coderabbit ob * fix: coderabbit clean up update * fix: coderabbit clean up update * fix: coderabbit clean up update * fix: clean up * fix: clean up * fix: page restructuring and status on the receipt * fix: revamp receipt and structure * fix: rm unused file * fix: clean up * fix: update & clean up * fix: update * fix: rm the svg * fix: revamp formatSystemPrompts * fix: revamp msg to formatSystemPrompts * fix: update * fix: refactor the receipt page * fix: rm public key * fix: update * fix: update * fix: update * fix: code refactor for error and loading rendering * ref: calling secret keys from server * ref: receipt page and small fix * fix: rm file * fix(impr): subs & flow ux + cleanup * fix(masterbots.ai): OG not redering (#224) * fix: og to render first letter of username if there's no avatar * fix: clean up * fix: clean up * fix(masterbots.ai): share function (#225) * feat: create action.ts * fix: upt share button * fix: add axios module * fix: add resend module * fix: update vercel env config * fix: split share function * fix: update share component * [coderabbitai] style: upt thread-user-actions condition Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat(hasura): update user db schema for pro users (#227) * feat: add get_free_month column to user table * feat: create referral table * feat: add is_blocked column to user table * feat: add pro_user_subscription_id column to user table * fix: upt metadata * fix: update relationship name * feat(hasura): add Ai Model Tracker To Threads (#229) * feat: create 'models' table AI models * fix: add 'model' column to 'thread' table with foreign key constraint * feat: add model_value into models * [masterbots.ai] feat: multi AI models integration (#228) * [masterbots.ai]feat:(multimodels-integration)add actions - helpers - routes * [masterbots.ai]feat:(multimodels-integration)add NextTopLoader * [masterbots.ai]feat:(multimodels-integration)add NextTopLoaders * [masterbots.ai]feat:(multimodels-integration)add new chat components * [masterbots.ai]chore:next version * [masterbots.ai]feat:(multimodels-integration)update use context * [masterbots.ai]feat:(multimodels-integration)icons update * [masterbots.ai]chore:command ui * [masterbots.ai]refactor:moving chat componets to folder * [masterbots.ai]feat:env checker * [masterbots.ai]feat:env guard * docs: site map diagram * feat: set up stripe and context * wip: implementing subscription * fix: rm the svg * fix: replace secret with variable * fix: chat restructure * fix(update): chat restructure * fix(deployment error): can't find an icon or not exported * fix: deployment issues * fix: deployment issues * fix: deployment issues * fix: adjust design * fix: clean up * fix: clean up * fix: color var updaye * [coderabbitai] impr: update apps/masterbots.ai/components/stripe-element.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * [coderabitai] impr: update apps/masterbots.ai/components/succes-content.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: success close button * fix: bg image for yearly card * fix: move func to util * ref: receipt page function to use reac-use * fix: move depencies to the app * fix: clean up * ref: wizard to use radix dialog components * update * fix: coderabitai update --------- Co-authored-by: Roberto Lucas Co-authored-by: Nathanael Liu Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> * [masterbots.ai] fix: llama3 models (#236) * fix-guards + dom warning * fix-rename env var - vercel name * fix-changed PERPLEXITY-LLama model * [masterbots.ai] impr(fix): ui tweaks (#237) * fix(UI):varius UI fixes * fix(UI):varius UI fixes * fix(UI): Tailwind class corrections, conflict resolution, text alignent to the left * fix(UI):update * fix(masterbots.ai): payment feedbacks (#240) * fix: make the dialog content responsive * fix: free plan card adjusted * fix: update * fix: update receipt styles * fix: build error * fix: build error * fix: build error update * fix: update * fix: observation * fix(masterbots.ai): update env variable (#244) * feat: sitemap (#238) * feat: add redirection rules * fix: update all links with new shorten urls * fix: update all links with new shorten urls * feat: make folder structure according to sitemap * [coderabbitai] impr(masterbots.ai): update app/c/page.tsx error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * [coderabbitai] impr(masterbots.ai): update app/c/[category]/[chatbot]/page.tsx error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: build error * [coderabbitai] impr(masterbots.ai): update app/c/[category]/[chatbot]/page.tsx error handling Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * feat: add sitemap and metagraph * fix: use original generateMetadata * fix: update page links * fix: show only filtered threads on page reload * fix: build error --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(masterbots.ai): show first question & answer in thread list (#246) * feat: add 'disabled' state to ChatAccordion * fix: show default question's answer in thread list * fix: use braces and create explicit statement blocks * fix: subscription mobile responsive tweaks (#245) * update * fix: update * fix: responsiveness * fix: update * fix: few clean up * fix: rm unused image * fix: rm unused image * fix(impr): models enum table migrations (#247) * impr(hasura): db tables * impr(hasura): db tables * fix(hasura): user permissions * impr(hasura): sql models enum migration * fix(hasura): models_enum pk * fix(hasura): ci/cd default regional log bucket * docs: bun to requirements (#250) Co-authored-by: b * feat: next auth, email/pw strategy (#249) * (masterbots.ia)-chore-auth-dependencies * (masterbots.ia)-feat-webauth-nextauth * wip(masterbots.ai): email/pw login + signup * feat-login ui * feat-login-component+page * feat-login-component+page * feat-auth-middleware.ts * feat-auth-nextauth + googleauth * feat-auth-coderabit-feedback * feat-auth-callback + elements added * wip(webapp): email/pw login+signup * feat:add toke storage for webauth * feat:updates webauth * feat:updates webauth * fix(masterbots.ai): blankBot fetch --------- Co-authored-by: Roberto Lucas Co-authored-by: Roberto Romero Lucas * docs: mb sytem diagram v1.0a * feat(impr): next auth environment helper function (#251) * (masterbots.ia)-chore-auth-dependencies * (masterbots.ia)-feat-webauth-nextauth * wip(masterbots.ai): email/pw login + signup * feat-login ui * feat-login-component+page * feat-login-component+page * feat-auth-middleware.ts * feat-auth-nextauth + googleauth * feat-auth-coderabit-feedback * feat-auth-callback + elements added * wip(webapp): email/pw login+signup * feat:add toke storage for webauth * feat:updates webauth * feat:updates webauth * fix(masterbots.ai): blankBot fetch * feat:protecting env --------- Co-authored-by: Roberto Lucas Co-authored-by: Roberto Romero Lucas * impr(masterbots.ai): sign up form + sign in session data * docs: claude3 project knowledge docs * fix(masterbots.ai): devMode conditional * chore(masterbots.ai): rm console.log * chore: upt default hardcoded gpt model * fix: toSlug imports * fix: typo * fix(hasura): seeds * chore(impr): MB seeds update and upgrade (#253) * wip: upt seeds * chore: rm alter and table creations * chore(impr): MB seeds update and upgrade * fix: set thread to private by default * fix: prompt row typo * chore(hasura): seeds update default thread publicity * fix(masterbots.ai): adjust arrow direction in thread list (#255) * feat(impr): Vercel AI SDK Update (#256) * chore:ai version upt * chore:ai version upt * upt-ai delete * upt-ai versions * upt-sdk-actions * upt-complete-sdk-3.3 + dev notes * upt-@anthropic-ai/sdk + MessageParam * Delete apps/masterbots.ai/apps/masterbots.ai/package.json * Delete apps/masterbots.ai/apps/masterbots.ai/package-lock.json * impr-convertToCoreMessages ternary * Leandro/develop (#257) * chore: create thread-component to avoid to become thread list into a client component * refactor: remove unnecesary hooks from thread component * refactor: remove unnecesary hooks on thread componen * impr(masterbots): components folder structur (#259) * impr:refactor components folders + names + imports * hotfix:chat-list useEffect dependency removal * fix(masterbots): google signIn (#260) * fix(masterbots.ai): fix thread-component loop (#261) * fix:(masterbots.ai) add useScroll hook (#263) * fix:introducing Two-phase scroll * impr: new hook to handle scrolling * impr: useScroll + respo * feat(masterbots.ai): chat sidebar filtering (#264) * sidebar refactor with ai * fix: sidebar AI V - Prev Jun (#262) * fix:semistable * fix:stable v * impr:delete nonused component * fix: upt category filtering * fix typo --------- Co-authored-by: Roberto Lucas * feat: sidebar state * fix(masterbots.ai): logic typo * fix(masterbots.ai): ts typo --------- Co-authored-by: Jun Dam Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> * fix(masterbots.ai): bot button redirect change (#265) * wip(masterbots.ai): seo data impr (#267) * wip: seo data impr * impr(chore): ga tags * feat: add chat publicity trigger (#258) * update * feat: design thread visibilty * fix: added the backend * fix: added the backend * fix: rm files * fix: few clean up * fix(masterbots): google signIn (#260) * feat: design thread visibilty * fix: added the backend * fix: few clean up * Leandro/develop (#257) * chore: create thread-component to avoid to become thread list into a client component * refactor: remove unnecesary hooks from thread component * refactor: remove unnecesary hooks on thread componen * impr(masterbots): components folder structur (#259) * impr:refactor components folders + names + imports * hotfix:chat-list useEffect dependency removal * feat: design thread visibilty * fix: added the backend * fix: few clean up * fix: update * fix: add permission * fix: update query * fix(masterbots.ai): fix thread-component loop (#261) * feat: design thread visibilty * fix: added the backend * fix: few clean up * feat: design thread visibilty * fix: added the backend * fix: few clean up * Leandro/develop (#257) * chore: create thread-component to avoid to become thread list into a client component * refactor: remove unnecesary hooks from thread component * refactor: remove unnecesary hooks on thread componen * impr(masterbots): components folder structur (#259) * impr:refactor components folders + names + imports * hotfix:chat-list useEffect dependency removal * feat: design thread visibilty * fix: added the backend * fix: few clean up * update * fix: update * fix: publicity toggle * fix: error catch in the functions * fix: observations * fix: design impr * fix: thread pop-up height * chore(masterbots.ai): log rm & app version upt --------- Co-authored-by: Roberto Lucas Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Roberto Lucas * feat(masterbots.ai): user messages ai refactor (#266) * feat:userMessages refactor + hooks and utils * upt:rm console.log * fix:rollback useAiChat hook * fix:rollback - actions * fix(masterbots.ai): sidebar trigger * chore(hasura: s --------- Co-authored-by: Roberto Lucas * wip: browse sidebar * impr(masterbots.ai): browse sidebar (#270) * fix: browse layout * feat(masterbots.ai): browse sidebar * fix: browse sidebar link condition * chore: upt signup default profile pic * chore: seeds upt (#269) * wip: seeds upt * chore(hasura): seeds review * feat(hasura): add "is_approved" thread field + seeds * chore: mb-genql upt * fix(hasura): thread param permission * fix(masterbots.ai): typo * fix(masterbots.ai): allow svg content-type * fix: chat + browse layout * style: clean up * Seo data (#273) * fix: build error * feat: Add SEO data to the chat page * feat: add default image, if not found * feat: Add SEO data to the browse page * fix: generates the image with error, in api/og * Update route.tsx fix: generates the image with error, in api/og * impr(masterbots.ai): title impr prompt * impr(masterbots.ai): improve current features v2 (#274) * add-impr-chat-prompt-footer-header-disclaimer * add-impr-chat-prompt-footer-header-disclaimer * add-UI-upt * add-UI-upt * add-action-prompt * add-clickable-upt * add-clickable-upt * Masterbots/fix redirects (#275) * fix:avatar-redirects * fix:avatar-redirect * fix(masterbots.ai): upt components/ui/button.tsx Coderabbitai suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix:URL correction --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * [masterbots.ai] feat: wordware api (#276) * feat: add wordware api + vercel sdk strategy * feat: add wordware api + vercel sdk * wordware describe feat * wordware run + interface * impr(masterbots.ai): upt /api/wordware/describe/route.ts coderabbitai code suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * impr(masterbots.ai): upt /api/wordware/describe/route.ts coderabbitai code suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(masterbots.ai): typo /api/wordware/describe/route.ts coderabbitai code suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * doc: mb system diagram upt * wip: icl calls integrations * impr(masterbots.ai): permission for thread & user action mode (#281) * update * feat: added permissions & new column * fix: rm unnessecary files * fix: rm permission check * feat(masterbots.ai): create password recovery (#282) * feat:add-recovery-strategy * chore:add nodeemailer * upt:hasura * upt:hasura * upt:gmail service * feat(hasura): otp, token table + junction w/user + mb-genql gen * feat:add recovery password API * fix:ai suggestion + UX * feat:improve ux show password feat * chore:env sample * chore:useSetState * chore:roles --------- Co-authored-by: Roberto Lucas * [masterbots.ai] impr: WW API sanitize and keep alive (#284) * keep-alive + API sanitize + timeOut guard * impr streamAndValidateResponse fn * wip(masterbots.ai): impr createImprovementPrompt * style(masterbots.ai): chat loading states comments * feat(masterbots.ai): add admin mode to approve thread (#283) * feat:added mode toggle and approve btn * feat: added migration for user role * feat: user role flow implet * fix: impr admin approve process * fix: clean up * fix: toggle CTA changed * fix: update * fix: update * fix: observ * fix: obs clean up * fix: update * fix: clean up * impr(masterbots.ai): alpha metadata chatbot labels (#288) * wip: metadata chatbot labels * wip(masterbots.ai): chatbot metadata labels * impr(masterbots.ai): gen chatMetadata * impr: simplifying prompt defitions + biome.json base config * impr(masterbots.ai): recursive improved text prompt * style: code comments + eslint chk * impr: biome.json config * fix(masterbots.ai): conflicts typo fix * style(impr): cleanPrompt + followingQuestionsPrompt relocation & cleanup * doc: map system (simplified) * fix(masterbots.ai): sideBar updating URL (#286) * fix:sideBar updating URL * feat: coderabbit-ai suggestions * fix: Implement auto-expanding sidebar categories and chatbot highlighting based on URL * feat: optimize sidebar navigation with Link * feat: thread options (#287) * feat: added verified and label to the options * usethreadvisibility as context * feat: added option design and functions * fix: clean up * fix: update * fix: update * fix: obsv * fix: merge and update * fix: update the delete popup * fix: observ * fix: update * fix: delete thread flow * update * fix: update * fix: types * fix: chatbot not required * fix: testing * fix: rm bun.lock * fix: clean up * fix: update * fix(masterbots.ai): temp freezing next version --------- Co-authored-by: Roberto Lucas * [masterbots.ai] feat: email verification (#289) * feat: email verification * feat: email verification * feat: email verification * upt:build * feat: handle error redirection * chore:cron task * upt: cron blocking instead erasing * feat(hasura): create social following table. (#292) * feat(db): create social following table. * create user following and followers relationships. * fix(db): ensure users can only manage their own follow relationships. * feat(db): social following and user table permissions improvements. * feat(db): improving social following table with timestamp and idx. * impr(db): permissions and tracked object relationships. * impr(db): avoid self follow. * chore(masterbots.ai): guard WordWare for prod routing * [masterbots.ai] fix: public/private tag bg on dark mode (#294) * fix: tag bg * fix: text color * fix: browse page error * fix: debugging * fix: debugging * fix: debugging * fix: added func to generate short link * fix(hasura): upt user permissions (#296) * update user permission * fix: reverse the following table * fix(hasura): build error (#297) * fix: error build * fix: reverse select perm * [masterbots.ai] feat: thread list display + components comments for ai (#299) * merged from develop * feat:add new ui-thread-representation-browse * feat:add comments for ai - C * feat:add comments for ai - b/p * feat:add comments for ai - b/p * feat:add comments for ai - b/p * feat:add app theme colors effects * feat:add comments for ai - b/p * [masterbots.ai] feat: chatbot search tool v0.1a (#295) * wip: chatbot search tool * wip(impr): ww api + chat ui tweaks * fix: init sidebar load state * fix: nesting layout * fix: thread-popup ui header * wip(impr): chatbot tooling * impr: loading state + debug chatbot tools * wip(fix): nodejs context * fix(temp): rm edge runtime api config * [masterbots.ai] feat: reorganize navigation menu for mobile view (#298) * feat: reorganize navigation menu for mobile view * UI: add sideBar style * feat: add link profile and logout icon * Update profile-sidebar.tsx Tailwind class fix * [masterbots.ai] feat: UI + Logic Improvements (#301) * feat:impr responsive * feat:impr password strenght checker * feat:impr responsive * upt-build * feat:respomsive tweask * feat:back arrow aria label * fix:chat mobile layout * fix:code section * fix:chat pannel * fix:chatBot redirection * feat:restore appConfig header * [masterbots.ai] fix: restore desktop navigation link - browse section (#303) * fix:restore desktop navigation link - browse * fix:formating * feat:yellow combobox btn (JUN-REQUEST) * glowing effect variant * upt:removed /b navigation as original v * feat:powerup mode + provider * [masterbots.ai] fix(impr): browse and chat content search (#304) * feat:browse title and content search * feat:browse title and content search * fix:typo * impr:reusable non result component * feat:skeletons * feat:guard * fix:skeletons * fix:chat searching * fix: add accent colour --------- Co-authored-by: Roberto Lucas * [masterbots.ai] impr: seo sitemap (#306) * chore: sitemap creation * chore: add description based on category * chore: update queries in services * chore: truncate text * impr: upt (browse)/[category]/[threadId]/sitemap.ts coderabbitai code suggestion. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Roberto Lucas Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * [masterbots.ai] impr: ai tools (#302) * wip: ai tools * fix: WW json regexp * impr: simplifying main ai call * wip(fix): chat component re-render + cleanup * impr(refactor): chat hooks * fix: ts build * fix: ts build * fix: ts typo * fix: typo * impr: ai feedbacks * [masterbots.ai] wip(impr): web search (#309) * impr: web search tool call * fix: colour values * fix: typo * impr: code suggestions * fix: class name typo * wip(fix): web search false positive response + webSearch context * fix: web search callback * fix: typo * feat: profile page (#300) * feat: user card * fix: update * merge develop && update * feat: user generate bio & favourite topic * fix: update user card * feat: added profile sidebar * fix: update * update * update * update * fix: fetch approved and public threads * fix: fetch approved and public threads * update * fix: clean up and update * update * make fetch user work with bio * update * update * design updating * update * update * fix: few changes * update * fix: design update * fix: footer in layout * fix: update * fix: resercation * update * profile upload * feat: move the cloudinary key to env * fix: layout * fix: layout update * [masterbots.ai] fix: shallow routing for category & chatbots for chat & profile page (#313) * update * feat: added shallow link to the sidebar link * update' * fix: routing and content fetching * fix:update on routing * fix:update * update * update * update * fix: clean up * update * update * [masterbots.ai] feat: update ChatChatbotDetails (#314) * feat: new bot profile - chat * chore: dev comments * chore: white bg bot avatar * feat: add skeleton bot profile * [masterbots.ai] feat: include custom settings options (#317) * feat:relocation of theme switch(jun) * feat: create font-size accessibility provider(jun) * feat: r-sidebar theme switcher relocation + skeleton * feat: impr add rem instead px * [masterbots.ai] feat: integrate drizzle ORM (#320) * feat: create mb-drizzle package initial structure * feat:(masterbots.ai) add drizzle endpoint + service * chore: include database url * chore: upt mb-drizzle * feat: refactor drizzle config + generations * chore: impr migrate * chore: add working drizzle connection + migrations * feat: add centralized actions * chore: add ai review recomendations * chore: webSearch feature flag + use cloudinary upload preset * fix: responsive sidebar fix * fix: ts chk build * fix: sidebar async call * fix: ts build * chore: typo * [masterbots.ai] fix: browse category navigation (#316) * update * fix: rm category * update * fix: pop up on the user threads * update * update clean up * update * fix: clean up * fix: clean up and update * fix: update * fix: popup on navigation * fix: update * update * update * update * clean up * update * merge * fix: hasura thread delete + user dup permissions (#330) --------- Co-authored-by: Gabo Esquivel Co-authored-by: Jimoh sherifdeen <63134009+sheriffjimoh@users.noreply.github.com> Co-authored-by: Nathanael Liu Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Brandon Fernández <31634868+Bran18@users.noreply.github.com> Co-authored-by: Anouk Rímola <77553677+AnoukRImola@users.noreply.github.com> Co-authored-by: Trivium <25100787+Nemunas@users.noreply.github.com> Co-authored-by: Leandro Gavidia Santamaria <93232139+leandrogavidia@users.noreply.github.com> Co-authored-by: Jun Dam Co-authored-by: Luis Carrión <41096968+luighis@users.noreply.github.com> Co-authored-by: Marco Ledezma --- .../masterbots/tables/public_user.yaml | 17 -- .../app/(browse)/[category]/page.tsx | 4 +- .../layout/sidebar/sidebar-link.tsx | 33 +-- .../layout/sidebar/sidebar-responsive.tsx | 7 +- .../components/layout/sidebar/sidebar.tsx | 15 ++ .../routes/browse/browse-list-item.tsx | 4 +- .../components/routes/browse/browse-list.tsx | 25 ++- .../components/routes/chat/chat-accordion.tsx | 21 +- .../routes/thread/thread-component.tsx | 21 +- .../routes/thread/user-thread-panel.tsx | 56 +++-- apps/masterbots.ai/lib/hooks/use-mb-chat.ts | 24 +-- apps/masterbots.ai/lib/hooks/use-profile.tsx | 17 +- apps/masterbots.ai/lib/url.ts | 82 ++++++- .../services/hasura/hasura.service.ts | 201 +++++++++--------- 14 files changed, 303 insertions(+), 224 deletions(-) mode change 100644 => 100755 apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx mode change 100644 => 100755 apps/masterbots.ai/components/layout/sidebar/sidebar-responsive.tsx mode change 100644 => 100755 apps/masterbots.ai/components/routes/browse/browse-list-item.tsx mode change 100644 => 100755 apps/masterbots.ai/components/routes/thread/thread-component.tsx mode change 100644 => 100755 apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx mode change 100644 => 100755 apps/masterbots.ai/services/hasura/hasura.service.ts diff --git a/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml b/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml index ac96b81f..354c518a 100644 --- a/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml +++ b/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml @@ -141,23 +141,6 @@ select_permissions: - username filter: {} comment: "" - - role: moderator - permission: - columns: - - date_joined - - email - - get_free_month - - is_blocked - - is_verified - - last_login - - pro_user_subscription_id - - profile_picture - - role - - slug - - user_id - - username - filter: {} - comment: "" - role: user permission: columns: diff --git a/apps/masterbots.ai/app/(browse)/[category]/page.tsx b/apps/masterbots.ai/app/(browse)/[category]/page.tsx index 32629b69..ababbe55 100644 --- a/apps/masterbots.ai/app/(browse)/[category]/page.tsx +++ b/apps/masterbots.ai/app/(browse)/[category]/page.tsx @@ -15,10 +15,10 @@ export default async function BrowseCategoryPage({ return (
- + /> */}
diff --git a/apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx b/apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx old mode 100644 new mode 100755 index 63bbae2a..57b5595e --- a/apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx +++ b/apps/masterbots.ai/components/layout/sidebar/sidebar-link.tsx @@ -3,6 +3,7 @@ import { Checkbox } from "@/components/ui/checkbox" import { IconCaretRight } from '@/components/ui/icons' import { useSidebar } from '@/lib/hooks/use-sidebar' +import { urlBuilders } from '@/lib/url' import { cn } from '@/lib/utils' import { Category, Chatbot } from 'mb-genql' import { toSlug } from 'mb-lib' @@ -20,7 +21,7 @@ interface SidebarLinkProps { export default function SidebarLink({ category, isFilterMode, page }: SidebarLinkProps) { const router = useRouter() const pathname = usePathname() - const isBrowse = !pathname.includes('/c') && !pathname.includes('/u') + const isBrowse = !/^\/(?:c|u)(?:\/|$)/.test(pathname) const { slug } = useParams() const { @@ -53,13 +54,17 @@ export default function SidebarLink({ category, isFilterMode, page }: SidebarLin navigateTo({ page, slug: typeof slug === 'string' ? slug : undefined, - categoryName: toSlug(category.name.toLowerCase()) + categoryName: toSlug(category.name.toLowerCase()), + isBrowse }) - } else { + } + else { + setActiveChatbot(null) navigateTo({ page, slug: typeof slug === 'string' ? slug : undefined, + isBrowse }) } return newCategory @@ -138,21 +143,22 @@ export default function SidebarLink({ category, isFilterMode, page }: SidebarLin return ( ) @@ -177,7 +183,7 @@ const ChatbotComponent: React.FC = React.memo(function Ch }) { const { selectedChatbots, toggleChatbotSelection, navigateTo } = useSidebar() const pathname = usePathname() - const isBrowse = !pathname.includes('/c') && !pathname.includes('/u') + const isBrowse = !/^\/(?:c|u)(?:\/|$)/.test(pathname) const { slug } = useParams() const handleChatbotClick = useCallback((e: React.MouseEvent) => { @@ -188,7 +194,8 @@ const ChatbotComponent: React.FC = React.memo(function Ch page, slug: slug as string, categoryName: toSlug(category.name.toLowerCase()), - chatbotName: chatbot.name.toLowerCase() + chatbotName: chatbot.name.toLowerCase(), + isBrowse }) } }, [chatbot, setActiveChatbot, isFilterMode]) @@ -206,7 +213,7 @@ const ChatbotComponent: React.FC = React.memo(function Ch className={cn( 'flex items-center p-2 w-full', isActive && 'bg-blue-100 dark:bg-blue-900', - 'hover:bg-gray-100 dark:hover:bg-gray-800' + 'hover:bg-gray-100 dark:hover:bg-gray-800', )} > {isFilterMode && ( @@ -228,7 +235,7 @@ const ChatbotComponent: React.FC = React.memo(function Ch ) : ( - {/* */} - {/*

Chat history

*/} - {/* */} - + w-[300px] lg:w-[250px] xl:w-[300px]"/> ) } diff --git a/apps/masterbots.ai/components/layout/sidebar/sidebar.tsx b/apps/masterbots.ai/components/layout/sidebar/sidebar.tsx index 9bd33f40..308ff070 100644 --- a/apps/masterbots.ai/components/layout/sidebar/sidebar.tsx +++ b/apps/masterbots.ai/components/layout/sidebar/sidebar.tsx @@ -5,10 +5,25 @@ import { SidebarHeader } from '@/components/layout/sidebar/sidebar-header' import { useSidebar } from '@/lib/hooks/use-sidebar' import { cn } from '@/lib/utils' import React from 'react' +import { usePathname } from 'next/navigation' +import { useThread } from '@/lib/hooks/use-thread' export function Sidebar({ className }: React.ComponentProps<'div'>) { const { isSidebarOpen, isLoading } = useSidebar() + const prevPathRef = React.useRef(usePathname()); + const pathname = usePathname(); + const { setActiveThread, setIsOpenPopup } = useThread() + const rootAndChatRegex = /^\/(?:c)?$/; + React.useEffect(() => { + if (rootAndChatRegex.test(pathname)) { + setActiveThread(null); + setIsOpenPopup(false); + } + prevPathRef.current = pathname; + }, [pathname]); + + if (isLoading) return null return ( diff --git a/apps/masterbots.ai/components/routes/browse/browse-list-item.tsx b/apps/masterbots.ai/components/routes/browse/browse-list-item.tsx old mode 100644 new mode 100755 index f668afb2..fbd75ad4 --- a/apps/masterbots.ai/components/routes/browse/browse-list-item.tsx +++ b/apps/masterbots.ai/components/routes/browse/browse-list-item.tsx @@ -36,6 +36,8 @@ import Image from 'next/image' import { useRouter } from 'next/navigation' import React from 'react' import { ChatOptions } from '../chat/chat-options' +import { urlBuilders } from '@/lib/url' + let initialUrl: string | null = null @@ -139,7 +141,7 @@ export default function BrowseListItem({ e.preventDefault() e.stopPropagation() if (thread?.user?.slug) { - router.push(`/u/${thread?.user?.slug}/t`) + router.push(urlBuilders.userProfileUrl({ userSlug: thread.user.slug })) } } diff --git a/apps/masterbots.ai/components/routes/browse/browse-list.tsx b/apps/masterbots.ai/components/routes/browse/browse-list.tsx index ddd2b285..b37c78c8 100644 --- a/apps/masterbots.ai/components/routes/browse/browse-list.tsx +++ b/apps/masterbots.ai/components/routes/browse/browse-list.tsx @@ -41,12 +41,12 @@ export default function BrowseList() { const [filteredThreads, setFilteredThreads] = React.useState([]) const [loading, setLoading] = React.useState(false) const [count, setCount] = React.useState(0) - const { selectedCategories, selectedChatbots } = useSidebar() + const { selectedCategories, selectedChatbots, activeCategory, activeChatbot } = useSidebar() const fetchThreads = async ({ categoriesId, chatbotsId, - keyword + keyword, }: { categoriesId: number[] chatbotsId: number[] @@ -55,10 +55,17 @@ export default function BrowseList() { setLoading(true) // ? Seting loading before fetch try { const threads = await getBrowseThreads({ - categoriesId, - chatbotsId, - keyword, - limit: PAGE_SIZE + ...(activeCategory !== null || activeChatbot !== null + ? { + categoryId: activeCategory, + chatbotName: activeChatbot?.name, + } + : { + categoriesId, + chatbotsId, + keyword, + }), + limit: PAGE_SIZE, }) setThreads(threads) setFilteredThreads(threads) @@ -108,12 +115,8 @@ export default function BrowseList() { categoriesId: selectedCategories, chatbotsId: selectedChatbots }) + }, [selectedCategories, selectedChatbots, activeCategory, activeChatbot]) - console.log({ - selectedCategories, - selectedChatbots - }) - }, [selectedCategories, selectedChatbots]) // biome-ignore lint/correctness/useExhaustiveDependencies: React.useEffect(() => { diff --git a/apps/masterbots.ai/components/routes/chat/chat-accordion.tsx b/apps/masterbots.ai/components/routes/chat/chat-accordion.tsx index 08ef6af8..3ce4b94c 100644 --- a/apps/masterbots.ai/components/routes/chat/chat-accordion.tsx +++ b/apps/masterbots.ai/components/routes/chat/chat-accordion.tsx @@ -1,8 +1,10 @@ //* Component for displaying a collapsible chat thread accordion import { useThread } from '@/lib/hooks/use-thread' +import { urlBuilders } from '@/lib/url' import { ChevronDown } from 'lucide-react' import type { Thread } from 'mb-genql' +import { useParams, usePathname, useRouter } from 'next/navigation' import React from 'react' export const ChatAccordion = ({ @@ -42,8 +44,13 @@ export const ChatAccordion = ({ isOpenPopup } = useThread() + const pathname = usePathname() + const params = useParams() + const router = useRouter(); + //* Sets the initial open state based on defaultState prop const initialState = defaultState + const profilePage = /^\/u\/[^/]+\/t(?:\/|$)/.test(pathname) const [open, setOpen] = React.useState(initialState) const isMainThread = !isOpenPopup @@ -52,12 +59,24 @@ export const ChatAccordion = ({ const handleClick = (e: React.MouseEvent) => { e.stopPropagation() - if (isMainThread && thread) { + if (isMainThread && thread && !profilePage) { //* Main thread click - open modal setActiveThread(thread) setIsOpenPopup(true) } else { //* Sub-conversation click - toggle accordion + if (profilePage) { + setIsOpenPopup(false) + setActiveThread(null) + const category = thread?.chatbot?.categories[0]?.category?.name + const chatbot = thread?.chatbot?.name + const slug = params.slug; + if (!category || !chatbot || !slug) { + console.error('Missing required navigation parameters'); + return; + } + router.push(urlBuilders.threadUrl({ slug: slug as string, category, chatbot, threadId: thread?.threadId })) + } toggle() } } diff --git a/apps/masterbots.ai/components/routes/thread/thread-component.tsx b/apps/masterbots.ai/components/routes/thread/thread-component.tsx old mode 100644 new mode 100755 index f76cc720..a4c9596a --- a/apps/masterbots.ai/components/routes/thread/thread-component.tsx +++ b/apps/masterbots.ai/components/routes/thread/thread-component.tsx @@ -37,12 +37,9 @@ import { useScroll } from '@/lib/hooks/use-scroll' import { useThread } from '@/lib/hooks/use-thread' import { useThreadVisibility } from '@/lib/hooks/use-thread-visibility' import type { Thread } from 'mb-genql' -import { toSlug } from 'mb-lib' -import { redirect, useParams, usePathname } from 'next/navigation' import { useRef } from 'react' import { AdminModeApprove } from '../chat/admin-mode-approve' import { ChatOptions } from '../chat/chat-options' - export default function ThreadComponent({ thread, loadMore, @@ -60,8 +57,6 @@ export default function ThreadComponent({ const contentRef = useRef(null) const { isNewResponse } = useThread() const { isAdminMode } = useThreadVisibility() - const pathname = usePathname() - const params = useParams() const { isNearBottom, scrollToTop } = useScroll({ containerRef: contentRef, @@ -74,22 +69,8 @@ export default function ThreadComponent({ }) const threadId = thread.threadId - const handleAccordionToggle = () => { - - if (pathname.includes('u') && pathname.includes('t')) { - const category = thread?.chatbot?.categories[0]?.category?.name - const chatbot = thread?.chatbot?.name - const slug = params.slug; - - if (!category || !chatbot || !slug) { - console.error('Missing required navigation parameters'); - return scrollToTop(); - } - redirect(`/u/${slug}/t/${toSlug(category)}/${toSlug(chatbot)}/${thread.threadId}`) - } else { - scrollToTop() - } + scrollToTop() } return (
  • diff --git a/apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx b/apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx old mode 100644 new mode 100755 index b77b556e..b62a1432 --- a/apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx +++ b/apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx @@ -35,11 +35,10 @@ import { useThreadVisibility } from '@/lib/hooks/use-thread-visibility' import { getBrowseThreads, getThreads, getUserBySlug } from '@/services/hasura' import type { Thread } from 'mb-genql' import { useSession } from 'next-auth/react' -import { useParams } from 'next/navigation' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useParams, usePathname } from 'next/navigation' +import { useEffect, useMemo, useRef, useState } from 'react' import { useAsync } from 'react-use' - const PAGE_SIZE = 20 export default function UserThreadPanel({ @@ -61,7 +60,7 @@ export default function UserThreadPanel({ const [loading, setLoading] = useState(false) const { threads: hookThreads } = useThreadVisibility() const [searchTerm, setSearchTerm] = useState('') - const { slug } = params; + const { slug, threadId } = params; const userWithSlug = useAsync(async () => { if (!slug) return { user: null } @@ -81,6 +80,8 @@ export default function UserThreadPanel({ const [totalThreads, setTotalThreads] = useState(0) const prevCategoryRef = useRef(activeCategory); const prevChatbotRef = useRef(activeChatbot); + const prevPathRef = useRef(usePathname()); + const pathname = usePathname(); useEffect(() => { setThreads(finalThreads) @@ -111,8 +112,9 @@ export default function UserThreadPanel({ console.log('🟡 Loading More Content') setLoading(true) let moreThreads: Thread[] = [] - - if (page === 'profile' && !session?.user) { + const userOnSlug = userWithSlug.value?.user + const isOwnProfile = session?.user?.id === userOnSlug?.userId; + if (page === 'profile' && !session?.user || !isOwnProfile) { moreThreads = await fetchBrowseThreads(); } else { moreThreads = await getThreads({ @@ -131,23 +133,20 @@ export default function UserThreadPanel({ const handleThreadsChange = async () => { let threads: Thread[] = [] - - console.log('🟡 Fetching Threads') setLoading(true) - const isOwnProfile = session?.user?.slug === slug; - if (!session?.user || !isOwnProfile) { - if (page === 'profile') { - threads = await fetchBrowseThreads(); - setThreads(_prev => threads ?? []) - setCount(_prev => threads.length ?? 0) - setTotalThreads(threads?.length ?? 0) - } + const userOnSlug = userWithSlug.value?.user + const isOwnProfile = session?.user?.id === userOnSlug?.userId; + if (!session?.user || !isOwnProfile && page === 'profile') { + threads = await fetchBrowseThreads(); + setThreads(_prev => threads ?? []) + setCount(_prev => threads.length ?? 0) + setTotalThreads(threads?.length ?? 0) setLoading(false) return; } + const currentFetchId = Date.now() // Generate a unique identifier for the current fetch fetchIdRef.current = currentFetchId - threads = await getThreads({ jwt: session!.user?.hasuraJwt, userId: session!.user.id, @@ -166,31 +165,26 @@ export default function UserThreadPanel({ setLoading(false) } - - const shouldFetchThreads = useCallback(() => { - if (isOpenPopup) return false; + useEffect(() => { + // Skip if popup is open + if (isOpenPopup) return; const shouldFetch = activeCategory || activeChatbot || (prevCategoryRef.current && !activeCategory) || - (prevChatbotRef.current && !activeChatbot); + (prevChatbotRef.current && !activeChatbot) || + pathname !== prevPathRef.current; // Add pathname check - // Update refs after checking + // Update refs prevCategoryRef.current = activeCategory; prevChatbotRef.current = activeChatbot; + prevPathRef.current = pathname; - return shouldFetch; - }, [isOpenPopup, activeCategory, activeChatbot]); - - - useEffect(() => { - if (shouldFetchThreads()) { + if (shouldFetch) { handleThreadsChange(); } - }, [activeCategory, activeChatbot, isOpenPopup, shouldFetchThreads]); - - + }, [activeCategory, activeChatbot, isOpenPopup, pathname]); useEffect(() => { if ( diff --git a/apps/masterbots.ai/lib/hooks/use-mb-chat.ts b/apps/masterbots.ai/lib/hooks/use-mb-chat.ts index 05827fa0..98390289 100644 --- a/apps/masterbots.ai/lib/hooks/use-mb-chat.ts +++ b/apps/masterbots.ai/lib/hooks/use-mb-chat.ts @@ -2,7 +2,6 @@ import { improveMessage } from '@/app/actions' import { formatSystemPrompts } from '@/lib/actions' import { followingQuestionsPrompt, - setDefaultPrompt, setDefaultUserPreferencesPrompt } from '@/lib/constants/prompts' import { useModel } from '@/lib/hooks/use-model' @@ -16,7 +15,7 @@ import { getThread, saveNewMessage } from '@/services/hasura' -import type { AiClientType, AiToolCall, CleanPromptResult } from '@/types/types' +import type { AiClientType, AiToolCall } from '@/types/types' import type { Message as AiMessage, ChatRequestOptions, @@ -58,7 +57,7 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback { messagesFromDB: [] as Message[] }) - console.log('[HOOK] webSearch', webSearch) + // console.log('[HOOK] webSearch', webSearch) const params = useParams<{ chatbot: string; threadId: string }>() const { selectedModel, clientType } = useModel() @@ -75,11 +74,11 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback { // format all user prompts and chatgpt 'assistant' messages const userAndAssistantMessages: AiMessage[] = activeThread ? messagesFromDB.map(m => ({ - id: m.messageId, - role: m.role as AiMessage['role'], - content: m.content, - createdAt: m.createdAt - })) + id: m.messageId, + role: m.role as AiMessage['role'], + content: m.content, + createdAt: m.createdAt + })) : [] // concatenate all message to pass it to chat component @@ -265,12 +264,9 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback { isNewChat ? { ...userMessage, content: userContentRef.current } : { - ...userMessage, - content: followingQuestionsPrompt( - userContentRef.current, - messages - ) - } + ...userMessage, + content: followingQuestionsPrompt(userContentRef.current, messages) + } // ? Provide chat attachments here... // { // experimental_attachments: [], diff --git a/apps/masterbots.ai/lib/hooks/use-profile.tsx b/apps/masterbots.ai/lib/hooks/use-profile.tsx index 3e79e0a2..69acbc31 100644 --- a/apps/masterbots.ai/lib/hooks/use-profile.tsx +++ b/apps/masterbots.ai/lib/hooks/use-profile.tsx @@ -1,15 +1,15 @@ 'use client' -import * as React from 'react' import { getUserBySlug, updateUserPersonality } from '@/services/hasura' -import { useSession } from 'next-auth/react' import { User } from 'mb-genql' +import { useSession } from 'next-auth/react' +import * as React from 'react' import toast from 'react-hot-toast' interface profileContextProps { getuserInfo: (username: string) => Promise isSameUser: (userId: string) => boolean - updateUserInfo: (bio: string | null, topic: string | null, profilePicture: string | null) => void + updateUserInfo: (bio: string | null, topic: string | null, profilePicture: string | null) => void currentUser: User | null, setCurrentUser: React.Dispatch> } @@ -42,9 +42,10 @@ export function ProfileProvider({ children }: ProfileProviderProps) { throw new Error('Slug is required') } try { + const sessionSlug = session?.user.slug ? session?.user.slug.toLowerCase() : session?.user.name?.toLowerCase() const userInfo = await getUserBySlug({ slug, - isSameUser: session?.user.slug == slug + isSameUser: sessionSlug === slug }) if (!userInfo) { throw new Error('User not found') @@ -59,12 +60,12 @@ export function ProfileProvider({ children }: ProfileProviderProps) { const isSameUser = (userId: string) => { if (!userId?.trim() || !session?.user?.id) { - return false - } + return false + } return session?.user.id === userId } - const updateUserInfo = async (bio: string | null, topic: string | null, profilePicture: string | null ) => { + const updateUserInfo = async (bio: string | null, topic: string | null, profilePicture: string | null) => { try { const jwt = session?.user?.hasuraJwt; if (!jwt || !session.user?.id) { @@ -85,7 +86,7 @@ export function ProfileProvider({ children }: ProfileProviderProps) { return ( {children} diff --git a/apps/masterbots.ai/lib/url.ts b/apps/masterbots.ai/lib/url.ts index 759d9d58..8e1e6355 100644 --- a/apps/masterbots.ai/lib/url.ts +++ b/apps/masterbots.ai/lib/url.ts @@ -1,4 +1,5 @@ import { z, ZodSchema } from 'zod' +import { toSlug } from 'mb-lib' // Zod schema for validating slug strings export const SlugSchema: ZodSchema = z @@ -16,4 +17,83 @@ export const encodeQuery = (input: string): string => { export const decodeQuery = (input: string): string => { return decodeURIComponent(input.replace(/\+/g, ' ')) -} \ No newline at end of file +} + + +interface ThreadUrlParams { + slug?: string; + category?: string; + chatbot?: string; + threadId?: string; +} + +interface ProfileUrlParams { + slug?: string; + category?: string; + chatbot?: string; +} + +interface UserProfileParams { + userSlug?: string; +} + +export const urlBuilders = { + threadUrl: (params: ThreadUrlParams): string => { + try { + const { slug, category, chatbot, threadId } = params; + + if (!slug || !category || !chatbot || !threadId) { + const missing = Object.entries(params) + .filter(([_, value]) => !value) + .map(([key]) => key) + .join(', '); + + console.error(`Missing required parameters for thread URL: ${missing}`); + return '/'; + } + + return `/u/${encodeURIComponent(slug)}/t/${toSlug(category)}/${toSlug(chatbot)}/${threadId}`; + } catch (error) { + console.error('Error constructing thread URL:', error); + return '/'; + } + }, + + userChatbotUrl: (params: ProfileUrlParams): string => { + try { + const { slug, category, chatbot } = params; + + if (!slug || !category || !chatbot) { + const missing = Object.entries(params) + .filter(([_, value]) => !value) + .map(([key]) => key) + .join(', '); + + console.error(`Missing required parameters for profile URL: ${missing}`); + return '/'; + } + + return `/u/${encodeURIComponent(slug)}/t/${toSlug(category)}/${chatbot.toLowerCase()}`; + } catch (error) { + console.error('Error constructing profile URL:', error); + return '/'; + } + }, + + userProfileUrl: (params: UserProfileParams): string => { + try { + const { userSlug } = params; + + if (!userSlug) { + console.error('Missing user slug for profile URL'); + return '/'; + } + + return `/u/${encodeURIComponent(userSlug)}/t`; + } catch (error) { + console.error('Error constructing user profile URL:', error); + return '/'; + } + }, +}; + diff --git a/apps/masterbots.ai/services/hasura/hasura.service.ts b/apps/masterbots.ai/services/hasura/hasura.service.ts old mode 100644 new mode 100755 index 5785f481..10b51eb3 --- a/apps/masterbots.ai/services/hasura/hasura.service.ts +++ b/apps/masterbots.ai/services/hasura/hasura.service.ts @@ -680,6 +680,107 @@ export async function approveThread({ } } +export async function getUserRoleByEmail({ + email +}: { + email: string | null | undefined +}) { + try { + const client = getHasuraClient({ jwt: '' }) + const { user } = await client.query({ + user: { + __args: { + where: { email: { _eq: email } } + }, + role: true, + slug: true + } + }) + return { users: user as User[] } + } catch (error) { + console.error('Error fetching user role by email:', error) + return { users: [], error: 'Failed to fetch user role by email.' } + } +} + +export async function deleteThread({ + threadId, + jwt, + userId +}: { + threadId: string + jwt: string | undefined + userId: string | undefined +}) { + try { + if (!jwt) { + throw new Error('Authentication required for thread deletion') + } + + const client = getHasuraClient({ jwt }) + await client.mutation({ + deleteThread: { + __args: { + where: { threadId: { _eq: threadId }, userId: { _eq: userId } } + }, + returning: { + threadId: true + }, + affectedRows: true + } + }) + + return { success: true } + } catch (error) { + console.error('Error deleting thread:', error) + return { success: false, error: 'Failed to delete the thread.' } + } +} + +// get all threads that are not approved +export async function getUnapprovedThreads({ jwt }: { jwt: string }) { + if (!jwt) { + throw new Error('Authentication required to access unapproved threads') + } + const client = getHasuraClient({ jwt }) + const { thread } = await client.query({ + thread: { + __args: { + where: { isApproved: { _eq: false } }, + orderBy: [{ createdAt: 'DESC' }], + limit: 20 + }, + chatbot: { + ...everything, + categories: { + category: { + ...everything + }, + ...everything + }, + threads: { + threadId: true + }, + prompts: { + prompt: everything + } + }, + messages: { + ...everything, + __args: { + orderBy: [{ createdAt: 'ASC' }], + limit: 2 + } + }, + isApproved: true, + isPublic: true, + ...everything + } + }) + + return thread as Thread[] +} + export async function getUserBySlug({ slug, isSameUser @@ -804,7 +905,7 @@ export async function updateUserPersonality({ updateArgs._set = { ...(bio !== null && { bio }), - ...(topic !== null && { favourite_topic: topic }), + ...(topic !== null && { favouriteTopic: topic }), ...(profilePicture !== null && { profilePicture }) } @@ -824,104 +925,6 @@ export async function updateUserPersonality({ } } -export async function getUserRoleByEmail({ - email -}: { - email: string | null | undefined -}) { - try { - const client = getHasuraClient({ jwt: '' }) - const { user } = await client.query({ - user: { - __args: { - where: { email: { _eq: email } } - }, - role: true, - slug: true - } - }) - return { users: user as User[] } - } catch (error) { - console.error('Error fetching user role by email:', error) - return { users: [], error: 'Failed to fetch user role by email.' } - } -} - -export async function deleteThread({ - threadId, - jwt, - userId -}: { - threadId: string - jwt: string | undefined - userId: string | undefined -}) { - try { - if (!jwt) { - throw new Error('Authentication required for thread deletion') - } - - const client = getHasuraClient({ jwt }) - await client.mutation({ - deleteThread: { - __args: { - where: { threadId: { _eq: threadId }, userId: { _eq: userId } } - } - }, - affected_rows: true - }) - - return { success: true } - } catch (error) { - console.error('Error deleting thread:', error) - return { success: false, error: 'Failed to delete the thread.' } - } -} - -// get all threads that are not approved -export async function getUnapprovedThreads({ jwt }: { jwt: string }) { - if (!jwt) { - throw new Error('Authentication required to access unapproved threads') - } - const client = getHasuraClient({ jwt }) - const { thread } = await client.query({ - thread: { - __args: { - where: { isApproved: { _eq: false } }, - orderBy: [{ createdAt: 'DESC' }], - limit: 20 - }, - chatbot: { - ...everything, - categories: { - category: { - ...everything - }, - ...everything - }, - threads: { - threadId: true - }, - prompts: { - prompt: everything - } - }, - messages: { - ...everything, - __args: { - orderBy: [{ createdAt: 'ASC' }], - limit: 2 - } - }, - isApproved: true, - isPublic: true, - ...everything - } - }) - - return thread as Thread[] -} - export async function subtractChatbotMetadataLabels( metadataHeaders: ChatbotMetadataHeaders, userPrompt: string,