feat: Implement resource booking functionality
- Add service timeline builder for appointments to manage available slots. - Create a hook to fetch resource booking services with effective durations. - Develop ResourceBookingSlotController to handle API requests for resource booking slots. - Implement ResourceBookingSlotService to calculate available time slots based on resource occupancy and service durations. - Add tests for resource appointment creation and booking slot functionality to ensure correct behavior and edge cases.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { formatTime } from '../../lib/utils';
|
||||
import { CANCELLED_STATUSES } from './turnStatus';
|
||||
import type { Appointment } from '../../types';
|
||||
import type { TimelineSlot } from './types';
|
||||
|
||||
/** یک بازهٔ کاری: شیفتِ منبع یا سشنِ برنامهٔ هفتگیِ پزشک. */
|
||||
export interface WorkingWindow {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* تایملاینِ نوبتدهی **سرویسی**: نوبتهای رزروشده + بازههای خالیِ بینشان.
|
||||
*
|
||||
* حالت سرویسی اسلاتِ ثابت ندارد — طول هر نوبت از سرویسهایش میآید — پس ردیفها از
|
||||
* روی بازهٔ کاری و نوبتهای واقعی ساخته میشوند، نه از شبکهٔ اسلات.
|
||||
*
|
||||
* پزشک و منبع همین یک الگوریتم را دارند: بازهٔ کاری یکی از برنامهٔ هفتگی میآید و
|
||||
* دیگری از تقویم منبع، ولی چیدنِ کارتها فرقی نمیکند و دو نسخهاش یعنی دو رفتار.
|
||||
*/
|
||||
export function buildServiceTimeline(
|
||||
windows: WorkingWindow[],
|
||||
appointments: Appointment[],
|
||||
now: number = Math.floor(Date.now() / 1000),
|
||||
): TimelineSlot[] {
|
||||
const booked = appointments
|
||||
.filter(a => !CANCELLED_STATUSES.has(a.status) && !a.is_reserve)
|
||||
.map(a => ({
|
||||
appointment: a,
|
||||
start: Number(a.slot_start),
|
||||
end: Number(a.slot_end),
|
||||
}))
|
||||
.sort((a, b) => a.start - b.start);
|
||||
|
||||
const out: TimelineSlot[] = [];
|
||||
|
||||
/** بازهٔ خالی؛ تکهٔ گذشتهاش بریده میشود چون قابل رزرو نیست. */
|
||||
const pushFree = (start: number, end: number) => {
|
||||
const from = start < now ? now : start;
|
||||
if (end <= from) return;
|
||||
out.push({
|
||||
start: from, end,
|
||||
start_time: formatTime(from), end_time: formatTime(end),
|
||||
is_available: true, appointment: null, cancelled_appointment: null,
|
||||
});
|
||||
};
|
||||
|
||||
windows.forEach(({ start: winStart, end: winEnd }) => {
|
||||
let cursor = winStart;
|
||||
|
||||
booked
|
||||
.filter(b => b.start >= winStart && b.start < winEnd)
|
||||
.forEach(({ appointment, start, end }) => {
|
||||
if (start > cursor) pushFree(cursor, start);
|
||||
out.push({
|
||||
start, end,
|
||||
start_time: formatTime(start), end_time: formatTime(end),
|
||||
is_available: false, appointment, cancelled_appointment: null,
|
||||
});
|
||||
cursor = Math.max(cursor, end);
|
||||
});
|
||||
|
||||
if (cursor < winEnd) pushFree(cursor, winEnd);
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user