diff --git a/.claude/skills/qa-clinicpro/driver.mjs b/.claude/skills/qa-clinicpro/driver.mjs index cfacc455..5c870e92 100644 --- a/.claude/skills/qa-clinicpro/driver.mjs +++ b/.claude/skills/qa-clinicpro/driver.mjs @@ -227,9 +227,16 @@ async function withPage(url, opts, fn) { state: { token: access_token, refreshToken: refresh_token, isAuthenticated: true }, version: 0, }; + // `--ui '{"darkMode":true,"density":"compact"}'` تم را پیش از اولین رندر می‌کارد. + const ui = opts.ui + ? `localStorage.setItem('clinicpro-ui', ${JSON.stringify( + JSON.stringify({ state: JSON.parse(opts.ui), version: 0 }), + )});` + : ''; + await S('Runtime.evaluate', { expression: `localStorage.setItem('clinicpro-auth', ${JSON.stringify(JSON.stringify(auth))}); - localStorage.setItem('pwa-dismissed','1');`, + localStorage.setItem('pwa-dismissed','1');${ui}`, }); // Errors before this point belong to the login page, not the page under test. @@ -458,6 +465,9 @@ const opts = { wait: Number(flag('wait', 4000)), full: argv.includes('--full'), body: flag('body', null), + // تم و چگالی در `localStorage['clinicpro-ui']` می‌نشینند و بدون seed کردنشان + // دارک‌مود و حالت فشرده اصلاً قابل اسکرین‌شات نیستند. + ui: flag('ui', null), }; try { diff --git a/assets/admin/components/AppointmentSegmentsCard.test.tsx b/assets/admin/components/AppointmentSegmentsCard.test.tsx index 15d0cf5a..38a90dc6 100644 --- a/assets/admin/components/AppointmentSegmentsCard.test.tsx +++ b/assets/admin/components/AppointmentSegmentsCard.test.tsx @@ -37,7 +37,8 @@ describe('AppointmentSegmentsCard', () => { renderWithProviders(); - await waitFor(() => expect(screen.getByText('60 دقیقه')).toBeInTheDocument()); + // ارقام فارسی‌اند: ۲۰ + ۴۰ = ۶۰ + await waitFor(() => expect(screen.getByText('۶۰ دقیقه')).toBeInTheDocument()); }); /** ⭐ مدتی که بیمار روی صندلی نیست باید دیده شود، وگرنه «۹۰ دقیقه» گمراه‌کننده است. */ diff --git a/assets/admin/components/AppointmentSegmentsCard.tsx b/assets/admin/components/AppointmentSegmentsCard.tsx index e2dacf02..d9b793aa 100644 --- a/assets/admin/components/AppointmentSegmentsCard.tsx +++ b/assets/admin/components/AppointmentSegmentsCard.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useAppointmentSegments } from '../hooks/useResourceBooking'; +import { formatNumber } from '../lib/utils'; const timeOf = (ts: number) => new Date(ts * 1000).toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' }); @@ -23,14 +24,14 @@ export default function AppointmentSegmentsCard({ appointmentUuid }: { appointme

بخش‌های نوبت

