feat(reports): prior-period comparison toggle on the Sales report
Adds a "Compare to prior period" toggle to the Sales report header. When on, the API recomputes the KPI window for the equal-length window immediately preceding the selected range (previousPeriodBounds) behind `?compare=1`, and the five window-derived KPI tiles (Won, Lost, Win rate, Avg time-to-close, New leads) render colour-correct "vs prior" deltas. Point-in-time tiles (Active interests, Pipeline value) have no prior-window analogue and intentionally show no delta. The prior-window query runs in parallel with the main batch and resolves to null when the toggle is off (zero cost). Toggle state persists in the saved-template config. Closes the spec's "period comparison on every report" gap for Sales; Operational already rendered period-start deltas. Pure helpers TDD'd: previousPeriodBounds (range.ts) + computeSalesKpiComparison (sales-comparison.ts), 7 unit tests. tsc + lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,3 +100,23 @@ export function rangeSpanDays(range: DateRange): number {
|
||||
}
|
||||
return rangeToDays(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a concrete {from, to} window, return the equal-length window
|
||||
* immediately preceding it — used for "this period vs prior period"
|
||||
* comparison on report KPIs. The prior window is contiguous (its `to`
|
||||
* equals the current window's `from`) and exactly the same duration, so
|
||||
* a 30-day current window compares against the prior 30 days.
|
||||
*
|
||||
* Pure: takes Dates in, returns fresh Dates, never mutates the input.
|
||||
*/
|
||||
export function previousPeriodBounds(bounds: { from: Date; to: Date }): {
|
||||
from: Date;
|
||||
to: Date;
|
||||
} {
|
||||
const lengthMs = bounds.to.getTime() - bounds.from.getTime();
|
||||
return {
|
||||
from: new Date(bounds.from.getTime() - lengthMs),
|
||||
to: new Date(bounds.from.getTime()),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user