feat: Implement resource-based appointment booking flow

- Updated DoctorPage component to accept bookingResources prop for appointment list.
- Added serviceQuery function to serialize service item UUIDs for API requests.
- Introduced new API endpoints for fetching booking resources and resource slots.
- Enhanced tests for new resource-based booking functionality, including resource selection and service availability.
- Created ResourceSelect component for selecting appointment types, including doctor and resource options.
- Updated appointment submission logic to include resource_uuid in payload when applicable.
- Ensured UI reflects changes in booking flow without disrupting existing doctor-centric experience.
This commit is contained in:
hamed
2026-08-09 10:45:52 +03:30
parent 1668ef8890
commit 54bebbd41a
23 changed files with 1094 additions and 32 deletions
+52
View File
@@ -73,4 +73,56 @@ describe('request wrappers — قرارداد به لایه‌ی API', () => {
request.postAppointment({ slot: 5 });
expect(api.post).toHaveBeenCalledWith('api/v1/appointment', { slot: 5 }, { requireAuth: true });
});
// --- نوبت‌دهی منبع‌محور ---
it('getBookingResources → بدون کلینیک، مسیر ساده', () => {
request.getBookingResources('doc-1');
expect(api.get.mock.calls[0][0]).toBe('api/v1/appointment-booking-resources/doc-1');
});
it('getBookingResources → با کلینیک، clinic_uuid با ? می‌آید', () => {
request.getBookingResources('doc-1', 'cl-1');
expect(api.get.mock.calls[0][0]).toBe(
'api/v1/appointment-booking-resources/doc-1?clinic_uuid=cl-1'
);
});
it('getResourceSlots → هر سرویس یک service_item_uuids[] جدا می‌گیرد', () => {
request.getResourceSlots('res-1', '2026-08-10', ['s1', 's2']);
const url = api.get.mock.calls[0][0];
expect(url).toContain('resource_uuid=res-1');
expect(url).toContain('date=2026-08-10');
expect(url).toContain('&service_item_uuids[]=s1');
expect(url).toContain('&service_item_uuids[]=s2');
});
it('getResourceSlots → uuid با کاراکتر ویژه encode می‌شود', () => {
request.getResourceSlots('res-1', '2026-08-10', ['a/b']);
expect(api.get.mock.calls[0][0]).toContain('service_item_uuids[]=a%2Fb');
});
it('getResourceSlots → فهرست خالی هیچ پارامتر سرویسی نمی‌سازد', () => {
request.getResourceSlots('res-1', '2026-08-10', []);
expect(api.get.mock.calls[0][0]).not.toContain('service_item_uuids');
});
it('getResourceMonthAvailability → سال و ماه و سرویس‌ها در query', () => {
request.getResourceMonthAvailability('res-1', 2026, 9, ['s1']);
const url = api.get.mock.calls[0][0];
expect(url).toContain('api/v1/appointment-resource-month-availability/res-1');
expect(url).toContain('year=2026');
expect(url).toContain('month=9');
expect(url).toContain('&service_item_uuids[]=s1');
});
it('هر سه اندپوینت عمومی‌اند — هدر Authorization حذف می‌شود', () => {
request.getBookingResources('doc-1');
request.getResourceSlots('res-1', '2026-08-10', ['s1']);
request.getResourceMonthAvailability('res-1', 2026, 9, ['s1']);
for (const call of api.get.mock.calls) {
expect(call[1]?.headers?.Authorization).toBe('');
}
});
});