/** * Editor de Fármaco (Vademécum TES) * * Editor completo para crear/editar fármacos * Basado en: docs/VADEMECUM_COMPLETO_TES.md */ import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Save, X, Send, CheckCircle, Plus, Trash2 } from 'lucide-react'; import { useAuth } from '../contexts/AuthContext'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; interface DrugFormData { generic_name: string; trade_name?: string; category: string; line: 'first' | 'second'; frequency: 'high' | 'medium' | 'low'; presentation: string; adult_dose: string; pediatric_dose?: string; routes: string[]; dilution?: string; indications: string[]; contraindications: string[]; side_effects?: string; antidote?: string; notes: string[]; critical_points: string[]; source?: string; status: 'draft' | 'in_review' | 'approved' | 'published' | 'archived'; } const ROUTES_OPTIONS = ['IV', 'IO', 'IM', 'Subcutánea', 'Oral', 'Rectal', 'Intranasal', 'Nebulización', 'MDI']; const CATEGORIES = [ 'cardiovascular', 'respiratorio', 'neurologico', 'analgesico', 'fluidos', 'antidoto', 'hemostatico', 'diuretico', 'corticosteroide', 'antiepileptico', 'anestesico', 'metabolico', 'antiagregante', ]; export default function DrugEditorPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { hasPermission } = useAuth(); const isNew = id === 'new'; const [isLoading, setIsLoading] = useState(!isNew); const [isSaving, setIsSaving] = useState(false); const [formData, setFormData] = useState({ generic_name: '', trade_name: '', category: 'cardiovascular', line: 'first', frequency: 'high', presentation: '', adult_dose: '', pediatric_dose: '', routes: [], dilution: '', indications: [], contraindications: [], side_effects: '', antidote: '', notes: [], critical_points: [], source: '', status: 'draft', }); // Cargar fármaco si es edición useEffect(() => { if (!isNew && id) { loadDrug(id); } }, [id, isNew]); const loadDrug = async (drugId: string) => { setIsLoading(true); try { const token = localStorage.getItem('admin_token'); const response = await fetch(`${API_URL}/api/drugs/${drugId}`, { headers: { 'Authorization': `Bearer ${token}`, }, }); if (response.ok) { const drug = await response.json(); setFormData({ generic_name: drug.generic_name || '', trade_name: drug.trade_name || '', category: drug.category || 'cardiovascular', line: drug.line || 'first', frequency: drug.frequency || 'high', presentation: drug.presentation || '', adult_dose: drug.adult_dose || '', pediatric_dose: drug.pediatric_dose || '', routes: drug.routes || [], dilution: drug.dilution || '', indications: drug.indications || [], contraindications: drug.contraindications || [], side_effects: drug.side_effects || '', antidote: drug.antidote || '', notes: drug.notes || [], critical_points: drug.critical_points || [], source: drug.source || '', status: drug.status || 'draft', }); } else { alert('Error cargando fármaco'); navigate('/drugs'); } } catch (error) { console.error('Error cargando fármaco:', error); alert('Error cargando fármaco'); } finally { setIsLoading(false); } }; const handleSave = async () => { setIsSaving(true); try { const token = localStorage.getItem('admin_token'); const url = isNew ? `${API_URL}/api/drugs` : `${API_URL}/api/drugs/${id}`; const method = isNew ? 'POST' : 'PUT'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify(formData), }); if (response.ok) { const data = await response.json(); if (isNew) { navigate(`/drugs/${data.drug.id}/edit`); } else { alert('Fármaco guardado correctamente'); } } else { const error = await response.json(); alert(`Error: ${error.error || 'Error al guardar'}\n${error.details?.join('\n') || ''}`); } } catch (error) { console.error('Error guardando fármaco:', error); alert('Error al guardar fármaco'); } finally { setIsSaving(false); } }; const handleSubmit = async () => { if (!confirm('¿Enviar este fármaco a revisión?')) return; try { const token = localStorage.getItem('admin_token'); const response = await fetch(`${API_URL}/api/drugs/${id}/submit`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, }); if (response.ok) { alert('Fármaco enviado a revisión'); navigate('/drugs'); } else { const error = await response.json(); alert(`Error: ${error.error || 'Error al enviar a revisión'}`); } } catch (error) { console.error('Error enviando a revisión:', error); alert('Error al enviar a revisión'); } }; const addArrayItem = (field: 'routes' | 'indications' | 'contraindications' | 'notes' | 'critical_points') => { setFormData(prev => ({ ...prev, [field]: [...prev[field], ''], })); }; const updateArrayItem = ( field: 'routes' | 'indications' | 'contraindications' | 'notes' | 'critical_points', index: number, value: string ) => { setFormData(prev => ({ ...prev, [field]: prev[field].map((item, i) => i === index ? value : item), })); }; const removeArrayItem = ( field: 'routes' | 'indications' | 'contraindications' | 'notes' | 'critical_points', index: number ) => { setFormData(prev => ({ ...prev, [field]: prev[field].filter((_, i) => i !== index), })); }; if (isLoading) { return
Cargando fármaco...
; } return (

{isNew ? 'Nuevo Fármaco' : `Editar: ${formData.generic_name}`}

{isNew ? 'Crear nuevo fármaco en el vademécum' : 'Editar información del fármaco'}

{!isNew && hasPermission('content:submit') && formData.status === 'draft' && ( )} {!isNew && hasPermission('validation:approve') && formData.status === 'in_review' && ( )} {!isNew && hasPermission('content:publish') && formData.status === 'approved' && ( )}
{/* Información Básica */}

Información Básica

setFormData(prev => ({ ...prev, generic_name: e.target.value }))} className="w-full px-3 py-2 bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Ej: Adrenalina" />
setFormData(prev => ({ ...prev, trade_name: e.target.value }))} className="w-full px-3 py-2 bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Ej: Adrenalina 1mg/1ml" />
{/* Presentación y Dosificación */}

Presentación y Dosificación

setFormData(prev => ({ ...prev, presentation: e.target.value }))} className="w-full px-3 py-2 bg-background border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" placeholder="Ej: 1mg/1ml ampolla" />