'use client' import { useState } from 'react' import { useTranslations } from 'next-intl' import type { PromoCode } from '@/lib/admin-promo' export function AdminPromoManager({ initial }: { initial: PromoCode[] }) { const t = useTranslations('Admin') const [codes, setCodes] = useState(initial) const [form, setForm] = useState({ code: '', pd: '0', pv: '0', maxUses: '1', expiresAt: '' }) const [busy, setBusy] = useState(false) const [error, setError] = useState(null) function upd(k: string, v: string) { setForm((f) => ({ ...f, [k]: v })) } async function create(e: React.FormEvent) { e.preventDefault() if (busy || !form.code.trim()) return setBusy(true) setError(null) try { const res = await fetch('/api/admin/promo', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ code: form.code.trim(), pd: Number(form.pd), pv: Number(form.pv), maxUses: Number(form.maxUses), expiresAt: form.expiresAt, }), }) const data: { success?: boolean; id?: number; error?: string } = await res.json() if (data.success && data.id) { setCodes([ { id: data.id, code: form.code.trim(), pd: Number(form.pd), pv: Number(form.pv), max_uses: Number(form.maxUses), uses: 0, active: 1, expires_at: form.expiresAt ? new Date(form.expiresAt).toISOString() : null, redemptions: 0, }, ...codes, ]) setForm({ code: '', pd: '0', pv: '0', maxUses: '1', expiresAt: '' }) } else { setError(data.error === 'duplicate' ? t('promoDuplicate') : t('promoEmptyError')) } } finally { setBusy(false) } } async function remove(id: number) { if (!confirm(t('promoConfirmDelete'))) return const res = await fetch(`/api/admin/promo/${id}`, { method: 'DELETE', credentials: 'same-origin' }) if ((await res.json()).success) setCodes(codes.filter((c) => c.id !== id)) } return (
upd('code', e.target.value)} placeholder={t('promoCode')} /> upd('pd', e.target.value)} placeholder={t('promoPd')} /> upd('pv', e.target.value)} placeholder={t('promoPv')} /> upd('maxUses', e.target.value)} placeholder={t('promoMaxUses')} /> upd('expiresAt', e.target.value)} placeholder={t('promoExpires')} />
{error &&

{error}

}
{codes.length === 0 ? (

{t('noPromo')}

) : ( {codes.map((c) => ( remove(c.id)} /> ))}
)}
) } function PromoRow({ promo, onDelete }: { promo: PromoCode; onDelete: () => void }) { const t = useTranslations('Admin') const [pd, setPd] = useState(String(promo.pd)) const [pv, setPv] = useState(String(promo.pv)) const [maxUses, setMaxUses] = useState(String(promo.max_uses)) const [active, setActive] = useState(promo.active === 1) const [busy, setBusy] = useState(false) const [saved, setSaved] = useState(false) async function save() { setBusy(true) setSaved(false) try { const res = await fetch(`/api/admin/promo/${promo.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ pd: Number(pd), pv: Number(pv), maxUses: Number(maxUses), active }), }) if ((await res.json()).success) { setSaved(true) setTimeout(() => setSaved(false), 2000) } } finally { setBusy(false) } } return ( {promo.code}

{t('promoUses')}: {promo.uses}/{promo.max_uses} · {t('promoRedemptions')}: {promo.redemptions} {promo.expires_at ? ` · ${new Date(promo.expires_at).toLocaleString('es-ES')}` : ''}

{' '} {' '} {' '} {' '} ) }