fix(doctors): improve filter performance and resolve modal closing issues

This commit is contained in:
hamed
2026-06-21 15:47:37 +03:30
parent 2fc74a664e
commit cb13ba3f45
10 changed files with 232 additions and 58 deletions
@@ -0,0 +1,196 @@
# فیکس کندی و باگ‌های فیلتر صفحه پزشکان
## پروژه
`nobat724_front`
## زمینه
صفحه `/doctors` بعد از `npm run build && npm run start` (production mode) سه مشکل دارد:
۱. سرعت کلی سایت کند می‌شود
۲. مودال انتخاب شهر/استان بعد از کلیک «تایید و ادامه» دیر بسته می‌شود و فیلتر با تاخیر اعمال می‌شود
۳. دسته‌بندی (category/specialty) در مودال فیلتر درست کار نمی‌کند
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `nobat724_front/app/component/modalSearchCity/Content.js` | مودال انتخاب شهر/استان — دکمه «تایید و ادامه» |
| `nobat724_front/app/component/modalSearchCity/index.js` | wrapper مودال شهر |
| `nobat724_front/components/doctors/modal/ButtonApply.js` | دکمه «اعمال تغییرات» در مودال فیلتر |
| `nobat724_front/components/doctors/modal/Content.js` | محتوای مودال فیلتر (category/specialty) |
| `nobat724_front/components/doctors/modal/form/index.js` | فرم فیلتر — CateSelector برای category و specialty |
| `nobat724_front/components/doctors/head/index.js` | `sendReq` — تابع اصلی fetch |
| `nobat724_front/helper/index.js` (خط ۴۲۰) | `QueryForDoctorsReq` — تبدیل filter به params |
| `nobat724_front/helper/index.js` (خط ۲۱۵) | `filterList` — تولید parentList و childrenList |
## وضعیت فعلی
### باگ ۱ — مودال شهر/استان دیر بسته می‌شود
`Content.js` خط ۲۴: `getStateInfoClient()` در هر render صدا زده می‌شود:
```js
// app/component/modalSearchCity/Content.js
const { matchedState } = getStateInfoClient();
```
و دکمه «تایید و ادامه» منتظر `sendReq()` می‌ماند قبل از بستن:
```js
const handleClick = () => {
setLoading(true);
sendReq().finally(() => {
setLoading(false);
handleClose(); // ← مودال فقط بعد از پایان fetch بسته می‌شود
});
};
```
`sendReq` در `head/index.js` یک HTTP request کامل است — تا پایان fetch مودال باز می‌ماند.
همچنین دو `disabled` prop روی دکمه تایید وجود دارد (یکی `loading` و یکی `!filter?.city || !filter?.state`) که در JSX اشتباه است — دومی override می‌کند.
### باگ ۲ — دسته‌بندی کار نمی‌کند
در `modal/Content.js`:
```js
function Content({ filter, setFilter, updateData, setDataInURL }) {
const changeSpecialty = (name, value) => {
const newFilter = { ...filter, [name]: value };
if (name === "category") {
const childrenList = specialties.filter((item) => item.parent);
const filteredChildrenList = childrenList.filter(
(item) => item.parent === value.id // ← value می‌تواند null باشد (وقتی clear می‌شود)
);
const firstChildren = filteredChildrenList[0];
newFilter.specialty = firstChildren || "";
}
setFilter(newFilter);
setDataInURL(newFilter);
return newFilter;
};
```
وقتی `value` (category) null است (کاربر انتخاب را پاک می‌کند)، `value.id` crash می‌کند.
و `filterList` در `helper/index.js`:
```js
export const filterList = (data) => {
const parentList = specialties.filter((item) => !item.parent);
const childrenList = specialties.filter((item) => item.parent);
const filteredChildrenList =
data && data.category
? childrenList.filter((item) => item.parent === data.category.id)
: [];
// ← item.parent (string از JSON) vs data.category.id (ممکن است number باشد)
```
`specialties.json` فیلد `parent` را به‌صورت string ذخیره می‌کند (مثلاً `"1"`) اما `category.id` ممکن است number باشد — type mismatch.
### باگ ۳ — کندی کلی
احتمال اصلی: `getStateInfoClient()` و `cities.filter()` و `states.find()` در هر render اجرا می‌شوند بدون memoization. همچنین `sendReq` در `ButtonApply` و `Content` هر دو منتظر کامل شدن fetch قبل از بستن مودال هستند.
## وظایف
### ۱. فیکس بستن سریع مودال شهر/استان
در `app/component/modalSearchCity/Content.js` مودال را فوری ببند و fetch در پس‌زمینه ادامه یابد:
```js
const handleClick = () => {
handleClose(); // فوری ببند
sendReq(); // fetch در background
};
```
همچنین دو `disabled` را روی دکمه یکی کن:
```jsx
<Button
disabled={!filter?.city || !filter?.state}
onClick={handleClick}
variant="contained"
>
```
### ۲. فیکس بستن سریع مودال فیلتر
در `components/doctors/modal/ButtonApply.js` همین الگو را اعمال کن:
```js
const handleClick = () => {
setOpen(false); // فوری ببند
sendReq(); // fetch در background
};
```
state `loading` را می‌توانی حذف کنی چون دیگر منتظر fetch نمی‌ماند.
### ۳. فیکس crash دسته‌بندی هنگام clear
در `components/doctors/modal/Content.js` خط مربوط به `value.id`:
```js
const changeSpecialty = (name, value) => {
const newFilter = { ...filter, [name]: value };
if (name === "category") {
if (value) {
const filteredChildrenList = specialties
.filter((item) => item.parent)
.filter((item) => String(item.parent) === String(value.id)); // ← String() برای type safety
newFilter.specialty = filteredChildrenList[0] || null;
} else {
newFilter.specialty = null; // clear category → clear specialty هم
}
}
setFilter(newFilter);
setDataInURL(newFilter);
return newFilter;
};
```
### ۴. فیکس type mismatch در filterList
در `helper/index.js` خط ۲۱۹:
```js
const filteredChildrenList =
data && data.category
? childrenList.filter(
(item) => String(item.parent) === String(data.category.id)
)
: [];
```
### ۵. بررسی کندی کلی
- در `app/component/modalSearchCity/index.js`، `useEffect` وابسته به `stateSelected` هر بار کل `cities` را filter می‌کند — با `useMemo` بهینه کن:
```js
const filteredCities = useMemo(() => {
if (!stateSelected) return [];
const selectedState = states.find((s) => s.name === stateSelected);
if (!selectedState) return [];
return cities.filter((c) => c.province_id === selectedState.id);
}, [stateSelected]);
// حذف useState و useEffect مربوطه
```
- `getStateInfoClient()` در `Content.js` را به بیرون از component ببر یا با `useMemo` cache کن.
## نکات مهم
- `specialties.json` فیلد `parent` را string ذخیره می‌کند (`"1"` نه `1`) — همیشه `String()` برای مقایسه استفاده کن
- مودال‌ها باید فوری بسته شوند (UX) و fetch در background ادامه یابد — کاربر نباید منتظر پاسخ API بماند
- `sendReq` در `head/index.js` یک Promise برمی‌گرداند — می‌توان بدون `await` صدا زد
- `disabled` دو بار روی یک `<Button>` در JSX: دومی اول override می‌کند — فقط یکی نگه‌دار
- بعد از تغییر، با `npm run build && npm run start` تست کن (نه dev mode)