161 lines
5.5 KiB
TypeScript
161 lines
5.5 KiB
TypeScript
export const WEEKDAY_KEYS = ["0", "1", "2", "3", "4", "5", "6"] as const;
|
|
|
|
export type WeekdayKey = (typeof WEEKDAY_KEYS)[number];
|
|
|
|
export type DayAvailability = {
|
|
enabled: boolean;
|
|
start: string;
|
|
end: string;
|
|
};
|
|
|
|
export type WeekdayAvailability = Record<WeekdayKey, DayAvailability>;
|
|
|
|
const TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
const DEFAULT_START = "09:00";
|
|
const DEFAULT_END = "17:00";
|
|
const DEFAULT_ENABLED = new Set<WeekdayKey>(["0", "1", "2", "3", "4"]);
|
|
|
|
export function isValidTimeValue(value: string | undefined | null) {
|
|
return TIME_RE.test(value ?? "");
|
|
}
|
|
|
|
function parseWeekdayCsv(raw: string | undefined | null) {
|
|
const parsed = (raw ?? "")
|
|
.split(",")
|
|
.map((part) => part.trim())
|
|
.filter((part): part is WeekdayKey => WEEKDAY_KEYS.includes(part as WeekdayKey));
|
|
return Array.from(new Set(parsed));
|
|
}
|
|
|
|
export function createDefaultWeekdayAvailability(): WeekdayAvailability {
|
|
return {
|
|
"0": { enabled: true, start: DEFAULT_START, end: DEFAULT_END },
|
|
"1": { enabled: true, start: DEFAULT_START, end: DEFAULT_END },
|
|
"2": { enabled: true, start: DEFAULT_START, end: DEFAULT_END },
|
|
"3": { enabled: true, start: DEFAULT_START, end: DEFAULT_END },
|
|
"4": { enabled: true, start: DEFAULT_START, end: DEFAULT_END },
|
|
"5": { enabled: false, start: DEFAULT_START, end: DEFAULT_END },
|
|
"6": { enabled: false, start: DEFAULT_START, end: DEFAULT_END }
|
|
};
|
|
}
|
|
|
|
export function createWeekdayAvailabilityFromLegacy(
|
|
weekdaysRaw: string | undefined | null,
|
|
startRaw: string | undefined | null,
|
|
endRaw: string | undefined | null
|
|
): WeekdayAvailability {
|
|
const enabledKeys = parseWeekdayCsv(weekdaysRaw);
|
|
const start = isValidTimeValue(startRaw) ? (startRaw as string) : DEFAULT_START;
|
|
const end = isValidTimeValue(endRaw) ? (endRaw as string) : DEFAULT_END;
|
|
const hasValidRange = start < end;
|
|
const safeStart = hasValidRange ? start : DEFAULT_START;
|
|
const safeEnd = hasValidRange ? end : DEFAULT_END;
|
|
const normalizedEnabled =
|
|
enabledKeys.length > 0 ? new Set<WeekdayKey>(enabledKeys) : DEFAULT_ENABLED;
|
|
|
|
return {
|
|
"0": { enabled: normalizedEnabled.has("0"), start: safeStart, end: safeEnd },
|
|
"1": { enabled: normalizedEnabled.has("1"), start: safeStart, end: safeEnd },
|
|
"2": { enabled: normalizedEnabled.has("2"), start: safeStart, end: safeEnd },
|
|
"3": { enabled: normalizedEnabled.has("3"), start: safeStart, end: safeEnd },
|
|
"4": { enabled: normalizedEnabled.has("4"), start: safeStart, end: safeEnd },
|
|
"5": { enabled: normalizedEnabled.has("5"), start: safeStart, end: safeEnd },
|
|
"6": { enabled: normalizedEnabled.has("6"), start: safeStart, end: safeEnd }
|
|
};
|
|
}
|
|
|
|
function normalizeDayAvailability(
|
|
value: unknown,
|
|
fallback: DayAvailability
|
|
): DayAvailability {
|
|
if (!value || typeof value !== "object") {
|
|
return fallback;
|
|
}
|
|
|
|
const raw = value as Partial<DayAvailability>;
|
|
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : fallback.enabled;
|
|
const start = isValidTimeValue(raw.start) ? (raw.start as string) : fallback.start;
|
|
const end = isValidTimeValue(raw.end) ? (raw.end as string) : fallback.end;
|
|
|
|
if (start >= end) {
|
|
return {
|
|
enabled,
|
|
start: fallback.start,
|
|
end: fallback.end
|
|
};
|
|
}
|
|
|
|
return {
|
|
enabled,
|
|
start,
|
|
end
|
|
};
|
|
}
|
|
|
|
export function normalizeWeekdayAvailability(
|
|
value: unknown,
|
|
fallback?: WeekdayAvailability
|
|
): WeekdayAvailability {
|
|
const base = fallback ?? createDefaultWeekdayAvailability();
|
|
const source = value && typeof value === "object" ? (value as Record<string, unknown>) : {};
|
|
|
|
return {
|
|
"0": normalizeDayAvailability(source["0"], base["0"]),
|
|
"1": normalizeDayAvailability(source["1"], base["1"]),
|
|
"2": normalizeDayAvailability(source["2"], base["2"]),
|
|
"3": normalizeDayAvailability(source["3"], base["3"]),
|
|
"4": normalizeDayAvailability(source["4"], base["4"]),
|
|
"5": normalizeDayAvailability(source["5"], base["5"]),
|
|
"6": normalizeDayAvailability(source["6"], base["6"])
|
|
};
|
|
}
|
|
|
|
export function parseWeekdayAvailabilityJson(
|
|
raw: string | undefined | null,
|
|
fallback?: WeekdayAvailability
|
|
): WeekdayAvailability {
|
|
if (!raw) {
|
|
return normalizeWeekdayAvailability(undefined, fallback);
|
|
}
|
|
|
|
try {
|
|
const parsed = JSON.parse(raw);
|
|
return normalizeWeekdayAvailability(parsed, fallback);
|
|
} catch {
|
|
return normalizeWeekdayAvailability(undefined, fallback);
|
|
}
|
|
}
|
|
|
|
export function serializeWeekdayAvailability(value: WeekdayAvailability) {
|
|
const normalized = normalizeWeekdayAvailability(value);
|
|
return JSON.stringify(normalized);
|
|
}
|
|
|
|
export function hasAtLeastOneEnabledDay(value: WeekdayAvailability) {
|
|
return WEEKDAY_KEYS.some((key) => {
|
|
const day = value[key];
|
|
return day.enabled && isValidTimeValue(day.start) && isValidTimeValue(day.end) && day.start < day.end;
|
|
});
|
|
}
|
|
|
|
export function deriveLegacyAvailability(
|
|
value: WeekdayAvailability
|
|
): {
|
|
bookingAllowedWeekdays: string;
|
|
bookingDayStartTime: string;
|
|
bookingDayEndTime: string;
|
|
} {
|
|
const normalized = normalizeWeekdayAvailability(value);
|
|
const enabledKeys = WEEKDAY_KEYS.filter((key) => normalized[key].enabled);
|
|
const finalEnabled = enabledKeys.length > 0 ? enabledKeys : (["0", "1", "2", "3", "4"] as WeekdayKey[]);
|
|
|
|
const starts = finalEnabled.map((key) => normalized[key].start).sort();
|
|
const ends = finalEnabled.map((key) => normalized[key].end).sort();
|
|
|
|
return {
|
|
bookingAllowedWeekdays: finalEnabled.join(","),
|
|
bookingDayStartTime: starts[0] ?? DEFAULT_START,
|
|
bookingDayEndTime: ends[ends.length - 1] ?? DEFAULT_END
|
|
};
|
|
}
|