- 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.
70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { buildServiceTimeline } from './serviceTimeline';
|
|
import type { Appointment } from '../../types';
|
|
|
|
const DAY = 1_800_000_000; // نیمهشبِ فرضی
|
|
const at = (h: number) => DAY + h * 3600;
|
|
|
|
function appointment(from: number, to: number, over: Partial<Appointment> = {}): Appointment {
|
|
return {
|
|
uuid: `a-${from}`, patient_name: 'بیمار', patient_mobile: '09120000000',
|
|
doctor_uuid: 'd1', doctor_name: 'دکتر', slot_start: from, slot_end: to,
|
|
appointment_date: '', appointment_time: '', end_time: '',
|
|
status: 'confirmed', version: 1, created_at: '',
|
|
...over,
|
|
} as Appointment;
|
|
}
|
|
|
|
describe('buildServiceTimeline', () => {
|
|
const window = [{ start: at(8), end: at(14) }];
|
|
|
|
it('یک نوبت، بازهٔ کاری را به «خالی — نوبت — خالی» میشکند', () => {
|
|
const rows = buildServiceTimeline(window, [appointment(at(10), at(11))], at(0));
|
|
|
|
expect(rows.map(r => [r.start, r.end, r.appointment !== null])).toEqual([
|
|
[at(8), at(10), false],
|
|
[at(10), at(11), true],
|
|
[at(11), at(14), false],
|
|
]);
|
|
});
|
|
|
|
it('بدون نوبت، کل بازهٔ کاری یک ردیفِ خالی است', () => {
|
|
const rows = buildServiceTimeline(window, [], at(0));
|
|
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].is_available).toBe(true);
|
|
});
|
|
|
|
it('نوبت لغوشده جای خالی را نمیگیرد', () => {
|
|
const rows = buildServiceTimeline(
|
|
window,
|
|
[appointment(at(10), at(11), { status: 'cancelled_by_doctor' })],
|
|
at(0),
|
|
);
|
|
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].appointment).toBeNull();
|
|
});
|
|
|
|
it('نوبتِ رزرو (روزانه) بازهای اشغال نمیکند', () => {
|
|
const rows = buildServiceTimeline(window, [appointment(at(10), at(11), { is_reserve: true })], at(0));
|
|
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].appointment).toBeNull();
|
|
});
|
|
|
|
it('بازهٔ خالیِ گذشته به «اکنون» بریده میشود و ردیفِ تمامگذشته حذف', () => {
|
|
const rows = buildServiceTimeline([{ start: at(8), end: at(9) }, { start: at(10), end: at(14) }], [], at(11));
|
|
|
|
expect(rows).toHaveLength(1);
|
|
expect(rows[0].start).toBe(at(11));
|
|
expect(rows[0].end).toBe(at(14));
|
|
});
|
|
|
|
it('نوبتِ خارج از بازهٔ کاری، ردیف نمیسازد', () => {
|
|
const rows = buildServiceTimeline(window, [appointment(at(20), at(21))], at(0));
|
|
|
|
expect(rows.every(r => r.appointment === null)).toBe(true);
|
|
});
|
|
});
|