119 lines
5.0 KiB
TypeScript
119 lines
5.0 KiB
TypeScript
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 { 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]',
|
|
}
|
|
|
|
export function UserButton({ type, text, textList, priceErrorMessage }: UserButtonConfig) {
|
|
if (type === '') return null
|
|
|
|
// 부가정보 입력은 폼이라 가운데정렬 덱이 아니라 전체폭으로 편다. text = 저장 후 보낼 동의 문구.
|
|
if (type === 'extra-info') {
|
|
return (
|
|
<div className="w-full px-6 py-4 max-[1180px]:px-4">
|
|
<ExtraInfoBar proceedText={text || ''} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex w-full justify-center overflow-x-auto px-6 py-4 max-[1180px]:px-4">
|
|
<div className="flex justify-center">
|
|
{type === 'one-black' && <OneBlack text={text || '확인'} />}
|
|
{type === 'one-gray' && <OneGray text={text || '확인'} />}
|
|
{type === 'black-white' && <BlackWhite textList={[textList?.[0] || '예', textList?.[1] || '아니오']} />}
|
|
{type === 'percent' && <Percent />}
|
|
{type === 'three-black' && (
|
|
<ThreeBlack textList={[textList?.[0] || '협력사배송', textList?.[1] || '지정택배배송', textList?.[2] || '픽업배송']} />
|
|
)}
|
|
{type === 'price' && <Price priceErrorMessage={priceErrorMessage} />}
|
|
{type === 'loading' && <LoadingDots />}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// agent 응답 대기 중(협상 중) 버튼 자리에 표시하는 "..." 점 애니메이션. 비활성(클릭 불가).
|
|
function LoadingDots() {
|
|
return (
|
|
<div className={cn(style.black, 'cursor-default pointer-events-none')} aria-label="협상 중" role="status">
|
|
<span className="flex gap-[6px]">
|
|
<span className="size-[8px] rounded-full bg-primary-foreground animate-bounce [animation-delay:-0.3s]" />
|
|
<span className="size-[8px] rounded-full bg-primary-foreground animate-bounce [animation-delay:-0.15s]" />
|
|
<span className="size-[8px] rounded-full bg-primary-foreground animate-bounce" />
|
|
</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
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 (
|
|
<button className={style.black} onClick={onClick}>
|
|
{text}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function OneGray({ text }: { text: string }) {
|
|
const sendMessage = useChatStore((s) => s.sendMessage)
|
|
return (
|
|
<button className={style.gray} onClick={() => sendMessage(text)}>
|
|
{text}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function ThreeBlack({ textList }: { textList: [string, string, string] }) {
|
|
const sendMessage = useChatStore((s) => s.sendMessage)
|
|
return (
|
|
<div className="flex gap-3">
|
|
{textList.map((t) => (
|
|
<button key={t} className={style.black} onClick={() => sendMessage(t)}>
|
|
{t}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
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 (
|
|
<div className="flex gap-3">
|
|
<button className={style.black} onClick={() => sendMessage(textList[0])}>
|
|
{textList[0]}
|
|
</button>
|
|
<button className={style.white} onClick={() => sendMessage(textList[1])}>
|
|
{textList[1]}
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|