- 채팅 링크로 바로 진입하면 세션이 협상생성(1)에 머물러 오프닝 메시지가 seed 되지 않던 문제: chat init/messages 에서 participate 와 동일하게 협상중(2)으로 전이(마감 견적·마감시간 초과는 제외) - 부가정보 저장이 1301 로 실패하던 문제: '협상완료' 요약은 chat_end=false 라 세션이 아직 협상중이므로, 마지막 말풍선이 summaryRSP/CM 이면 협상중 세션도 저장 허용 - 채팅 언마운트 시 messages 캐시도 제거 — staleTime:Infinity 라 빈 목록이 남아 재진입해도 빈 화면이던 문제 - 채팅 스크롤을 컨테이너 기준 scrollTo 로 변경(rAF 후 실행) — 요약·폼이 뒤늦게 레이아웃되면 중간에 멈추던 문제 - 모바일 채팅 상단 여백 제거(pt-[64px] 는 우측 협상절차 카드가 있는 lg 이상만) - 노치 대응: viewport-fit=cover + safe-t/b/x 유틸 신설, 헤더·하단 액션 덱·드로어·랜딩 헤더에 적용, h-screen→100dvh
51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import { type ReactNode, useEffect } from 'react'
|
|
import { createPortal } from 'react-dom'
|
|
import { X } from 'lucide-react'
|
|
import { cn } from '@/lib'
|
|
|
|
interface MobileDrawerProps {
|
|
open: boolean
|
|
onClose: () => void
|
|
side?: 'left' | 'right'
|
|
title: string
|
|
children: ReactNode
|
|
}
|
|
|
|
// 모바일 전용 슬라이드 드로어(lg 미만). 데스크톱에선 절대 노출되지 않도록 lg:hidden 을 강제한다.
|
|
export function MobileDrawer({ open, onClose, side = 'left', title, children }: MobileDrawerProps) {
|
|
useEffect(() => {
|
|
if (!open) return
|
|
const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose()
|
|
window.addEventListener('keydown', onKey)
|
|
return () => window.removeEventListener('keydown', onKey)
|
|
}, [open, onClose])
|
|
|
|
if (!open) return null
|
|
|
|
return createPortal(
|
|
<div className="fixed inset-0 z-[60] lg:hidden">
|
|
<div className="absolute inset-0 bg-black/50 animate-fade-in" onClick={onClose} />
|
|
<div
|
|
className={cn(
|
|
'absolute top-0 bottom-0 flex w-[88%] max-w-[360px] flex-col bg-white shadow-xl',
|
|
side === 'left' ? 'left-0' : 'right-0',
|
|
)}
|
|
>
|
|
<div className="flex h-14 box-content safe-t shrink-0 items-center justify-between border-b border-border px-5">
|
|
<span className="text-base font-bold text-neutral-90">{title}</span>
|
|
<button
|
|
type="button"
|
|
onClick={onClose}
|
|
aria-label="닫기"
|
|
className="flex size-8 items-center justify-center rounded-full text-neutral-60 hover:bg-neutral-10"
|
|
>
|
|
<X className="size-4" />
|
|
</button>
|
|
</div>
|
|
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto safe-b">{children}</div>
|
|
</div>
|
|
</div>,
|
|
document.body,
|
|
)
|
|
}
|