2023-06-02 15:33:48 -04:00
|
|
|
import { Login } from '@/components/ui/login'
|
|
|
|
|
import { NextChatLogo } from '@/components/ui/nextchat-logo'
|
|
|
|
|
import { UserMenu } from '@/components/ui/user-menu'
|
|
|
|
|
import { kv } from '@vercel/kv'
|
|
|
|
|
import { Chat } from '@/lib/types'
|
|
|
|
|
import { cn } from '@/lib/utils'
|
|
|
|
|
import { type Session } from '@auth/nextjs/types'
|
|
|
|
|
import { Plus } from 'lucide-react'
|
|
|
|
|
import Link from 'next/link'
|
|
|
|
|
import { ExternalLink } from './external-link'
|
|
|
|
|
import { SidebarItem } from './sidebar-item'
|
2023-05-19 12:33:56 -04:00
|
|
|
|
|
|
|
|
export interface SidebarProps {
|
2023-06-02 15:33:48 -04:00
|
|
|
session?: Session
|
|
|
|
|
newChat?: boolean
|
2023-05-19 12:33:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function Sidebar({ session, newChat }: SidebarProps) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="hidden shrink-0 bg-zinc-200/80 dark:bg-black md:flex md:w-[260px] md:flex-col">
|
|
|
|
|
<div className="flex h-full min-h-0 flex-col ">
|
|
|
|
|
<div className="scrollbar-trigger relative h-full w-full flex-1 items-start">
|
|
|
|
|
<aside className="flex h-full w-full flex-col p-2 shadow-lg ring-1 ring-zinc-900/10 dark:ring-zinc-200/10 relative z-10">
|
|
|
|
|
<div className="flex flex-row gap-1 items-center justify-between text-base font-semibold tracking-tight antialiased bg-black text-white px-4 py-4 -m-2 mb-2">
|
2023-05-23 17:17:27 +02:00
|
|
|
<div className="flex flex-row gap-2 whitespace-nowrap items-center">
|
2023-05-19 16:06:02 -04:00
|
|
|
<NextChatLogo className="h-6 w-6" />
|
2023-05-19 14:25:15 -04:00
|
|
|
<span className="select-none">Next.js Chatbot</span>
|
2023-05-19 12:33:56 -04:00
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
{session?.user ? <UserMenu session={session} /> : <Login />}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<Link
|
|
|
|
|
href="/"
|
|
|
|
|
className={cn(
|
2023-06-02 15:33:48 -04:00
|
|
|
'flex shrink-0 cursor-pointer items-center gap-2 rounded p-2 text-sm text-zinc-800 dark:text-zinc-200 font-medium transition-colors duration-300 dark:hover:bg-zinc-300/20 select-none',
|
2023-05-19 12:33:56 -04:00
|
|
|
newChat
|
2023-06-02 15:33:48 -04:00
|
|
|
? 'bg-zinc-500/20 text-zinc-900 font-semibold hover:bg-zinc-500/30 dark:text-white'
|
|
|
|
|
: 'hover:bg-zinc-500/10'
|
2023-05-19 12:33:56 -04:00
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<Plus className="h-4 w-4" />
|
|
|
|
|
New Chat
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
|
|
<div className="mt-2 pt-2 border-t border-zinc-300 dark:border-zinc-700 flex-1 flex-col overflow-y-auto overflow-x-hidden transition-opacity duration-500">
|
|
|
|
|
<div className="flex flex-col pb-2 text-sm text-zinc-100">
|
|
|
|
|
{/* @ts-ignore */}
|
|
|
|
|
<SidebarList session={session} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2023-05-23 16:49:07 +02:00
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<div className="flex gap-4 items-center justify-center text-sm font-medium leading-4 whitespace-nowrap">
|
|
|
|
|
<a
|
|
|
|
|
href="https://github.com/vercel/nextjs-ai-chatbot/"
|
|
|
|
|
target="_blank"
|
|
|
|
|
className="inline-flex gap-2 px-3 py-2 items-center border border-zinc-300 rounded-md hover:border-zinc-600 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
aria-label="Vercel logomark"
|
|
|
|
|
height="13"
|
|
|
|
|
role="img"
|
|
|
|
|
className="w-auto overflow-hidden"
|
|
|
|
|
viewBox="0 0 74 64"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z"
|
|
|
|
|
fill="var(--geist-foreground)"
|
|
|
|
|
></path>
|
|
|
|
|
</svg>
|
|
|
|
|
<span>Deploy</span>
|
|
|
|
|
</a>
|
|
|
|
|
<ExternalLink href="https://github.com/vercel/nextjs-ai-chatbot/">
|
|
|
|
|
View on GitHub
|
|
|
|
|
</ExternalLink>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2023-05-19 12:33:56 -04:00
|
|
|
</aside>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2023-06-02 15:33:48 -04:00
|
|
|
)
|
2023-05-19 12:33:56 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-02 15:33:48 -04:00
|
|
|
Sidebar.displayName = 'Sidebar'
|
2023-05-19 12:33:56 -04:00
|
|
|
|
|
|
|
|
async function SidebarList({ session }: { session?: Session }) {
|
2023-06-02 15:33:48 -04:00
|
|
|
const results: Chat[] = await getChats(session?.user?.email ?? '')
|
2023-05-22 13:37:56 +02:00
|
|
|
|
2023-06-02 15:33:48 -04:00
|
|
|
return results.map(c => (
|
2023-06-02 14:28:05 -04:00
|
|
|
<SidebarItem
|
|
|
|
|
key={c.id}
|
|
|
|
|
title={c.title}
|
2023-06-02 15:33:48 -04:00
|
|
|
userId={session?.user?.email ?? ''}
|
2023-06-02 14:28:05 -04:00
|
|
|
href={`/chat/${c.id}`}
|
|
|
|
|
id={c.id}
|
|
|
|
|
/>
|
2023-06-02 15:33:48 -04:00
|
|
|
))
|
2023-05-19 12:33:56 -04:00
|
|
|
}
|
2023-06-02 15:15:35 -04:00
|
|
|
|
|
|
|
|
async function getChats(userId: string) {
|
|
|
|
|
try {
|
2023-06-02 15:33:48 -04:00
|
|
|
const pipeline = kv.pipeline()
|
|
|
|
|
const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1)
|
2023-06-02 15:15:35 -04:00
|
|
|
|
|
|
|
|
for (const chat of chats) {
|
2023-06-02 15:33:48 -04:00
|
|
|
pipeline.hgetall(chat)
|
2023-06-02 15:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-02 15:33:48 -04:00
|
|
|
const results = await pipeline.exec()
|
2023-06-02 15:15:35 -04:00
|
|
|
|
2023-06-02 15:33:48 -04:00
|
|
|
return results as Chat[]
|
2023-06-02 15:15:35 -04:00
|
|
|
} catch (error) {
|
2023-06-02 15:33:48 -04:00
|
|
|
return []
|
2023-06-02 15:15:35 -04:00
|
|
|
}
|
|
|
|
|
}
|