From e48ab9a974ad44a19590d86e4ef93b7115c2de0d Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Sun, 9 Aug 2026 07:56:48 +0330 Subject: [PATCH] feat(settings): implement grouped menu structure and update related components --- .../layout/PurchaseSubscriptionSidebar.tsx | 88 ++++++++------- .../components/layout/settingsMenu.test.ts | 76 +++++++++++++ .../admin/components/layout/settingsMenu.ts | 93 +++++++++++++--- .../pages/PracticeDomainSettingsPage.test.tsx | 60 +++++++++++ .../pages/PracticeDomainSettingsPage.tsx | 12 ++- assets/admin/pages/SettingsMenuPage.tsx | 100 ++++++++++-------- 6 files changed, 328 insertions(+), 101 deletions(-) create mode 100644 assets/admin/components/layout/settingsMenu.test.ts create mode 100644 assets/admin/pages/PracticeDomainSettingsPage.test.tsx diff --git a/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx b/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx index 4adf92ef..0404a26a 100644 --- a/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx +++ b/assets/admin/components/layout/PurchaseSubscriptionSidebar.tsx @@ -3,7 +3,7 @@ import { Link } from 'react-router'; import { SearchHeaderP } from '../../pages/subscriptionIcons'; import { useAuthStore } from '../../stores/authStore'; import { usePermissions } from '../../hooks/usePermissions'; -import { menuForRole, type SettingsMenuItem } from './settingsMenu'; +import { groupMenu, menuForRole, type SettingsMenuItem } from './settingsMenu'; /** * سایدبار تنظیمات — همان فهرستی که `SettingsMenuPage` روی موبایل نشان می‌دهد @@ -21,6 +21,7 @@ const SECURITY_ITEM: SettingsMenuItem = { key: 'security', label: 'تنظیمات', icon: () => null, + group: 'account', alwaysOpen: true, disabled: true, }; @@ -30,13 +31,18 @@ export default function PurchaseSubscriptionSidebar({ active }: { active: string const primaryRole = useAuthStore((s) => s.primaryRole); const scope = useAuthStore((s) => s.context?.scope); const { can } = usePermissions(); - const items = useMemo( - () => [ - ...menuForRole(primaryRole, can, scope).filter((i) => !HIDDEN_KEYS.has(i.key)), - SECURITY_ITEM, - ].filter((i) => i.label.includes(query.trim())), + // گروه‌ها بعد از فیلترِ جستجو ساخته می‌شوند تا تیترِ دسته‌ای که هیچ نتیجه‌ای ندارد + // بالای فضای خالی نماند. + const groups = useMemo( + () => groupMenu( + [ + ...menuForRole(primaryRole, can, scope).filter((i) => !HIDDEN_KEYS.has(i.key)), + SECURITY_ITEM, + ].filter((i) => i.label.includes(query.trim())), + ), [query, primaryRole, scope, can], ); + const itemCount = groups.reduce((sum, g) => sum + g.items.length, 0); return (