- 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.
59 lines
2.7 KiB
JavaScript
59 lines
2.7 KiB
JavaScript
/**
|
|
* قاعدهٔ مشترک نمایش تخصصهای پزشک — منبع واحد کارت و پوستر.
|
|
*
|
|
* پزشک میتواند چند تخصص داشته باشد و معمولاً هم دارد: ذخیرهٔ یک زیرتخصص در
|
|
* بکاند والدهایش را هم مینشاند، پس «جراح گوارش» عملاً یعنی «جراحی عمومی» +
|
|
* زیرشاخه. چاپ همهٔ نامها پشتسرهم، در موبایل ارتفاع کارت را باد میکند و در
|
|
* پوستر از کادر ثابت بیرون میزند.
|
|
*
|
|
* نمایش در دو جا متفاوت است — کارت `+N` کلیکشدنی دارد و پوستر ندارد — اما
|
|
* «کدام تخصص اصلی است» یک قاعده بیشتر نیست و اینجا میماند.
|
|
*/
|
|
|
|
const SEPARATOR = " · ";
|
|
|
|
/**
|
|
* تخصص «اصلی» و بقیه.
|
|
*
|
|
* ریشه (بدون `parent_id`) اصلی است: عنوانی است که بیمار میشناسد و چون هنگام
|
|
* ذخیره خودکار اضافه میشود تقریباً همیشه وجود دارد. اگر پزشکی فقط زیرتخصص داشت،
|
|
* اولین آیتم آرایه.
|
|
*
|
|
* @param {Array<{name?: string, parent_id?: string|number|null}>} list
|
|
* @returns {{primary: object|null, rest: Array<object>}}
|
|
*/
|
|
export function splitSpecialties(list) {
|
|
const items = (list ?? []).filter((s) => s?.name);
|
|
if (items.length === 0) return { primary: null, rest: [] };
|
|
|
|
const primary = items.find((s) => s.parent_id == null) ?? items[0];
|
|
|
|
return { primary, rest: items.filter((s) => s !== primary) };
|
|
}
|
|
|
|
/**
|
|
* زیرتخصصها بهشکل یک خط متنی، بریده روی مرز کلمه با بودجهٔ کاراکتر.
|
|
*
|
|
* پوستر کادر ثابت ۱۰۸۰×۱۳۵۰ با `overflow-hidden` دارد؛ هر ردیف اضافه بخشهای
|
|
* پایین را بیرون میاندازد. برش بر اساس طول متن است نه تعداد ثابت، چون
|
|
* «جراحی لاپاراسکوپی» و «قلب» یکاندازه جا نمیگیرند.
|
|
*
|
|
* @param {Array<{name?: string}>} rest
|
|
* @param {number} budget حداکثر کاراکترِ خط
|
|
* @returns {{text: string, hidden: number}}
|
|
*/
|
|
export function posterSpecialtyLine(rest, budget = 90) {
|
|
const names = (rest ?? []).filter((s) => s?.name).map((s) => s.name);
|
|
const shown = [];
|
|
let used = 0;
|
|
|
|
for (const name of names) {
|
|
const cost = name.length + (shown.length ? SEPARATOR.length : 0);
|
|
if (shown.length && used + cost > budget) break;
|
|
shown.push(name);
|
|
used += cost;
|
|
}
|
|
|
|
return { text: shown.join(SEPARATOR), hidden: names.length - shown.length };
|
|
}
|