"use client" import Link from './LocalizedLink' import { useRouter } from 'next/navigation' import { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { ChevronRight, Loader2, Package, Search } from 'lucide-react' import { API_BASE } from '../lib/api' import { useLang } from '../hooks/useLang' import { getPathWithLocale } from '../lib/locales' import { toneClass } from '../lib/theme' type TrackResponse = | { success: true; orderId: number } | { error?: string } function parseStoredOrders(value: string | null) { if (!value) return [] try { const parsed = JSON.parse(value) return Array.isArray(parsed) ? parsed.map(Number).filter((id) => Number.isFinite(id) && id > 0) : [] } catch { return [] } } function orderLabel(id: number) { return `#${id.toString().padStart(4, '0')}` } interface TrackOrderClientProps { lang?: string } export default function TrackOrderClient({ lang: propLang }: TrackOrderClientProps = {}) { const router = useRouter() const contextLang = useLang() const lang = propLang || contextLang || 'th' const { t: i18nT } = useTranslation() const t = useCallback( (key: string, options?: Record) => { return i18nT(key, { lng: lang, ...options }) }, [i18nT, lang], ) const [orderId, setOrderId] = useState('') const [phone, setPhone] = useState('') const [localOrders, setLocalOrders] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) useEffect(() => { const storedOrders = parseStoredOrders(localStorage.getItem('app_local_orders')) queueMicrotask(() => setLocalOrders(storedOrders)) }, []) const saveLocalOrder = (id: number) => { setLocalOrders((current) => { const next = [id, ...current.filter((item) => item !== id)].slice(0, 12) localStorage.setItem('app_local_orders', JSON.stringify(next)) return next }) } const handleSubmit = async (event: React.FormEvent) => { event.preventDefault() setLoading(true) setError(null) const normalizedOrderId = Number.parseInt(orderId.replace(/[^0-9]/g, ''), 10) if (!Number.isFinite(normalizedOrderId) || normalizedOrderId <= 0) { setError(t('track.errors.invalidOrderId')) setLoading(false) return } try { const response = await fetch(`${API_BASE}/orders/track`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId: normalizedOrderId, phone, }), }) const data = await response.json() as TrackResponse if (response.ok && 'success' in data && data.success) { saveLocalOrder(data.orderId) router.push(getPathWithLocale(`/order/${data.orderId}`, lang)) return } setError('error' in data && data.error ? data.error : t('track.errors.notFound')) } catch (err) { setError(err instanceof Error ? err.message : t('track.errors.networkError')) } finally { setLoading(false) } } return (

{t('track.search.eyebrow')}

{t('track.search.title')}

{error && (
{error}
)}
setOrderId(event.target.value)} className="ui-form-shell" placeholder={t('track.search.orderIdPlaceholder')} type="text" />
setPhone(event.target.value)} className="ui-form-shell" placeholder={t('track.search.phonePlaceholder')} type="tel" />

{t('track.recent.title')}

{localOrders.length === 0 ? (

{t('track.recent.emptyTitle')}

{t('track.recent.emptyDesc')}

) : (
{localOrders.map((id) => (

{t('track.recent.orderLabel')}

{orderLabel(id)}

))}
)}
) }