diff --git a/dripzone-app/src/app/admin/configuracion/page.tsx b/dripzone-app/src/app/admin/configuracion/page.tsx index 567254c..55fa64a 100644 --- a/dripzone-app/src/app/admin/configuracion/page.tsx +++ b/dripzone-app/src/app/admin/configuracion/page.tsx @@ -186,22 +186,54 @@ export default function AdminSettingsPage() { Integración con Bold.co (Link de Pago, Botón & QR) - +
+
+ + +
+ + +
- +
+ + + {(settings.boldEnvironment ?? 'production') === 'production' ? 'Modo Producción (En Vivo)' : 'Modo Pruebas (Sandbox)'} + +
; + badge: string; + icon: string; + requiresDeposit: boolean; + depositAmount: number; + description: string; + accountInfo: string; + boldPaymentLink: string; +}> = [ + { + id: 'pay-bold-deposit-10k', + name: 'Separación con $10.000 (Bold) + Saldo Contraentrega', + type: 'contraentrega', + boldChannel: 'deposit', + badge: 'Bold ⚡ Anticipo Oficial', + icon: 'Zap', + requiresDeposit: true, + depositAmount: 10000, + description: 'Separa tu talla con solo $10.000 COP en línea a través de Bold (PSE, tarjetas de crédito/débito, Nequi o QR Bre-B) y cancelas el saldo restante en efectivo o transferencia al recibir en tu puerta.', + accountInfo: 'Pasarela Bold Oficial • PSE, Tarjetas Visa/Mastercard, Nequi y QR Bre-B', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-pse', + name: 'PSE • Débito desde cualquier Banco (vía Bold)', + type: 'bold', + boldChannel: 'pse', + badge: 'Bold 🏦 PSE Débito', + icon: 'Landmark', + requiresDeposit: false, + depositAmount: 0, + description: 'Paga el 100% de tu pedido al instante debitando directamente desde tu cuenta bancaria de ahorros o corriente de cualquier banco en Colombia a través de Bold.', + accountInfo: 'Débito en línea disponible para Bancolombia, Davivienda, Banco de Bogotá, BBVA y más de 20 bancos', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-cards', + name: 'Tarjetas Débito y Crédito (Visa, Mastercard, Amex - vía Bold)', + type: 'bold', + boldChannel: 'card', + badge: 'Bold 💳 Tarjetas & Cuotas', + icon: 'CreditCard', + requiresDeposit: false, + depositAmount: 0, + description: 'Paga 100% seguro a cuotas o de contado con tarjeta Visa, Mastercard, American Express o Diners Club respaldado con cifrado bancario de Bold.', + accountInfo: 'Acepta tarjetas nacionales e internacionales a cuotas con verificación antifraude', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-nequi', + name: 'Nequi en Línea (Pasarela Bold)', + type: 'bold', + boldChannel: 'nequi', + badge: 'Bold 📱 Nequi Oficial', + icon: 'Smartphone', + requiresDeposit: false, + depositAmount: 0, + description: 'Paga directo desde tu app Nequi mediante la pasarela segura de Bold con notificación push inmediata y confirmación automática.', + accountInfo: 'Nequi en línea procesado directamente por la infraestructura de Bold', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-bancolombia', + name: 'Botón Bancolombia (Transferencia Directa vía Bold)', + type: 'bold', + boldChannel: 'bancolombia', + badge: 'Bold ⚡ Botón Bancolombia', + icon: 'Zap', + requiresDeposit: false, + depositAmount: 0, + description: 'Transfiere en segundos desde tu aplicación Bancolombia sin digitar números de cuenta ni comprobantes manuales, debitado vía Bold.', + accountInfo: 'Botón oficial Bancolombia integrado en la pasarela Bold', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-bre-b', + name: 'Código QR Bre-B • Interoperabilidad Inmediata (vía Bold)', + type: 'bold', + boldChannel: 'bre_b', + badge: 'Bold ⚡ Bre-B Banco República', + icon: 'QrCode', + requiresDeposit: false, + depositAmount: 0, + description: 'Escanea y paga con el nuevo sistema interoperable Bre-B del Banco de la República desde cualquier billetera digital o entidad bancaria en Colombia.', + accountInfo: 'Código QR de interoperabilidad nacional procesado por Bold', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-bold-checkout', + name: 'Checkout Global Bold • Todos los Métodos Digitales', + type: 'bold', + boldChannel: 'all', + badge: 'Bold 🌐 Checkout Integral', + icon: 'ShieldCheck', + requiresDeposit: false, + depositAmount: 0, + description: 'Pasarela integral de Bold donde el cliente puede elegir entre PSE, Tarjetas Débito/Crédito, Nequi, Botón Bancolombia o QR Bre-B en una sola pantalla.', + accountInfo: 'Pasarela Oficial Bold.co • Enlace seguro con cifrado bancario', + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + }, + { + id: 'pay-cod-full', + name: 'Pago 100% Contraentrega en Efectivo (Cali y Alrededores)', + type: 'contraentrega', + boldChannel: 'custom', + badge: '🤝 Entrega en Puerta', + icon: 'Truck', + requiresDeposit: false, + depositAmount: 0, + description: 'Pagas el 100% del valor en efectivo o transferencia directa al mensajero al momento de recibir en tu puerta (válido para entregas urbanas en 24 horas).', + accountInfo: 'Entrega urbana express • Cancelas al recibir', + boldPaymentLink: '', + }, + { + id: 'pay-direct-nequi-daviplata', + name: 'Transferencia Directa Nequi / Daviplata (Carlos Lasso)', + type: 'nequi', + boldChannel: 'custom', + badge: '📱 Transferencia Directa', + icon: 'Smartphone', + requiresDeposit: false, + depositAmount: 0, + description: 'Transferencia manual directa a Nequi o Daviplata 316 745 5877 para clientes que prefieren pagar directo al titular.', + accountInfo: 'Nequi / Daviplata: 316 745 5877 • Titular: Carlos Andrés Lasso', + boldPaymentLink: '', + }, +]; + export default function AdminPaymentMethodsPage() { - const [methods, setMethods] = useState(INITIAL_PAYMENT_METHODS); + const [methods, setMethods] = useState([]); + const [settings, setSettings] = useState>({ + boldPaymentLink: 'https://checkout.bold.co/payment/LNK_AJPFKOPB0C', + boldEnvironment: 'production', + boldEnabled: true, + }); const [isLoading, setIsLoading] = useState(true); + const [isSavingSettings, setIsSavingSettings] = useState(false); + const [isSyncingDefaults, setIsSyncingDefaults] = useState(false); const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); + // Filtro + const [activeTab, setActiveTab] = useState<'all' | 'bold' | 'deposit' | 'direct'>('all'); + // Modal Crear / Editar const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [editingMethod, setEditingMethod] = useState | null>(null); + const [selectedPresetId, setSelectedPresetId] = useState('pay-bold-deposit-10k'); // Modal Confirmar Eliminación const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [methodToDelete, setMethodToDelete] = useState(null); useEffect(() => { - loadPaymentMethods(); + loadData(); }, []); - const loadPaymentMethods = async () => { + const loadData = async () => { setIsLoading(true); try { - const res = await fetch('/api/payment-methods'); - const data = await res.json(); - if (data.success && Array.isArray(data.paymentMethods)) { - setMethods(data.paymentMethods); + const [resMethods, resSettings] = await Promise.all([ + fetch('/api/payment-methods'), + fetch('/api/settings'), + ]); + const dataMethods = await resMethods.json(); + const dataSettings = await resSettings.json(); + + if (dataMethods.success && Array.isArray(dataMethods.paymentMethods)) { + setMethods(dataMethods.paymentMethods); + } + if (dataSettings.success && dataSettings.settings) { + setSettings((prev) => ({ ...prev, ...dataSettings.settings })); } } catch (err) { - console.warn('Error cargando métodos de pago:', err); + console.warn('Error cargando métodos y configuración de Bold:', err); } finally { setIsLoading(false); } }; + const handleUpdateBoldEnvironment = async (env: 'production' | 'sandbox') => { + const updated = { ...settings, boldEnvironment: env }; + setSettings(updated); + setIsSavingSettings(true); + try { + const res = await fetch('/api/settings', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ boldEnvironment: env }), + }); + const data = await res.json(); + if (data.success) { + setMessage({ + type: 'success', + text: `⚡ Entorno de Bold configurado exitosamente en: ${env === 'production' ? 'MODO PRODUCCIÓN (En Vivo)' : 'MODO PRUEBAS (Sandbox)'}`, + }); + } else { + setMessage({ type: 'error', text: data.error || 'No se pudo actualizar el entorno de Bold' }); + } + } catch (err: any) { + setMessage({ type: 'error', text: err.message || 'Error de conexión al cambiar entorno' }); + } finally { + setIsSavingSettings(false); + } + }; + + const handleSaveBoldLink = async (e: React.FormEvent) => { + e.preventDefault(); + setIsSavingSettings(true); + try { + const res = await fetch('/api/settings', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + boldPaymentLink: settings.boldPaymentLink, + boldEnvironment: settings.boldEnvironment || 'production', + boldEnabled: settings.boldEnabled !== false, + }), + }); + const data = await res.json(); + if (data.success) { + setMessage({ + type: 'success', + text: '✅ Enlace de Checkout Global de Bold guardado y sincronizado correctamente.', + }); + } else { + setMessage({ type: 'error', text: data.error || 'Error al guardar enlace de Bold' }); + } + } catch (err: any) { + setMessage({ type: 'error', text: err.message || 'Error de conexión' }); + } finally { + setIsSavingSettings(false); + } + }; + + const handleSyncBoldDefaults = async () => { + if (!confirm('¿Deseas restaurar y organizar todos los métodos oficiales de pago que ofrece Bold (PSE, Tarjetas, Nequi, Botón Bancolombia, QR Bre-B y Separación)?')) { + return; + } + setIsSyncingDefaults(true); + try { + const res = await fetch('/api/payment-methods', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'sync_bold_defaults' }), + }); + const data = await res.json(); + if (data.success && Array.isArray(data.paymentMethods)) { + setMethods(data.paymentMethods); + setMessage({ + type: 'success', + text: '🎉 ¡Métodos oficiales de Bold sincronizados y organizados con éxito en Appwrite!', + }); + } else { + setMessage({ type: 'error', text: data.error || 'Error al sincronizar métodos de Bold' }); + } + } catch (err: any) { + setMessage({ type: 'error', text: err.message || 'Error de conexión al sincronizar' }); + } finally { + setIsSyncingDefaults(false); + } + }; + const handleOpenCreateModal = () => { + const defaultPreset = BOLD_TEMPLATES[0]; + setSelectedPresetId(defaultPreset.id); setEditingMethod({ - name: '', - type: 'contraentrega', - description: 'Paga al recibir en tu puerta', - requiresDeposit: false, - depositAmount: 10000, - accountInfo: '', - boldPaymentLink: '', + name: defaultPreset.name, + type: defaultPreset.type, + boldChannel: defaultPreset.boldChannel, + badge: defaultPreset.badge, + icon: defaultPreset.icon, + description: defaultPreset.description, + requiresDeposit: defaultPreset.requiresDeposit, + depositAmount: defaultPreset.depositAmount, + accountInfo: defaultPreset.accountInfo, + boldPaymentLink: settings.boldPaymentLink || defaultPreset.boldPaymentLink, boldQrUrl: '', isActive: true, }); setIsEditModalOpen(true); }; + const handleSelectPreset = (presetId: string) => { + setSelectedPresetId(presetId); + const template = BOLD_TEMPLATES.find((t) => t.id === presetId); + if (template && editingMethod) { + setEditingMethod({ + ...editingMethod, + name: template.name, + type: template.type, + boldChannel: template.boldChannel, + badge: template.badge, + icon: template.icon, + description: template.description, + requiresDeposit: template.requiresDeposit, + depositAmount: template.depositAmount, + accountInfo: template.accountInfo, + boldPaymentLink: template.boldPaymentLink || settings.boldPaymentLink || '', + }); + } + }; + const handleOpenEditModal = (method: PaymentMethod) => { setEditingMethod({ ...method }); setIsEditModalOpen(true); @@ -72,7 +353,9 @@ export default function AdminPaymentMethodsPage() { }); const data = await res.json(); if (data.success) { - setMethods((prev) => prev.map((m) => (m.id === editingMethod.id ? { ...m, ...editingMethod } as PaymentMethod : m))); + setMethods((prev) => + prev.map((m) => (m.id === editingMethod.id ? ({ ...m, ...editingMethod } as PaymentMethod) : m)) + ); setMessage({ type: 'success', text: `Método "${editingMethod.name}" actualizado en Appwrite.` }); } else { setMessage({ type: 'error', text: data.error || 'Error al actualizar método de pago' }); @@ -138,33 +421,86 @@ export default function AdminPaymentMethodsPage() { } }; + // Filtrado de Métodos + const filteredMethods = methods.filter((m) => { + if (activeTab === 'bold') { + return m.type === 'bold' || m.boldChannel !== undefined; + } + if (activeTab === 'deposit') { + return m.requiresDeposit || m.type === 'contraentrega'; + } + if (activeTab === 'direct') { + return m.type === 'nequi' || m.type === 'transferencia' || m.type === 'daviplata'; + } + return true; + }); + + const getMethodIcon = (method: PaymentMethod) => { + if (method.boldChannel === 'pse' || method.name.toLowerCase().includes('pse')) { + return ; + } + if (method.boldChannel === 'card' || method.type === 'tarjeta' || method.name.toLowerCase().includes('tarjeta')) { + return ; + } + if (method.boldChannel === 'nequi' || method.type === 'nequi' || method.name.toLowerCase().includes('nequi')) { + return ; + } + if (method.boldChannel === 'bancolombia' || method.name.toLowerCase().includes('bancolombia')) { + return ; + } + if (method.boldChannel === 'bre_b' || method.name.toLowerCase().includes('bre-b') || method.name.toLowerCase().includes('qr')) { + return ; + } + if (method.requiresDeposit || method.boldChannel === 'deposit') { + return ; + } + if (method.type === 'contraentrega') { + return ; + } + return ; + }; + return (
{/* Header */}
-

