Files
inq-roi-simulador-web/sprints/sprint-6/ETAPA_1_PROMPT.md
Marcos Benítez dc610f8a1e
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
Resumen del fix:
loadImageBase64 ahora retorna { base64, pixelWidth, pixelHeight } (320×210px tras el resize) en vez de solo el string.
PdfHeaderOptions agrega logoPixelWidth/logoPixelHeight.
drawSharedHeader: logo a 15mm de ancho con alto calculado proporcionalmente desde las dimensiones reales (≈9.8mm, ratio real ~1.53:1, no el 3.56:1 hardcodeado anterior). El logo se posiciona arriba (MARGIN - 1), y processName + fecha bajan a la línea siguiente sin superponerse. clientName baja una línea adicional cuando hay logo (para no chocar con la fecha), ajustando y antes del border-bottom.
Fallback a texto "InQ ROI" intacto cuando no hay logo.
2026-06-24 12:16:25 -03:00

5.8 KiB

Etapa 1 — Logo InQuality en header de PDFs + whitespace-nowrap

Sprint: 6 Fecha: 2026-06-23 Alcance: 3 PDFs (Actual, Automatizado, ROI) + un fix de una línea en ComparisonTable.


Contexto

El header compartido de los 3 PDFs (src/lib/export/pdf-sections-shared.ts, función drawSharedHeader) hoy dibuja el texto "InQ ROI" en naranja bold como identidad de marca. El logo PNG de InQuality ya existe en assets/. El objetivo es reemplazar el texto por el logo, manteniendo el layout del header sin cambios estructurales.


Parte A — Logo en header de PDFs

Assets disponibles

En assets/ (ruta desde la raíz del proyecto):

  • MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png — logo horizontal color, sobre fondos claros — usar este
  • MARCA FINAL 2023 AREA DE SEGURIDAD 1 BCO.png — logo horizontal blanco (no aplica, el header es blanco)

Cómo cargar el PNG en jsPDF

Importar la URL del asset con Vite:

// En pdf-export.ts (o en un helper de carga)
import logoColorUrl from '../../../assets/MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png?url'

Convertir a base64 antes de generar cualquier PDF (operación async, una vez por export):

async function loadImageBase64(url: string): Promise<string> {
  const response = await fetch(url)
  const blob = await response.blob()
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result as string)
    reader.onerror = reject
    reader.readAsDataURL(blob)
  })
}

Llamar una vez al inicio de cada función de export (exportPdf, exportRoiPdf) y pasar el resultado como parámetro.

Cambios en PdfHeaderOptions

Agregar un campo opcional:

export interface PdfHeaderOptions {
  pageNumber: number
  processName: string
  sectionTitle?: string
  clientName?: string
  simulatedAt: number
  logoBase64?: string   // ← nuevo, opcional para retrocompatibilidad
}

Cambios en drawSharedHeader

Reemplazar el bloque de texto "InQ ROI" por lógica condicional:

// ANTES:
doc.setFont('helvetica', 'bold')
doc.setFontSize(13)
doc.setTextColor(...PDF_COLORS.inqOrange)
doc.text('InQ ROI', MARGIN, y)

// DESPUÉS:
if (options.logoBase64) {
  // Logo PNG: ancho 32mm, alto proporcional (~9mm para este logo horizontal)
  // Alinear el baseline del logo con la primera línea de texto: y - 7 (arriba del baseline)
  doc.addImage(options.logoBase64, 'PNG', MARGIN, y - 7, 32, 9)
} else {
  // Fallback al texto (retrocompatibilidad y tests)
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(13)
  doc.setTextColor(...PDF_COLORS.inqOrange)
  doc.text('InQ ROI', MARGIN, y)
}

Nota sobre dimensiones: el logo horizontal de InQuality tiene una proporción aproximada de 3.5:1 (ancho:alto). A 32mm de ancho → ~9mm de alto. Ajustar si el resultado visual no queda bien — la validación visual del director confirma antes del OK formal.

Cambios en pdf-export.ts

En las dos funciones de export (exportPdf y exportRoiPdf), agregar la carga del logo al inicio:

export async function exportPdf(...): Promise<void> {
  const logoBase64 = await loadImageBase64(logoColorUrl).catch(() => undefined)

  const headerOpts: PdfHeaderOptions = {
    // ...opciones existentes...
    logoBase64,
  }
  // resto sin cambios
}

El .catch(() => undefined) garantiza que si el fetch del asset falla (ej: entorno sin red), el PDF se genera igual con el fallback de texto. No bloquear el export por el logo.

Importante — NO cambiar

  • La estructura del header (posiciones de proceso, cliente, fecha, border-bottom) no cambia.
  • El footer ("Powered by InQuality") no cambia.
  • drawSharedFooter y applyFootersToAllPages no se tocan.
  • No agregar el logo en páginas 1 de cada PDF que tengan su propio diseño de portada (verificar si drawScenarioPage1 y drawRoiPage1 usan o no drawSharedHeader — si no lo usan, el logo solo aplica a las páginas que sí lo llaman).

Parte B — whitespace-nowrap en celda de Eficiencia

En src/features/report/ComparisonTable.tsx, dentro de MetricCell, el <span> que muestra el valor numérico de la columna "Eficiencia" se corta en dos líneas ("1.02" / "USD/min") porque la celda es angosta.

Fix: agregar whitespace-nowrap al className del <span>:

// Buscar el span que tiene el valor formateado de la Eficiencia y agregar whitespace-nowrap
<span className="font-mono text-slate-700 text-xs w-14 text-right whitespace-nowrap">
  {format(value)}
</span>

Una línea de cambio. Sin tests que actualizar.


Criterios de validación

  • Logo visible en el header de todas las páginas de los 3 PDFs (Actual, Automatizado, ROI)
  • Logo en tamaño coherente con el header — no dominante, no microscópico
  • Alineación correcta: logo a la izquierda, fecha y cliente a la derecha
  • El footer "Powered by InQuality" sigue presente en todas las páginas
  • Si el asset no carga (fetch falla), el PDF se genera igual con texto "InQ ROI" como fallback
  • "1.02 USD/min" aparece en una sola línea en ComparisonTable
  • npm run lint sin errores
  • npm run build limpio
  • npm run test → 542 tests verdes (sin regresiones — los tests de PDF existentes usan mocks y no verifican el logo)
  • Validación visual del director sobre el PDF exportado antes del OK formal — esta es la validación principal de la etapa

Archivos a modificar

  1. src/lib/export/pdf-sections-shared.tsPdfHeaderOptions + drawSharedHeader
  2. src/lib/export/pdf-export.ts — carga del logo + pasar logoBase64 a headerOpts
  3. src/features/report/ComparisonTable.tsxwhitespace-nowrap en MetricCell

No modificar ningún otro archivo. En particular, no tocar los tests de PDF existentes — el fallback de texto garantiza que sigan pasando sin cambios.