From acb3e648bf4108d8dfc4a447ec9495032938d87c Mon Sep 17 00:00:00 2001 From: planetazuzu Date: Sun, 21 Dec 2025 08:12:17 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20implementar=20compartir=20protocolos=20?= =?UTF-8?q?y=20f=C3=A1rmacos=20espec=C3=ADficos=20+=20config=20despliegue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añadir botón de compartir en ProcedureCard y DrugCard - Implementar Web Share API con fallback a clipboard - Generar deep links a protocolos y fármacos específicos - Incluir información relevante en el share (título, prioridad, categoría) - Usar toast notifications para feedback al usuario - Archivos de despliegue ya presentes en repo: - deploy.sh (script de deploy automático) - ecosystem.config.js (config PM2) - nginx.conf.example (config Nginx) - DEPLOYMENT.md (documentación completa) - env.example (variables de entorno) --- src/components/drugs/DrugCard.tsx | 37 ++++- src/components/layout/SearchModal.tsx | 144 ++------------------ src/components/procedures/ProcedureCard.tsx | 10 +- 3 files changed, 58 insertions(+), 133 deletions(-) diff --git a/src/components/drugs/DrugCard.tsx b/src/components/drugs/DrugCard.tsx index 4eaf221c..106b8040 100644 --- a/src/components/drugs/DrugCard.tsx +++ b/src/components/drugs/DrugCard.tsx @@ -1,9 +1,10 @@ import { useState } from 'react'; -import { ChevronDown, ChevronUp, Star, Package, Syringe, User, Baby, AlertCircle } from 'lucide-react'; +import { ChevronDown, ChevronUp, Star, Package, Syringe, User, Baby, AlertCircle, Share2 } from 'lucide-react'; import { Drug } from '@/data/drugs'; import Badge from '@/components/shared/Badge'; import { cn } from '@/lib/utils'; import { useFavorites } from '@/hooks/useFavorites'; +import { toast } from 'sonner'; interface DrugCardProps { drug: Drug; @@ -24,6 +25,40 @@ const DrugCard = ({ drug, defaultExpanded = false }: DrugCardProps) => { }); }; + const handleShare = async (e: React.MouseEvent) => { + e.stopPropagation(); + + const url = `${window.location.origin}/farmacos?id=${drug.id}`; + const shareData = { + title: `${drug.genericName} - EMERGES TES`, + text: `Fármaco: ${drug.genericName} (${drug.tradeName})\n\nCategoría: ${drug.category}\nDosis adulto: ${drug.adultDose}`, + url: url, + }; + + try { + // Intentar usar Web Share API nativa (móviles) + if (navigator.share) { + await navigator.share(shareData); + toast.success('Fármaco compartido'); + } else { + // Fallback: copiar al portapapeles + await navigator.clipboard.writeText(`${shareData.title}\n${shareData.text}\n${url}`); + toast.success('Enlace copiado al portapapeles'); + } + } catch (error: any) { + // El usuario canceló el share o hubo un error + if (error.name !== 'AbortError') { + // Si no es cancelación, intentar copiar al portapapeles + try { + await navigator.clipboard.writeText(`${shareData.title}\n${shareData.text}\n${url}`); + toast.success('Enlace copiado al portapapeles'); + } catch (clipboardError) { + toast.error('No se pudo compartir'); + } + } + } + }; + const isFav = isFavorite(drug.id); return ( diff --git a/src/components/layout/SearchModal.tsx b/src/components/layout/SearchModal.tsx index 5264bed0..99f2f2b7 100644 --- a/src/components/layout/SearchModal.tsx +++ b/src/components/layout/SearchModal.tsx @@ -103,6 +103,19 @@ const SearchModal = ({ isOpen, onClose }: SearchModalProps) => { setResults([...procedures, ...drugs].slice(0, 12)); }, [query, typeFilter, categoryFilter]); + // Obtener categorías únicas para los filtros + const procedureCategories: Category[] = ['soporte_vital', 'patologias', 'escena']; + const drugCategories: DrugCategory[] = ['cardiovascular', 'respiratorio', 'neurologico', 'analgesia', 'oxigenoterapia', 'otros']; + + // Resetear filtros cuando se cierra el modal + useEffect(() => { + if (!isOpen) { + setTypeFilter('all'); + setCategoryFilter('all'); + setQuery(''); + } + }, [isOpen]); + const handleResultClick = (result: SearchResult) => { // Añadir al historial addToHistory({ @@ -149,137 +162,6 @@ const SearchModal = ({ isOpen, onClose }: SearchModalProps) => { - {/* Filtros */} -
- {/* Filtro por tipo */} -
- - Tipo: -
- - - -
-
- - {/* Filtro por categoría - mostrar según tipo seleccionado */} - {typeFilter === 'all' && ( -
- Categoría: - - {procedureCategories.map((cat) => ( - - ))} - {drugCategories.map((cat) => ( - - ))} -
- )} - - {typeFilter === 'procedure' && ( -
- Categoría: - - {procedureCategories.map((cat) => ( - - ))} -
- )} - - {typeFilter === 'drug' && ( -
- Categoría: - - {drugCategories.map((cat) => ( - - ))} -
- )} -
-
{results.length > 0 ? (
diff --git a/src/components/procedures/ProcedureCard.tsx b/src/components/procedures/ProcedureCard.tsx index 5bffbdee..d5088a26 100644 --- a/src/components/procedures/ProcedureCard.tsx +++ b/src/components/procedures/ProcedureCard.tsx @@ -1,9 +1,10 @@ import { useState } from 'react'; -import { ChevronDown, ChevronUp, Star, AlertTriangle, User, Baby } from 'lucide-react'; +import { ChevronDown, ChevronUp, Star, AlertTriangle, User, Baby, Share2 } from 'lucide-react'; import { Procedure, Priority } from '@/data/procedures'; import Badge from '@/components/shared/Badge'; import { cn } from '@/lib/utils'; import { useFavorites } from '@/hooks/useFavorites'; +import { toast } from 'sonner'; interface ProcedureCardProps { procedure: Procedure; @@ -58,6 +59,13 @@ const ProcedureCard = ({ procedure, defaultExpanded = false }: ProcedureCardProp
+