import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { Star, Edit2, Check, X, Plus, Clock, Tag, Package } from 'lucide-react'; import Layout from '../components/Layout'; import { Card, Button, Input, TextArea, Modal, EmptyState, PageHeader, Skeleton, toast, } from '../components/ui'; import { odooApi, type Service } from '../services/odoo'; const Servicios: FC = () => { const [services, setServices] = useState([]); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [editing, setEditing] = useState(null); const [editPrice, setEditPrice] = useState(''); const [editPackagePrice, setEditPackagePrice] = useState(''); const [editPackageSessions, setEditPackageSessions] = useState(''); const [editPackageNotes, setEditPackageNotes] = useState(''); const [createOpen, setCreateOpen] = useState(false); const [form, setForm] = useState({ name: '', code: '', category: '', price: '', package_price: '', package_sessions: '', package_notes: '', duration_min: '', description: '', color: '#78716c', service_group: '', }); const load = async () => { try { setLoading(true); setError(null); const res = await odooApi.getServices(); if (res.status === 'success') setServices(res.services); } catch (err) { setError('Error al cargar servicios'); toast.error('Error al cargar servicios'); console.error(err); } finally { setLoading(false); } }; useEffect(() => { load(); }, []); const toggleFavorite = async (s: Service) => { try { await odooApi.updateService(s.id, { is_favorite: !s.is_favorite }); toast.success('Favorito actualizado'); await load(); } catch (err) { toast.error('Error al actualizar favorito'); console.error(err); } }; const startEdit = (s: Service) => { setEditing(s); setEditPrice(String(s.price)); setEditPackagePrice(String(s.package_price ?? '')); setEditPackageSessions(String(s.package_sessions ?? '')); setEditPackageNotes(s.package_notes || ''); }; const savePrice = async () => { if (!editing) return; const price = parseFloat(editPrice); const packagePrice = editPackagePrice === '' ? 0 : parseFloat(editPackagePrice); const packageSessions = editPackageSessions === '' ? 0 : parseInt(editPackageSessions, 10); if (Number.isNaN(price) || price < 0) { toast.error('Precio inválido'); return; } try { await odooApi.updateService(editing.id, { price, package_price: Number.isNaN(packagePrice) ? 0 : packagePrice, package_sessions: Number.isNaN(packageSessions) ? 0 : packageSessions, package_notes: editPackageNotes, }); toast.success('Servicio actualizado'); setEditing(null); await load(); } catch (err) { toast.error('Error al actualizar servicio'); console.error(err); } }; const create = async () => { const price = parseFloat(form.price); const duration = parseInt(form.duration_min, 10); const packagePrice = form.package_price === '' ? 0 : parseFloat(form.package_price); const packageSessions = form.package_sessions === '' ? 0 : parseInt(form.package_sessions, 10); if (!form.name || Number.isNaN(price) || price < 0) { toast.error('Nombre y precio válidos son obligatorios'); return; } try { setSubmitting(true); await odooApi.createService({ name: form.name, code: form.code, category: form.category, price, package_price: Number.isNaN(packagePrice) ? 0 : packagePrice, package_sessions: Number.isNaN(packageSessions) ? 0 : packageSessions, package_notes: form.package_notes, duration_min: Number.isNaN(duration) ? 0 : duration, description: form.description, color: form.color, service_group: form.service_group, }); toast.success('Servicio creado'); setCreateOpen(false); setForm({ name: '', code: '', category: '', price: '', package_price: '', package_sessions: '', package_notes: '', duration_min: '', description: '', color: '#78716c', service_group: '', }); await load(); } catch (err) { toast.error('Error al crear servicio'); console.error(err); } finally { setSubmitting(false); } }; const formatCurrency = (value: number) => new Intl.NumberFormat('es-MX', { style: 'currency', currency: 'MXN', maximumFractionDigits: 0 }).format(value); return ( {error &&

{error}

} {loading ? (
{Array.from({ length: 6 }).map((_, i) => )}
) : services.length === 0 ? ( setCreateOpen(true)} /> ) : (
{services.map((s) => (

{s.name}

{s.category || 'Sin categoría'} {s.duration_min} min
{editing?.id === s.id ? (
setEditPrice(e.target.value)} /> setEditPackagePrice(e.target.value)} />
setEditPackageSessions(e.target.value)} /> setEditPackageNotes(e.target.value)} />
) : (

Precio sesión

{formatCurrency(s.price)}

{(s.package_price ?? 0) > 0 && (s.package_sessions ?? 0) > 0 && (

Paquete {s.package_sessions} sesiones: {formatCurrency(s.package_price ?? 0)}

{s.package_notes &&

{s.package_notes}

}
)}
)} ))}
)} setCreateOpen(false)} title="Nuevo servicio" maxWidth="md" footer={ <> } >
setForm({ ...form, name: e.target.value })} />
setForm({ ...form, code: e.target.value })} /> setForm({ ...form, category: e.target.value })} />
setForm({ ...form, price: e.target.value })} /> setForm({ ...form, duration_min: e.target.value })} />
setForm({ ...form, package_price: e.target.value })} /> setForm({ ...form, package_sessions: e.target.value })} />
setForm({ ...form, package_notes: e.target.value })} /> setForm({ ...form, color: e.target.value })} />