feat(appointments): enhance doctor and secretary views with scheduling context and resource management
This commit is contained in:
@@ -233,15 +233,21 @@ describe('AppointmentsPage — منشی', () => {
|
||||
* منشی در هر دو ساختار باید تایملاین ببیند. لیست پزشکانِ مجاز از اندپوینت
|
||||
* احرازشدهٔ /my/clinic-doctors میآید (نه لیست عمومی کلینیک).
|
||||
*/
|
||||
function mockSecretary(doctors: { uuid: string; name: string }[], scope: string | null) {
|
||||
function mockSecretary(
|
||||
doctors: { uuid: string; name: string; has_schedule?: boolean }[],
|
||||
scope: string | null,
|
||||
resources: unknown[] = [],
|
||||
) {
|
||||
useAuthStore.setState({
|
||||
primaryRole: 'secretary',
|
||||
dbUuid: scope === 'clinic' ? 'clinic1' : 'doc1',
|
||||
context: scope ? { type: scope, scope } : null,
|
||||
availableContexts: [],
|
||||
} as any);
|
||||
get.mockImplementation((url?: string) => {
|
||||
if (typeof url !== 'string') return Promise.resolve({ success: true, data: [] });
|
||||
if (url.includes('today-stats')) return Promise.resolve({ success: true, data: { total: 11, completed: 2, waiting: 7, cancelled: 2 } });
|
||||
if (url.includes('/api/v1/resources')) return Promise.resolve({ success: true, data: resources });
|
||||
if (url.includes('/my/clinic-doctors')) return Promise.resolve({ success: true, data: { data: doctors } });
|
||||
if (url.includes('appointment-slots')) return Promise.resolve({ success: true, data: { sessions: [], empty_reason: 'holiday' } });
|
||||
if (url.includes('/my/appointments')) return Promise.resolve({ success: true, data: [], meta: { totalRecords: 0, totalPages: 0, currentPage: 1 } });
|
||||
@@ -280,4 +286,83 @@ describe('AppointmentsPage — منشی', () => {
|
||||
const usedPublicList = get.mock.calls.some((c: any[]) => typeof c[0] === 'string' && c[0].includes('/clinic/doctor-list/'));
|
||||
expect(usedPublicList).toBe(false);
|
||||
});
|
||||
|
||||
/** منشی هم باید همان پیام و همان میانبُرِ منابع را ببیند، نه تایملاین خالی. */
|
||||
it('منشی: پزشکِ بدون برنامه پیام میگیرد و منابعش قابل رزروند', async () => {
|
||||
mockSecretary([{ uuid: 'doc1', name: 'دکتر موسوی', has_schedule: false }], null, [
|
||||
{ uuid: 'r-9', name: 'لیزر', type_name: 'دستگاه', supervisor: { uuid: 'doc1', name: 'دکتر موسوی' } },
|
||||
]);
|
||||
renderWithProviders(<AppointmentsPage />);
|
||||
|
||||
expect(await screen.findByText('ساعت کاری تنظیم نشده است')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'ثبت نوبت' })).toBeInTheDocument();
|
||||
expect(screen.queryByText('این روز تعطیل است')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* پروفایل خودِ پزشک: تب پزشکان ندارد، پس تنها راهِ دانستنِ «برنامه ندارم» همان
|
||||
* `has_schedule`ِ /my/clinic-doctors است.
|
||||
*/
|
||||
describe('AppointmentsPage — پروفایل خود پزشک بدون برنامهٔ کاری', () => {
|
||||
function mockDoctor(hasSchedule: boolean, contexts: any[] = []) {
|
||||
useAuthStore.setState({
|
||||
primaryRole: 'doctor', dbUuid: 'doc1', doctorUuid: 'doc1',
|
||||
context: { type: 'doctor', db_uuid: 'doc1', name: 'مطب من', role: 'doctor' },
|
||||
availableContexts: contexts,
|
||||
} as any);
|
||||
get.mockImplementation((url?: string) => {
|
||||
if (typeof url !== 'string') return Promise.resolve({ success: true, data: [] });
|
||||
if (url.includes('today-stats')) return Promise.resolve({ success: true, data: { total: 0, completed: 0, waiting: 0, cancelled: 0 } });
|
||||
if (url.includes('/my/clinic-doctors')) {
|
||||
return Promise.resolve({ success: true, data: { data: [{ uuid: 'doc1', name: 'دکتر موسوی', has_schedule: hasSchedule }] } });
|
||||
}
|
||||
if (url.includes('appointment-slots')) return Promise.resolve({ success: true, data: { sessions: [], empty_reason: 'no_schedule' } });
|
||||
if (url.includes('/my/appointments')) return Promise.resolve({ success: true, data: [], meta: { totalRecords: 0, totalPages: 0, currentPage: 1 } });
|
||||
if (url.includes('/api/v1/resources')) return Promise.resolve({ success: true, data: [
|
||||
{ uuid: 'r-7', name: 'کندلا', type_name: 'دستگاه لیزر', supervisor: { uuid: 'doc1', name: 'دکتر موسوی' } },
|
||||
] });
|
||||
return Promise.resolve({ success: true, data: [] });
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => get.mockReset());
|
||||
|
||||
it('پیام «ساعت کاری تنظیم نشده است» و منابعِ قابل رزرو را نشان میدهد', async () => {
|
||||
mockDoctor(false);
|
||||
renderWithProviders(<AppointmentsPage />);
|
||||
|
||||
expect(await screen.findByText('ساعت کاری تنظیم نشده است')).toBeInTheDocument();
|
||||
expect(screen.getAllByRole('button', { name: 'کندلا' }).length).toBeGreaterThan(0);
|
||||
expect(screen.getByRole('button', { name: 'ثبت نوبت' })).toBeInTheDocument();
|
||||
// لینک تنظیمات به صفحهٔ خودِ پزشک میرود، نه به تنظیمات کلینیک.
|
||||
expect(screen.getByRole('link', { name: 'تنظیم ساعت کاری' })).toHaveAttribute('href', '/admin/appointment-settings');
|
||||
});
|
||||
|
||||
it('برنامهٔ کاری که باشد، تایملاین سرِ جایش میماند', async () => {
|
||||
mockDoctor(true);
|
||||
renderWithProviders(<AppointmentsPage />);
|
||||
|
||||
expect(await screen.findByText('برنامهٔ نوبتدهی ثبت نشده')).toBeInTheDocument();
|
||||
expect(screen.queryByText('ساعت کاری تنظیم نشده است')).toBeNull();
|
||||
});
|
||||
|
||||
/** منابعِ کلینیک در محیط کلینیکاند؛ «نیست» با «جای دیگر است» اشتباه نشود. */
|
||||
it('در مطب شخصی، محیطهای کلینیکیِ دیگر یادآوری میشوند', async () => {
|
||||
mockDoctor(false, [
|
||||
{ type: 'doctor', db_uuid: 'doc1', name: 'مطب من', role: 'doctor' },
|
||||
{ type: 'clinic', db_uuid: 'cl-1', name: 'مدیسا', role: 'doctor' },
|
||||
]);
|
||||
get.mockImplementation((url?: string) => {
|
||||
if (typeof url !== 'string') return Promise.resolve({ success: true, data: [] });
|
||||
if (url.includes('/my/clinic-doctors')) return Promise.resolve({ success: true, data: { data: [{ uuid: 'doc1', name: 'دکتر موسوی', has_schedule: false }] } });
|
||||
if (url.includes('today-stats')) return Promise.resolve({ success: true, data: { total: 0, completed: 0, waiting: 0, cancelled: 0 } });
|
||||
if (url.includes('/my/appointments')) return Promise.resolve({ success: true, data: [], meta: { totalRecords: 0, totalPages: 0, currentPage: 1 } });
|
||||
return Promise.resolve({ success: true, data: [] }); // منبعی در محیط شخصی نیست
|
||||
});
|
||||
renderWithProviders(<AppointmentsPage />);
|
||||
|
||||
expect(await screen.findByText(/مدیسا/)).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'تغییر محیط کاری' })).toHaveAttribute('href', '/admin/select-context');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user