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

@@ -66,33 +66,80 @@ export const useProcessStore = create<ProcessState>((set, get) => ({
updateActivity: async (activity) => {
await activityRepo.save(activity)
set((state) => ({
activities: state.activities.map((a) => (a.id === activity.id ? activity : a)),
}))
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await processRepo.save(updatedProcess)
set((state) => ({
activities: state.activities.map((a) => (a.id === activity.id ? activity : a)),
currentProcess: updatedProcess,
}))
} else {
set((state) => ({
activities: state.activities.map((a) => (a.id === activity.id ? activity : a)),
}))
}
},
updateGateway: async (gateway) => {
await gatewayRepo.save(gateway)
set((state) => ({
gateways: state.gateways.map((g) => (g.id === gateway.id ? gateway : g)),
}))
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await processRepo.save(updatedProcess)
set((state) => ({
gateways: state.gateways.map((g) => (g.id === gateway.id ? gateway : g)),
currentProcess: updatedProcess,
}))
} else {
set((state) => ({
gateways: state.gateways.map((g) => (g.id === gateway.id ? gateway : g)),
}))
}
},
addResource: async (resource) => {
await resourceRepo.save(resource)
set((state) => ({ resources: [...state.resources, resource] }))
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await processRepo.save(updatedProcess)
set((state) => ({ resources: [...state.resources, resource], currentProcess: updatedProcess }))
} else {
set((state) => ({ resources: [...state.resources, resource] }))
}
},
updateResource: async (resource) => {
await resourceRepo.save(resource)
set((state) => ({
resources: state.resources.map((r) => (r.id === resource.id ? resource : r)),
}))
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await processRepo.save(updatedProcess)
set((state) => ({
resources: state.resources.map((r) => (r.id === resource.id ? resource : r)),
currentProcess: updatedProcess,
}))
} else {
set((state) => ({
resources: state.resources.map((r) => (r.id === resource.id ? resource : r)),
}))
}
},
deleteResource: async (resourceId) => {
await resourceRepo.delete(resourceId)
set((state) => ({ resources: state.resources.filter((r) => r.id !== resourceId) }))
const current = get().currentProcess
if (current) {
const updatedProcess = { ...current, updatedAt: Date.now() }
await processRepo.save(updatedProcess)
set((state) => ({
resources: state.resources.filter((r) => r.id !== resourceId),
currentProcess: updatedProcess,
}))
} else {
set((state) => ({ resources: state.resources.filter((r) => r.id !== resourceId) }))
}
},
reset: () => set({ currentProcess: null, activities: [], gateways: [], resources: [], error: null }),