feat(sprint-3): biblioteca, recursos TO-BE, ROI mejorado e identidad de marca

Sprint 3 completo — 7 etapas:

- Etapa 1-2: biblioteca de procesos con agrupación por cliente (Dexie v4,
  LibraryPage, library-store, groupId/tags en Process)
- Etapa 3: modal de configuración global por proceso (horizonte, frecuencia,
  inversión, moneda) con validación y persistencia
- Etapa 4: panel de recursos rediseñado con soporte de unidades y minutos
  de utilización (utilizationMinutes + units)
- Etapa 5: recursos en escenario automatizado — motor de simulación,
  UI de edición en ActivityPanel, comparación AS-IS/TO-BE en reporte
- Etapa 6: PDF recursos automatizados, automatedAssignedResources requerido,
  561 tests pasando
- Etapa 7: identidad de marca — AppHeader gradiente naranja/magenta con logo
  InQuality en 5 páginas, favicon con logo real, logo/marca navegan a home

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 11:49:43 -03:00
parent d2746f07d1
commit 67e259e6ed
57 changed files with 4372 additions and 82 deletions

View File

@@ -157,9 +157,10 @@ describe('RoiKpiBar', () => {
expect(screen.getByText(/Inmediato/i)).toBeInTheDocument()
})
it('ROI Infinity (inversión cero) → muestra "∞%"', () => {
it('ROI Infinity (inversión cero) → muestra "—" con texto accionable', () => {
render(<RoiKpiBar roi={roiZeroInvestment} currency="USD" horizonYears={3} />)
expect(screen.getByText('∞%')).toBeInTheDocument()
expect(screen.getByText('')).toBeInTheDocument()
expect(screen.getByText(/Configurá la inversión/i)).toBeInTheDocument()
})
it('ahorro negativo: "breaksEvenInHorizon = false" → subtexto fuera del horizonte', () => {
@@ -311,6 +312,7 @@ const makeActivityDomain = (id: string, name: string, automatable: boolean, zero
automatable,
automatedCostFixed: zeroCosts ? 0 : 50,
automatedTimeMinutes: zeroCosts ? 0 : 10,
automatedAssignedResources: [],
})
describe('TransparencySection', () => {
@@ -586,6 +588,7 @@ const mockProcessBase = {
currency: 'USD', overheadPercentage: 0.2,
annualFrequency: 1200, analysisHorizonYears: 3, automationInvestment: 50_000,
createdAt: Date.now() - 3600_000, updatedAt: Date.now() - 3600_000,
groupId: null, tags: [],
}
const mockSimulationBase = {
@@ -598,6 +601,7 @@ const automtableActivity: Activity = {
id: 'act-1', processId: 'test-proc-id', bpmnElementId: 'bpmn_a1', name: 'Recibir solicitud',
type: 'task', directCostFixed: 500, executionTimeMinutes: 60, assignedResources: [],
automatable: true, automatedCostFixed: 50, automatedTimeMinutes: 5,
automatedAssignedResources: [],
}
const nonAutomatableActivity: Activity = {