"use client" import { useSearchParams, useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" import { ArrowLeft, Leaf, Printer } from "lucide-react" import { apiFetch } from "@/lib/apiutils" import { useEffect, useState } from "react" import { ModeToggle } from "@/components/mode-toggle" import { createPortal } from "react-dom" import { toJpeg } from "html-to-image" import { jsPDF } from "jspdf" import { toast } from "sonner" import { RecetaDocumento } from "@/components/receta-documento" import { Share2, FileDown } from "lucide-react" export default function VerRecetaPage() { const searchParams = useSearchParams() const router = useRouter() const recetaId = searchParams.get("id") as string const [receta, setReceta] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { const fetchReceta = async () => { try { const res = await apiFetch(`/recetas/${recetaId}`) if (res.ok) { const data = await res.json() setReceta(data) } else { setReceta(null) } } catch (e) { console.error(e) } finally { setLoading(false) } } fetchReceta() }, [recetaId]) if (loading) { return
Cargando receta...
} if (!receta) { return (

Receta no encontrada

) } const handlePrint = () => { window.print() } const handleSharePdf = async (action: 'descarga' | 'compartir') => { const elementId = `hidden-pdf-container-${receta.id}` const element = document.getElementById(elementId) if (!element) return const filename = `Receta-${receta.numero}.pdf` try { toast.loading("Generando archivo PDF...", { id: "pdfToast" }) let dataUrl = "" try { dataUrl = await toJpeg(element, { quality: 0.95, pixelRatio: 2 }) } catch (internalErr) { console.warn("html-to-image falló (posible bug en Firefox), reintentando sin cargar tipografías externas", internalErr) dataUrl = await toJpeg(element, { quality: 0.95, pixelRatio: 2, fontEmbedCSS: '', skipFonts: true }) } // 2. Instanciar un PDF en formato A4 (210x297mm) const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }) // 3. Calcular la escala para que encaje horizontal y verticalmente EN UNA SOLA PÁGINA const imgProps = pdf.getImageProperties(dataUrl) const pdfPageWidth = pdf.internal.pageSize.getWidth() const pdfPageHeight = pdf.internal.pageSize.getHeight() // A4 height es ~297mm let finalWidth = pdfPageWidth let finalHeight = (imgProps.height * finalWidth) / imgProps.width // Si la receta es muy larga y se pasaría de hoja (provocando el corte por la mitad en la foto), // escalamos inversamente para que encaje en el total del alto de una sola carilla A4. if (finalHeight > pdfPageHeight) { finalHeight = pdfPageHeight finalWidth = (imgProps.width * finalHeight) / imgProps.height } // Centramos horizontalmente si hubo que achicar a lo alto const marginLeft = (pdfPageWidth - finalWidth) / 2 pdf.addImage(dataUrl, 'JPEG', marginLeft, 0, finalWidth, finalHeight) // 4. Extraer el archivo físico Blob en memoria RAM const blob = pdf.output('blob') const file = new File([blob], filename, { type: 'application/pdf' }) toast.dismiss("pdfToast") // ------------------------------------------------------------- // LÓGICA MULTIPLATAFORMA (Experiencia de Usuario Segura) // ------------------------------------------------------------- // A. NATIVE SHARE (SMARTPHONE): Si soporta API de Compartición Remota if (action === 'compartir' && navigator.canShare && navigator.canShare({ files: [file] })) { try { await navigator.share({ files: [file], title: filename, text: `Te envío la receta ${filename} adjunta.` }) toast.success("Abriendo menú de compartir...") return } catch (err) { console.log("El usuario canceló el Share Sheet", err) return } } // B. DESKTOP FALLBACK: En PC o si falla el share nativo, forzamos Descarga. const url = URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) toast.success("El PDF ha sido descargado.") } catch(e) { console.error(e) toast.dismiss("pdfToast") toast.error("Error crítico al procesar el archivo.") } } return (
{/* Botones de acción - No se imprimen */}
{/* Botón Descargar Genérico (Visible siempre en PC, Opcional en móviles) */} {/* Botón Compartir Nativos (Oculto en PC [xl:hidden], visible en Tablet/Celular) */}
{/* Documento de Receta - Diseño tipo planilla digital profesional */} {/* Agregado overflow-x-auto y min-width fijo para no colapsar la vista en móviles, simulando la lectura de un PDF real pidiéndole al usuario que haga un swipe para explorar el archivo horizontalmente */}
{createPortal(
, document.body )} {/* Estilos de impresión */}
) }