mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-02 15:33:12 +00:00
* feat(work-orders): align Due Date and Past Due with SH-132 FE contract [SH-132] * fix(work-orders): highlight Schedule On for unscheduled rows Restore forceScheduleHighlight for Unscheduled section rows while keeping Due Date highlight for past-due and attempt feedback. Co-authored-by: Cursor <cursoragent@cursor.com> * test(work-orders): cover unscheduled Schedule On highlight [SH-132] Add row-level public-interface regression proving Unscheduled rows force-highlight Schedule On, not Due Date (SH-165). Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Alexandre Brandizzi <alex_brandizzi@hotmail.com>
109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
import type { WorkOrderAuditEntry } from "@/domain/work-orders/types/work-order-detail";
|
|
|
|
export type AuditActionSource = Pick<
|
|
WorkOrderAuditEntry,
|
|
"action" | "fieldName" | "oldValue" | "newValue"
|
|
>;
|
|
|
|
export type FormattedAuditValue = {
|
|
text: string;
|
|
/** Per-item quotes already applied; omit outer quotes in sentence templates. */
|
|
isQuotedList: boolean;
|
|
};
|
|
|
|
export function wrapAuditValue(value: FormattedAuditValue): string {
|
|
if (!value.text) return value.text;
|
|
return value.isQuotedList ? value.text : `"${value.text}"`;
|
|
}
|
|
|
|
export type AuditActionRuleContext = {
|
|
entry: AuditActionSource;
|
|
fieldKey: string;
|
|
actionKey: string;
|
|
oldValue: FormattedAuditValue;
|
|
newValue: FormattedAuditValue;
|
|
};
|
|
|
|
export type AuditActionRule = (ctx: AuditActionRuleContext) => string | null;
|
|
|
|
function tryStatusRule({ fieldKey, actionKey, newValue }: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey.includes("status") || fieldKey === "lifecyclestatus" || actionKey.includes("status");
|
|
if (!matches || !newValue.text) return null;
|
|
|
|
return `Changed status to ${wrapAuditValue(newValue)}`;
|
|
}
|
|
|
|
function tryApptRule({
|
|
fieldKey,
|
|
actionKey,
|
|
oldValue,
|
|
newValue,
|
|
}: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey.includes("appt") || fieldKey.includes("appointment") || actionKey.includes("appt");
|
|
if (!matches) return null;
|
|
|
|
if (oldValue.text && newValue.text) {
|
|
return `Changed appt time from ${wrapAuditValue(oldValue)} to ${wrapAuditValue(newValue)}`;
|
|
}
|
|
if (newValue.text) return `Changed appt time to ${wrapAuditValue(newValue)}`;
|
|
|
|
return null;
|
|
}
|
|
|
|
function tryScheduleRule({ fieldKey, actionKey, newValue }: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey.includes("scheduled") ||
|
|
fieldKey === "schedule" ||
|
|
fieldKey.includes("scheduledate") ||
|
|
fieldKey.includes("duedate") ||
|
|
actionKey === "rescheduled" ||
|
|
actionKey.includes("reschedule");
|
|
if (!matches) return null;
|
|
|
|
if (newValue.text) return `Changed schedule to ${wrapAuditValue(newValue)}`;
|
|
|
|
return "Rescheduled work order";
|
|
}
|
|
|
|
function tryCarriedOverRule({ fieldKey, actionKey, entry }: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey.includes("carriedover") ||
|
|
actionKey === "weekrolled" ||
|
|
actionKey.includes("carryover");
|
|
if (!matches) return null;
|
|
|
|
const increment = Number(entry.newValue?.trim() ?? "");
|
|
if (Number.isFinite(increment) && increment > 0) {
|
|
return `Carried over to the next week (increment #${increment})`;
|
|
}
|
|
|
|
return "Carried over to the next week";
|
|
}
|
|
|
|
function tryPastDueRule({ fieldKey, actionKey }: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey.includes("pastdue") || actionKey.includes("pastdue") || actionKey === "markedpastdue";
|
|
if (!matches) return null;
|
|
|
|
return "WO marked as Past Due. Due date has passed without completion.";
|
|
}
|
|
|
|
function tryCreatedRule({ fieldKey, actionKey }: AuditActionRuleContext): string | null {
|
|
const matches =
|
|
fieldKey === "created" || actionKey === "workordercreated" || actionKey === "created";
|
|
if (!matches) return null;
|
|
|
|
return "Work order created in the system.";
|
|
}
|
|
|
|
/** Applied in order; the first non-null result wins. */
|
|
export const BOARD_AUDIT_ACTION_RULES: AuditActionRule[] = [
|
|
tryStatusRule,
|
|
tryApptRule,
|
|
tryScheduleRule,
|
|
tryCarriedOverRule,
|
|
tryPastDueRule,
|
|
tryCreatedRule,
|
|
];
|