import { useState, useCallback } from "react"; import { useParams, Link } from "react-router-dom"; import { API_URL, apiFetch } from "../../utils/api"; import { htmlReportsConfig } from "../../config/htmlReports"; import ModalSearchTemplate from "../ui/ModalSearchTemplate"; import Icon from "../ui/Icon"; import type { F4Config } from "../../types/reports"; export default function HtmlReportRunner() { const { module: moduleKey, docCode } = useParams<{ module: string; docCode: string }>(); const definition = htmlReportsConfig[moduleKey || ""]?.find((r) => r.id === docCode); const parameters = definition?.parameters || []; const [paramValues, setParamValues] = useState>(() => { const initial: Record = {}; for (const p of parameters) { initial[p.name] = p.defaultValue ?? ""; } return initial; }); const [f4State, setF4State] = useState<{ param: (typeof parameters)[number]; config: F4Config; } | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [previewUrl, setPreviewUrl] = useState(""); const handleChange = useCallback((name: string, value: any) => { setParamValues((prev) => ({ ...prev, [name]: value })); }, []); const handleF4Confirm = useCallback( (rows: any[]) => { if (!f4State) return; const { param, config } = f4State; handleChange(param.name, rows[0]?.[config.valueField] ?? ""); setF4State(null); }, [f4State, handleChange], ); const handleGenerate = async () => { if (!definition) return; const body: Record = {}; for (const p of parameters) { const raw = paramValues[p.name]; body[p.name] = p.inputType === "number" ? Number(raw) : raw; } setLoading(true); setError(""); setPreviewUrl(""); try { const res = await apiFetch(`${API_URL}/api/reports/${definition.endpoint}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (!res.ok) { const errData = await res.json().catch(() => null); throw new Error(errData?.detail || "Error al generar el reporte"); } const blob = await res.blob(); setPreviewUrl(URL.createObjectURL(blob)); } catch (err: any) { setError(err.message || "Error de conexión"); } finally { setLoading(false); } }; const renderField = (param: (typeof parameters)[number]) => { const val = paramValues[param.name] ?? ""; const required = param.required; switch (param.inputType) { case "text": return (
handleChange(param.name, e.target.value)} className="w-full px-2 py-1 h-[28px] border border-[var(--color-input-border)] bg-[var(--color-surface)] outline-none focus:border-[var(--color-input-focus)] text-xs" />
); case "number": return (
handleChange(param.name, e.target.value)} className="w-full px-2 py-1 h-[28px] border border-[var(--color-input-border)] bg-[var(--color-surface)] outline-none focus:border-[var(--color-input-focus)] text-xs" />
); case "date": return (
handleChange(param.name, e.target.value)} className="w-full px-2 py-1 h-[28px] border border-[var(--color-input-border)] bg-[var(--color-surface)] outline-none focus:border-[var(--color-input-focus)] text-xs" />
); case "select": return (
); case "f4-modal": { const config = param.f4Config; if (!config) return null; const displayVal = val ? String(val) : ""; return (
setF4State({ param, config })} />
); } default: return null; } }; return (
Reportes HTML / {definition?.title || docCode}

{definition?.title || docCode}

{error && (
{error}
)} {parameters.length > 0 && (
{parameters.map((p) => (
{renderField(p)}
))}
)} {parameters.length === 0 && (
Este reporte no tiene parámetros definidos
)} {previewUrl && (