diff --git a/admin/src/app/settings/page.tsx b/admin/src/app/settings/page.tsx index 4a78f3c..cccfe47 100644 --- a/admin/src/app/settings/page.tsx +++ b/admin/src/app/settings/page.tsx @@ -4,48 +4,59 @@ import { useEffect, useState, useCallback } from 'react'; import { api } from '@/lib/api'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { toast } from 'sonner'; import { Input } from '@/components/ui/input'; -import { Save, ExternalLink, Copy, FileText, Shield, Map, Eye, EyeOff, CheckCircle2, XCircle } from 'lucide-react'; +import { Badge } from '@/components/ui/badge'; +import { toast } from 'sonner'; +import { + Save, ExternalLink, Copy, FileText, Shield, Map, + Eye, EyeOff, CheckCircle2, XCircle, Clock, Smartphone, Phone, Mail, +} from 'lucide-react'; const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api/v1'; -const PUBLIC_BASE = API_BASE.replace('/api/v1', ''); + +interface GlobalSettings { + app_version_android?: string; + app_version_ios?: string; + support_schedule?: string; + support_email?: string; + support_phone?: string; + maintenance_mode?: boolean; + [key: string]: any; +} const POLICY_ITEMS = [ - { - key: 'privacy', - label: 'Política de Privacidad', - icon: Shield, - description: 'Cómo se recopilan, usan y protegen los datos personales de los usuarios.', - }, - { - key: 'terms', - label: 'Términos y Condiciones', - icon: FileText, - description: 'Condiciones de uso de la plataforma ProsApp.', - }, + { key: 'privacy', label: 'Política de Privacidad', icon: Shield, description: 'Cómo se recopilan, usan y protegen los datos personales.' }, + { key: 'terms', label: 'Términos y Condiciones', icon: FileText, description: 'Condiciones de uso de la plataforma ProsApp.' }, ]; export default function SettingsPage() { - const [policies, setPolicies] = useState>({ privacy: '', terms: '' }); - const [saving, setSaving] = useState(null); const [loading, setLoading] = useState(true); - // Maps key state + // Global + const [global, setGlobal] = useState({}); + const [savingGlobal, setSavingGlobal] = useState(false); + + // Maps const [mapsConfigured, setMapsConfigured] = useState(false); const [mapsKey, setMapsKey] = useState(''); const [showMapsKey, setShowMapsKey] = useState(false); const [savingMaps, setSavingMaps] = useState(false); + // Policies + const [policies, setPolicies] = useState>({ privacy: '', terms: '' }); + const [savingPolicy, setSavingPolicy] = useState(null); + const load = useCallback(() => { setLoading(true); Promise.all([ + api.get('/settings'), + api.get<{ configured: boolean }>('/settings/maps-key'), api.get<{ privacy: string | null; terms: string | null }>('/settings/policies'), - api.get<{ configured: boolean; api_key: string }>('/settings/maps-key'), ]) - .then(([policiesData, mapsData]) => { - setPolicies({ privacy: policiesData.privacy || '', terms: policiesData.terms || '' }); + .then(([globalData, mapsData, policiesData]) => { + setGlobal(globalData || {}); setMapsConfigured(mapsData.configured); + setPolicies({ privacy: policiesData.privacy || '', terms: policiesData.terms || '' }); }) .catch(() => toast.error('Error al cargar configuración')) .finally(() => setLoading(false)); @@ -53,6 +64,18 @@ export default function SettingsPage() { useEffect(() => { load(); }, [load]); + const saveGlobal = async () => { + setSavingGlobal(true); + try { + await api.patch('/settings', global); + toast.success('Configuración guardada'); + } catch (e: any) { + toast.error(e?.message || 'Error al guardar'); + } finally { + setSavingGlobal(false); + } + }; + const saveMapsKey = async () => { if (!mapsKey.trim()) return toast.error('Ingresa una API Key'); setSavingMaps(true); @@ -69,82 +92,176 @@ export default function SettingsPage() { }; const savePolicy = async (key: string) => { - setSaving(key); + setSavingPolicy(key); try { await api.patch(`/settings/policies/${key}`, { content: policies[key] }); toast.success('Política guardada'); } catch (e: any) { toast.error(e?.message || 'Error al guardar'); } finally { - setSaving(null); + setSavingPolicy(null); } }; const copyLink = (key: string) => { - const url = `${API_BASE}/settings/policy/${key}`; - navigator.clipboard.writeText(url); + navigator.clipboard.writeText(`${API_BASE}/settings/policy/${key}`); toast.success('Enlace copiado'); }; + const setG = (field: keyof GlobalSettings, value: any) => + setGlobal((g) => ({ ...g, [field]: value })); + if (loading) return
Cargando...
; return (

Configuración

-

Gestiona las políticas legales y ajustes globales de ProsApp.

+

Ajustes globales, integraciones y documentos legales de ProsApp.

- {/* Google Maps */} - - - - - Google Maps API Key - - - Requerida para mostrar mapas y detectar la ubicación en la app web y móvil. - Habilita Maps JavaScript API y Geocoding API en Google Cloud Console. - - - -
- {mapsConfigured ? ( - <>Configurada - ) : ( - <>No configurada - )} -
-
-
- setMapsKey(e.target.value)} - className="pr-10 font-mono" - /> - -
- -
-

- La app web carga la key desde el backend al abrir el mapa. Agrega restricción HTTP en Google Cloud: https://app.prosapp.co/* -

-
-
+ {/* ── Ajustes globales ── */} +
+

Ajustes generales

- {/* Policies */} -
+ + + + + Versión de la app + + + +
+ + setG('app_version_android', e.target.value)} + /> +
+
+ + setG('app_version_ios', e.target.value)} + /> +
+
+
+ + + + + + Soporte + + + +
+ + setG('support_schedule', e.target.value)} + /> +
+
+
+ + setG('support_email', e.target.value)} + /> +
+
+ + setG('support_phone', e.target.value)} + /> +
+
+
+
+ + + + Modo mantenimiento + Cuando está activo, la app muestra un mensaje de mantenimiento a los usuarios. + + + + + {global.maintenance_mode ? 'Activo' : 'Inactivo'} + + + + + +
+ + {/* ── Google Maps ── */} +
+

Integraciones

+ + + + + Google Maps API Key + + + Requerida para mostrar mapas y detectar ubicación. Habilita Maps JavaScript API y Geocoding API en Google Cloud Console. + + + +
+ {mapsConfigured + ? <>Configurada + : <>No configurada} +
+
+
+ setMapsKey(e.target.value)} + className="pr-10 font-mono" + /> + +
+ +
+

+ Restricción HTTP recomendada: https://app.prosapp.co/* +

+
+
+
+ + {/* ── Documentos legales ── */} +

Documentos legales

{POLICY_ITEMS.map(({ key, label, icon: Icon, description }) => { const publicUrl = `${API_BASE}/settings/policy/${key}`; @@ -159,25 +276,18 @@ export default function SettingsPage() {