diff --git a/src/Den.Client.Web/src/components/app-sidebar.tsx b/src/Den.Client.Web/src/components/app-sidebar.tsx index e9d559a..c6d5303 100644 --- a/src/Den.Client.Web/src/components/app-sidebar.tsx +++ b/src/Den.Client.Web/src/components/app-sidebar.tsx @@ -7,6 +7,8 @@ import { useMeQuery } from "@/lib/state/queries/auth"; import { t } from "i18next"; import { Link } from "@tanstack/react-router"; import { useAuth } from "@/lib/state/auth"; +import { useEffect, useState } from "react"; +import { useBudgetsListQuery } from "@/lib/state/queries/budgets"; type MenuItem = { type: 'group'; @@ -26,117 +28,155 @@ type MenuItem = { icon?: LucideIcon; }; -const items = [ - { - type: 'group', - title: t('menu.home.title'), - children: [ - { - type: 'link', - title: t('menu.home.dashboard'), - url: '/', - icon: Home - } - ], - }, +export const AppSidebar = () => { + const [items, setItems] = useState([ + { + type: 'group', + title: t('menu.home.title'), + children: [ + { + type: 'link', + title: t('menu.home.dashboard'), + url: '/', + icon: Home + } + ], + }, - { - type: 'group', - title: t('menu.organisation.title'), - children: [ - { - type: 'link', - title: t('menu.organisation.groceries'), - url: '#', - icon: ShoppingBasketIcon, - badge: 15, - }, - { - type: 'link', - title: t('menu.organisation.calendar'), - url: '#', - icon: CalendarIcon, - badge: 3, - }, - { - type: 'link', - title: t('menu.organisation.reminders'), - url: '#', - icon: LightbulbIcon, - badge: 10, - }, - { - type: 'link', - title: t('menu.organisation.recipes'), - url: '#', - icon: UtensilsIcon, - badge: 56 - }, - ], - }, + { + type: 'group', + title: t('menu.organisation.title'), + children: [ + { + type: 'link', + title: t('menu.organisation.groceries'), + url: '#', + icon: ShoppingBasketIcon, + badge: 15, + }, + { + type: 'link', + title: t('menu.organisation.calendar'), + url: '#', + icon: CalendarIcon, + badge: 3, + }, + { + type: 'link', + title: t('menu.organisation.reminders'), + url: '#', + icon: LightbulbIcon, + badge: 10, + }, + { + type: 'link', + title: t('menu.organisation.recipes'), + url: '#', + icon: UtensilsIcon, + badge: 56 + }, + ], + }, - { - type: 'group', - title: t('menu.budgeting.title'), - children: [ - { - type: 'submenu', - title: t('menu.budgeting.budgets'), - icon: CirclePoundSterlingIcon, - children: [ - { - type: 'link', - title: 'Household', - url: '#', - }, - { - type: 'link', - title: 'Grocery', - url: '#', - }, - { - type: 'link', - title: 'Bills & Services', - url: '#', - }, - { - type: 'link', - title: 'Disposable Income', - url: '#', - }, - { - type: 'link', - title: t('menu.budgeting.allBudgets'), - url: '/budgets', - }, - ] - }, - ], - }, + { + type: 'group', + title: t('menu.budgeting.title'), + children: [ + { + type: 'submenu', + title: t('menu.budgeting.budgets'), + icon: CirclePoundSterlingIcon, + children: [ + { + type: 'link', + title: t('menu.budgeting.allBudgets'), + url: '/budgets', + }, + ] + }, + ], + }, - { - type: 'group', - title: t('menu.admin.title'), - children: [ - { - type: 'link', - title: t('menu.admin.settings'), - url: '#', - icon: CogIcon, - }, - { - type: 'link', - title: t('menu.admin.users'), - url: '#', - icon: UsersIcon, - }, - ], - }, -] as MenuItem[]; + { + type: 'group', + title: t('menu.admin.title'), + children: [ + { + type: 'link', + title: t('menu.admin.settings'), + url: '#', + icon: CogIcon, + }, + { + type: 'link', + title: t('menu.admin.users'), + url: '#', + icon: UsersIcon, + }, + ], + }, + ]); -export const AppSidebar = () => { const { logout } = useAuth(); const { data, isLoading } = useMeQuery(); + const { data: budgetsData } = useBudgetsListQuery(); + + useEffect(() => { + if (budgetsData) { + setItems((prevItems) => { + const budgetingGroupIndex = prevItems.findIndex( + (item) => item.type === 'group' && item.title === t('menu.budgeting.title') + ); + + if (budgetingGroupIndex === -1) return prevItems; + + const budgetingGroup = prevItems[budgetingGroupIndex]; + if (budgetingGroup.type !== 'group') return prevItems; + + const budgetsSubmenuIndex = budgetingGroup.children.findIndex( + (child) => child.type === 'submenu' && child.title === t('menu.budgeting.budgets') + ); + + if (budgetsSubmenuIndex === -1) return prevItems; + + const budgetsSubmenu = budgetingGroup.children[budgetsSubmenuIndex]; + if (budgetsSubmenu.type !== 'submenu') return prevItems; + + const dynamicBudgetItems: MenuItem[] = budgetsData.map((budget) => ({ + type: 'link', + title: budget.displayName, + url: `/budgets/${budget.id}`, + })); + + const updatedBudgetsSubmenu = { + ...budgetsSubmenu, + children: [ + { + type: 'link' as const, + title: t('menu.budgeting.allBudgets'), + url: '/budgets', + }, + ...dynamicBudgetItems, + ], + }; + + const updatedBudgetingGroup = { + ...budgetingGroup, + children: [ + ...budgetingGroup.children.slice(0, budgetsSubmenuIndex), + updatedBudgetsSubmenu, + ...budgetingGroup.children.slice(budgetsSubmenuIndex + 1), + ], + }; + + return [ + ...prevItems.slice(0, budgetingGroupIndex), + updatedBudgetingGroup, + ...prevItems.slice(budgetingGroupIndex + 1), + ]; + }); + } + }, [budgetsData]); return (