guardia-mall/frontend/src/shop/Cs.tsx

96 lines
5.7 KiB
TypeScript

import { useState } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { Headset, Sparkles, Send } from 'lucide-react'
import { Link, useNavigate } from 'react-router-dom'
import { getMyCs, createCs, aiCardMessage } from '../api/client'
import { useShop } from '../store/shop'
import StatusBadge from '../components/StatusBadge'
const CATS = ['DELIVERY', 'PRODUCT', 'PAYMENT', 'REFUND', 'OTHER']
export default function Cs() {
const qc = useQueryClient()
const nav = useNavigate()
const { custToken } = useShop()
const [category, setCategory] = useState('DELIVERY')
const [orderNo, setOrderNo] = useState('')
const [subject, setSubject] = useState('')
const [content, setContent] = useState('')
const [msg, setMsg] = useState('')
// AI 카드메시지 도우미
const [occasion, setOccasion] = useState('Birthday')
const [tone, setTone] = useState('Warm')
const [recipient, setRecipient] = useState('')
const [cardSuggestions, setCardSuggestions] = useState<string[]>([])
const { data: tickets } = useQuery({ queryKey: ['cs'], queryFn: getMyCs, enabled: !!custToken })
const submit = async (e: React.FormEvent) => {
e.preventDefault(); setMsg('')
if (!custToken) { nav('/account'); return }
try {
const r = await createCs({ orderNo, category, subject, content })
setMsg(r?.aiReply ? `AI auto-reply: ${r.aiReply}` : 'Your request has been submitted.')
setSubject(''); setContent(''); qc.invalidateQueries({ queryKey: ['cs'] })
} catch { setMsg('Failed to submit your request.') }
}
const genCard = async () => {
const r = await aiCardMessage(occasion, tone, recipient).catch(() => null)
setCardSuggestions(r?.messages || [])
}
return (
<div className="max-w-3xl mx-auto px-4 py-8">
<div className="flex items-center gap-2 mb-6"><Headset className="text-bloom" size={22} /><h1 className="font-serif text-2xl font-bold text-blush-900">Customer Support (1:1)</h1></div>
{/* AI 카드 메시지 작성 도우미 */}
<div className="bg-petal rounded-2xl p-5 mb-6">
<div className="flex items-center gap-2 text-bloom2 font-medium text-sm mb-3"><Sparkles size={16} /> AI Card Message Helper</div>
<div className="grid grid-cols-3 gap-2 mb-3">
<input value={occasion} onChange={e => setOccasion(e.target.value)} placeholder="Occasion (e.g. Birthday)" className="px-3 py-2 rounded-lg border border-blush-100 text-sm bg-white outline-none" />
<input value={tone} onChange={e => setTone(e.target.value)} placeholder="Tone" className="px-3 py-2 rounded-lg border border-blush-100 text-sm bg-white outline-none" />
<input value={recipient} onChange={e => setRecipient(e.target.value)} placeholder="Recipient" className="px-3 py-2 rounded-lg border border-blush-100 text-sm bg-white outline-none" />
</div>
<button onClick={genCard} className="bg-bloom text-white text-sm font-semibold px-4 py-2 rounded-full">Suggest Messages</button>
{!!cardSuggestions.length && (
<ul className="mt-3 space-y-2">
{cardSuggestions.map((m, i) => <li key={i} className="bg-white rounded-lg px-3 py-2 text-sm text-gray-700">{m}</li>)}
</ul>
)}
</div>
{/* 문의 작성 */}
<form onSubmit={submit} className="bg-white rounded-2xl border border-blush-100/60 p-5 space-y-3 mb-8">
<div className="grid grid-cols-2 gap-3">
<select value={category} onChange={e => setCategory(e.target.value)} className="px-3 py-2 rounded-xl border border-blush-100 text-sm bg-white">
{CATS.map(c => <option key={c} value={c}>{c}</option>)}
</select>
<input value={orderNo} onChange={e => setOrderNo(e.target.value)} placeholder="Order number (optional)" className="px-3 py-2 rounded-xl border border-blush-100 text-sm outline-none focus:border-bloom" />
</div>
<input value={subject} onChange={e => setSubject(e.target.value)} required placeholder="Subject" className="w-full px-3 py-2.5 rounded-xl border border-blush-100 text-sm outline-none focus:border-bloom" />
<textarea value={content} onChange={e => setContent(e.target.value)} rows={4} required placeholder="Tell us how we can help. Our AI will try to answer first." className="w-full px-3 py-2.5 rounded-xl border border-blush-100 text-sm outline-none focus:border-bloom" />
{msg && <div className="text-sm text-leaf bg-leaf/10 rounded-lg px-3 py-2">{msg}</div>}
<button className="flex items-center gap-1.5 bg-bloom text-white font-semibold px-6 py-2.5 rounded-full hover:bg-bloom2"><Send size={16} /> Submit Request</button>
{!custToken && <p className="text-xs text-gray-400">Please log in to submit a request. <Link to="/account" className="text-bloom">Log In</Link></p>}
</form>
<h2 className="font-serif text-lg font-bold mb-3">My Requests</h2>
<div className="space-y-2">
{(tickets || []).map((t: any) => (
<div key={t.id} className="bg-white rounded-2xl border border-blush-100/60 p-4">
<div className="flex items-center justify-between">
<span className="font-medium text-sm">{t.subject}</span>
<StatusBadge status={t.status} />
</div>
<p className="text-sm text-gray-600 mt-1">{t.content}</p>
{t.aiReply && <div className="mt-2 text-xs text-bloom2 bg-petal rounded-lg px-3 py-2"><b>AI Reply:</b> {t.aiReply}</div>}
{t.itsmSrId && <div className="text-[11px] text-gray-400 mt-1">ITSM SR: {t.itsmSrId}</div>}
</div>
))}
{!(tickets || []).length && <div className="text-gray-400 text-sm py-6 text-center">No requests submitted yet.</div>}
</div>
</div>
)
}