o2o-negosium-original/frontend/src/pages/ChatPage.tsx

115 lines
3.7 KiB
TypeScript

import { type ReactNode } from 'react'
import { useNavigate, useSearchParams, Navigate } from 'react-router'
import { ArrowLeft, Package, ClipboardList } from 'lucide-react'
import { cn, interactive } from '@/lib'
import { MainLayout, MainHeaderBar } from '@/layouts'
import { ChatContainer, ItemSection, RemainingTime } from '@/features/chat'
import { MobileDrawer } from '@/features/chat/components/MobileDrawer'
import { MenuSection } from '@/features/chat/components/menu/MenuSection'
import { useChatUiStore } from '@/features/chat/stores/useChatUiStore'
import { SidebarFooter } from '@/features/auth'
export function ChatPage() {
const [searchParams] = useSearchParams()
const sessionId = searchParams.get('session_id') ?? ''
const drawer = useChatUiStore((s) => s.drawer)
const close = useChatUiStore((s) => s.close)
// session_id 없이 진입하면 목록으로 되돌린다.
if (!sessionId) return <Navigate to="/list" replace />
return (
<>
<MainLayout
sidebarWidth="chat"
sidebar={<Sidebar />}
header={
<MainHeaderBar className="px-4 sm:px-6 min-[1180px]:px-8">
<div className="flex w-full items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-2">
<BackToListButton />
<span className="hidden h-4 w-px bg-border lg:inline-block" />
<span className="hidden size-2 shrink-0 rounded-full bg-brand-600 animate-pulse lg:inline-block" />
<span className="hidden truncate text-sm font-bold text-neutral-90 lg:inline">
</span>
</div>
<div className="flex items-center gap-1.5">
<PanelToggle icon={<Package className="size-4" />} label="상품" panel="product" />
<PanelToggle icon={<ClipboardList className="size-4" />} label="현황" panel="status" />
<RemainingTime />
</div>
</div>
</MainHeaderBar>
}
>
<ChatContainer sessionId={sessionId} />
</MainLayout>
{/* 모바일 드로어 (lg 미만) */}
<MobileDrawer open={drawer === 'product'} onClose={close} side="left" title="상품 정보">
<ItemSection />
<SidebarFooter />
</MobileDrawer>
<MobileDrawer open={drawer === 'status'} onClose={close} side="right" title="협상 현황">
<MenuSection variant="drawer" />
</MobileDrawer>
</>
)
}
// 헤더 좌상단: 목록으로 돌아가기 (텍스트 + ← 아이콘)
function BackToListButton() {
const navigate = useNavigate()
return (
<button
type="button"
onClick={() => navigate('/list')}
className={cn(
'flex shrink-0 items-center gap-1.5 rounded-lg px-2 py-1.5 text-sm font-bold text-neutral-70 hover:bg-neutral-10',
interactive,
)}
>
<ArrowLeft className="size-4" />
<span className="hidden sm:inline"> </span>
</button>
)
}
// 헤더 우측: 상품/현황 패널 드로어 토글 (모바일 전용)
function PanelToggle({
icon,
label,
panel,
}: {
icon: ReactNode
label: string
panel: 'product' | 'status'
}) {
const open = useChatUiStore((s) => s.open)
return (
<button
type="button"
onClick={() => open(panel)}
className={cn(
'flex items-center gap-1 rounded-lg border border-border px-2 py-1.5 text-xs font-bold text-neutral-70 hover:bg-neutral-10 lg:hidden',
interactive,
)}
>
{icon}
<span className="hidden min-[480px]:inline">{label}</span>
</button>
)
}
function Sidebar() {
return (
<>
<ItemSection />
<SidebarFooter />
</>
)
}
export default ChatPage