- - Configuración de Medios de Pago & Anticipos +

+
+ +
+ Configuración de Medios de Pago Bold & Anticipos

- Administra pasarelas de pago, anticipos de $10.000 COP para contraentrega, transferencias y enlaces Bold con persistencia en Appwrite. + Administra los métodos de pago ofrecidos a través de la pasarela oficial Bold.co (PSE, Tarjetas Débito/Crédito, Nequi, Botón Bancolombia, QR Bre-B y Separación) con persistencia en Appwrite.

- +
+ + + +
{/* Notification Message */} {message && (
)} + {/* Hero: Panel de Control de Pasarela Bold & Selector de Modo (Producción / Pruebas) */} +
+
+
+
+ ⚡ BOLD +
+
+
+

Pasarela de Pagos Oficial Bold.co

+ + {settings.boldEnvironment === 'production' ? '● MODO PRODUCCIÓN (EN VIVO)' : '○ MODO PRUEBAS (SANDBOX)'} + +
+

+ Procesa en línea transacciones con PSE, Tarjetas Débito/Crédito, Nequi, Botón Bancolombia y QR Bre-B. +

+
+
+ + {/* Selector de Modo Producción o Pruebas */} +
+ + + +
+
+ + {/* Formulario rápido para Enlace Oficial Bold */} +
+
+ +
+ setSettings({ ...settings, boldPaymentLink: e.target.value })} + placeholder="https://checkout.bold.co/payment/LNK_AJPFKOPB0C" + className="w-full bg-neutral-950/90 border border-indigo-500/40 rounded-2xl pl-3.5 pr-10 py-2.5 text-xs text-white font-mono outline-hidden focus:border-indigo-400" + /> + +
+
+ +
+ + + {settings.boldPaymentLink && ( + + + + )} +
+
+ + {/* Badges de soporte oficial Bold */} +
+ + + PSE Débito + + + + Tarjetas Visa / Mastercard / Amex + + + + Nequi en Línea + + + + Botón Bancolombia + + + + QR Bre-B Banco de la República + + + + Separación $10.000 + Contraentrega + +
+
+ + {/* Filtros / Tabs */} +
+ + + + + + + +
+ {/* Methods Grid / Cards */}
{isLoading ? ( -
Cargando métodos de pago desde Appwrite...
- ) : methods.length === 0 ? ( -
No hay métodos de pago registrados. Haz clic en "Nuevo Método de Pago".
+
+ Cargando métodos de pago desde Appwrite... +
+ ) : filteredMethods.length === 0 ? ( +
+

No hay métodos de pago en esta categoría.

+ +
) : ( - methods.map((method) => ( + filteredMethods.map((method) => (
-
-
- {method.type === 'contraentrega' ? ( - - ) : method.type === 'bold' ? ( - - ) : ( - - )} +
+
+ {getMethodIcon(method)}
-
-

{method.name}

+
+

{method.name}

+ + {method.badge && ( + + {method.badge} + + )} + {method.requiresDeposit && ( - + Anticipo {formatCOP(method.depositAmount)} )} + + {!method.requiresDeposit && method.type === 'bold' && ( + + 100% en Línea + + )} +
+
+ Tipo: {method.type} + {method.boldChannel && • Canal Bold: {method.boldChannel}}
- Tipo: {method.type}
@@ -250,29 +803,31 @@ export default function AdminPaymentMethodsPage() {
Descripción para el Cliente: -

{method.description || 'Sin descripción'}

+

{method.description || 'Sin descripción'}

- {method.accountInfo && ( -
- Cuentas / Datos Bancarios: -

{method.accountInfo}

-
- )} +
+ {method.accountInfo && ( +
+ Cuentas o Instrucciones: +

{method.accountInfo}

+
+ )} - {method.boldPaymentLink && ( -
- Link de Pago Bold: - - {method.boldPaymentLink} - -
- )} + {method.boldPaymentLink && ( +
+ Enlace de Pago Bold: + + {method.boldPaymentLink} + +
+ )} +
)) @@ -281,9 +836,9 @@ export default function AdminPaymentMethodsPage() { {/* Modal para Crear / Editar Método de Pago */} {isEditModalOpen && editingMethod && ( -
+
-
+

{editingMethod.id ? 'Editar Método de Pago' : 'Nuevo Método de Pago'} @@ -296,14 +851,34 @@ export default function AdminPaymentMethodsPage() {

-
+ + {/* Plantilla rápida de Bold */} + {!editingMethod.id && ( +
+ + +
+ )} +
- + setEditingMethod({ ...editingMethod, name: e.target.value })} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden focus:border-purple-500" @@ -313,20 +888,49 @@ export default function AdminPaymentMethodsPage() {
+
+ + +
+ +
+ + setEditingMethod({ ...editingMethod, badge: e.target.value })} + className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3 py-2 text-xs text-white outline-hidden focus:border-purple-500" + /> +
+
+ Dejar en 0 para pago 100% anticipado o contraentrega total.
@@ -344,7 +949,7 @@ export default function AdminPaymentMethodsPage() {