fix(doctors): improve filter performance and resolve modal closing issues
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user