mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-02 06:13:13 +00:00
109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
import { compactWeekLabel } from "@/domain/work-orders/utils/list-week-utils";
|
|
import { formatRescheduleCountLabel } from "@/domain/work-orders/utils/reschedule-indicator";
|
|
import { deriveDayFields } from "@/domain/work-orders/utils/table-day-utils";
|
|
import { addDaysIso, mondayOf } from "@/domain/work-orders/utils/wizard-date-utils";
|
|
|
|
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
const WEEKDAY_COUNT = 7;
|
|
const FRIDAY_OFFSET = 4;
|
|
|
|
export type CarryOverRow = {
|
|
scheduledOn: string;
|
|
status?: string;
|
|
carriedOver?: number;
|
|
};
|
|
|
|
export function isTerminalCarryOverStatus(status?: string): boolean {
|
|
return status === "Completed" || status === "Canceled";
|
|
}
|
|
|
|
export function shouldShowCarriedOverPill(count: number, status?: string): boolean {
|
|
return count >= 2 && !isTerminalCarryOverStatus(status);
|
|
}
|
|
|
|
export function toIsoDate(value?: string): string {
|
|
if (!value) {
|
|
return "";
|
|
}
|
|
const iso = value.slice(0, 10);
|
|
return ISO_DATE.test(iso) ? iso : "";
|
|
}
|
|
|
|
export function resolveCarryOverSourceWeek(input: {
|
|
originalWeek?: string;
|
|
originalDate?: string;
|
|
scheduledOn?: string;
|
|
}): string {
|
|
const originalWeek = toIsoDate(input.originalWeek);
|
|
if (originalWeek) {
|
|
return mondayOf(originalWeek);
|
|
}
|
|
const originalDate = toIsoDate(input.originalDate);
|
|
if (originalDate) {
|
|
return mondayOf(originalDate);
|
|
}
|
|
const scheduledOn = toIsoDate(input.scheduledOn);
|
|
return scheduledOn ? mondayOf(scheduledOn) : "";
|
|
}
|
|
|
|
export function formatCarriedOverHover(count: number, sourceWeekIso?: string): string {
|
|
const times = formatRescheduleCountLabel(count);
|
|
const base = `Carried over ${times} — this WO was not completed and moved to the next period`;
|
|
const sourceLabel = sourceWeekIso ? compactWeekLabel(sourceWeekIso) : "";
|
|
if (!sourceLabel) {
|
|
return base;
|
|
}
|
|
return `${base}. Source week: ${sourceLabel}.`;
|
|
}
|
|
|
|
/** Non-terminal WOs scheduled before the viewed week are display carry-overs. */
|
|
export function isCarryOverDisplayRow(row: CarryOverRow, weekMonday: string): boolean {
|
|
if (isTerminalCarryOverStatus(row.status)) {
|
|
return false;
|
|
}
|
|
const scheduled = toIsoDate(row.scheduledOn);
|
|
return Boolean(scheduled) && scheduled < weekMonday;
|
|
}
|
|
|
|
export function mapCarryOverDisplayDay(scheduledOn: string, weekMonday: string): string {
|
|
const scheduled = toIsoDate(scheduledOn);
|
|
if (!scheduled || !ISO_DATE.test(weekMonday)) {
|
|
return "";
|
|
}
|
|
const sourceMonday = mondayOf(scheduled);
|
|
const offsetMs =
|
|
new Date(`${scheduled}T12:00:00`).getTime() - new Date(`${sourceMonday}T12:00:00`).getTime();
|
|
const offset = Math.round(offsetMs / 86_400_000);
|
|
if (offset < 0 || offset >= WEEKDAY_COUNT) {
|
|
return weekMonday;
|
|
}
|
|
if (offset > FRIDAY_OFFSET) {
|
|
return weekMonday;
|
|
}
|
|
return addDaysIso(weekMonday, offset);
|
|
}
|
|
|
|
export function rowMatchesCarryOverDay(
|
|
row: CarryOverRow,
|
|
selectedDayIso: string,
|
|
weekMonday: string,
|
|
): boolean {
|
|
if (!isCarryOverDisplayRow(row, weekMonday)) {
|
|
return false;
|
|
}
|
|
return mapCarryOverDisplayDay(row.scheduledOn, weekMonday) === selectedDayIso;
|
|
}
|
|
|
|
/** Aligns UI day keys with the mapped weekday so reorder stays on the displayed tab. */
|
|
export function applyCarryOverDisplayDayFields<
|
|
T extends CarryOverRow & { dayGroup: string; dayLabel: string },
|
|
>(row: T, weekMonday: string): T {
|
|
if (!isCarryOverDisplayRow(row, weekMonday)) {
|
|
return row;
|
|
}
|
|
const displayDay = mapCarryOverDisplayDay(row.scheduledOn, weekMonday);
|
|
if (!displayDay) {
|
|
return row;
|
|
}
|
|
return { ...row, ...deriveDayFields(displayDay) };
|
|
}
|