- KT-NEGOWIZ /chat 을 현재 아키텍처(Vite·React Router·feature 구조)로 이식 - 사이드 ItemSection(+이미지 확대), 헤더 잔여시간, 채팅(메시지/템플릿/입력), 메뉴 섹션 - 메시지 템플릿: 협상 성공률·협상요약·투찰요약·재협상/재견적 폼 - zustand 스토어 + mock 데이터(정적 쇼케이스, 제출 시 로컬 append) - Next.js·KT 의존 제거(next/image·navigation, 로고·서비스명·연락처, 팝업 보류) - ChatPage 배선: ChatContainer / ItemSection / RemainingTime + auth SidebarFooter 재사용 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
import { Loader2 } from 'lucide-react'
|
|
import { cn } from '@/lib'
|
|
|
|
// reject 폼 공유 컨트롤 (RejectCM / RejectRSP 공용)
|
|
|
|
export function SelectRadio({
|
|
text,
|
|
value,
|
|
name,
|
|
selectedValue,
|
|
onChange,
|
|
errorMessage,
|
|
disabled,
|
|
}: {
|
|
text: string
|
|
value: string
|
|
name: string
|
|
selectedValue: string
|
|
onChange: (value: string) => void
|
|
errorMessage: string
|
|
disabled?: boolean
|
|
}) {
|
|
const isChecked = selectedValue === value
|
|
return (
|
|
<label className={cn('flex items-center gap-2', disabled ? 'cursor-not-allowed' : 'cursor-pointer')}>
|
|
<input
|
|
className={cn(
|
|
'appearance-none w-[16px] h-[16px] min-w-[16px] min-h-[16px] rounded-full border-[1.5px] whitespace-nowrap',
|
|
disabled ? 'cursor-not-allowed' : 'cursor-pointer',
|
|
isChecked
|
|
? 'border-neutral-70 bg-[radial-gradient(circle,var(--neutral-70)_40%,white_40%)]'
|
|
: errorMessage
|
|
? 'border-negative bg-white'
|
|
: 'border-neutral-60 bg-white',
|
|
)}
|
|
type="radio"
|
|
name={name}
|
|
value={value}
|
|
checked={isChecked}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
disabled={disabled}
|
|
/>
|
|
<div className={cn('reject break-keep', disabled && 'text-neutral-60')}>{text}</div>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
export function SubmitButton({
|
|
isValid,
|
|
isLoading,
|
|
isSubmitted,
|
|
onSubmit,
|
|
}: {
|
|
isValid: boolean
|
|
isLoading: boolean
|
|
isSubmitted: boolean
|
|
onSubmit: () => void
|
|
}) {
|
|
if (isSubmitted) return null
|
|
|
|
const style = isLoading
|
|
? 'bg-neutral-40 text-neutral-80 cursor-not-allowed'
|
|
: isValid
|
|
? 'bg-neutral-90 text-white cursor-pointer hover:bg-neutral-80'
|
|
: 'bg-neutral-20 text-neutral-60 cursor-not-allowed'
|
|
|
|
return (
|
|
<button
|
|
className={cn(
|
|
'flex items-center justify-center w-[280px] h-[48px] rounded-[12px] text-base font-bold tracking-[-0.32px] transition-all duration-200',
|
|
style,
|
|
)}
|
|
onClick={onSubmit}
|
|
disabled={!isValid || isLoading}
|
|
>
|
|
{isLoading ? <Loader2 className="size-5 animate-spin" /> : '제출'}
|
|
</button>
|
|
)
|
|
}
|