Replace the placeholder row list on the patient detail «نوبتها» tab with the
card-grid design ported pixel-for-pixel from clinic-pro-tauri TurnsSection:
- New AppointmentTurnCard mirrors tauri TurnsCard (success icon, title, date/time
chips, personnel, status). Status uses the live AppointmentStatusDropdown
instead of the tauri mock.
- New AppointmentsTab in PatientDetailPage: sort/filter toolbar (client-side) +
reserve/new buttons linking to existing /admin/appointments pages + card grid.
- Add CalendarD/ClockP/UserD/StatusGlobe icons (verbatim from tauri).
- Backend: expose version on GET /patient/{uuid}/appointments so the status
dropdown can optimistic-lock. No new endpoint.
- Tests: PatientAppointmentsTest (shape/version/order/empty/ownership) +
AppointmentTurnCard + tab data/empty cases. docs/api/patient.md updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
1.8 KiB
TypeScript
39 lines
1.8 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { screen } from '@testing-library/react';
|
|
import { renderWithProviders } from '../test/utils';
|
|
|
|
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
|
|
vi.mock('../lib/api', () => ({
|
|
api: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn() },
|
|
ApiError: class extends Error {},
|
|
}));
|
|
|
|
import AppointmentTurnCard, { type AppointmentCardData } from './AppointmentTurnCard';
|
|
|
|
const base: AppointmentCardData = {
|
|
uuid: 'a1', starts_at: 1754000000, status: 'confirmed', version: 1,
|
|
doctor_name: 'دکتر ژیلا فتحی', service_name: null,
|
|
};
|
|
|
|
describe('AppointmentTurnCard', () => {
|
|
it('renders title, date/time labels, doctor and the live status label', () => {
|
|
renderWithProviders(<AppointmentTurnCard appointment={base} queryKey={['x']} />);
|
|
expect(screen.getByText('نوبت')).toBeInTheDocument(); // no service → generic title
|
|
expect(screen.getByText('تاریخ:')).toBeInTheDocument();
|
|
expect(screen.getByText('ساعت:')).toBeInTheDocument();
|
|
expect(screen.getByText('پرسنل:')).toBeInTheDocument();
|
|
expect(screen.getByText('دکتر ژیلا فتحی')).toBeInTheDocument();
|
|
expect(screen.getByText('قطعی شده')).toBeInTheDocument(); // confirmed via STATUS_META
|
|
});
|
|
|
|
it('falls back to «—» when the doctor is missing', () => {
|
|
renderWithProviders(<AppointmentTurnCard appointment={{ ...base, doctor_name: null }} queryKey={['x']} />);
|
|
expect(screen.getByText('—')).toBeInTheDocument();
|
|
});
|
|
|
|
it('prefers the service name as the title when present', () => {
|
|
renderWithProviders(<AppointmentTurnCard appointment={{ ...base, service_name: 'لیزر' }} queryKey={['x']} />);
|
|
expect(screen.getByText('لیزر')).toBeInTheDocument();
|
|
});
|
|
});
|