+ );
+}
+```
+
+- `min`/`max` را حذف کن (استفادهای ندارند). اگر خواستی امنتر باشی، نگهشان دار ولی
+ بدون اثر — ترجیح: حذف، مطابق قاعدهی «کد مرده ننویس».
+- استایل لایهی visible دقیقاً همان مقادیر فعلی فایل بماند (height 36، `--border`،
+ `--surface`، `minWidth 148`، fontSize 13، رنگ placeholder با `--text-3`).
+
+### ۲. فعالکردن انتخاب سال برای تاریخ تولد
+
+در `pages/PatientRecordFormPage.tsx:132` (فیلد `birth_date`) پراپ `enableYearPicker` را بده
+تا کاربر بتواند سریع سال تولد را انتخاب کند:
+
+```tsx
+ form.setValue('birth_date', v)} enableYearPicker />
+```
+
+(الگوی مشابه از قبل در `PatientRecordInfoForm.tsx:133` با `PersianDatePicker … enableYearPicker` هست.)
+
+### ۳. رفع همپوشانی SOLID (اختیاری ولی توصیهشده)
+
+بعد از این تغییر، `PersianDateInput` و `PersianDatePicker` تقریباً یکی میشوند
+(هر دو = لایهی متنی + PersianCalendar). برای پرهیز از دوگانگی:
+- گزینهی ساده: `PersianDateInput` را یک روکش نازک روی `PersianDatePicker` کن
+ (`return `)، یا
+- در همین تسک فقط رفتار را یکی کن و در کامنت بالای فایل اشاره کن که این دو باید
+ در آینده ادغام شوند. حذف کامل یکی از آنها → نیازمند بهروزرسانی همهی importها است؛
+ اگر انجامش میدهی، همهی call siteها را هم اصلاح کن و tscرا سبز نگه دار.
+
+## نکات مهم
+
+- بعد از تغییر، حتماً تایپچک: `ddev exec npx tsc --noEmit --project tsconfig.json` باید سبز شود.
+- خروجی `PersianCalendar.onChange` همان `YYYY-MM-DD` میلادی است؛ قرارداد دادهی ارسالی
+ به API تغییر نمیکند — فقط UI تقویم شمسی میشود. رفتار submit/فیلترها نباید عوض شود.
+- `DoctorDetailPage.tsx` یک `PersianDateInput` **محلیِ درونفایل** دارد (تعریف حدود خط ۱۷۷)
+ که با `jalaali-js` از قبل شمسی است و پراپ `minDate` دارد؛ به فایل مشترک ربطی ندارد — دست نزن.
+- تستها: اگر تستی برای `PersianDateInput` هست، آپدیت کن؛ در غیر این صورت یک تست کوتاه
+ Vitest اضافه کن که کلیک روی input، پیکر شمسی را باز میکند و انتخاب روز، `onChange`
+ با `YYYY-MM-DD` را صدا میزند (حالت موفق + پاککردن مقدار).
+- تغییرِ فقط-UI است؛ backend و `docs/api/*` نیاز به تغییر ندارند.
diff --git a/assets/admin/components/ui/PersianDateInput.test.tsx b/assets/admin/components/ui/PersianDateInput.test.tsx
new file mode 100644
index 00000000..f9556533
--- /dev/null
+++ b/assets/admin/components/ui/PersianDateInput.test.tsx
@@ -0,0 +1,43 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen, fireEvent } from '@testing-library/react';
+import PersianDateInput from '@/components/ui/PersianDateInput';
+
+describe('PersianDateInput', () => {
+ it('placeholder را وقتی مقدار خالی است نشان میدهد', () => {
+ render();
+ expect(screen.getByText('از تاریخ')).toBeInTheDocument();
+ });
+
+ it('از تقویم شمسی استفاده میکند نه input بومی میلادی', () => {
+ const { container } = render();
+ expect(container.querySelector('input[type="date"]')).toBeNull();
+ });
+
+ it('با کلیک، تقویم شمسی باز میشود (نام ماه فارسی)', () => {
+ const { container } = render();
+ fireEvent.click((container.firstChild as HTMLElement).firstChild as Element);
+ // 2024-03-25 میلادی = ۶ فروردین ۱۴۰۳ شمسی
+ expect(screen.getByText('فروردین')).toBeInTheDocument();
+ });
+
+ it('انتخاب روز، onChange را با YYYY-MM-DD میلادی صدا میزند', () => {
+ const onChange = vi.fn();
+ const { container } = render();
+ fireEvent.click((container.firstChild as HTMLElement).firstChild as Element);
+ const target = Array.from(container.querySelectorAll('button')).find(
+ (b) => b.textContent?.trim() === '۱۵',
+ );
+ expect(target).toBeTruthy();
+ fireEvent.click(target as Element);
+ expect(onChange).toHaveBeenCalledWith(expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/));
+ });
+
+ it('دکمه پاککردن، onChange با رشته خالی میفرستد', () => {
+ const onChange = vi.fn();
+ const { container } = render();
+ const svgs = container.querySelectorAll('svg');
+ const clearIcon = svgs[svgs.length - 1];
+ fireEvent.click(clearIcon.parentElement as Element);
+ expect(onChange).toHaveBeenCalledWith('');
+ });
+});
diff --git a/assets/admin/components/ui/PersianDateInput.tsx b/assets/admin/components/ui/PersianDateInput.tsx
index 10360233..6116745d 100644
--- a/assets/admin/components/ui/PersianDateInput.tsx
+++ b/assets/admin/components/ui/PersianDateInput.tsx
@@ -1,69 +1,17 @@
-import React, { useRef } from 'react';
-import { CalendarDaysIcon, XMarkIcon } from '@heroicons/react/24/outline';
-import { formatDate } from '../../lib/utils';
+import PersianDatePicker from './PersianDatePicker';
interface Props {
- value: string;
+ value: string; // YYYY-MM-DD میلادی
onChange: (v: string) => void;
placeholder?: string;
- min?: string;
- max?: string;
- style?: React.CSSProperties;
- className?: string;
+ /** انتخاب سال→ماه→روز را فعال میکند (مناسب تاریخ تولد). */
+ enableYearPicker?: boolean;
}
-export default function PersianDateInput({ value, onChange, placeholder = 'انتخاب تاریخ', min, max, style, className }: Props) {
- const hiddenRef = useRef(null);
-
- const open = () => {
- const el = hiddenRef.current;
- if (!el) return;
- if (typeof el.showPicker === 'function') {
- try { el.showPicker(); } catch { el.focus(); }
- } else {
- el.focus();
- }
- };
-
- return (
-