feat(get-user): keep custom bottom-nav slot choices across tenants

Merge stored bottom items from the shared catalog so selected menus are not reset to the four defaults.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-24 12:14:55 +03:30
co-authored by Cursor
parent abaacf5a99
commit 8f2f27b4a1
+60 -5
View File
@@ -31,6 +31,20 @@ export const KHANEGI_SAMPLE_BOTTOM: KhanegiNavItem[] = [
{ id: 'user', label: 'تنظیمات', icon: 'vuesax-linear:setting-2', route: 'user', order: 4, visible: true },
]
function cloneJson<T>(value: T): T {
return JSON.parse(JSON.stringify(value)) as T
}
export function getKhanegiBottomNavChoices(): KhanegiNavItem[] {
const byId = new Map<string, KhanegiNavItem>()
for (const item of KHANEGI_SAMPLE_BOTTOM) byId.set(item.id, cloneJson(item))
for (const item of KHANEGI_SAMPLE_SIDEBAR) {
if (item.id === 'home') continue
if (!byId.has(item.id)) byId.set(item.id, cloneJson(item))
}
return Array.from(byId.values())
}
export function mergeNavItemsFromSample(
sample: KhanegiNavItem[],
stored: unknown,
@@ -72,11 +86,52 @@ export function mergeNavItemsFromSample(
return kept.map((item, index) => ({ ...item, order: index + 1 }))
}
/** دقیقاً ۴ جایگاه؛ انتخاب ذخیره‌شده از کاتالوگ، بقیه از پیش‌فرض پر می‌شود */
export function mergeBottomNavSlots(stored: unknown): KhanegiNavItem[] {
const choices = getKhanegiBottomNavChoices()
const defaults = KHANEGI_SAMPLE_BOTTOM.slice(0, MAX_BOTTOM_NAV_SLOTS)
const byId = new Map(choices.map((item) => [item.id, item]))
const slots: KhanegiNavItem[] = []
const seen = new Set<string>()
const storedList = Array.isArray(stored) ? stored : []
for (const prev of storedList) {
if (slots.length >= MAX_BOTTOM_NAV_SLOTS) break
if (!prev || typeof prev !== 'object' || typeof prev.id !== 'string') continue
if (seen.has(prev.id)) continue
const base = byId.get(prev.id)
if (!base) continue
seen.add(prev.id)
slots.push({
...base,
label: prev.label || base.label,
icon: prev.icon || base.icon,
visible: typeof prev.visible === 'boolean' ? prev.visible : true,
query: prev.query ?? base.query,
})
}
for (const item of defaults) {
if (slots.length >= MAX_BOTTOM_NAV_SLOTS) break
if (seen.has(item.id)) continue
seen.add(item.id)
slots.push({ ...item, visible: true })
}
for (const item of choices) {
if (slots.length >= MAX_BOTTOM_NAV_SLOTS) break
if (seen.has(item.id)) continue
seen.add(item.id)
slots.push({ ...item, visible: true })
}
return slots.slice(0, MAX_BOTTOM_NAV_SLOTS).map((item, index) => ({
...item,
order: index + 1,
}))
}
export function applyKhanegiNavSample(navigation: Record<string, any>) {
navigation.sidebar = mergeNavItemsFromSample(KHANEGI_SAMPLE_SIDEBAR, navigation.sidebar)
navigation.bottom = mergeNavItemsFromSample(
KHANEGI_SAMPLE_BOTTOM.slice(0, MAX_BOTTOM_NAV_SLOTS),
navigation.bottom,
MAX_BOTTOM_NAV_SLOTS,
).slice(0, MAX_BOTTOM_NAV_SLOTS)
navigation.bottom = mergeBottomNavSlots(navigation.bottom)
}