shoc-frontend-new/src/domain/work-orders/utils/wizard-date-utils.ts

176 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export const MONTH_NAMES = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
export function pad2(n: number): string {
return String(n).padStart(2, "0");
}
export function todayIso(): string {
const d = new Date();
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}
export function fmtDate(iso: string): string {
if (!/^\d{4}-\d{2}-\d{2}$/.test(iso)) {
return "";
}
const [y, m, d] = iso.split("-").map(Number);
return `${MONTH_NAMES[m - 1].slice(0, 3)} ${d}, ${y}`;
}
export function addDaysIso(iso: string, days: number): string {
const d = new Date(`${iso}T12:00:00`);
d.setDate(d.getDate() + days);
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}
export function mondayOf(iso: string): string {
const d = new Date(`${iso}T12:00:00`);
const dow = d.getDay();
d.setDate(d.getDate() + (dow === 0 ? -6 : 1 - dow));
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}
export function weeksOfMonth(y: number, m: number): string[] {
const firstIso = `${y}-${pad2(m)}-01`;
const lastIso = `${y}-${pad2(m)}-${pad2(new Date(y, m, 0).getDate())}`;
const out: string[] = [];
for (let mon = mondayOf(firstIso); mon <= lastIso; mon = addDaysIso(mon, 7)) {
if (addDaysIso(mon, 4) >= firstIso) {
out.push(mon);
}
}
return out;
}
export function weekRangeLabel(mondayIso: string): string {
if (!/^\d{4}-\d{2}-\d{2}$/.test(mondayIso)) {
return "";
}
const fri = addDaysIso(mondayIso, 4);
const [, sm, sd] = mondayIso.split("-").map(Number);
const [, em, ed] = fri.split("-").map(Number);
return `${MONTH_NAMES[sm - 1].slice(0, 3)} ${sd} – ${MONTH_NAMES[em - 1].slice(0, 3)} ${ed}`;
}
export function fmtWeekRange(startIso: string): string {
if (!/^\d{4}-\d{2}-\d{2}$/.test(startIso)) {
return fmtDate(startIso);
}
return weekRangeLabel(startIso);
}
/** Short date for ranges: "Jun 8". */
export function fmtShortDate(iso: string): string {
if (!iso || !/^\d{4}-\d{2}-\d{2}$/.test(iso)) {
return "—";
}
const [, m, d] = iso.split("-").map(Number);
return `${MONTH_NAMES[m - 1].slice(0, 3)} ${d}`;
}
/** "Jun 8 – Jun 12" for a Schedule On range. */
export function fmtDateRange(start: string, end: string): string {
return `${fmtShortDate(start)} – ${fmtShortDate(end)}`;
}
/** Inclusive day count between two ISO dates (order-independent). */
export function rangeDayCount(a: string, b: string): number {
const d1 = new Date(`${a}T12:00:00`).getTime();
const d2 = new Date(`${b}T12:00:00`).getTime();
return Math.abs(Math.round((d2 - d1) / 86400000)) + 1;
}
export function fmt12(t: string): string {
const [h, m] = t.split(":").map(Number);
const ampm = h < 12 ? "AM" : "PM";
const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
return `${h12}:${String(m).padStart(2, "0")} ${ampm}`;
}
export function calcDuration(s: string, e: string): string {
const [sh, sm] = s.split(":").map(Number);
const [eh, em] = e.split(":").map(Number);
const mins = eh * 60 + em - (sh * 60 + sm);
if (mins <= 0) {
return "";
}
const h = Math.floor(mins / 60);
const m = mins % 60;
if (h && m) {
return `${h}h ${m}m`;
}
if (h) {
return `${h}h`;
}
return `${m}m`;
}
export function formatApptRange(start: string, end: string): string {
if (!start) {
return "—";
}
return end ? `${fmt12(start)} – ${fmt12(end)}` : fmt12(start);
}
export const TIME_SLOTS: string[] = (() => {
const out: string[] = [];
for (let m = 5 * 60; m <= 22 * 60; m += 30) {
const h = Math.floor(m / 60);
const mm = m % 60;
out.push(`${String(h).padStart(2, "0")}:${String(mm).padStart(2, "0")}`);
}
return out;
})();
export function parseApptTime(appt: string): { start: string; end: string } {
const m = appt.match(/(\d{1,2}):(\d{2})\s*[–-]\s*(\d{1,2}):(\d{2})/);
if (m) {
return {
start: `${m[1].padStart(2, "0")}:${m[2]}`,
end: `${m[3].padStart(2, "0")}:${m[4]}`,
};
}
const single = appt.match(/(\d{1,2}):(\d{2})\s*(AM|PM)/i);
if (single) {
let h = Number(single[1]) % 12;
if (/pm/i.test(single[3])) {
h += 12;
}
return { start: `${pad2(h)}:${single[2]}`, end: "" };
}
const startOnly = appt.trim().match(/^(\d{1,2}):(\d{2})$/);
if (startOnly) {
return {
start: `${startOnly[1].padStart(2, "0")}:${startOnly[2]}`,
end: "",
};
}
return { start: "", end: "" };
}
export function formatApptTimeValue(start: string, end: string): string {
if (!start) {
return "";
}
return end ? `${start} – ${end}` : start;
}
export function fmtWeekOf(mondayIso: string): string {
if (!mondayIso) {
return "";
}
return `Week of ${weekRangeLabel(mondayIso)}`;
}