diff --git a/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx b/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx index 1f203e3d..4a3d0699 100644 --- a/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx +++ b/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx @@ -1,19 +1,22 @@ -import { getThread } from '@/services/hasura' -import { BrowseThread } from '@/components/browse/browse-thread' +import { getMessagePairs, getThread } from '@/services/hasura' + import type { ChatPageProps } from '@/app/c/[chatbot]/[threadId]/page' -import Shortlink from '@/components/browse/shortlink-button' +import Shortlink from '@/components/routes/browse/shortlink-button' +import { ThreadAccordion } from '@/components/shared/thread-accordion' export default async function ThreadLandingPage({ params }: ChatPageProps) { const thread = await getThread({ threadId: params.threadId }) - return ( - <> -
- -
+ const initialMessagePairs = await getMessagePairs(thread.threadId) - - + return ( +
+ + +
) } diff --git a/apps/masterbots.ai/app/(browse)/[category]/page.tsx b/apps/masterbots.ai/app/(browse)/[category]/page.tsx index 6e85dee8..2320051e 100644 --- a/apps/masterbots.ai/app/(browse)/[category]/page.tsx +++ b/apps/masterbots.ai/app/(browse)/[category]/page.tsx @@ -1,6 +1,6 @@ -import BrowseList from '@/components/shared/thread-dialog/thread-list' -import { BrowseCategoryTabs } from '@/components/browse/browse-category-tabs' -import { BrowseSearchInput } from '@/components/browse/browse-search-input' +import BrowseList from '@/components/shared/thread-list' +import { BrowseCategoryTabs } from '@/components/routes/browse/browse-category-tabs' +import { BrowseSearchInput } from '@/components/routes/browse/browse-search-input' import { getBrowseThreads, getCategories } from '@/services/hasura' export const revalidate = 3600 // revalidate the data at most every hour diff --git a/apps/masterbots.ai/app/(browse)/page.tsx b/apps/masterbots.ai/app/(browse)/page.tsx index 9fb09e1e..0a502c0e 100644 --- a/apps/masterbots.ai/app/(browse)/page.tsx +++ b/apps/masterbots.ai/app/(browse)/page.tsx @@ -1,6 +1,6 @@ -import BrowseList from '@/components/shared/thread-dialog/thread-list' -import { BrowseCategoryTabs } from '@/components/browse/browse-category-tabs' -import { BrowseSearchInput } from '@/components/browse/browse-search-input' +import BrowseList from '@/components/shared/thread-list' +import { BrowseCategoryTabs } from '@/components/routes/browse/browse-category-tabs' +import { BrowseSearchInput } from '@/components/routes/browse/browse-search-input' import { getBrowseThreads, getCategories } from '@/services/hasura' export const revalidate = 3600 // revalidate the data at most every hour diff --git a/apps/masterbots.ai/app/b/[id]/page.tsx b/apps/masterbots.ai/app/b/[id]/page.tsx index 6d5d9911..4a1efe3c 100644 --- a/apps/masterbots.ai/app/b/[id]/page.tsx +++ b/apps/masterbots.ai/app/b/[id]/page.tsx @@ -1,6 +1,6 @@ import { getChatbot, getBrowseThreads } from '@/services/hasura' import { botNames } from '@/lib/bots-names' -import BotDetails from '@/components/b/bot-details' +import BotDetails from '@/components/routes/b/bot-details' const PAGE_SIZE = 50 diff --git a/apps/masterbots.ai/app/c/[chatbot]/[threadId]/page.tsx b/apps/masterbots.ai/app/c/[chatbot]/[threadId]/page.tsx index 3403606f..c7d48640 100644 --- a/apps/masterbots.ai/app/c/[chatbot]/[threadId]/page.tsx +++ b/apps/masterbots.ai/app/c/[chatbot]/[threadId]/page.tsx @@ -2,7 +2,7 @@ import { redirect } from 'next/navigation' import type { Message } from 'ai/react' import { isTokenExpired } from '@repo/mb-lib' import { cookies } from 'next/headers' -import { Chat } from '@/components/c/chat' +import { Chat } from '@/components/routes/c/chat' import { getThread } from '@/services/hasura' import { getUserProfile } from '@/services/supabase' diff --git a/apps/masterbots.ai/app/c/[chatbot]/page.tsx b/apps/masterbots.ai/app/c/[chatbot]/page.tsx index 970aad53..0141b9e1 100644 --- a/apps/masterbots.ai/app/c/[chatbot]/page.tsx +++ b/apps/masterbots.ai/app/c/[chatbot]/page.tsx @@ -3,8 +3,8 @@ import { isTokenExpired } from '@repo/mb-lib' import { nanoid } from 'nanoid' import { cookies } from 'next/headers' import { redirect } from 'next/navigation' -import { ChatChatbot } from '@/components/c/chat-chatbot' -import ThreadPanel from '@/components/c/thread-panel' +import { ChatChatbot } from '@/components/routes/c/chat-chatbot' +import ThreadPanel from '@/components/routes/c/thread-panel' import { botNames } from '@/lib/bots-names' import { getChatbot, getThreads } from '@/services/hasura' import { getUserProfile } from '@/services/supabase' diff --git a/apps/masterbots.ai/app/c/layout.tsx b/apps/masterbots.ai/app/c/layout.tsx index 86ab7fd8..54821f7b 100644 --- a/apps/masterbots.ai/app/c/layout.tsx +++ b/apps/masterbots.ai/app/c/layout.tsx @@ -1,5 +1,5 @@ -import { ChatLayoutSection } from '@/components/c/chat-layout-section' -import { ResponsiveSidebar } from '@/components/c/sidebar/sidebar-responsive' +import { ChatLayoutSection } from '@/components/routes/c/chat-layout-section' +import { ResponsiveSidebar } from '@/components/routes/c/sidebar/sidebar-responsive' import FooterCT from '@/components/layout/footer-ct' interface ChatLayoutProps { diff --git a/apps/masterbots.ai/app/c/page.tsx b/apps/masterbots.ai/app/c/page.tsx index 1979a52f..d0917350 100644 --- a/apps/masterbots.ai/app/c/page.tsx +++ b/apps/masterbots.ai/app/c/page.tsx @@ -1,8 +1,8 @@ import { isTokenExpired } from '@repo/mb-lib' import { redirect } from 'next/navigation' import { cookies } from 'next/headers' -import ChatThreadListPanel from '@/components/c/chat-thread-list-panel' -import ThreadPanel from '@/components/c/thread-panel' +import ChatThreadListPanel from '@/components/routes/c/chat-thread-list-panel' +import ThreadPanel from '@/components/routes/c/thread-panel' import { getThreads } from '@/services/hasura' import { getUserProfile } from '@/services/supabase' diff --git a/apps/masterbots.ai/app/globals.css b/apps/masterbots.ai/app/globals.css index fe0cea82..741d1bc0 100644 --- a/apps/masterbots.ai/app/globals.css +++ b/apps/masterbots.ai/app/globals.css @@ -100,32 +100,21 @@ } .scrollbar { - overflow: auto; + overflow: auto; } .scrollbar::-webkit-scrollbar { - width: 4px; - height: 4px; + width: 1px; + height: 1px; } .scrollbar::-webkit-scrollbar-track, .scrollbar::-webkit-scrollbar-corner { - background: var(--scrollbar-track) !important; + background: var(--scrollbar-track); } .scrollbar::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 2px; } -/* .scrollbar::-webkit-scrollbar-thumb:hover { - background: var(--scrollbar-thumb-hover); -} */ - -@media screen and (min-width: 1024px) { - .scrollbar::-webkit-scrollbar { - width: 8px; - height: 8px; - } -} - .scrollbar.small-thumb::-webkit-scrollbar-thumb { border-left: 300px solid #f9f9fa; @@ -151,3 +140,7 @@ overflow: visible; text-overflow: clip; } + +.hide-buttons > button { + display: none; +} diff --git a/apps/masterbots.ai/app/p/page.tsx b/apps/masterbots.ai/app/p/page.tsx index d2325d98..2086576f 100644 --- a/apps/masterbots.ai/app/p/page.tsx +++ b/apps/masterbots.ai/app/p/page.tsx @@ -1,5 +1,5 @@ import { Suspense } from 'react' -import { WorkEarlyAccessForm } from '@/components/p/early-access-from' +import { WorkEarlyAccessForm } from '@/components/routes/p/early-access-from' export default function WorkPage() { return ( diff --git a/apps/masterbots.ai/app/u/[slug]/page.tsx b/apps/masterbots.ai/app/u/[slug]/page.tsx index 495f20db..193ae474 100644 --- a/apps/masterbots.ai/app/u/[slug]/page.tsx +++ b/apps/masterbots.ai/app/u/[slug]/page.tsx @@ -1,5 +1,5 @@ import { getBrowseThreads, getUserInfoFromBrowse } from '@/services/hasura' -import BrowseUserDetails from '@/components/browse/browse-user-details' +import BrowseUserDetails from '@/components/routes/browse/browse-user-details' const PAGE_SIZE = 50 diff --git a/apps/masterbots.ai/components/browse/browse-chat-message-list.tsx b/apps/masterbots.ai/components/browse/browse-chat-message-list.tsx deleted file mode 100644 index a92f313a..00000000 --- a/apps/masterbots.ai/components/browse/browse-chat-message-list.tsx +++ /dev/null @@ -1,77 +0,0 @@ -// Inspired by Chatbot-UI and modified to fit the needs of this project -// @see https://github.com/mckaywrigley/chatbot-ui/blob/main/components/Chat/ChatcleanMessage.tsx - -import type { Chatbot, Message, User } from '@repo/mb-genql' - -import React from 'react' -import { cn, createMessagePairs } from '@/lib/utils' -import { ChatAccordion } from '../shared/thread-dialog/thread-accordion' -import type { MessagePair } from './browse-chat-messages' -import { convertMessage } from './browse-chat-messages' -import { BrowseChatMessage } from './browse-chat-message' - -export function BrowseChatMessageList({ - messages, - user, - chatbot, - isThread = false -}: { - messages: Message[] - user?: User - chatbot?: Chatbot - isThread?: boolean -}) { - const [pairs, setPairs] = React.useState([]) - - React.useEffect(() => { - if (messages.length) { - const prePairs: MessagePair[] = createMessagePairs( - messages - ) as MessagePair[] - setPairs(prePairs) - } else setPairs([]) - }, [messages]) - - return ( -
- {pairs.map((pair: MessagePair, key: number) => ( - - {/* Thread Title */} - {key !== 0 || isThread ? ( -
-
- {pair.userMessage.content} -
-
- ) : null} - - {/* Thread Description */} - <> - - {/* Thread Content */} -
- {pair.chatGptMessage.length > 0 - ? pair.chatGptMessage.map((message, index) => ( - - )) - : ''} -
-
- ))} -
- ) -} diff --git a/apps/masterbots.ai/components/browse/browse-chat-messages.tsx b/apps/masterbots.ai/components/browse/browse-chat-messages.tsx deleted file mode 100644 index a8c94dc9..00000000 --- a/apps/masterbots.ai/components/browse/browse-chat-messages.tsx +++ /dev/null @@ -1,58 +0,0 @@ -// Inspired by Chatbot-UI and modified to fit the needs of this project -// @see https://github.com/mckaywrigley/chatbot-ui/blob/main/components/Chat/ChatcleanMessage.tsx - -import type * as AI from 'ai' -import type { Chatbot, Message, User } from '@repo/mb-genql' -import React from 'react' -import { getMessages } from '@/services/hasura' -import BrowseChatbotDetails from '../b/bot-details' -import { BrowseChatMessageList } from './browse-chat-message-list' - -export interface MessagePair { - userMessage: Message - chatGptMessage: Message[] -} - -export function convertMessage(message: Message) { - return { - id: message.messageId, - content: message.content, - createAt: message.createdAt, - role: message.role - } as AI.Message -} - -export function BrowseChatMessages({ - threadId, - user, - chatbot -}: { - threadId: string - user?: User - chatbot?: Chatbot -}) { - const [messages, setMessages] = React.useState([]) - const fetchMessages = async () => { - if (threadId && !messages.length) { - const messages = await getMessages({ threadId }) - setMessages(messages) - } - } - React.useEffect(() => { - fetchMessages() - }, [threadId]) - - return ( -
- -
- -
-
- ) -} diff --git a/apps/masterbots.ai/components/browse/browse-thread.tsx b/apps/masterbots.ai/components/browse/browse-thread.tsx deleted file mode 100644 index aa010ad7..00000000 --- a/apps/masterbots.ai/components/browse/browse-thread.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'use client' - -import type { Thread } from '@repo/mb-genql' -import { cn } from '@/lib/utils' -import { BrowseChatMessages } from './browse-chat-messages' - -export function BrowseThread({ - thread, - className -}: { - thread: Thread - className?: string -}) { - // we merge past assistant and user messages for ui only - // we remove system prompts from ui - // we extend append function to add our system prompts - - return ( -
- {thread.messages.length ? ( - - ) : ( - '' - )} -
- ) -} diff --git a/apps/masterbots.ai/components/external-link.tsx b/apps/masterbots.ai/components/external-link.tsx deleted file mode 100644 index e5a1baee..00000000 --- a/apps/masterbots.ai/components/external-link.tsx +++ /dev/null @@ -1,30 +0,0 @@ -export function ExternalLink({ - href, - children -}: { - href: string - children: React.ReactNode -}) { - return ( - - {children} - - - ) -} diff --git a/apps/masterbots.ai/components/layout/header.tsx b/apps/masterbots.ai/components/layout/header.tsx index 513c977a..bd35304e 100644 --- a/apps/masterbots.ai/components/layout/header.tsx +++ b/apps/masterbots.ai/components/layout/header.tsx @@ -4,9 +4,9 @@ import { isTokenExpired } from '@repo/mb-lib' import { cookies } from 'next/headers' import { Button } from '@/components/ui/button' import { IconSeparator } from '@/components/ui/icons' -import { UserMenu } from '@/components/user-menu' +import { UserMenu } from '@/components/layout/user-menu' import { getUserProfile } from '@/services/supabase' -import { SidebarToggle } from '../c/sidebar/sidebar-toggle' +import { SidebarToggle } from '../routes/c/sidebar/sidebar-toggle' // https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating diff --git a/apps/masterbots.ai/components/layout/providers.tsx b/apps/masterbots.ai/components/layout/providers.tsx index 8361f35d..09e35119 100644 --- a/apps/masterbots.ai/components/layout/providers.tsx +++ b/apps/masterbots.ai/components/layout/providers.tsx @@ -6,15 +6,20 @@ import type { ThemeProviderProps } from 'next-themes/dist/types' import { SidebarProvider } from '@/hooks/use-sidebar' import { TooltipProvider } from '@/components/ui/tooltip' import { ThreadProvider } from '@/hooks/use-thread' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' + +const queryClient = new QueryClient() export function Providers({ children, ...props }: ThemeProviderProps) { return ( - - - {children} - - + + + + {children} + + + ) } diff --git a/apps/masterbots.ai/components/tailwind-indicator.tsx b/apps/masterbots.ai/components/layout/tailwind-indicator.tsx similarity index 100% rename from apps/masterbots.ai/components/tailwind-indicator.tsx rename to apps/masterbots.ai/components/layout/tailwind-indicator.tsx diff --git a/apps/masterbots.ai/components/theme-toggle.tsx b/apps/masterbots.ai/components/layout/theme-toggle.tsx similarity index 100% rename from apps/masterbots.ai/components/theme-toggle.tsx rename to apps/masterbots.ai/components/layout/theme-toggle.tsx diff --git a/apps/masterbots.ai/components/user-menu.tsx b/apps/masterbots.ai/components/layout/user-menu.tsx similarity index 100% rename from apps/masterbots.ai/components/user-menu.tsx rename to apps/masterbots.ai/components/layout/user-menu.tsx diff --git a/apps/masterbots.ai/components/modal-coming-soon.tsx b/apps/masterbots.ai/components/modal-coming-soon.tsx deleted file mode 100644 index 6da04058..00000000 --- a/apps/masterbots.ai/components/modal-coming-soon.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client' - -import * as React from 'react' -import { cn } from '@/lib/utils' -import { IconClose } from './ui/icons' - -export interface ModalComingSoonProps extends React.ComponentProps<'div'> { - isOpen: boolean - onClose: () => void -} - -export function ModalComingSoon({ - className, - children, - isOpen, - onClose -}: ModalComingSoonProps) { - return ( -
-
-
-
- -
-
- Coming Soon! -
-
-
- ) -} diff --git a/apps/masterbots.ai/components/b/bot-details.tsx b/apps/masterbots.ai/components/routes/b/bot-details.tsx similarity index 98% rename from apps/masterbots.ai/components/b/bot-details.tsx rename to apps/masterbots.ai/components/routes/b/bot-details.tsx index 1145d029..95267e16 100644 --- a/apps/masterbots.ai/components/b/bot-details.tsx +++ b/apps/masterbots.ai/components/routes/b/bot-details.tsx @@ -1,7 +1,7 @@ import type { Chatbot } from '@repo/mb-genql' import Image from 'next/image' import Link from 'next/link' -import { Separator } from '../ui/separator' +import { Separator } from '../../ui/separator' export default function BrowseChatbotDetails({ chatbot diff --git a/apps/masterbots.ai/components/browse/browse-category-link.tsx b/apps/masterbots.ai/components/routes/browse/browse-category-link.tsx similarity index 100% rename from apps/masterbots.ai/components/browse/browse-category-link.tsx rename to apps/masterbots.ai/components/routes/browse/browse-category-link.tsx diff --git a/apps/masterbots.ai/components/browse/browse-category-tabs.tsx b/apps/masterbots.ai/components/routes/browse/browse-category-tabs.tsx similarity index 100% rename from apps/masterbots.ai/components/browse/browse-category-tabs.tsx rename to apps/masterbots.ai/components/routes/browse/browse-category-tabs.tsx diff --git a/apps/masterbots.ai/components/browse/browse-search-input.tsx b/apps/masterbots.ai/components/routes/browse/browse-search-input.tsx similarity index 100% rename from apps/masterbots.ai/components/browse/browse-search-input.tsx rename to apps/masterbots.ai/components/routes/browse/browse-search-input.tsx diff --git a/apps/masterbots.ai/components/browse/browse-user-details.tsx b/apps/masterbots.ai/components/routes/browse/browse-user-details.tsx similarity index 97% rename from apps/masterbots.ai/components/browse/browse-user-details.tsx rename to apps/masterbots.ai/components/routes/browse/browse-user-details.tsx index bb848475..eccfd76a 100644 --- a/apps/masterbots.ai/components/browse/browse-user-details.tsx +++ b/apps/masterbots.ai/components/routes/browse/browse-user-details.tsx @@ -4,7 +4,7 @@ import type { User } from '@repo/mb-genql' import Image from 'next/image' import { useEffect, useState } from 'react' import { getBrowseThreads } from '@/services/hasura' -import { Separator } from '../ui/separator' +import { Separator } from '../../ui/separator' export default function BrowseChatbotDetails({ user }: { user?: User | null }) { const [threadNum, setThreadNum] = useState(0) diff --git a/apps/masterbots.ai/components/browse/shortlink-button.tsx b/apps/masterbots.ai/components/routes/browse/shortlink-button.tsx similarity index 97% rename from apps/masterbots.ai/components/browse/shortlink-button.tsx rename to apps/masterbots.ai/components/routes/browse/shortlink-button.tsx index 03585e9e..85c5bde8 100644 --- a/apps/masterbots.ai/components/browse/shortlink-button.tsx +++ b/apps/masterbots.ai/components/routes/browse/shortlink-button.tsx @@ -21,7 +21,7 @@ export default function Shortlink() { ) return ( - +
diff --git a/apps/masterbots.ai/components/c/button-scroll-to-bottom.tsx b/apps/masterbots.ai/components/routes/c/button-scroll-to-bottom.tsx similarity index 100% rename from apps/masterbots.ai/components/c/button-scroll-to-bottom.tsx rename to apps/masterbots.ai/components/routes/c/button-scroll-to-bottom.tsx diff --git a/apps/masterbots.ai/components/shared/thread-dialog/thread-accordion.tsx b/apps/masterbots.ai/components/routes/c/chat-accordion.tsx similarity index 100% rename from apps/masterbots.ai/components/shared/thread-dialog/thread-accordion.tsx rename to apps/masterbots.ai/components/routes/c/chat-accordion.tsx diff --git a/apps/masterbots.ai/components/c/chat-chatbot-details.tsx b/apps/masterbots.ai/components/routes/c/chat-chatbot-details.tsx similarity index 98% rename from apps/masterbots.ai/components/c/chat-chatbot-details.tsx rename to apps/masterbots.ai/components/routes/c/chat-chatbot-details.tsx index bb71adca..f1c47d38 100644 --- a/apps/masterbots.ai/components/c/chat-chatbot-details.tsx +++ b/apps/masterbots.ai/components/routes/c/chat-chatbot-details.tsx @@ -6,7 +6,7 @@ import { useSidebar } from '@/hooks/use-sidebar' import { getCategory, getThreads } from '@/services/hasura' import { useThread } from '@/hooks/use-thread' import { useGlobalStore } from '@/hooks/use-global-store' -import { Separator } from '../ui/separator' +import { Separator } from '../../ui/separator' export default function ChatChatbotDetails() { const { user, hasuraJwt } = useGlobalStore() diff --git a/apps/masterbots.ai/components/c/chat-chatbot.tsx b/apps/masterbots.ai/components/routes/c/chat-chatbot.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-chatbot.tsx rename to apps/masterbots.ai/components/routes/c/chat-chatbot.tsx diff --git a/apps/masterbots.ai/components/c/chat-clickable-text.tsx b/apps/masterbots.ai/components/routes/c/chat-clickable-text.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-clickable-text.tsx rename to apps/masterbots.ai/components/routes/c/chat-clickable-text.tsx diff --git a/apps/masterbots.ai/components/c/chat-history.tsx b/apps/masterbots.ai/components/routes/c/chat-history.tsx similarity index 94% rename from apps/masterbots.ai/components/c/chat-history.tsx rename to apps/masterbots.ai/components/routes/c/chat-history.tsx index 5c2a22c7..225dfc34 100644 --- a/apps/masterbots.ai/components/c/chat-history.tsx +++ b/apps/masterbots.ai/components/routes/c/chat-history.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import Link from 'next/link' import { cn } from '@/lib/utils' -import { SidebarList } from '@/components/c/sidebar/sidebar-list' +import { SidebarList } from '@/components/routes/c/sidebar/sidebar-list' import { buttonVariants } from '@/components/ui/button' import { IconPlus } from '@/components/ui/icons' diff --git a/apps/masterbots.ai/components/c/chat-layout-section.tsx b/apps/masterbots.ai/components/routes/c/chat-layout-section.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-layout-section.tsx rename to apps/masterbots.ai/components/routes/c/chat-layout-section.tsx diff --git a/apps/masterbots.ai/components/c/chat-list.tsx b/apps/masterbots.ai/components/routes/c/chat-list.tsx similarity index 87% rename from apps/masterbots.ai/components/c/chat-list.tsx rename to apps/masterbots.ai/components/routes/c/chat-list.tsx index a3f1317e..ff94d467 100644 --- a/apps/masterbots.ai/components/c/chat-list.tsx +++ b/apps/masterbots.ai/components/routes/c/chat-list.tsx @@ -1,11 +1,12 @@ import { type Message } from 'ai' import type { Chatbot } from '@repo/mb-genql' import React from 'react' -import { ChatMessage } from '@/components/c/chat-message' -import { cn, createMessagePairs } from '@/lib/utils' +import { ChatMessage } from '@/components/routes/c/chat-message' +import { cn } from '@/lib/utils' import { useThread } from '@/hooks/use-thread' -import { ShortMessage } from '../shared/thread-dialog/thread-excerpt' -import { ChatAccordion } from '../shared/thread-dialog/thread-accordion' +import { ShortMessage } from '../../shared/thread-short-message' +import { ChatAccordion } from './chat-accordion' +import { createMessagePairs } from '@/lib/threads' export interface ChatList { messages: Message[] @@ -36,14 +37,14 @@ export function ChatList({ const [pairs, setPairs] = React.useState([]) const { isNewResponse } = useThread() - React.useEffect(() => { - if (messages.length) { - const prePairs: MessagePair[] = createMessagePairs( - messages - ) as MessagePair[] - setPairs(prePairs) - } else setPairs([]) - }, [messages]) + // React.useEffect(() => { + // if (messages.length) { + // const prePairs: MessagePair[] = createMessagePairs( + // messages as Message[] + // ) as MessagePair[] + // setPairs(prePairs) + // } else setPairs([]) + // }, [messages]) if (!messages.length) return null return ( diff --git a/apps/masterbots.ai/components/c/chat-message-actions.tsx b/apps/masterbots.ai/components/routes/c/chat-message-actions.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-message-actions.tsx rename to apps/masterbots.ai/components/routes/c/chat-message-actions.tsx diff --git a/apps/masterbots.ai/components/c/chat-message.tsx b/apps/masterbots.ai/components/routes/c/chat-message.tsx similarity index 91% rename from apps/masterbots.ai/components/c/chat-message.tsx rename to apps/masterbots.ai/components/routes/c/chat-message.tsx index 05700d7e..c3e20772 100644 --- a/apps/masterbots.ai/components/c/chat-message.tsx +++ b/apps/masterbots.ai/components/routes/c/chat-message.tsx @@ -5,11 +5,12 @@ import type { Message } from 'ai' import type { Chatbot } from '@repo/mb-genql' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' -import { ClickableText } from '@/components/c/chat-clickable-text' -import { ChatMessageActions } from '@/components/c/chat-message-actions' -import { MemoizedReactMarkdown } from '@/components/markdown' +import { ClickableText } from '@/components/routes/c/chat-clickable-text' +import { ChatMessageActions } from '@/components/routes/c/chat-message-actions' +import { MemoizedReactMarkdown } from '@/components/shared/markdown' import { CodeBlock } from '@/components/ui/codeblock' -import { cleanPrompt, cn } from '@/lib/utils' +import { cn } from '@/lib/utils' +import { cleanPrompt } from '@/lib/threads' export interface ChatMessageProps { message: Message diff --git a/apps/masterbots.ai/components/c/chat-panel.tsx b/apps/masterbots.ai/components/routes/c/chat-panel.tsx similarity index 94% rename from apps/masterbots.ai/components/c/chat-panel.tsx rename to apps/masterbots.ai/components/routes/c/chat-panel.tsx index 04498e99..1861b4b3 100644 --- a/apps/masterbots.ai/components/c/chat-panel.tsx +++ b/apps/masterbots.ai/components/routes/c/chat-panel.tsx @@ -2,11 +2,11 @@ import * as React from 'react' import { type UseChatHelpers } from 'ai/react' import { Chatbot } from '@repo/mb-genql' import { Button } from '@/components/ui/button' -import { PromptForm } from '@/components/c/prompt-form' -import { ButtonScrollToBottom } from '@/components/c/button-scroll-to-bottom' +import { PromptForm } from '@/components/routes/c/prompt-form' +import { ButtonScrollToBottom } from '@/components/routes/c/button-scroll-to-bottom' import { IconRefresh, IconShare, IconStop } from '@/components/ui/icons' import { FooterText } from '@/components/layout/footer' -import { ChatShareDialog } from '@/components/c/chat-share-dialog' +import { ChatShareDialog } from '@/components/routes/c/chat-share-dialog' import { cn } from '@/lib/utils' import { useThread } from '@/hooks/use-thread' diff --git a/apps/masterbots.ai/components/c/chat-scroll-anchor.tsx b/apps/masterbots.ai/components/routes/c/chat-scroll-anchor.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-scroll-anchor.tsx rename to apps/masterbots.ai/components/routes/c/chat-scroll-anchor.tsx diff --git a/apps/masterbots.ai/components/c/chat-search-input.tsx b/apps/masterbots.ai/components/routes/c/chat-search-input.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-search-input.tsx rename to apps/masterbots.ai/components/routes/c/chat-search-input.tsx diff --git a/apps/masterbots.ai/components/c/chat-share-dialog.tsx b/apps/masterbots.ai/components/routes/c/chat-share-dialog.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-share-dialog.tsx rename to apps/masterbots.ai/components/routes/c/chat-share-dialog.tsx diff --git a/apps/masterbots.ai/components/c/chat-thread-list-panel.tsx b/apps/masterbots.ai/components/routes/c/chat-thread-list-panel.tsx similarity index 100% rename from apps/masterbots.ai/components/c/chat-thread-list-panel.tsx rename to apps/masterbots.ai/components/routes/c/chat-thread-list-panel.tsx diff --git a/apps/masterbots.ai/components/c/chat.tsx b/apps/masterbots.ai/components/routes/c/chat.tsx similarity index 96% rename from apps/masterbots.ai/components/c/chat.tsx rename to apps/masterbots.ai/components/routes/c/chat.tsx index e8ccc0ad..b3d6b801 100644 --- a/apps/masterbots.ai/components/c/chat.tsx +++ b/apps/masterbots.ai/components/routes/c/chat.tsx @@ -9,16 +9,17 @@ import type { Chatbot } from '@repo/mb-genql' import { useParams } from 'next/navigation' import React, { useEffect } from 'react' import { toast } from 'react-hot-toast' -import { ChatList } from '@/components/c/chat-list' -import { ChatPanel } from '@/components/c/chat-panel' -import { ChatScrollAnchor } from '@/components/c/chat-scroll-anchor' -import { cn, extractBetweenMarkers, scrollToBottomOfElement } from '@/lib/utils' +import { ChatList } from '@/components/routes/c/chat-list' +import { ChatPanel } from '@/components/routes/c/chat-panel' +import { ChatScrollAnchor } from '@/components/routes/c/chat-scroll-anchor' +import { cn, extractBetweenMarkers } from '@/lib/utils' import { useAtBottom } from '@/hooks/use-at-bottom' import { createThread, getThread, saveNewMessage } from '@/services/hasura' import { useThread } from '@/hooks/use-thread' import { botNames } from '@/lib/bots-names' import { useSidebar } from '@/hooks/use-sidebar' import { useGlobalStore } from '@/hooks/use-global-store' +import { scrollToBottomOfElement } from '@/lib/animation' export function Chat({ initialMessages, diff --git a/apps/masterbots.ai/components/c/new-chat.tsx b/apps/masterbots.ai/components/routes/c/new-chat.tsx similarity index 100% rename from apps/masterbots.ai/components/c/new-chat.tsx rename to apps/masterbots.ai/components/routes/c/new-chat.tsx diff --git a/apps/masterbots.ai/components/c/prompt-form.tsx b/apps/masterbots.ai/components/routes/c/prompt-form.tsx similarity index 100% rename from apps/masterbots.ai/components/c/prompt-form.tsx rename to apps/masterbots.ai/components/routes/c/prompt-form.tsx diff --git a/apps/masterbots.ai/components/clear-history.tsx b/apps/masterbots.ai/components/routes/c/sidebar/clear-history.tsx similarity index 100% rename from apps/masterbots.ai/components/clear-history.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/clear-history.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/index.tsx b/apps/masterbots.ai/components/routes/c/sidebar/index.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/index.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/index.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-actions.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-actions.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/sidebar-actions.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-actions.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-category-general.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-category-general.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/sidebar-category-general.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-category-general.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-footer.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-footer.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/sidebar-footer.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-footer.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-item.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-item.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/sidebar-item.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-item.tsx diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-items.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-items.tsx similarity index 90% rename from apps/masterbots.ai/components/c/sidebar/sidebar-items.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-items.tsx index c4491bd8..714b6c82 100644 --- a/apps/masterbots.ai/components/c/sidebar/sidebar-items.tsx +++ b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-items.tsx @@ -2,7 +2,7 @@ import { AnimatePresence, motion } from 'framer-motion' import type { Chat } from '@/lib/types' -import { SidebarItem } from '@/components/c/sidebar/sidebar-item' +import { SidebarItem } from '@/components/routes/c/sidebar/sidebar-item' interface SidebarItemsProps { chats?: Chat[] diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-link.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-link.tsx similarity index 99% rename from apps/masterbots.ai/components/c/sidebar/sidebar-link.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-link.tsx index c6407316..46d2a4af 100644 --- a/apps/masterbots.ai/components/c/sidebar/sidebar-link.tsx +++ b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-link.tsx @@ -8,7 +8,7 @@ import React from 'react' import { getChatbots } from '@/services/hasura' import { cn } from '@/lib/utils' import { useSidebar } from '@/hooks/use-sidebar' -import { IconCaretRight } from '../../ui/icons' +import { IconCaretRight } from '../../../ui/icons' const PAGE_SIZE = 20 diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-list.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-list.tsx similarity index 83% rename from apps/masterbots.ai/components/c/sidebar/sidebar-list.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-list.tsx index b1881ebd..f8c45c66 100644 --- a/apps/masterbots.ai/components/c/sidebar/sidebar-list.tsx +++ b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-list.tsx @@ -1,7 +1,6 @@ import { cache } from 'react' -import { ClearHistory } from '@/components/clear-history' -import { SidebarItems } from '@/components/c/sidebar/sidebar-items' -import { ThemeToggle } from '@/components/theme-toggle' +import { SidebarItems } from '@/components/routes/c/sidebar/sidebar-items' +import { ThemeToggle } from '@/components/layout/theme-toggle' interface SidebarListProps { userId?: string diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-mobile.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-mobile.tsx similarity index 93% rename from apps/masterbots.ai/components/c/sidebar/sidebar-mobile.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-mobile.tsx index ebff107d..eacfa285 100644 --- a/apps/masterbots.ai/components/c/sidebar/sidebar-mobile.tsx +++ b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-mobile.tsx @@ -1,7 +1,7 @@ 'use client' import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet' -import { Sidebar } from '@/components/c/sidebar' +import { Sidebar } from '@/components/routes/c/sidebar' import { Button } from '@/components/ui/button' import { IconSidebar } from '@/components/ui/icons' diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-responsive.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-responsive.tsx similarity index 91% rename from apps/masterbots.ai/components/c/sidebar/sidebar-responsive.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-responsive.tsx index 0252dfcd..7f0ae2b9 100644 --- a/apps/masterbots.ai/components/c/sidebar/sidebar-responsive.tsx +++ b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-responsive.tsx @@ -1,4 +1,4 @@ -import { Sidebar } from '@/components/c/sidebar' +import { Sidebar } from '@/components/routes/c/sidebar' // import { ChatHistory } from '@/components/chat-history' import { SidebarGeneralCategory } from './sidebar-category-general' diff --git a/apps/masterbots.ai/components/c/sidebar/sidebar-toggle.tsx b/apps/masterbots.ai/components/routes/c/sidebar/sidebar-toggle.tsx similarity index 100% rename from apps/masterbots.ai/components/c/sidebar/sidebar-toggle.tsx rename to apps/masterbots.ai/components/routes/c/sidebar/sidebar-toggle.tsx diff --git a/apps/masterbots.ai/components/c/thread-date-range-picker.tsx b/apps/masterbots.ai/components/routes/c/thread-date-range-picker.tsx similarity index 100% rename from apps/masterbots.ai/components/c/thread-date-range-picker.tsx rename to apps/masterbots.ai/components/routes/c/thread-date-range-picker.tsx diff --git a/apps/masterbots.ai/components/c/thread-list.tsx b/apps/masterbots.ai/components/routes/c/thread-list.tsx similarity index 97% rename from apps/masterbots.ai/components/c/thread-list.tsx rename to apps/masterbots.ai/components/routes/c/thread-list.tsx index 4c39d6b8..b8ac8382 100644 --- a/apps/masterbots.ai/components/c/thread-list.tsx +++ b/apps/masterbots.ai/components/routes/c/thread-list.tsx @@ -6,8 +6,8 @@ import React from 'react' import { useThread } from '@/hooks/use-thread' import { useSidebar } from '@/hooks/use-sidebar' import { cn, sleep } from '@/lib/utils' -import { ShortMessage } from '../shared/thread-dialog/thread-excerpt' -import { ChatAccordion } from '../shared/thread-dialog/thread-accordion' +import { ShortMessage } from '../../shared/thread-short-message' +import { ChatAccordion } from './chat-accordion' import { ChatList } from './chat-list' export default function ThreadList({ diff --git a/apps/masterbots.ai/components/c/thread-panel/index.tsx b/apps/masterbots.ai/components/routes/c/thread-panel/index.tsx similarity index 77% rename from apps/masterbots.ai/components/c/thread-panel/index.tsx rename to apps/masterbots.ai/components/routes/c/thread-panel/index.tsx index db5f9b93..eacc3ff3 100644 --- a/apps/masterbots.ai/components/c/thread-panel/index.tsx +++ b/apps/masterbots.ai/components/routes/c/thread-panel/index.tsx @@ -1,5 +1,5 @@ import type { Thread } from '@repo/mb-genql' -import UserThreadPanel from '@/components/c/thread-panel/user-thread-panel' +import UserThreadPanel from '@/components/routes/c/thread-panel/user-thread-panel' export default async function ThreadPanel({ chatbot, diff --git a/apps/masterbots.ai/components/c/thread-panel/user-thread-panel.tsx b/apps/masterbots.ai/components/routes/c/thread-panel/user-thread-panel.tsx similarity index 96% rename from apps/masterbots.ai/components/c/thread-panel/user-thread-panel.tsx rename to apps/masterbots.ai/components/routes/c/thread-panel/user-thread-panel.tsx index f3eee1d7..e4ddc093 100644 --- a/apps/masterbots.ai/components/c/thread-panel/user-thread-panel.tsx +++ b/apps/masterbots.ai/components/routes/c/thread-panel/user-thread-panel.tsx @@ -2,8 +2,8 @@ import type { Thread } from '@repo/mb-genql' import React, { useEffect, useRef, useState } from 'react' -import { ChatSearchInput } from '@/components/c/chat-search-input' -import ThreadList from '@/components/c/thread-list' +import { ChatSearchInput } from '@/components/routes/c/chat-search-input' +import ThreadList from '@/components/routes/c/thread-list' import { useSidebar } from '@/hooks/use-sidebar' import { useThread } from '@/hooks/use-thread' import { getThreads } from '@/services/hasura' diff --git a/apps/masterbots.ai/components/c/thread-popup.tsx b/apps/masterbots.ai/components/routes/c/thread-popup.tsx similarity index 96% rename from apps/masterbots.ai/components/c/thread-popup.tsx rename to apps/masterbots.ai/components/routes/c/thread-popup.tsx index c090ae60..55bf68fd 100644 --- a/apps/masterbots.ai/components/c/thread-popup.tsx +++ b/apps/masterbots.ai/components/routes/c/thread-popup.tsx @@ -3,11 +3,12 @@ import { useEffect, useRef } from 'react' import { useScroll } from 'framer-motion' import { useThread } from '@/hooks/use-thread' -import { cn, scrollToBottomOfElement } from '@/lib/utils' +import { cn } from '@/lib/utils' import { useAtBottom } from '@/hooks/use-at-bottom' -import { IconClose } from '../ui/icons' +import { IconClose } from '../../ui/icons' import { Chat } from './chat' import { ChatList } from './chat-list' +import { scrollToBottomOfElement } from '@/lib/animation' export function ThreadPopup({ className }: { className?: string }) { const { diff --git a/apps/masterbots.ai/components/p/early-access-from.tsx b/apps/masterbots.ai/components/routes/p/early-access-from.tsx similarity index 96% rename from apps/masterbots.ai/components/p/early-access-from.tsx rename to apps/masterbots.ai/components/routes/p/early-access-from.tsx index cb71bd58..1ab55f8d 100644 --- a/apps/masterbots.ai/components/p/early-access-from.tsx +++ b/apps/masterbots.ai/components/routes/p/early-access-from.tsx @@ -6,7 +6,7 @@ import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' -import { Input } from '../ui/input' +import { Input } from '../../ui/input' const schema = z.object({ otherText: z.string().min(1).optional(), @@ -87,7 +87,9 @@ export async function WorkEarlyAccessForm() { )}
{formState.errors.otherText ?

Please specify other interest

: null} - {formState.isSubmitted && formState.errors && !formState.isValid ?

Please select at least one option

: null} + {formState.isSubmitted && formState.errors && !formState.isValid ? ( +

Please select at least one option

+ ) : null}
diff --git a/apps/masterbots.ai/components/markdown.tsx b/apps/masterbots.ai/components/shared/markdown.tsx similarity index 100% rename from apps/masterbots.ai/components/markdown.tsx rename to apps/masterbots.ai/components/shared/markdown.tsx diff --git a/apps/masterbots.ai/components/shared/mb-avatar.tsx b/apps/masterbots.ai/components/shared/mb-avatar.tsx index 10612c58..0072fc95 100644 --- a/apps/masterbots.ai/components/shared/mb-avatar.tsx +++ b/apps/masterbots.ai/components/shared/mb-avatar.tsx @@ -1,6 +1,7 @@ import { cn } from '@/lib/utils' import Image from 'next/image' import Link from 'next/link' +import { IconUser } from '../ui/icons' export function MbAvatar({ href, alt, src }: MbAvatarProp) { return ( @@ -11,13 +12,17 @@ export function MbAvatar({ href, alt, src }: MbAvatarProp) { href={href} title={alt} > - {alt} + {src ? ( + {alt} + ) : ( + + )} ) } @@ -25,5 +30,5 @@ export function MbAvatar({ href, alt, src }: MbAvatarProp) { interface MbAvatarProp { href: string alt: string - src: string + src?: string } diff --git a/apps/masterbots.ai/components/shared/thread-accordion.tsx b/apps/masterbots.ai/components/shared/thread-accordion.tsx new file mode 100644 index 00000000..9f8b16d2 --- /dev/null +++ b/apps/masterbots.ai/components/shared/thread-accordion.tsx @@ -0,0 +1,95 @@ +'use client' + +import { useEffect } from 'react' + +import { getMessagePairs } from '@/services/hasura' + +import { useQuery } from '@tanstack/react-query' +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger +} from '@/components/ui/accordion' + +import { Thread } from '@repo/mb-genql' +import { ThreadHeading } from './thread-heading' +import { MessagePair, convertMessage } from '@/lib/threads' +import { BrowseChatMessage } from './thread-message' + +export function ThreadAccordion({ + thread, + initialMessagePairs, + clientFetch = false +}: ThreadAccordionProps) { + // initalMessages is coming from server ssr on load. the rest of messages on demand on mount + const { + data: pairs, + isLoading, + error + } = useQuery({ + queryKey: [`messages-${thread.threadId}`], + queryFn: () => getMessagePairs(thread.threadId), + initialData: initialMessagePairs, + refetchOnMount: true, + enabled: clientFetch + }) + + // update url when dialog opens and closes + useEffect(() => { + const initialUrl = location.href + const threadUrl = `/${thread.chatbot.categories[0].category.name.toLowerCase().replaceAll(' ', '_').replaceAll('&', '_')}/${thread.threadId}` + console.log(`Updating URL to ${threadUrl}, initialUrl was ${initialUrl}`) + + window.history.pushState({}, '', threadUrl) + return () => { + window.history.pushState({}, '', initialUrl) + } + }) + + if (error) return
There was an error loading thread messages
+ + // if no initial message and still loading show loading message + if (!pairs?.length && isLoading) return
Loading thread messages ...
+ + console.log(pairs.map((_p, key) => `pair-${key}`)) + return ( + + {pairs.map((p, key) => { + return ( + + + {key ? ( + p.userMessage.content + ) : ( + + )} + + + {p.chatGptMessage.map((message, index) => ( + + ))} + + + ) + })} + + ) +} + +interface ThreadAccordionProps { + thread: Thread + initialMessagePairs?: MessagePair[] + clientFetch?: boolean +} diff --git a/apps/masterbots.ai/components/shared/thread-dialog.tsx b/apps/masterbots.ai/components/shared/thread-dialog.tsx new file mode 100644 index 00000000..f2a414e6 --- /dev/null +++ b/apps/masterbots.ai/components/shared/thread-dialog.tsx @@ -0,0 +1,38 @@ +'use client' + +import type { Thread } from '@repo/mb-genql' +import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' +import { ThreadAccordion } from './thread-accordion' +import { ThreadHeading } from './thread-heading' +import { cn } from '@/lib/utils' + +export function ThreadDialog({ thread }: ThreadDialogProps) { + const firstQuestion = + thread.messages.find(m => m.role === 'user')?.content || 'not found' + const firstResponse = + thread.messages.find(m => m.role === 'assistant')?.content || 'not found' + + return ( + + + + + + + + + + ) +} + +interface ThreadDialogProps { + thread: Thread +} diff --git a/apps/masterbots.ai/components/shared/thread-dialog/index.ts b/apps/masterbots.ai/components/shared/thread-dialog/index.ts deleted file mode 100644 index 97ac0f47..00000000 --- a/apps/masterbots.ai/components/shared/thread-dialog/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './thread-dialog' diff --git a/apps/masterbots.ai/components/shared/thread-dialog/thread-dialog.tsx b/apps/masterbots.ai/components/shared/thread-dialog/thread-dialog.tsx deleted file mode 100644 index c6fe7dd4..00000000 --- a/apps/masterbots.ai/components/shared/thread-dialog/thread-dialog.tsx +++ /dev/null @@ -1,96 +0,0 @@ -'use client' - -import type { Thread } from '@repo/mb-genql' -import { cn } from '@/lib/utils' -import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' -import { ShortMessage } from './thread-excerpt' -import { BrowseChatMessageList } from '../../browse/browse-chat-message-list' -import { useAsync } from 'react-use' -import { getMessages } from '@/services/hasura' -import { useEffect } from 'react' -import { MbAvatar } from '../mb-avatar' - -export function ThreadDialog({ thread, excerpt, question }: ThreadDialogProps) { - const messages = useAsync(async () => - getMessages({ threadId: thread.threadId }) - ) - - // update url when dialog opens and closes - useEffect(() => { - const initialUrl = location.href - const threadUrl = `/${thread.chatbot.categories[0].category.name.toLowerCase().replaceAll('', '_').replaceAll('&', '_')}/${thread.threadId}` - history.pushState({}, threadUrl) - return () => { - history.pushState({}, initialUrl) - } - }) - - return ( - - - - - - - ) -} - -function ThreadDialogTrigger({ thread, excerpt, question }: ThreadDialogProps) { - return ( - -
div>div>button]:!hidden`)} - > -
- - -
- {question} - - by - - - -
-
- -
-
-
-
-
-
- ) -} - -interface ThreadDialogProps { - className?: string - handleOpen?: () => void - thread: Thread - excerpt: string - question: string -} diff --git a/apps/masterbots.ai/components/shared/thread-heading.tsx b/apps/masterbots.ai/components/shared/thread-heading.tsx new file mode 100644 index 00000000..5b48fabe --- /dev/null +++ b/apps/masterbots.ai/components/shared/thread-heading.tsx @@ -0,0 +1,58 @@ +import { Thread } from '@repo/mb-genql' +import { ShortMessage } from './thread-short-message' +import { MbAvatar } from './mb-avatar' +import { cn } from '@/lib/utils' + +export function ThreadHeading({ + thread, + response, + question +}: ThreadHeadingProps) { + return ( +
+
+ + +
+ {question} + + by + + +
+
+ + {response ? ( +
+ +
+ ) : null} +
+ ) +} + +interface ThreadHeadingProps { + thread: Thread + response?: string + question: string +} diff --git a/apps/masterbots.ai/components/shared/thread-dialog/thread-list.tsx b/apps/masterbots.ai/components/shared/thread-list.tsx similarity index 77% rename from apps/masterbots.ai/components/shared/thread-dialog/thread-list.tsx rename to apps/masterbots.ai/components/shared/thread-list.tsx index 2f34b275..8a580002 100644 --- a/apps/masterbots.ai/components/shared/thread-dialog/thread-list.tsx +++ b/apps/masterbots.ai/components/shared/thread-list.tsx @@ -7,7 +7,7 @@ import { useBrowse } from '@/hooks/use-browse' import { getBrowseThreads } from '@/services/hasura' import { ThreadDialog } from './thread-dialog' -export default function BrowseList({ initialThreads }: BrowseListProps) { +export default function ThreadList({ initialThreads }: ThreadListProps) { const { keyword, tab } = useBrowse() const [threads, setThreads] = useState(initialThreads) const [filteredThreads, setFilteredThreads] = @@ -68,24 +68,15 @@ export default function BrowseList({ initialThreads }: BrowseListProps) { }, [hasMore, loading, loadMore]) return ( -
+
{filteredThreads.map((thread: Thread, key) => ( - + ))}
) } -type BrowseListProps = { +type ThreadListProps = { initialThreads: Thread[] } - -const excerpt = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed id mauris rhoncus, imperdiet dui a, viverra eros. Nullam eget metus ante. Etiam maximus erat ut libero rutrum, non cursus sapien condimentum. Quisque ultricies suscipit augue eu aliquam. Donec fringilla tristique vestibulum.' -const question = 'why is the sky blue?' diff --git a/apps/masterbots.ai/components/browse/browse-chat-message.tsx b/apps/masterbots.ai/components/shared/thread-message.tsx similarity index 82% rename from apps/masterbots.ai/components/browse/browse-chat-message.tsx rename to apps/masterbots.ai/components/shared/thread-message.tsx index ce6f45e0..722b7e3b 100644 --- a/apps/masterbots.ai/components/browse/browse-chat-message.tsx +++ b/apps/masterbots.ai/components/shared/thread-message.tsx @@ -1,16 +1,11 @@ -// Inspired by Chatbot-UI and modified to fit the needs of this project -// @see https://github.com/mckaywrigley/chatbot-ui/blob/main/components/Chat/ChatcleanMessage.tsx - import type { Message } from 'ai' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' -import Image from 'next/image' import type { Chatbot } from '@repo/mb-genql' -import { cleanPrompt, cn } from '@/lib/utils' +import { cn } from '@/lib/utils' import { CodeBlock } from '@/components/ui/codeblock' -import { MemoizedReactMarkdown } from '@/components/markdown' -import { IconOpenAI, IconUser } from '@/components/ui/icons' -import { ChatMessageActions } from '../c/chat-message-actions' +import { MemoizedReactMarkdown } from '@/components/shared/markdown' +import { cleanPrompt } from '@/lib/threads' export interface ChatMessageProps { message: Message diff --git a/apps/masterbots.ai/components/shared/thread-dialog/thread-excerpt.tsx b/apps/masterbots.ai/components/shared/thread-short-message.tsx similarity index 93% rename from apps/masterbots.ai/components/shared/thread-dialog/thread-excerpt.tsx rename to apps/masterbots.ai/components/shared/thread-short-message.tsx index 547a4c66..6ff0a501 100644 --- a/apps/masterbots.ai/components/shared/thread-dialog/thread-excerpt.tsx +++ b/apps/masterbots.ai/components/shared/thread-short-message.tsx @@ -1,7 +1,7 @@ import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' -import { MemoizedReactMarkdown } from '../../markdown' -import { CodeBlock } from '../../ui/codeblock' +import { MemoizedReactMarkdown } from './markdown' +import { CodeBlock } from '../ui/codeblock' export function ShortMessage({ content }: { content: string }) { return ( diff --git a/apps/masterbots.ai/hooks/use-thread.tsx b/apps/masterbots.ai/hooks/use-thread.tsx index cc8bb50a..5befd2d4 100644 --- a/apps/masterbots.ai/hooks/use-thread.tsx +++ b/apps/masterbots.ai/hooks/use-thread.tsx @@ -12,7 +12,7 @@ import { Message as AIMessage } from 'ai' import { uniqBy } from 'lodash' import toast from 'react-hot-toast' import { Chatbot, Message, Thread } from '@repo/mb-genql' -import { getAllUserMessagesAsStringArray } from '@/components/c/chat' +import { getAllUserMessagesAsStringArray } from '@/components/routes/c/chat' import { useSidebar } from './use-sidebar' import { useScroll } from 'framer-motion' import { useAtBottom } from './use-at-bottom' diff --git a/apps/masterbots.ai/lib/animation.ts b/apps/masterbots.ai/lib/animation.ts new file mode 100644 index 00000000..3cfcd9df --- /dev/null +++ b/apps/masterbots.ai/lib/animation.ts @@ -0,0 +1,34 @@ +// Easing function for smooth animation +export const easeInOutQuad = (t: number, b: number, c: number, d: number) => { + t /= d / 2 + if (t < 1) return (c / 2) * t * t + b + t-- + return (-c / 2) * (t * (t - 2) - 1) + b +} + +let animationFrameId: number +export const scrollToBottomOfElement = (element?: HTMLElement) => { + if (!element) return + const targetScroll = element.scrollHeight - element.clientHeight + const duration = 500 + const startTime = performance.now() + + const animateScroll = (currentTime: number) => { + const elapsed = currentTime - startTime + const position = easeInOutQuad( + elapsed, + element.scrollTop, + targetScroll - element.scrollTop, + duration + ) + element.scrollTop = position + + if (elapsed < duration) { + animationFrameId = requestAnimationFrame(animateScroll) + } else { + cancelAnimationFrame(animationFrameId) + } + } + + animationFrameId = requestAnimationFrame(animateScroll) +} diff --git a/apps/masterbots.ai/lib/threads.ts b/apps/masterbots.ai/lib/threads.ts new file mode 100644 index 00000000..fab3891e --- /dev/null +++ b/apps/masterbots.ai/lib/threads.ts @@ -0,0 +1,71 @@ +import type * as AI from 'ai' +import { Message } from '@repo/mb-genql' +import { type Message as AIMessage } from 'ai/react' + +export function createMessagePairs(messages: Message[] | AIMessage[]) { + const messagePairs: MessagePair[] = [] + + for (let i = 0; i < messages.length; i++) { + const message = messages[i] + + if (message.role === 'user') { + const userMessage = message + const chatGptMessages = [] + for (let j = i + 1; j < messages.length; j++) { + const chatGptMessage = findNextAssistantMessage(messages, j) + if (!chatGptMessage) { + break + } else { + chatGptMessages.push(chatGptMessage) + continue + } + } + messagePairs.push({ + userMessage, + chatGptMessage: chatGptMessages + }) + } + } + + return messagePairs +} + +const findNextAssistantMessage = ( + messages: Message[] | AIMessage[], + startIndex: number +) => { + if (messages[startIndex].role === 'assistant') { + return { + ...messages[startIndex], + content: cleanPrompt(messages[startIndex].content) + } + } + return null +} + +// From chat-message.tsx +export function cleanPrompt(str: string) { + const marker = ']. Then answer this question:' + const index = str.indexOf(marker) + let extracted = '' + + if (index !== -1) { + extracted = str.substring(index + marker.length) + } + // console.log('cleanPrompt', str, extracted, index) + return extracted || str +} + +export interface MessagePair { + userMessage: Message | AI.Message + chatGptMessage: Message[] +} + +export function convertMessage(message: Message) { + return { + id: message.messageId, + content: message.content, + createAt: message.createdAt, + role: message.role + } as AI.Message +} diff --git a/apps/masterbots.ai/lib/utils.ts b/apps/masterbots.ai/lib/utils.ts index 0783e965..ccacf839 100644 --- a/apps/masterbots.ai/lib/utils.ts +++ b/apps/masterbots.ai/lib/utils.ts @@ -1,5 +1,3 @@ -import { type Message as AIMessage } from 'ai/react' -import type { Message } from '@repo/mb-genql' import { clsx, ClassValue } from 'clsx' import { customAlphabet } from 'nanoid' import { twMerge } from 'tailwind-merge' @@ -70,61 +68,6 @@ export function extractBetweenMarkers( return str.substring(startIndex, endIndex).trim() } -// From browse-list.tsx -export function createMessagePairs(messages: Message[] | AIMessage[]) { - const messagePairs = [] - - for (let i = 0; i < messages.length; i++) { - const message = messages[i] - - if (message.role === 'user') { - const userMessage = message - const chatGptMessages = [] - for (let j = i + 1; j < messages.length; j++) { - const chatGptMessage = findNextAssistantMessage(messages, j) - if (!chatGptMessage) { - break - } else { - chatGptMessages.push(chatGptMessage) - continue - } - } - messagePairs.push({ - userMessage, - chatGptMessage: chatGptMessages - }) - } - } - - return messagePairs -} - -const findNextAssistantMessage = ( - messages: Message[] | AIMessage[], - startIndex: number -) => { - if (messages[startIndex].role === 'assistant') { - return { - ...messages[startIndex], - content: cleanPrompt(messages[startIndex].content) - } - } - return null -} - -// From chat-message.tsx -export function cleanPrompt(str: string) { - const marker = ']. Then answer this question:' - const index = str.indexOf(marker) - let extracted = '' - - if (index !== -1) { - extracted = str.substring(index + marker.length) - } - // console.log('cleanPrompt', str, extracted, index) - return extracted || str -} - export const readingTime = (messages: { content: string }[]) => { let contentGroup: any = [] @@ -141,41 +84,6 @@ export const readingTime = (messages: { content: string }[]) => { return time } -// Easing function for smooth animation -export const easeInOutQuad = (t: number, b: number, c: number, d: number) => { - t /= d / 2 - if (t < 1) return (c / 2) * t * t + b - t-- - return (-c / 2) * (t * (t - 2) - 1) + b -} - -let animationFrameId: number -export const scrollToBottomOfElement = (element?: HTMLElement) => { - if (!element) return - const targetScroll = element.scrollHeight - element.clientHeight - const duration = 500 - const startTime = performance.now() - - const animateScroll = (currentTime: number) => { - const elapsed = currentTime - startTime - const position = easeInOutQuad( - elapsed, - element.scrollTop, - targetScroll - element.scrollTop, - duration - ) - element.scrollTop = position - - if (elapsed < duration) { - animationFrameId = requestAnimationFrame(animateScroll) - } else { - cancelAnimationFrame(animationFrameId) - } - } - - animationFrameId = requestAnimationFrame(animateScroll) -} - export async function sleep(time: number) { return new Promise(resolve => setTimeout(resolve, time)) } diff --git a/apps/masterbots.ai/package.json b/apps/masterbots.ai/package.json index 2b68566e..ffd1e0f9 100644 --- a/apps/masterbots.ai/package.json +++ b/apps/masterbots.ai/package.json @@ -36,6 +36,7 @@ "@repo/mb-lib": "workspace:*", "@repo/mb-types": "workspace:*", "@supabase/ssr": "^0.1.0", + "@tanstack/react-query": "^5.29.0", "@vercel/analytics": "^1.1.1", "@vercel/og": "^0.5.20", "ai": "^2.2.25", diff --git a/apps/masterbots.ai/services/hasura/hasura.service.ts b/apps/masterbots.ai/services/hasura/hasura.service.ts index e871f0a2..35d85245 100644 --- a/apps/masterbots.ai/services/hasura/hasura.service.ts +++ b/apps/masterbots.ai/services/hasura/hasura.service.ts @@ -20,6 +20,7 @@ import { SaveNewMessageParams, UpsertUserParams } from './hasura.service.type' +import { createMessagePairs } from '@/lib/threads' function getHasuraClient({ jwt, adminSecret }: GetHasuraClientParams) { return createMbClient({ @@ -541,3 +542,8 @@ export async function getUser({ }) return user[0] } + +export async function getMessagePairs(threadId) { + const messages = await getMessages({ threadId }) + return createMessagePairs(messages) +} diff --git a/bun.lockb b/bun.lockb index 1fa6a41f..21507a16 100755 Binary files a/bun.lockb and b/bun.lockb differ