diff --git a/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml b/apps/hasura/metadata/databases/masterbots/tables/public_user.yaml
index ac96b81f4..354c518a0 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 32629b690..ababbe556 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 63bbae2a3..57b5595e5
--- 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 9bd33f40e..308ff0703 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 f668afb2c..fbd75ad48
--- 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 ddd2b2859..b37c78c80 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 08ef6af8c..3ce4b94cc 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 f76cc7203..a4c9596a2
--- 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 b77b556e6..b62a14320
--- 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 05827fa0f..983902895 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 3e79e0a21..69acbc311 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 759d9d580..8e1e63555 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 5785f4816..10b51eb3e
--- 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,