feat: enhance ResourceWorkingHoursPanel with improved error handling and UI updates

- Added new icons and improved error messaging for better user feedback.
- Refactored state management to include baseline comparison for dirty state detection.
- Introduced functionality to copy shifts across all days and reset to baseline.
- Updated UI layout for better responsiveness and usability.
- Enhanced tests to cover new features and ensure proper functionality.

refactor: update ClinicAppointmentSettingsPage to use PageHeader component

- Replaced BackButton with PageHeader for a more consistent header layout.
- Simplified the structure of the appointment settings page for better readability.

test: improve ResourceDetailPage tests for shift management

- Updated tests to reflect changes in shift display and error handling.
- Added tests for new features including the reset functionality and copying shifts.

style: add styles for weekly shift layout in ResourceWorkingHoursPanel

- Introduced new CSS classes for better layout and responsiveness of the weekly shift display.
- Ensured styles are consistent with the overall design system.
This commit is contained in:
hamed
2026-08-03 09:24:50 +03:30
parent 4fe0c4f9bf
commit c42679d98c
5 changed files with 511 additions and 218 deletions
+63 -1
View File
@@ -94,7 +94,7 @@ describe('ResourceDetailPage', () => {
await waitFor(() => expect(screen.getByText('شنبه')).toBeInTheDocument());
expect(screen.getByText('جمعه')).toBeInTheDocument();
expect(screen.getAllByText('بدون شیفت')).toHaveLength(7);
expect(screen.getAllByText('بدون شیفت — این روز بسته است')).toHaveLength(7);
});
it('شیفت ذخیره‌شده را به‌صورت ساعت نشان می‌دهد', async () => {
@@ -125,6 +125,68 @@ describe('ResourceDetailPage', () => {
expect(screen.queryByText('no_shift')).not.toBeInTheDocument();
});
/**
* وقتی هیچ روزی شیفت ندارد، ۱۴ سطرِ یکسان نویز است و با یک حالت خالی جمع می‌شود.
* شرط باید تنگ بماند: تست بالا ثابت می‌کند دلیلِ غیر از `no_shift` سطرها را نگه می‌دارد.
*/
it('پیش‌نمایشِ کاملاً تعریف‌نشده را در یک حالت خالی جمع می‌کند', async () => {
mockApi(emptyDays(), [
{ date: 1785529800, day_of_week: 0, intervals: [], total_minutes: 0, reasons: ['no_shift'] },
{ date: 1785616200, day_of_week: 1, intervals: [], total_minutes: 0, reasons: ['no_shift'] },
]);
renderPage('/admin/resources/r1?tab=exceptions');
await waitFor(() =>
expect(screen.getByText(/در دو هفتهٔ آینده هیچ ساعتی باز نیست/)).toBeInTheDocument());
expect(screen.queryByText('شیفتی تعریف نشده')).not.toBeInTheDocument();
});
/** نوار ذخیره فقط وقتی ظاهر می‌شود که چیزی تغییر کرده باشد — خودش نشانهٔ dirty است. */
it('نوار ذخیره تا وقتی تغییری نباشد نمی‌آید', async () => {
const user = userEvent.setup();
mockApi();
renderPage('/admin/resources/r1?tab=hours');
await waitFor(() => expect(screen.getByText('شنبه')).toBeInTheDocument());
expect(screen.queryByRole('button', { name: 'ذخیرهٔ شیفت‌ها' })).not.toBeInTheDocument();
await user.click(screen.getAllByRole('button', { name: 'شیفت' })[0]);
expect(await screen.findByText('تغییرات شیفت ذخیره نشده است')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'ذخیرهٔ شیفت‌ها' })).toBeInTheDocument();
});
/** «بازگرداندن» باید به نسخهٔ سرور برگردد، نه صرفاً آخرین ویرایش را لغو کند. */
it('بازگرداندن، draft را به نسخهٔ سرور برمی‌گرداند', async () => {
const user = userEvent.setup();
mockApi();
renderPage('/admin/resources/r1?tab=hours');
await waitFor(() => expect(screen.getByText('شنبه')).toBeInTheDocument());
await user.click(screen.getAllByRole('button', { name: 'شیفت' })[0]);
await user.click(await screen.findByRole('button', { name: 'بازگرداندن' }));
await waitFor(() =>
expect(screen.queryByText('تغییرات شیفت ذخیره نشده است')).not.toBeInTheDocument());
expect(screen.getAllByText('بدون شیفت — این روز بسته است')).toHaveLength(7);
});
/** پرتکرارترین حالت یک ساعتِ یکسان برای کل هفته است؛ بدون کپی، ۱۵ تعامل لازم بود. */
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 }];
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: 'کپی شیفت‌های شنبه به همهٔ روزهای هفته' }));
await waitFor(() => expect(screen.getAllByDisplayValue('09:00')).toHaveLength(7));
expect(screen.getAllByDisplayValue('17:00')).toHaveLength(7);
expect(screen.queryByText('بدون شیفت — این روز بسته است')).not.toBeInTheDocument();
});
/** پیش‌نمایش نباید «وقت قابل رزرو» خوانده شود — نوبت‌ها هنوز کسر نشده‌اند. */
it('پیش‌نمایش را خام معرفی می‌کند', async () => {
mockApi();