// منطق خالص انتخاب چند‌تخصصی برای پیکر درختی پروفایل پزشک. // تخصص‌ها درختی‌اند: انتخاب یک فرزند، والدش را هم نگه می‌دارد (والد صرفاً برای // گسترش درختی سمت سرور است) و والد فقط وقتی حذف می‌شود که هیچ فرزند دیگری از او // انتخاب نمانده باشد. جدا از کامپوننت نگه داشته شده تا مستقل تست شود. /** id فرزندهای هر والد. */ export type ChildMap = Record; const uniq = (ids: number[]): number[] => [...new Set(ids)]; /** toggle یک تخصصِ فرزند؛ والد را در صورت لزوم اضافه/حذف می‌کند. */ export function toggleSpecialtyChild( selected: number[], childId: number, parentId: number, childMap: ChildMap, ): number[] { if (selected.includes(childId)) { const siblings = childMap[parentId] ?? []; const otherSelected = siblings.some(k => k.id !== childId && selected.includes(k.id)); return selected.filter(id => id !== childId && (otherSelected || id !== parentId)); } return uniq([...selected, parentId, childId]); } /** toggle یک تخصصِ ریشه‌ایِ بدون فرزند. */ export function toggleSpecialtyRoot(selected: number[], rootId: number): number[] { return selected.includes(rootId) ? selected.filter(id => id !== rootId) : uniq([...selected, rootId]); } /** حذف یک chip — فقط همان تخصص (و والدِ بی‌فرزندش)، نه پاک‌کردن همه. */ export function removeSpecialtyEntry( selected: number[], childId: number, parentId: number | null, childMap: ChildMap, ): number[] { if (parentId !== null) { const siblings = childMap[parentId] ?? []; const otherSelected = siblings.some(k => k.id !== childId && selected.includes(k.id)); return selected.filter(id => id !== childId && (otherSelected || id !== parentId)); } return selected.filter(id => id !== childId); }