- {total} دقیقه + {formatNumber(total)} دقیقه
{segments.map((s) => (
{segments.map((s) => (
  • - {s.sequence} + {formatNumber(s.sequence)} {s.name} {timeOf(s.starts_at)} – {timeOf(s.ends_at)} diff --git a/assets/admin/components/ResourceBlocksModal.tsx b/assets/admin/components/ResourceBlocksModal.tsx index 0b930e8f..cf48301e 100644 --- a/assets/admin/components/ResourceBlocksModal.tsx +++ b/assets/admin/components/ResourceBlocksModal.tsx @@ -89,7 +89,7 @@ export default function ResourceBlocksModal({ resourceUuid, resourceName, onClos

    -
    +
    @@ -121,7 +121,7 @@ export default function ResourceBlocksModal({ resourceUuid, resourceName, onClos
    -
    +
    {/* ── گروه‌ها ───────────────────────────────────────────────────────── */} -
    +

    گروه‌های انتخاب

    @@ -71,7 +71,7 @@ export default function ServiceGroupsTab({ serviceUuid, canEdit, initialRelation {canEdit && (
    -
    +
    -
    +
    {/* ── روابط ─────────────────────────────────────────────────────────── */} -
    +

    ناسازگاری و پیش‌نیاز

    @@ -299,7 +299,7 @@ export default function ServiceGroupsTab({ serviceUuid, canEdit, initialRelation
    {/* ── پیش‌نمایش زنده ────────────────────────────────────────────────── */} -
    +

    پیش‌نمایش انتخاب

    diff --git a/assets/admin/components/ServiceSegmentsTab.tsx b/assets/admin/components/ServiceSegmentsTab.tsx index a9189fd4..4c6ecc67 100644 --- a/assets/admin/components/ServiceSegmentsTab.tsx +++ b/assets/admin/components/ServiceSegmentsTab.tsx @@ -141,7 +141,7 @@ export default function ServiceSegmentsTab({ serviceUuid, canEdit }: Props) { return (
    -
    +

    بخش‌های نوبت

    @@ -378,9 +378,9 @@ export default function ServiceSegmentsTab({ serviceUuid, canEdit }: Props) {
    {/* ── نوار پیش‌نمایش زمانی ──────────────────────────────────────────── */} -
    +
    -
    +
    -
    +
    {loading && در حال بارگذاری…} -
    +
    -
    +
    {mode === 'percent' && ( -
    +
    +
    @@ -123,7 +123,7 @@ export default function CancellationPolicyPage() { اعتبار پکیج پس از لغو برمی‌گردد -
    +
    {!draft.uuid && ( -
    +
    )} -
    +
    ( -
    +
    {draft && (
    -
    +
    -
    +
    -
    +
    -
    +
    -
    +
    -
    -
    +
    +
    setDays(String(v ?? '30'))} options={RANGES} />
    diff --git a/assets/admin/pages/PolicyFormPage.tsx b/assets/admin/pages/PolicyFormPage.tsx index fda095ca..072271d8 100644 --- a/assets/admin/pages/PolicyFormPage.tsx +++ b/assets/admin/pages/PolicyFormPage.tsx @@ -72,7 +72,7 @@ export default function PolicyFormPage() { backTo="/admin/policies" /> -
    +
    -
    +
    -
    +
    -
    +
    {template?.inputs.map((input) => ( -
    +
    ) : ( <> -
    +
    {draft && (
    -
    +
    -
    +
    -
    +
    setDraft({ ...draft, valid_from: isoToUnix(iso) ?? draft.valid_from })} />
    -
    +
    -
    -
    +
    +
    -
    +
    -
    +
    {error && ( -
    +
    {error instanceof ApiError ? error.message : 'جستجوی وقت ناموفق بود'}
    )} {result && ( -
    +
    - مدت نوبت: {result.plan.total_minutes} دقیقه + مدت نوبت: {formatNumber(result.plan.total_minutes)} دقیقه - {result.plan.segments.length} بخش · {result.slots.length} وقت پیدا شد + {formatNumber(result.plan.segments.length)} بخش · {formatNumber(result.slots.length)} وقت پیدا شد
    @@ -215,7 +215,7 @@ export default function ResourceBookingPage() { )} {result && result.slots.length > 0 && ( -
    +
    @@ -262,7 +262,7 @@ export default function ResourceBookingPage() { )} {pickedSlot && ( -
    +

    {formatDate(pickedSlot.start)} · {timeOf(pickedSlot.start)} @@ -301,7 +301,7 @@ export default function ResourceBookingPage() { {/* در جابه‌جایی پزشک عوض نمی‌شود؛ پرسیدنش یعنی دعوت به تغییری که خواسته نشده. */} {!rebookUuid && ( -
    +
    - setName(e.target.value)} placeholder="دستگاه لیزر" /> + setName(e.target.value)} placeholder="دستگاه لیزر" />