+ Recursos TO-BE +
+ {/* Dropdown para agregar recurso */} + {availableAutomatedResources.length > 0 && ( + + )} ++ Sin recursos TO-BE — solo costo fijo automatizado. +
+ ) : ( +Min. por ejecución
+ + updateAutomatedAssignment( + assignment.resourceId, + 'utilizationMinutes', + Math.max(0, parseFloat(e.target.value) || 0) + ) + } + className="h-6 text-xs font-mono" + /> +Unidades
+ + updateAutomatedAssignment( + assignment.resourceId, + 'units', + Math.max(1, parseInt(e.target.value) || 1) + ) + } + className="h-6 text-xs font-mono" + /> +AS-IS
+ {/* Lista del pairedBreakdown (recursos AS-IS) */} + {pairedBreakdown[act.activityId].map((r) => ( +TO-BE
+ {act.resourceCostBreakdown.length === 0 + ?Sin recursos TO-BE
+ : act.resourceCostBreakdown.map((r) => ( +
+
+ {/* Nombre del producto */}
+
+ InQ ROI
+
+ + InQ ROI · Powered by InQuality · v0.1.0 · Hecho desde Paraguay 🇵🇾 +
+``` + +--- + +## ❌ Lo que NO entra en esta etapa + +- Cambios en stores, simulación, persistencia, dominio +- Cambios en componentes de UI que no sean los listados arriba +- Nuevo routing o cambios en `router.tsx` +- Modificar el logo PNG o cambiar la identidad visual establecida +- Agregar links de navegación en el `AppHeader` (solo marca, sin nav) +- `pdf-sections.ts` — el header del PDF ya tiene logo (implementado en sprints anteriores) + +--- + +## Verificación antes de entregar + +```bash +# 1. Build limpio +npm run build + +# 2. Tests sin regresión +npm run test + +# 3. Control de scope +git diff --name-only HEAD +``` + +El diff debe mostrar únicamente: +- `public/favicon.svg` +- `public/inquality-logo-white.png` (binario nuevo) +- `public/inquality-logo-color.png` (binario nuevo) +- `src/components/AppHeader.tsx` (nuevo) +- `src/features/library/LibraryPage.tsx` +- `src/features/workspace/WorkspacePage.tsx` +- `src/features/report/ReportPage.tsx` +- `src/features/import/ImportPage.tsx` +- `src/features/settings/SettingsPage.tsx` +- `src/components/AppFooter.tsx` + +Si aparece cualquier archivo de `src/store/`, `src/domain/`, `src/persistence/`, o `src/lib/export/`: **revertir y reportar**. + +### Verificación funcional mandatoria + +Antes de reportar, verificar manualmente: + +1. **Logo visible en biblioteca:** abrir la home → ver barra naranja/magenta con logo blanco de InQuality y "InQ ROI" a la derecha. +2. **Logo en workspace:** abrir un proceso → la barra aparece encima del header del proceso. +3. **Logo en reporte:** navegar al reporte → la barra está arriba de todo, incluso por encima del banner stale si existe. +4. **Logo en import:** ir a importar BPMN → la barra está presente. +5. **Logo en settings:** ir a configuración → la barra está presente. +6. **Favicon:** en el tab del browser se ve el fondo naranja con "Q", no el gráfico de barras azul. +7. **Sin regresión de layout:** el workspace no tiene scroll horizontal inesperado por la nueva barra. + +--- + +## Criterios de aceptación + +- [ ] Logo InQuality visible en las 5 páginas principales. +- [ ] Favicon actualizado a isotipo naranja InQ. +- [ ] Gradiente `#F59845 → #ED3E8F` correcto — no colores CONCILIA. +- [ ] Build sin errores TypeScript. +- [ ] Todos los tests previos siguen verdes (561). +- [ ] Validación visual del director aprobada — OK formal requerido antes de cerrar. + +--- + +## Reporte esperado al terminar + +1. Resultado de `git diff --name-only HEAD`. +2. Resultado de `npm run build` y `npm run test`. +3. Confirmación de los 7 casos de verificación funcional. +4. Cualquier decisión de iniciativa tomada (Nivel 1/2/3). + +--- + +## Referencias + +- `CLAUDE.md` — reglas de marca: gradiente `#F59845 → #ED3E8F`, no usar colores CONCILIA +- `assets/MARCA FINAL 2023 AREA DE SEGURIDAD 1 BCO.png` — logo horizontal blanco (para fondo naranja) +- `assets/MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png` — logo horizontal color (para fondo blanco) +- `src/components/AppFooter.tsx` — patrón de componente de marca existente +- `methodology/PATTERNS.md` — C.7 (git diff como control preventivo) diff --git a/src/components/AppFooter.tsx b/src/components/AppFooter.tsx index 261f76f..04cb505 100644 --- a/src/components/AppFooter.tsx +++ b/src/components/AppFooter.tsx @@ -1,7 +1,7 @@ export function AppFooter() { return ( diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx new file mode 100644 index 0000000..f773e5d --- /dev/null +++ b/src/components/AppHeader.tsx @@ -0,0 +1,39 @@ +import { Link } from '@tanstack/react-router' + +export function AppHeader() { + return ( +
+
+
+ InQ ROI
+
+ Ahorro anual proyectado
+Costo anual actual
+{process.name || 'Sin nombre'}
+Tu biblioteca está vacía
+Importá tu primer BPMN para empezar
+ ++ {filteredProcesses.length} resultado{filteredProcesses.length !== 1 ? 's' : ''} +
+ {filteredProcesses.length === 0 && ( +Sin resultados para esa búsqueda.
+ )} + {filteredProcesses.map((p) => { + const group = groups.find((g) => g.id === p.groupId) + return ( ++ {groupProcesses.length} proceso{groupProcesses.length !== 1 ? 's' : ''} +
+ + {/* Búsqueda */} ++ No hay procesos en este {settings.groupLabel.toLowerCase()}. +
+Importá un BPMN para comenzar.
++ {processes.length} proceso{processes.length !== 1 ? 's' : ''} · {totalGroups} {settings.groupLabel.toLowerCase()}{totalGroups !== 1 ? 's' : ''} +
+Sin desglose disponible
- )} - {act.resourceCostBreakdown.length === 0 && fixedCostExpected > 0 && ( -Sin recursos asignados — costo es 100% fijo
+ {pairedBreakdown?.[act.activityId] ? ( + <> +AS-IS
+ {pairedBreakdown[act.activityId].map((r) => ( +Sin recursos AS-IS
+ )} +TO-BE
+ {act.resourceCostBreakdown.length === 0 + ?Sin recursos TO-BE
+ : act.resourceCostBreakdown.map((r) => ( +Sin desglose disponible
+ )} + {act.resourceCostBreakdown.length === 0 && fixedCostExpected > 0 && ( +Sin recursos asignados — costo es 100% fijo
+ )} + > )}Personalización del workspace
++ Cómo se llama el nivel de agrupación en la biblioteca. Por defecto: 'Cliente'. +
+ { setLocalLabel(e.target.value); setIsDirty(true) }} + onBlur={save} + onKeyDown={(e) => { + if (e.key === 'Enter') { e.preventDefault(); inputRef.current?.blur() } + if (e.key === 'Escape') { setLocalLabel(settings.groupLabel); setIsDirty(false); inputRef.current?.blur() } + }} + className="text-sm px-3 py-2 rounded-lg border border-border bg-background focus:outline-none focus:ring-1 focus:ring-primary w-full max-w-xs" + placeholder="Cliente" + /> + {localLabel.trim() && ( ++ Los procesos se organizarán por {localLabel.trim()}. +
+ )} ++ Recursos TO-BE +
+ {availableAutomatedResources.length > 0 && ( + + )} ++ Sin recursos TO-BE — solo costo fijo automatizado. +
+ ) : ( +Min. por ejecución
+ + updateAutomatedAssignment( + assignment.resourceId, + 'utilizationMinutes', + Math.max(0, parseFloat(e.target.value) || 0) + ) + } + className="h-6 text-xs font-mono" + /> +Unidades
+ + updateAutomatedAssignment( + assignment.resourceId, + 'units', + Math.max(1, parseInt(e.target.value) || 1) + ) + } + className="h-6 text-xs font-mono" + /> +