feat: Refactor specialty display logic and enhance specialty filtering

- Introduced SpecialtyChips component to manage the display of doctor's specialties with a primary specialty and a count of additional specialties.
- Updated ItemDoctor component to utilize SpecialtyChips for better UI presentation.
- Enhanced PosterLight and Poster components to display primary specialties and a text line for sub-specialties.
- Implemented nextSpecialtyFilter function to improve specialty selection logic in the Content component.
- Updated search functionality to allow searching by both doctor name and specialty.
- Added new specialties to specialties.json for better coverage.
- Created sync-specialties script to synchronize specialties data with the backend during build.
- Added tests for new components and helper functions to ensure functionality and reliability.
This commit is contained in:
hamed
2026-08-08 17:19:22 +03:30
parent 94c22de8dd
commit 56e264e44c
16 changed files with 799 additions and 52 deletions
+41 -8
View File
@@ -267,20 +267,53 @@ export function clearDoctorClinicParams(router, slug) {
const newUrl = `/clinic/${clinicslug}`;
router.push(newUrl)
}
/** گزینهٔ «کل گروه» در فهرست زیرتخصص‌ها؛ با id تهی، چون حالتش نبودِ زیرتخصص است. */
export const allOfCategoryOption = (category) => ({
id: null,
name: `همه تخصص‌های ${category.name}`,
isAll: true,
});
/**
* فیلتر بعدی وقتی کاربر گروه یا زیرتخصص را عوض می‌کند.
*
* تابع خالص است چون همین قاعده بود که شکسته بود: انتخاب یک گروه بی‌صدا اولین
* زیرتخصصش را می‌نشاند و جستجوی کاربر را تنگ می‌کرد. داخل کامپوننت، تست‌پذیر نبود.
*/
export const nextSpecialtyFilter = (filter, name, value) => {
const next = { ...filter, [name]: value };
// گروه یعنی کل گروه، نه اولین فرزندش.
if (name === "category") next.specialty = null;
// «همه تخصص‌های X» زیرتخصص واقعی نیست؛ حالتش همان نبودِ زیرتخصص است. اگر خودش
// در فیلتر می‌نشست، نامش در URL می‌رفت و چون در specialties.json نیست، با رفرش
// یا اشتراک لینک بازسازی نمی‌شد.
if (name === "specialty" && value?.isAll) next.specialty = null;
return next;
};
export const filterList = (data) => {
const parentList = specialties.filter((item) => !item.parent_id);
const childrenList = specialties.filter((item) => item.parent_id);
const filteredChildrenList =
data && data.category
? childrenList.filter(
(item) => String(item.parent_id) === String(data.category.id)
)
: [];
if (!data?.category) {
return { parentList, childrenList: [] };
}
const ofCategory = childrenList.filter(
(item) => String(item.parent_id) === String(data.category.id)
);
// «همه» اول فهرست می‌نشیند تا برگشت از یک زیرتخصص به کل گروه ممکن باشد.
// خودش وارد فیلتر نمی‌شود؛ انتخابش یعنی specialty تهی، و آن‌وقت QueryForDoctorsReq
// به category.id برمی‌گردد که بک‌اند به همهٔ زیرشاخه‌ها گسترشش می‌دهد.
return {
parentList: parentList,
childrenList: filteredChildrenList,
parentList,
childrenList: ofCategory.length
? [allOfCategoryOption(data.category), ...ofCategory]
: [],
};
};