# انتخاب تاریخ تولد به‌صورت مرحله‌ای: سال ← ماه ← روز ## پروژه `nobat724_front` (سایت عمومی، داشبورد کاربر). > کاملاً frontend است. هیچ تغییری در بک‌اند یا قرارداد API لازم نیست؛ خروجی همان رشته‌ی جلالی فعلی است. ## زمینه در داشبورد (`/dashboard` → اطلاعات کاربری)، فیلد «تاریخ تولد» از `components/common/JalaliDatePicker` استفاده می‌کند که فقط یک نمای **ماهانه** دارد: هدر فقط «ماه سال» را نشان می‌دهد و با فلش‌ها فقط ماه‌به‌ماه جلو/عقب می‌رود. برای انتخاب سال تولد (مثلاً ۱۳۷۰) کاربر باید ده‌ها بار فلش بزند — تجربه‌ی بدی برای تاریخ تولد است. خواسته: تقویمِ تاریخ تولد باید مرحله‌ای باشد — **اول سال، بعد ماه، بعد روز**. ## مشکل / هدف افزودن یک حالتِ انتخابِ مرحله‌ای (year → month → day) به `JalaliDatePicker` به‌صورت **opt-in با prop**، و فعال‌کردن آن فقط برای فیلد تاریخ تولد. سایر استفاده‌ها (انتخاب تاریخ نوبت و پنل) باید **دست‌نخورده** بمانند. ## فایل‌های مرتبط | فایل | نقش | |------|-----| | `components/common/JalaliDatePicker.js` | date picker جلالیِ مشترک — افزودن حالت مرحله‌ای | | `components/dashboard/userAccount/detailUser/information/form/DateBirthday.js` | فیلد تاریخ تولد — فعال‌کردن حالت جدید با prop | > **هشدار سازگاری:** `JalaliDatePicker` در این فایل‌ها هم استفاده می‌شود و نباید رفتارشان تغییر کند: > `app/component/DatePickerContent.js`, `app/component/date/datePicker/date/FirstDatePicker.js`, `.../SecondDatePicker.js`, `components/layoutPanel/userDetail/Date.js`. پس حالت جدید باید پیش‌فرض **خاموش** باشد. ## وضعیت فعلی (کد واقعی) `JalaliDatePicker.js` — فقط نمای ماهانه. هدر و ناوبری: ```jsx const handlePrevMonth = () => setDisplayDate(moment(displayDate).subtract(1, "jMonth")); const handleNextMonth = () => setDisplayDate(moment(displayDate).add(1, "jMonth")); // ... // هدر: فقط ماه و سال + دو فلش ماه {MONTHS[displayDate.jMonth()]} {displayDate.jYear()} // ... سپس گرید روزها ``` `MONTHS` (۱۲ ماه جلالی) از قبل در همین فایل تعریف شده. `moment` = `moment-jalaali`؛ متدها: `jYear()`, `jMonth()`, `jDate()`, `moment.jDaysInMonth(y, m)`. `DateBirthday.js`: ```jsx changeData(convertToJalali(e._d), "birthday")} textFieldProps={{ /* CalendarEdit icon */ }} /> ``` ## وظایف ### ۱. افزودن حالت مرحله‌ای به `JalaliDatePicker` - یک prop جدید بگیر: `stepwise = false` (پیش‌فرض خاموش تا سازگاری حفظ شود). - یک state داخلی `viewMode` با مقادیر `"year" | "month" | "day"`. وقتی Popover با `stepwise=true` باز می‌شود، `viewMode` روی `"year"` شروع شود؛ در غیر این صورت رفتار فعلی (مستقیم نمای روز) حفظ شود. - **نمای سال:** یک گرید از سال‌ها (مثلاً ۱۲ سال در هر صفحه، با دو فلش برای صفحه‌ی قبل/بعدِ بازه‌ی سال‌ها). بازه‌ی منطقی برای تولد: از `currentJalaliYear - 100` تا `currentJalaliYear`. انتخاب سال → `displayDate` با آن سال به‌روز شود و `viewMode = "month"`. - **نمای ماه:** گرید ۱۲ ماه از `MONTHS`. انتخاب ماه → `displayDate` با آن ماه، و `viewMode = "day"`. - **نمای روز:** همان گرید روزهای فعلی (بدون تغییر). انتخاب روز → `onChange` صدا زده شود و Popover بسته شود (مثل حالا). - در هدرِ حالت مرحله‌ای، عنوان قابل‌کلیک باشد تا کاربر بتواند به مرحله‌ی بالاتر برگردد: در نمای ماه، کلیک روی سال → برگشت به نمای سال؛ در نمای روز، کلیک روی «ماه سال» → برگشت به نمای ماه. (ناوبری رو به عقب) - وقتی Popover بسته شد، `viewMode` برای بار بعد دوباره `"year"` شود. طرح کلی: ```jsx function JalaliDatePicker({ /* ...props */, stepwise = false }) { const [viewMode, setViewMode] = useState(stepwise ? "year" : "day"); // باز شدن popover (stepwise): setViewMode("year") // بسته شدن: setViewMode(stepwise ? "year" : "day") // نمای سال const renderYears = () => { /* گرید سال‌ها currentYear-100..currentYear */ }; // نمای ماه const renderMonths = () => { /* گرید MONTHS، onClick → setDisplayDate(jMonth) + setViewMode("day") */ }; // نمای روز = همان رندر فعلی // در بدنه‌ی Popover: // stepwise ? (viewMode==="year" ? renderYears() : viewMode==="month" ? renderMonths() : renderDays()) // : renderDays() } ``` - منطق `value`/`selectedDate`/`onChange` و خروجی (همان `moment` object که `DateBirthday` با `e._d` و `convertToJalali` مصرف می‌کند) **بدون تغییر** بماند. ### ۲. فعال‌کردن در `DateBirthday.js` فقط prop اضافه کن: ```jsx changeData(convertToJalali(e._d), "birthday")} textFieldProps={{ /* بدون تغییر */ }} /> ``` ## نکات مهم - **سازگاری عقب‌رو:** `stepwise` پیش‌فرض `false`؛ هیچ‌یک از ۴ مصرف‌کننده‌ی دیگر (تاریخ نوبت/پنل) نباید رفتارشان عوض شود. این را با grep تأیید کن و دست به آن فایل‌ها نزن. - خروجی `onChange` دقیقاً همان شیء `moment` فعلی باشد تا `convertToJalali(e._d)` در `DateBirthday` و مصرف بک‌اند (`birthday`/`date_of_birth`) نشکند. - بازه‌ی سال‌ها برای تولد: `[امسالِ جلالی - 100, امسالِ جلالی]`، نزولی (سال‌های جدیدتر بالا) یا صعودی — هرکدام UX بهتری دارد؛ پیش‌فرض نزولی منطقی‌تر است. - RTL، فونت Vazir، MUI v5 (`Box`/`Popover`/`IconButton` که از قبل import شده‌اند)؛ کتابخانه‌ی جدید اضافه نکن. از `MONTHS` و `moment-jalaali` موجود در همان فایل استفاده کن. - اعداد فارسی/لاتین: مطابق رفتار فعلی فایل (`usePersianDigits: false`) نگه‌دار تا یک‌دست بماند. - بعد از تغییر: `npm run build` بدون خطا؛ دستی تست کن — در داشبورد فیلد تاریخ تولد: کلیک → ابتدا گرید سال‌ها، انتخاب سال → ماه‌ها، انتخاب ماه → روزها، انتخاب روز → مقدار در فیلد ست شود؛ و یک فیلد تاریخِ نوبت را هم چک کن که هنوز مثل قبل (مستقیم نمای روز) کار می‌کند.