|
1 | | -//* Component for displaying details of the selected chatbot |
2 | | - |
3 | | -'use client' |
4 | | - |
5 | | -import { Separator } from '@/components/ui/separator' |
| 1 | +import { useSession } from 'next-auth/react' |
6 | 2 | import { useSidebar } from '@/lib/hooks/use-sidebar' |
7 | 3 | import { useThread } from '@/lib/hooks/use-thread' |
| 4 | +import { useParams } from 'next/navigation' |
| 5 | +import { useState, useEffect } from 'react' |
8 | 6 | import { getCategory, getThreads } from '@/services/hasura' |
9 | | -import { useSession } from 'next-auth/react' |
10 | 7 | import Image from 'next/image' |
11 | | -import { useParams } from 'next/navigation' |
12 | | -import { useEffect, useState } from 'react' |
| 8 | +import { Button } from '@/components/ui/button' |
| 9 | +import { MessageSquare, MessageCircle, Users } from 'lucide-react' |
| 10 | +import { cn } from '@/lib/utils' |
| 11 | +import { toSlug } from 'mb-lib' |
| 12 | +import { ChatChatbotDetailsSkeleton } from '@/components/shared/skeletons/chat-chatbot-details-skeleton' |
| 13 | + |
| 14 | +/** |
| 15 | + * Displays detailed information about a chatbot or welcome message in the Masterbots application. |
| 16 | + * It serves as both a welcome screen for new users and a details card for specific chatbots. |
| 17 | + * |
| 18 | + * @features |
| 19 | + * - Displays welcome message or chatbot information |
| 20 | + * - Shows chatbot avatar with customizable border colors for light/dark modes |
| 21 | + * - Presents thread count and follower statistics |
| 22 | + * - Provides quick actions (Follow, New Chat) |
| 23 | + * - Fully responsive design with mobile-first approach |
| 24 | + * - Supports both light and dark themes |
| 25 | + */ |
13 | 26 |
|
14 | 27 | export default function ChatChatbotDetails({ page }: { page?: string }) { |
15 | | - const { data: session } = useSession() //* Retrieves session data using next-auth |
16 | | - const { activeCategory, activeChatbot } = useSidebar() //* Retrieves active category and chatbot from sidebar state |
17 | | - const { randomChatbot } = useThread() //* Retrieves a random chatbot from thread state |
18 | | - const [threadNum, setThreadNum] = useState<number>(0) //* Stores the number of threads |
19 | | - const [categoryName, setCategoryName] = useState<string>('') //* Stores the name of the active category |
20 | | - // get current url params use UseParams hook from next/router to get the current url params and use it to fetch the data |
21 | | - const { slug } = useParams() |
22 | | - |
23 | | - //* Fetches the number of threads for the active category and user |
| 28 | + const { data: session } = useSession() |
| 29 | + const { activeCategory, activeChatbot } = useSidebar() |
| 30 | + const { randomChatbot } = useThread() |
| 31 | + const [threadNum, setThreadNum] = useState<number>(0) |
| 32 | + const [categoryName, setCategoryName] = useState<string>('') |
| 33 | + const { slug } = useParams() |
| 34 | + |
| 35 | + |
| 36 | + if (status === "loading") return <ChatChatbotDetailsSkeleton /> |
| 37 | + |
24 | 38 | const getThreadNum = async () => { |
25 | 39 | if (!session?.user) return |
26 | | - |
27 | 40 | const threads = await getThreads({ |
28 | 41 | jwt: session?.user?.hasuraJwt as string, |
29 | 42 | categoryId: activeCategory, |
30 | 43 | userId: session?.user.id as string |
31 | 44 | }) |
32 | | - setThreadNum(threads?.length ?? 0) //* Updates thread number state |
| 45 | + setThreadNum(threads?.length ?? 0) |
33 | 46 | } |
34 | 47 |
|
35 | | - //* Fetches the name of the active category |
36 | 48 | const getCategoryName = async () => { |
37 | | - const category = await getCategory({ categoryId: activeCategory as number }) //* Retrieves category details |
38 | | - setCategoryName(category.name) //* Updates category name state |
| 49 | + const category = await getCategory({ categoryId: activeCategory as number }) |
| 50 | + setCategoryName(category.name) |
39 | 51 | } |
40 | 52 |
|
41 | | - // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation> |
| 53 | + // eslint-disable-next-line react-hooks/rules-of-hooks |
42 | 54 | useEffect(() => { |
43 | | - //* Effect to fetch thread number or category name based on active category |
44 | 55 | if (!activeCategory) { |
45 | | - getThreadNum() //* Fetch thread number if no category is active |
| 56 | + getThreadNum() |
46 | 57 | } else { |
47 | 58 | getCategoryName() |
48 | 59 | } |
49 | | - // eslint-disable-next-line react-hooks/exhaustive-deps |
50 | 60 | }, [activeCategory, activeChatbot, session?.user]) |
51 | 61 |
|
| 62 | + const botName = activeChatbot?.name || 'BuildBot' |
| 63 | + |
52 | 64 | return ( |
53 | | - <div className="h-[calc(100vh-196px)] flex items-center justify-center"> |
54 | | - <div |
55 | | - className="dark:bg-[#09090B] bg-white rounded-lg md:w-[600px] w-[85%] |
56 | | - flex flex-col gap-[10px] relative font-mono" |
57 | | - > |
58 | | - <div className="w-[70%] flex flex-col gap-[10px] px-[24px] pt-[24px]"> |
59 | | - <div className="text-2xl font-black"> |
60 | | - { page != 'profile' ? (activeChatbot ? activeChatbot?.name : 'Welcome to Masterbots!') : `Browse ${slug}'s threads`} |
| 65 | + <div className="h-[calc(100vh-196px)] flex items-center justify-center -translate-y-8"> |
| 66 | + <div className="dark:bg-[#09090B] bg-white w-[85%] md:w-[600px] rounded-xl text-white relative"> |
| 67 | + {/* Card Header */} |
| 68 | + <div className="px-4 pt-4 md:px-6 md:pt-6"> |
| 69 | + <div className="text-base font-bold leading-relaxed md:text-2xl text-zinc-950 dark:text-gray-300"> |
| 70 | + Welcome to Masterbots! |
61 | 71 | </div> |
62 | | - <Separator className="bg-gray-300 dark:bg-mirage" /> |
63 | | - <div className="grow flex flex-col justify-between min-h-[137px]"> |
64 | | - { |
65 | | - page === 'profile' && ( |
66 | | - <div className="text-xl font-semibold"> |
67 | | - Select category or bot to see or browse more threads from {slug} |
68 | | - </div> |
69 | | - ) |
70 | | - } |
71 | | - {/* <div className="text-xl font-semibold"> |
72 | | - { page != 'profile' && (activeChatbot |
73 | | - ? categoryName |
74 | | - : activeCategory |
75 | | - ? `You are on the ${categoryName} category. Please select one of the bots on the sidebar to start a conversation.` |
76 | | - : 'Please select one of the categories and a bot on the sidebar to start a conversation.')} |
77 | | - </div> */} |
78 | | - <div className="text-base gap-[8px] flex flex-col pb-[8px]"> |
79 | | - {/* biome-ignore lint/complexity/useOptionalChain: <explanation> */} |
80 | | - {activeChatbot && activeChatbot?.description ? ( |
81 | | - <div className="font-medium">{activeChatbot.description}</div> |
82 | | - ) : ( |
83 | | - '' |
| 72 | + </div> |
| 73 | + |
| 74 | + {/* Separator Line - Extended to edges */} |
| 75 | + <div className="h-[3px] bg-zinc-200 dark:bg-slate-800 mt-6 relative"> |
| 76 | + {/* Floating Avatar - Responsive sizing */} |
| 77 | + <div className="absolute right-4 -top-10 md:right-6 md:-top-12"> |
| 78 | + <div |
| 79 | + className={cn( |
| 80 | + 'size-20 md:size-32 rounded-full p-2 md:p-2.5 relative', // Smaller size on mobile |
| 81 | + 'bg-zinc-200 dark:bg-black', |
| 82 | + 'ring-2 ring-[#be16e8] dark:ring-[#82e46a]' |
84 | 83 | )} |
85 | | - <div className="font-light"> |
86 | | - Threads made:{' '} |
87 | | - <span className="text-[#71717A]"> |
88 | | - {activeChatbot |
89 | | - ? (activeChatbot?.threads?.length ?? 0) |
90 | | - : threadNum} |
| 84 | + > |
| 85 | + <Image |
| 86 | + src={activeChatbot?.avatar || randomChatbot?.avatar || ''} |
| 87 | + alt={`${botName} avatar`} |
| 88 | + height={128} |
| 89 | + width={128} |
| 90 | + className="object-cover rounded-full" |
| 91 | + /> |
| 92 | + </div> |
| 93 | + </div> |
| 94 | + </div> |
| 95 | + |
| 96 | + {/* Description with right margin to avoid avatar overlap */} |
| 97 | + <div className="p-2 px-4 mr-2 md:p-3 md:px-6 md:mr-4"> |
| 98 | + <p className="pr-24 text-sm font-normal text-justify md:pr-32 md:text-base text-zinc-500 dark:text-zinc-500"> |
| 99 | + Here you can create new threads and share them to your network! |
| 100 | + Navigate with the sidebar and pick any bot of your interest. |
| 101 | + </p> |
| 102 | + </div> |
| 103 | + |
| 104 | + {/* Card Content */} |
| 105 | + <div className="px-4 pb-4 md:px-6 md:pb-6 flex flex-col items-center justify-start gap-1.5"> |
| 106 | + <div className="mb-3 text-center md:mb-4"> |
| 107 | + <h2 className="text-lg md:text-2xl font-semibold leading-[34.08px] text-zinc-950 dark:text-gray-300"> |
| 108 | + Your Journey Begins Here! |
| 109 | + </h2> |
| 110 | + <p className="text-base font-semibold leading-relaxed md:text-lg text-zinc-500 dark:text-zinc-500"> |
| 111 | + Try and start with: {botName} |
| 112 | + </p> |
| 113 | + </div> |
| 114 | + |
| 115 | + <div className="flex flex-col items-center w-full gap-3"> |
| 116 | + <div className="flex items-center justify-center gap-4 md:gap-6"> |
| 117 | + <div className="flex items-center gap-1"> |
| 118 | + <MessageSquare className="w-4 h-4 text-zinc-950 dark:text-gray-300" /> |
| 119 | + <span className="text-xs font-normal leading-tight md:text-sm text-zinc-950 dark:text-gray-300"> |
| 120 | + Threads:{' '} |
| 121 | + <span className="text-zinc-500 dark:text-zinc-500"> |
| 122 | + {activeChatbot |
| 123 | + ? (activeChatbot?.threads?.length ?? 0) |
| 124 | + : threadNum} |
| 125 | + </span> |
91 | 126 | </span> |
92 | 127 | </div> |
| 128 | + |
| 129 | + <div className="flex items-center gap-2 md:gap-3"> |
| 130 | + <div className="flex items-center gap-1"> |
| 131 | + <Users className="w-4 h-4 text-zinc-950 dark:text-gray-300" /> |
| 132 | + <span className="text-xs font-normal leading-tight md:text-sm text-zinc-950 dark:text-gray-300"> |
| 133 | + Followers:{' '} |
| 134 | + <span className="text-zinc-500 dark:text-zinc-500"> |
| 135 | + 3.2k |
| 136 | + </span> |
| 137 | + </span> |
| 138 | + </div> |
| 139 | + |
| 140 | + <Button |
| 141 | + variant="outline" |
| 142 | + size="sm" |
| 143 | + className="text-xs md:text-sm border-zinc-200 dark:border-zinc-100/50 text-zinc-500 dark:text-zinc-500" |
| 144 | + > |
| 145 | + Follow |
| 146 | + </Button> |
| 147 | + </div> |
93 | 148 | </div> |
| 149 | + |
| 150 | + <Button |
| 151 | + className={cn( |
| 152 | + 'w-auto px-4 md:px-6 py-2 text-sm md:text-base', |
| 153 | + 'bg-[#be16e8] hover:bg-[#be16e8]/90', |
| 154 | + 'dark:bg-[#82e46a] dark:hover:bg-[#82e46a]/90', |
| 155 | + 'text-white dark:text-zinc-950', |
| 156 | + 'leading-none' |
| 157 | + )} |
| 158 | + > |
| 159 | + <MessageCircle className="mr-2 size-4" /> |
| 160 | + New Chat With {botName} |
| 161 | + </Button> |
94 | 162 | </div> |
95 | 163 | </div> |
96 | | - <div className="size-24 absolute border-4 border-[#388DE2] right-0 top-0 translate-x-1/4 rounded-full translate-y-1/4 dark:bg-[#131316] bg-white"> |
97 | | - <Image |
98 | | - className="transition-opacity duration-300 rounded-full select-none size-full ring-1 ring-zinc-100/10 hover:opacity-80" |
99 | | - src={activeChatbot?.avatar || randomChatbot?.avatar || ''} |
100 | | - alt={activeChatbot?.avatar || randomChatbot?.avatar || 'ChatAvatar'} |
101 | | - height={108} |
102 | | - width={108} |
103 | | - /> |
104 | | - </div> |
105 | 164 | </div> |
106 | 165 | </div> |
107 | 166 | ) |
|
0 commit comments