almeira-web/dripzone-app/src/app/admin/metodos-pago/page.tsx

165 lines
7.1 KiB
TypeScript

'use client';
import React, { useState, useEffect } from 'react';
import { CreditCard, Zap, Save, Check, ShieldCheck, QrCode } from 'lucide-react';
import { PaymentMethod } from '@/types';
import { INITIAL_PAYMENT_METHODS } from '@/lib/data-service';
import { formatCOP } from '@/lib/pricing-engine';
export default function AdminPaymentMethodsPage() {
const [methods, setMethods] = useState<PaymentMethod[]>(INITIAL_PAYMENT_METHODS);
const [message, setMessage] = useState<string | null>(null);
useEffect(() => {
fetch('/api/payment-methods')
.then((r) => r.json())
.then((d) => d.success && setMethods(d.paymentMethods))
.catch(() => {});
}, []);
const handleToggleActive = async (method: PaymentMethod) => {
const updated = { ...method, isActive: !method.isActive };
setMethods((prev) => prev.map((m) => (m.id === method.id ? updated : m)));
await fetch('/api/payment-methods', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: method.id, updates: { isActive: updated.isActive } }),
});
setMessage(`Método "${method.name}" ${updated.isActive ? 'activado' : 'desactivado'}.`);
};
const handleUpdateField = (id: string, field: keyof PaymentMethod, val: any) => {
setMethods((prev) =>
prev.map((m) => (m.id === id ? { ...m, [field]: val } : m))
);
};
const handleSaveMethod = async (method: PaymentMethod) => {
await fetch('/api/payment-methods', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: method.id, updates: method }),
});
setMessage(`✅ Cambios guardados para "${method.name}".`);
};
return (
<div className="space-y-6">
{/* Header */}
<div>
<h1 className="text-2xl font-black text-white flex items-center gap-2">
<CreditCard className="w-6 h-6 text-purple-400" />
<span>Configuración de Medios de Pago & Anticipos</span>
</h1>
<p className="text-xs text-neutral-400 mt-1">
Habilita métodos de pago, configura el valor de separación de $10.000 COP y personaliza los datos de Nequi / Daviplata.
</p>
</div>
{message && (
<div className="bg-emerald-950/80 border border-emerald-800 text-emerald-300 px-4 py-3 rounded-2xl text-xs flex items-center justify-between">
<span>{message}</span>
<button onClick={() => setMessage(null)} className="font-bold text-white cursor-pointer">
✕
</button>
</div>
)}
{/* Methods Cards */}
<div className="space-y-4">
{methods.map((method) => (
<div
key={method.id}
className="bg-neutral-950 border border-neutral-800 rounded-3xl p-5 sm:p-6 space-y-4"
>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-neutral-800/80 pb-4">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 rounded-xl bg-neutral-900 border border-neutral-800 text-purple-400 flex items-center justify-center font-bold">
{method.type === 'contraentrega' ? <Zap className="w-5 h-5 fill-purple-400" /> : <CreditCard className="w-5 h-5" />}
</div>
<div>
<h3 className="font-bold text-white text-base">{method.name}</h3>
<span className="text-xs text-neutral-500 font-mono">Tipo: {method.type}</span>
</div>
</div>
<div className="flex items-center space-x-2">
<button
onClick={() => handleToggleActive(method)}
className={`text-xs font-bold px-3 py-1.5 rounded-xl transition-all cursor-pointer ${
method.isActive
? 'bg-emerald-500/20 text-emerald-400 hover:bg-emerald-500/30'
: 'bg-neutral-800 text-neutral-500 hover:bg-neutral-700'
}`}
>
{method.isActive ? 'Habilitado en Tienda' : 'Deshabilitado'}
</button>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-[11px] font-bold text-neutral-400 mb-1">Nombre Visible:</label>
<input
type="text"
value={method.name}
onChange={(e) => handleUpdateField(method.id, 'name', e.target.value)}
className="w-full bg-neutral-900 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden"
/>
</div>
<div>
<label className="block text-[11px] font-bold text-neutral-400 mb-1">Descripción para el Cliente:</label>
<input
type="text"
value={method.description}
onChange={(e) => handleUpdateField(method.id, 'description', e.target.value)}
className="w-full bg-neutral-900 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden"
/>
</div>
{method.requiresDeposit && (
<div>
<label className="block text-[11px] font-bold text-amber-400 mb-1">Valor de la Separación (COP):</label>
<input
type="number"
value={method.depositAmount}
onChange={(e) => handleUpdateField(method.id, 'depositAmount', parseInt(e.target.value, 10) || 0)}
className="w-full bg-neutral-900 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden font-bold"
/>
<span className="text-[10px] text-neutral-400 mt-1 block">
(El saldo restante se cobra contraentrega al recibir)
</span>
</div>
)}
<div>
<label className="block text-[11px] font-bold text-neutral-400 mb-1">Cuentas / Números de Pago (Nequi / Daviplata):</label>
<input
type="text"
value={method.accountInfo || ''}
onChange={(e) => handleUpdateField(method.id, 'accountInfo', e.target.value)}
className="w-full bg-neutral-900 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden"
placeholder="Ej: Nequi / Daviplata: 3XX XXX XXXX"
/>
</div>
</div>
<div className="flex justify-end pt-2">
<button
onClick={() => handleSaveMethod(method)}
className="bg-purple-600 hover:bg-purple-700 text-white font-bold text-xs px-4 py-2 rounded-xl flex items-center space-x-1.5 transition-all cursor-pointer shadow-lg shadow-purple-600/30"
>
<Save className="w-3.5 h-3.5" />
<span>Guardar Configuración</span>
</button>
</div>
</div>
))}
</div>
</div>
);
}