From 293abb6d2758efd107acd8a8ac28b2092f939665 Mon Sep 17 00:00:00 2001 From: Satyam Rastogi Date: Fri, 29 May 2026 17:10:53 +0530 Subject: [PATCH] feat(lifecycle): add pure project lifecycle stage model (stages, progress map, helpers) --- src/data/lifecycle.js | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/data/lifecycle.js diff --git a/src/data/lifecycle.js b/src/data/lifecycle.js new file mode 100644 index 0000000..a9a53ae --- /dev/null +++ b/src/data/lifecycle.js @@ -0,0 +1,53 @@ +// src/data/lifecycle.js +// The project lifecycle state machine (Master §9). Pure constants + helpers; no React. + +// Ordered linear stages. 'Rework In Progress' is an off-line regression state (entered on a failed +// final inspection), so it is NOT in the linear order array — handle it explicitly. +export const LIFECYCLE_STAGES = [ + 'Lead', + 'Damage Inspection Scheduled', + 'Damage Verified', + 'Scope Approved', + 'Contract Signed', + 'Work In Progress', + 'Work Complete — Awaiting Inspection', + 'Final Inspection Scheduled', + 'Final Inspection In Progress', + 'Project Completed', + 'Final Payment Received — Closed', +]; + +export const REWORK_STAGE = 'Rework In Progress'; + +// Stage → canonical progress %. Advancing to a stage sets the project's completionPercentage to this. +export const STAGE_PROGRESS = { + 'Lead': 5, + 'Damage Inspection Scheduled': 10, + 'Damage Verified': 20, + 'Scope Approved': 30, + 'Contract Signed': 40, + 'Work In Progress': 55, + 'Work Complete — Awaiting Inspection': 80, + 'Final Inspection Scheduled': 85, + 'Final Inspection In Progress': 90, + 'Rework In Progress': 75, + 'Project Completed': 95, + 'Final Payment Received — Closed': 100, +}; + +export const stageToPct = (stage) => STAGE_PROGRESS[stage] ?? 0; + +export const nextStage = (stage) => { + if (stage === REWORK_STAGE) return 'Final Inspection Scheduled'; // rework re-enters inspection + const i = LIFECYCLE_STAGES.indexOf(stage); + return i >= 0 && i < LIFECYCLE_STAGES.length - 1 ? LIFECYCLE_STAGES[i + 1] : stage; +}; + +export const prevStage = (stage) => { + const i = LIFECYCLE_STAGES.indexOf(stage); + return i > 0 ? LIFECYCLE_STAGES[i - 1] : stage; +}; + +// Is this stage at/after a reference stage? (for gating UI like "can schedule final inspection") +export const isAtOrAfter = (stage, ref) => + LIFECYCLE_STAGES.indexOf(stage) >= LIFECYCLE_STAGES.indexOf(ref);