import { useEffect } from 'react' import { useNavigate } from 'react-router' import { cn } from '@/lib' import { useChatStore } from '@/features/chat/stores/useChatStore' import { Percent, Price } from '@/features/chat/components/userInputs' import { ExtraInfoBar } from '@/features/chat/components/ExtraInfoBar' import { RejectForm } from '@/features/chat/components/RejectForm' import { GO_TO_LIST_TEXT } from '@/features/chat/lib/userButtonConfig' import type { UserButtonConfig } from '@/features/chat/types' // max-[1180px]: 채팅 폭이 좁아지면 버튼 패딩·최소폭 축소, 상품목록은 아이콘만 남긴다 const style = { black: 'flex min-w-[120px] px-[28px] max-[1180px]:min-w-[100px] max-[1180px]:px-[20px] h-[46px] bg-brand-600 hover:bg-brand-700 rounded-xl items-center justify-center text-sm font-bold text-white shadow-sm cursor-pointer whitespace-nowrap transition-all duration-200 ease-out active:scale-[0.98]', gray: 'flex min-w-[120px] px-[28px] max-[1180px]:min-w-[100px] max-[1180px]:px-[20px] h-[46px] bg-neutral-60 hover:brightness-[0.97] rounded-xl items-center justify-center text-sm font-bold text-white cursor-pointer whitespace-nowrap transition-all ease-out active:scale-[0.98]', white: 'flex min-w-[120px] px-[28px] max-[1180px]:min-w-[100px] max-[1180px]:px-[20px] h-[46px] bg-white hover:bg-neutral-10 rounded-xl items-center justify-center text-sm font-bold text-neutral-80 border border-border cursor-pointer whitespace-nowrap transition-all ease-out active:scale-[0.98]', } // onReject: 협상 거부 진입점. 넘어오면 버튼 덱 끝에 붙는다(입력 단계는 인풋이 넓어 좁은 화면에서 아랫줄로 wrap). export function UserButton({ type, text, textList, priceErrorMessage, onReject }: UserButtonConfig & { onReject?: () => void }) { if (type === '') return null // 부가정보 입력은 폼이라 가운데정렬 덱이 아니라 전체폭으로 편다. text = 저장 후 보낼 동의 문구. if (type === 'extra-info') { return (
) } // 결렬 통일 폼 — 부가정보와 같은 자리(액션바)에서 전체폭으로. if (type === 'reject') { return (
) } // 입력 단계는 에러 말풍선이 위로 삐져나가야 해서 overflow 클리핑 제외 (버튼 덱만 가로 스크롤 허용) const isInputStep = type === 'percent' || type === 'price' return (
{type === 'one-black' && } {type === 'one-gray' && } {type === 'black-white' && } {type === 'percent' && } {type === 'three-black' && ( )} {type === 'price' && } {type === 'loading' && }
{/* 오클릭 방지: 주 CTA 와 붙이지 않는다. 넓은 화면은 우측 끝 고정(가운데 CTA 는 그대로), 좁은 화면은 인풋 폭 때문에 같은 줄이 안 나오므로 wrap 되어 아랫줄로 내려간다. */} {onReject && ( )}
) } // agent 응답 대기 중(협상 중) 버튼 자리에 표시하는 "..." 점 애니메이션. 비활성(클릭 불가). function LoadingDots() { return (
) } function OneBlack({ text }: { text: string }) { const navigate = useNavigate() const sendMessage = useChatStore((s) => s.sendMessage) const onClick = () => (text === GO_TO_LIST_TEXT ? navigate('/list') : sendMessage(text)) return ( ) } function OneGray({ text }: { text: string }) { const sendMessage = useChatStore((s) => s.sendMessage) return ( ) } function ThreeBlack({ textList }: { textList: [string, string, string] }) { const sendMessage = useChatStore((s) => s.sendMessage) return (
{textList.map((t) => ( ))}
) } function BlackWhite({ textList }: { textList: [string, string] }) { const sendMessage = useChatStore((s) => s.sendMessage) // Enter = 첫 버튼(예). 입력창이 없는 선택 단계라 전역 Enter 를 잡아도 안전하다. useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === 'Enter' && !e.isComposing) { e.preventDefault() sendMessage(textList[0]) } } window.addEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey) }, [sendMessage, textList]) return (
) }