58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
|
|
/**
|
|||
|
|
* Working-days date math for the Quotes dashboard.
|
|||
|
|
*
|
|||
|
|
* "Working days" = weekdays only. Saturdays and Sundays are skipped.
|
|||
|
|
* Public holidays are intentionally NOT subtracted — the team can layer
|
|||
|
|
* that on later if it becomes a problem; for the current "show me the
|
|||
|
|
* aged quotes" indicator, weekday-only is the right baseline.
|
|||
|
|
*
|
|||
|
|
* All comparisons are done in the browser's local time. Quotes have
|
|||
|
|
* `created` timestamps in ISO UTC; we convert to local-day boundaries
|
|||
|
|
* before counting so "3 working days old" means "3 weekdays since the
|
|||
|
|
* day this row was created, in the user's timezone".
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
/** Strip a Date down to its local-day midnight. */
|
|||
|
|
function startOfLocalDay(d: Date): Date {
|
|||
|
|
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Number of working days (Mon–Fri) between `then` and `now`, exclusive
|
|||
|
|
* of both endpoints' days. So a quote created today returns 0; a quote
|
|||
|
|
* created yesterday on a weekday returns 1; a quote created Friday
|
|||
|
|
* morning checked Monday morning returns 1 (Sat/Sun skipped).
|
|||
|
|
*
|
|||
|
|
* Returns 0 when `then` is in the future or on the same day as `now`.
|
|||
|
|
*/
|
|||
|
|
export function workingDaysBetween(then: Date | string, now: Date = new Date()): number {
|
|||
|
|
const thenDate = typeof then === "string" ? new Date(then) : then;
|
|||
|
|
if (Number.isNaN(thenDate.getTime())) return 0;
|
|||
|
|
|
|||
|
|
const startThen = startOfLocalDay(thenDate);
|
|||
|
|
const startNow = startOfLocalDay(now);
|
|||
|
|
if (startNow <= startThen) return 0;
|
|||
|
|
|
|||
|
|
let count = 0;
|
|||
|
|
const cursor = new Date(startThen);
|
|||
|
|
cursor.setDate(cursor.getDate() + 1); // start counting the day AFTER creation
|
|||
|
|
while (cursor <= startNow) {
|
|||
|
|
const dow = cursor.getDay(); // 0 = Sunday, 6 = Saturday
|
|||
|
|
if (dow !== 0 && dow !== 6) count++;
|
|||
|
|
cursor.setDate(cursor.getDate() + 1);
|
|||
|
|
}
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* True iff `then` is older than `days` working days before `now`.
|
|||
|
|
* Convenience wrapper around `workingDaysBetween` for the age warning.
|
|||
|
|
*/
|
|||
|
|
export function isOlderThanWorkingDays(
|
|||
|
|
then: Date | string,
|
|||
|
|
days: number,
|
|||
|
|
now: Date = new Date()
|
|||
|
|
): boolean {
|
|||
|
|
return workingDaysBetween(then, now) >= days;
|
|||
|
|
}
|