+145
-105
src/Den.Client.Web/src/components/app-sidebar.tsx
+145
-105
src/Den.Client.Web/src/components/app-sidebar.tsx
···
7
7
import { t } from "i18next";
8
8
import { Link } from "@tanstack/react-router";
9
9
import { useAuth } from "@/lib/state/auth";
10
10
+
import { useEffect, useState } from "react";
11
11
+
import { useBudgetsListQuery } from "@/lib/state/queries/budgets";
10
12
11
13
type MenuItem = {
12
14
type: 'group';
···
26
28
icon?: LucideIcon;
27
29
};
28
30
29
29
-
const items = [
30
30
-
{
31
31
-
type: 'group',
32
32
-
title: t('menu.home.title'),
33
33
-
children: [
34
34
-
{
35
35
-
type: 'link',
36
36
-
title: t('menu.home.dashboard'),
37
37
-
url: '/',
38
38
-
icon: Home
39
39
-
}
40
40
-
],
41
41
-
},
31
31
+
export const AppSidebar = () => {
32
32
+
const [items, setItems] = useState<MenuItem[]>([
33
33
+
{
34
34
+
type: 'group',
35
35
+
title: t('menu.home.title'),
36
36
+
children: [
37
37
+
{
38
38
+
type: 'link',
39
39
+
title: t('menu.home.dashboard'),
40
40
+
url: '/',
41
41
+
icon: Home
42
42
+
}
43
43
+
],
44
44
+
},
42
45
43
43
-
{
44
44
-
type: 'group',
45
45
-
title: t('menu.organisation.title'),
46
46
-
children: [
47
47
-
{
48
48
-
type: 'link',
49
49
-
title: t('menu.organisation.groceries'),
50
50
-
url: '#',
51
51
-
icon: ShoppingBasketIcon,
52
52
-
badge: 15,
53
53
-
},
54
54
-
{
55
55
-
type: 'link',
56
56
-
title: t('menu.organisation.calendar'),
57
57
-
url: '#',
58
58
-
icon: CalendarIcon,
59
59
-
badge: 3,
60
60
-
},
61
61
-
{
62
62
-
type: 'link',
63
63
-
title: t('menu.organisation.reminders'),
64
64
-
url: '#',
65
65
-
icon: LightbulbIcon,
66
66
-
badge: 10,
67
67
-
},
68
68
-
{
69
69
-
type: 'link',
70
70
-
title: t('menu.organisation.recipes'),
71
71
-
url: '#',
72
72
-
icon: UtensilsIcon,
73
73
-
badge: 56
74
74
-
},
75
75
-
],
76
76
-
},
46
46
+
{
47
47
+
type: 'group',
48
48
+
title: t('menu.organisation.title'),
49
49
+
children: [
50
50
+
{
51
51
+
type: 'link',
52
52
+
title: t('menu.organisation.groceries'),
53
53
+
url: '#',
54
54
+
icon: ShoppingBasketIcon,
55
55
+
badge: 15,
56
56
+
},
57
57
+
{
58
58
+
type: 'link',
59
59
+
title: t('menu.organisation.calendar'),
60
60
+
url: '#',
61
61
+
icon: CalendarIcon,
62
62
+
badge: 3,
63
63
+
},
64
64
+
{
65
65
+
type: 'link',
66
66
+
title: t('menu.organisation.reminders'),
67
67
+
url: '#',
68
68
+
icon: LightbulbIcon,
69
69
+
badge: 10,
70
70
+
},
71
71
+
{
72
72
+
type: 'link',
73
73
+
title: t('menu.organisation.recipes'),
74
74
+
url: '#',
75
75
+
icon: UtensilsIcon,
76
76
+
badge: 56
77
77
+
},
78
78
+
],
79
79
+
},
77
80
78
78
-
{
79
79
-
type: 'group',
80
80
-
title: t('menu.budgeting.title'),
81
81
-
children: [
82
82
-
{
83
83
-
type: 'submenu',
84
84
-
title: t('menu.budgeting.budgets'),
85
85
-
icon: CirclePoundSterlingIcon,
86
86
-
children: [
87
87
-
{
88
88
-
type: 'link',
89
89
-
title: 'Household',
90
90
-
url: '#',
91
91
-
},
92
92
-
{
93
93
-
type: 'link',
94
94
-
title: 'Grocery',
95
95
-
url: '#',
96
96
-
},
97
97
-
{
98
98
-
type: 'link',
99
99
-
title: 'Bills & Services',
100
100
-
url: '#',
101
101
-
},
102
102
-
{
103
103
-
type: 'link',
104
104
-
title: 'Disposable Income',
105
105
-
url: '#',
106
106
-
},
107
107
-
{
108
108
-
type: 'link',
109
109
-
title: t('menu.budgeting.allBudgets'),
110
110
-
url: '/budgets',
111
111
-
},
112
112
-
]
113
113
-
},
114
114
-
],
115
115
-
},
81
81
+
{
82
82
+
type: 'group',
83
83
+
title: t('menu.budgeting.title'),
84
84
+
children: [
85
85
+
{
86
86
+
type: 'submenu',
87
87
+
title: t('menu.budgeting.budgets'),
88
88
+
icon: CirclePoundSterlingIcon,
89
89
+
children: [
90
90
+
{
91
91
+
type: 'link',
92
92
+
title: t('menu.budgeting.allBudgets'),
93
93
+
url: '/budgets',
94
94
+
},
95
95
+
]
96
96
+
},
97
97
+
],
98
98
+
},
116
99
117
117
-
{
118
118
-
type: 'group',
119
119
-
title: t('menu.admin.title'),
120
120
-
children: [
121
121
-
{
122
122
-
type: 'link',
123
123
-
title: t('menu.admin.settings'),
124
124
-
url: '#',
125
125
-
icon: CogIcon,
126
126
-
},
127
127
-
{
128
128
-
type: 'link',
129
129
-
title: t('menu.admin.users'),
130
130
-
url: '#',
131
131
-
icon: UsersIcon,
132
132
-
},
133
133
-
],
134
134
-
},
135
135
-
] as MenuItem[];
100
100
+
{
101
101
+
type: 'group',
102
102
+
title: t('menu.admin.title'),
103
103
+
children: [
104
104
+
{
105
105
+
type: 'link',
106
106
+
title: t('menu.admin.settings'),
107
107
+
url: '#',
108
108
+
icon: CogIcon,
109
109
+
},
110
110
+
{
111
111
+
type: 'link',
112
112
+
title: t('menu.admin.users'),
113
113
+
url: '#',
114
114
+
icon: UsersIcon,
115
115
+
},
116
116
+
],
117
117
+
},
118
118
+
]);
136
119
137
137
-
export const AppSidebar = () => {
138
120
const { logout } = useAuth();
139
121
const { data, isLoading } = useMeQuery();
122
122
+
const { data: budgetsData } = useBudgetsListQuery();
123
123
+
124
124
+
useEffect(() => {
125
125
+
if (budgetsData) {
126
126
+
setItems((prevItems) => {
127
127
+
const budgetingGroupIndex = prevItems.findIndex(
128
128
+
(item) => item.type === 'group' && item.title === t('menu.budgeting.title')
129
129
+
);
130
130
+
131
131
+
if (budgetingGroupIndex === -1) return prevItems;
132
132
+
133
133
+
const budgetingGroup = prevItems[budgetingGroupIndex];
134
134
+
if (budgetingGroup.type !== 'group') return prevItems;
135
135
+
136
136
+
const budgetsSubmenuIndex = budgetingGroup.children.findIndex(
137
137
+
(child) => child.type === 'submenu' && child.title === t('menu.budgeting.budgets')
138
138
+
);
139
139
+
140
140
+
if (budgetsSubmenuIndex === -1) return prevItems;
141
141
+
142
142
+
const budgetsSubmenu = budgetingGroup.children[budgetsSubmenuIndex];
143
143
+
if (budgetsSubmenu.type !== 'submenu') return prevItems;
144
144
+
145
145
+
const dynamicBudgetItems: MenuItem[] = budgetsData.map((budget) => ({
146
146
+
type: 'link',
147
147
+
title: budget.displayName,
148
148
+
url: `/budgets/${budget.id}`,
149
149
+
}));
150
150
+
151
151
+
const updatedBudgetsSubmenu = {
152
152
+
...budgetsSubmenu,
153
153
+
children: [
154
154
+
{
155
155
+
type: 'link' as const,
156
156
+
title: t('menu.budgeting.allBudgets'),
157
157
+
url: '/budgets',
158
158
+
},
159
159
+
...dynamicBudgetItems,
160
160
+
],
161
161
+
};
162
162
+
163
163
+
const updatedBudgetingGroup = {
164
164
+
...budgetingGroup,
165
165
+
children: [
166
166
+
...budgetingGroup.children.slice(0, budgetsSubmenuIndex),
167
167
+
updatedBudgetsSubmenu,
168
168
+
...budgetingGroup.children.slice(budgetsSubmenuIndex + 1),
169
169
+
],
170
170
+
};
171
171
+
172
172
+
return [
173
173
+
...prevItems.slice(0, budgetingGroupIndex),
174
174
+
updatedBudgetingGroup,
175
175
+
...prevItems.slice(budgetingGroupIndex + 1),
176
176
+
];
177
177
+
});
178
178
+
}
179
179
+
}, [budgetsData]);
140
180
141
181
return (
142
182
<Sidebar>