feat: enhance resource calendar validation and UI
- Implement real-time validation for overlapping shifts in the ResourceWorkingHoursPanel. - Remove the copy shift functionality to simplify the UI and prevent confusion. - Introduce ResourceExceptionsCard to manage resource exceptions, including leave and maintenance. - Update ClinicAppointmentSettingsPage to utilize new components and improve tab navigation for resource management. - Add comprehensive validation tests for resource calendar to ensure overlapping shifts are correctly handled. - Update API documentation to reflect new validation error messages and rules.
This commit is contained in:
@@ -171,20 +171,60 @@ describe('ResourceDetailPage', () => {
|
||||
expect(screen.getAllByText('بدون شیفت — این روز بسته است')).toHaveLength(7);
|
||||
});
|
||||
|
||||
/** پرتکرارترین حالت یک ساعتِ یکسان برای کل هفته است؛ بدون کپی، ۱۵ تعامل لازم بود. */
|
||||
it('شیفت یک روز را به همهٔ روزهای هفته کپی میکند', async () => {
|
||||
/**
|
||||
* دو شیفتِ متداخل در یک روز نباید ذخیره شود. سرور هم همین را رد میکند، ولی خطا
|
||||
* باید حین ویرایش دیده شود نه بعد از رفتوبرگشت شبکه.
|
||||
*/
|
||||
it('شیفتهای متداخل را رد میکند و ذخیره را میبندد', async () => {
|
||||
const days = emptyDays();
|
||||
days['0'] = [{ sequence: 0, start_minute: 540, end_minute: 1020, start_time: '09:00', end_time: '17:00', active: true }];
|
||||
days['0'] = [
|
||||
{ sequence: 0, start_minute: 540, end_minute: 780, start_time: '09:00', end_time: '13:00', active: true },
|
||||
{ sequence: 1, start_minute: 1020, end_minute: 1140, start_time: '17:00', end_time: '19:00', active: true },
|
||||
];
|
||||
const user = userEvent.setup();
|
||||
mockApi(days);
|
||||
renderPage('/admin/resources/r1?tab=hours');
|
||||
|
||||
await waitFor(() => expect(screen.getByDisplayValue('17:00')).toBeInTheDocument());
|
||||
expect(screen.queryByText(/تداخل دارند/)).not.toBeInTheDocument();
|
||||
|
||||
// ۱۷:۰۰–۱۹:۰۰ به ۱۲:۰۰ کشیده میشود و با ۰۹:۰۰–۱۳:۰۰ تداخل پیدا میکند.
|
||||
await user.clear(screen.getByLabelText('ساعت شروع شیفت ۲ روز شنبه'));
|
||||
await user.type(screen.getByLabelText('ساعت شروع شیفت ۲ روز شنبه'), '12:00');
|
||||
|
||||
// پیام دو جا میآید و باید بیاید: کنار خودِ روز، و در نوار ذخیره که دلیل قفل را میگوید.
|
||||
expect(await screen.findAllByText(/شیفتهای روز شنبه با هم تداخل دارند/)).toHaveLength(2);
|
||||
expect(screen.getByRole('button', { name: 'ذخیرهٔ شیفتها' })).toBeDisabled();
|
||||
});
|
||||
|
||||
/** بازهٔ بدون تداخل نباید قربانی اعتبارسنجی شود — مرز چسبیده مجاز است. */
|
||||
it('شیفتهای چسبیده اما بدون همپوشانی را میپذیرد', async () => {
|
||||
const days = emptyDays();
|
||||
days['0'] = [
|
||||
{ sequence: 0, start_minute: 540, end_minute: 780, start_time: '09:00', end_time: '13:00', active: true },
|
||||
{ sequence: 1, start_minute: 780, end_minute: 1020, start_time: '13:00', end_time: '17:00', active: true },
|
||||
];
|
||||
const user = userEvent.setup();
|
||||
mockApi(days);
|
||||
renderPage('/admin/resources/r1?tab=hours');
|
||||
|
||||
await waitFor(() => expect(screen.getByDisplayValue('09:00')).toBeInTheDocument());
|
||||
await user.click(screen.getByRole('button', { name: 'کپی شیفتهای شنبه به همهٔ روزهای هفته' }));
|
||||
expect(screen.queryByText(/تداخل دارند/)).not.toBeInTheDocument();
|
||||
|
||||
await waitFor(() => expect(screen.getAllByDisplayValue('09:00')).toHaveLength(7));
|
||||
expect(screen.getAllByDisplayValue('17:00')).toHaveLength(7);
|
||||
expect(screen.queryByText('بدون شیفت — این روز بسته است')).not.toBeInTheDocument();
|
||||
await user.click(screen.getAllByRole('button', { name: 'شیفت' })[1]);
|
||||
|
||||
expect(await screen.findByRole('button', { name: 'ذخیرهٔ شیفتها' })).toBeEnabled();
|
||||
});
|
||||
|
||||
/** آیکون کپی گمراهکننده بود و حذف شد. */
|
||||
it('دکمهٔ کپی شیفت ندارد', async () => {
|
||||
const days = emptyDays();
|
||||
days['0'] = [{ sequence: 0, start_minute: 540, end_minute: 1020, start_time: '09:00', end_time: '17:00', active: true }];
|
||||
mockApi(days);
|
||||
renderPage('/admin/resources/r1?tab=hours');
|
||||
|
||||
await waitFor(() => expect(screen.getByDisplayValue('09:00')).toBeInTheDocument());
|
||||
expect(screen.queryByRole('button', { name: /کپی/ })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
/** پیشنمایش نباید «وقت قابل رزرو» خوانده شود — نوبتها هنوز کسر نشدهاند. */
|
||||
|
||||
Reference in New Issue
Block a user