@campxdev/react-blueprint 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/preview.tsx +2 -0
- package/package.json +16 -15
- package/src/App.tsx +7 -1
- package/src/assets/images/icons.tsx +123 -0
- package/src/components/DropDownMenu/MenuItemButton.tsx +3 -6
- package/src/components/DropDownMenu/styles.tsx +1 -1
- package/src/components/Layout/Header/AppHeader.stories.tsx +9 -12
- package/src/components/Layout/Header/AppHeader.tsx +3 -0
- package/src/components/Layout/Header/HeaderActions/CogWheelMenu.tsx +8 -6
- package/src/components/Layout/Header/HeaderActions/HeaderActions.tsx +25 -22
- package/src/components/Layout/Header/HeaderActions/UserBox.tsx +41 -66
- package/src/components/Layout/Header/styles/styles.tsx +14 -14
- package/src/components/Layout/LayoutWrapper/LayoutWrapper.stories.tsx +31 -0
- package/src/components/Layout/LayoutWrapper/LayoutWrapper.tsx +64 -0
- package/src/components/Layout/SideNavigation/SideNavigation.stories.tsx +30 -0
- package/src/components/Layout/SideNavigation/SideNavigation.tsx +111 -0
- package/src/components/Layout/SideNavigation/styles/styles.tsx +84 -0
- package/src/components/Modals/DialogButton.stories.tsx +2 -7
- package/src/themes/commonTheme.ts +1 -0
package/.storybook/preview.tsx
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@campxdev/react-blueprint",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"main": "./export.ts",
|
|
5
5
|
"private": false,
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@emotion/react": "^11.11.4",
|
|
8
8
|
"@emotion/styled": "^11.11.5",
|
|
9
|
-
"@mui/icons-material": "^5.
|
|
10
|
-
"@mui/material": "^5.
|
|
9
|
+
"@mui/icons-material": "^5.14.11",
|
|
10
|
+
"@mui/material": "^5.14.11",
|
|
11
11
|
"@testing-library/jest-dom": "^5.14.1",
|
|
12
12
|
"@testing-library/react": "^13.0.0",
|
|
13
13
|
"@testing-library/user-event": "^13.2.1",
|
|
14
14
|
"@types/jest": "^27.0.1",
|
|
15
15
|
"@types/node": "^16.7.13",
|
|
16
|
+
"react-error-boundary": "^3.1.4",
|
|
16
17
|
"@types/react": "^18.0.0",
|
|
17
18
|
"@types/react-dom": "^18.0.0",
|
|
18
19
|
"axios": "^1.7.2",
|
|
@@ -54,21 +55,21 @@
|
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
|
57
|
-
"@chromatic-com/storybook": "^1.4.0",
|
|
58
|
-
"@storybook/addon-essentials": "^8.1.1",
|
|
59
|
-
"@storybook/addon-interactions": "^8.1.1",
|
|
60
|
-
"@storybook/addon-links": "^8.1.1",
|
|
61
|
-
"@storybook/addon-mdx-gfm": "^8.1.1",
|
|
62
|
-
"@storybook/addon-onboarding": "^8.1.1",
|
|
63
|
-
"@storybook/blocks": "^8.1.1",
|
|
64
|
-
"@storybook/preset-create-react-app": "^8.1.1",
|
|
65
|
-
"@storybook/react": "^8.1.1",
|
|
66
|
-
"@storybook/react-webpack5": "^8.1.1",
|
|
67
|
-
"@storybook/test": "^8.1.1",
|
|
68
58
|
"@types/js-cookie": "^3.0.5",
|
|
59
|
+
"@chromatic-com/storybook": "^1.4.0",
|
|
60
|
+
"@storybook/addon-essentials": "^8.1.4",
|
|
61
|
+
"@storybook/addon-interactions": "^8.1.4",
|
|
62
|
+
"@storybook/addon-links": "^8.1.4",
|
|
63
|
+
"@storybook/addon-mdx-gfm": "^8.1.4",
|
|
64
|
+
"@storybook/addon-onboarding": "^8.1.4",
|
|
65
|
+
"@storybook/blocks": "^8.1.4",
|
|
66
|
+
"@storybook/preset-create-react-app": "^8.1.4",
|
|
67
|
+
"@storybook/react": "^8.1.4",
|
|
68
|
+
"@storybook/react-webpack5": "^8.1.4",
|
|
69
|
+
"@storybook/test": "^8.1.4",
|
|
69
70
|
"eslint-plugin-storybook": "^0.8.0",
|
|
70
71
|
"prop-types": "^15.8.1",
|
|
71
|
-
"storybook": "^8.1.
|
|
72
|
+
"storybook": "^8.1.4",
|
|
72
73
|
"webpack": "^5.91.0"
|
|
73
74
|
}
|
|
74
75
|
}
|
package/src/App.tsx
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import "./App.css";
|
|
2
|
+
import { AppHeader, AppsMenu } from "./components/export";
|
|
2
3
|
import Providers from "./contexts/Providers";
|
|
3
4
|
|
|
4
5
|
function App() {
|
|
5
6
|
return (
|
|
6
7
|
<Providers>
|
|
7
8
|
{/* <AppHeader clientLogo={""} fullName={""} userBoxActions={[]} /> */}
|
|
8
|
-
|
|
9
|
+
<AppHeader
|
|
10
|
+
appsMenu={<AppsMenu apps={[]} />}
|
|
11
|
+
clientLogo={""}
|
|
12
|
+
fullName={""}
|
|
13
|
+
userBoxActions={[]}
|
|
14
|
+
/>
|
|
9
15
|
</Providers>
|
|
10
16
|
);
|
|
11
17
|
}
|
|
@@ -191,3 +191,126 @@ export const ClogWheelIcon = () => {
|
|
|
191
191
|
</svg>
|
|
192
192
|
);
|
|
193
193
|
};
|
|
194
|
+
|
|
195
|
+
export const RightIcon = () => (
|
|
196
|
+
<svg
|
|
197
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
198
|
+
id="vuesax_linear_logout"
|
|
199
|
+
data-name="vuesax/linear/logout"
|
|
200
|
+
width="24"
|
|
201
|
+
height="24"
|
|
202
|
+
viewBox="0 0 24 24"
|
|
203
|
+
>
|
|
204
|
+
<g id="logout">
|
|
205
|
+
<g
|
|
206
|
+
id="Group_5120"
|
|
207
|
+
data-name="Group 5120"
|
|
208
|
+
transform="translate(3.614 9.381)"
|
|
209
|
+
>
|
|
210
|
+
<path
|
|
211
|
+
id="Vector"
|
|
212
|
+
d="M0,5.363,2.682,2.682,0,0"
|
|
213
|
+
transform="translate(8.045)"
|
|
214
|
+
fill="none"
|
|
215
|
+
stroke="#292d32"
|
|
216
|
+
stroke-linecap="round"
|
|
217
|
+
stroke-linejoin="round"
|
|
218
|
+
stroke-width="1.5"
|
|
219
|
+
/>
|
|
220
|
+
<path
|
|
221
|
+
id="Vector-2"
|
|
222
|
+
data-name="Vector"
|
|
223
|
+
d="M0,0H10.653"
|
|
224
|
+
transform="translate(0 2.682)"
|
|
225
|
+
fill="none"
|
|
226
|
+
stroke="#292d32"
|
|
227
|
+
stroke-linecap="round"
|
|
228
|
+
stroke-linejoin="round"
|
|
229
|
+
stroke-width="1.5"
|
|
230
|
+
/>
|
|
231
|
+
</g>
|
|
232
|
+
<path
|
|
233
|
+
id="Vector-3"
|
|
234
|
+
data-name="Vector"
|
|
235
|
+
d="M0,16.76A8.015,8.015,0,0,0,8.38,8.38,8.015,8.015,0,0,0,0,0"
|
|
236
|
+
transform="translate(12.246 3.62)"
|
|
237
|
+
fill="none"
|
|
238
|
+
stroke="#292d32"
|
|
239
|
+
stroke-linecap="round"
|
|
240
|
+
stroke-linejoin="round"
|
|
241
|
+
stroke-width="1.5"
|
|
242
|
+
/>
|
|
243
|
+
<path
|
|
244
|
+
id="Vector-4"
|
|
245
|
+
data-name="Vector"
|
|
246
|
+
d="M0,24H24V0H0Z"
|
|
247
|
+
transform="translate(0 0)"
|
|
248
|
+
fill="none"
|
|
249
|
+
opacity="0"
|
|
250
|
+
/>
|
|
251
|
+
</g>
|
|
252
|
+
</svg>
|
|
253
|
+
);
|
|
254
|
+
export const LeftIcon = () => (
|
|
255
|
+
<svg
|
|
256
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
257
|
+
width="24"
|
|
258
|
+
height="24"
|
|
259
|
+
viewBox="0 0 24 24"
|
|
260
|
+
>
|
|
261
|
+
<g
|
|
262
|
+
id="vuesax_linear_logout"
|
|
263
|
+
data-name="vuesax/linear/logout"
|
|
264
|
+
transform="translate(-364 -444)"
|
|
265
|
+
>
|
|
266
|
+
<g id="logout">
|
|
267
|
+
<g
|
|
268
|
+
id="Group_5120"
|
|
269
|
+
data-name="Group 5120"
|
|
270
|
+
transform="translate(373.659 453.381)"
|
|
271
|
+
>
|
|
272
|
+
<path
|
|
273
|
+
id="Vector"
|
|
274
|
+
d="M2.682,5.363,0,2.682,2.682,0"
|
|
275
|
+
transform="translate(0)"
|
|
276
|
+
fill="none"
|
|
277
|
+
stroke="#292d32"
|
|
278
|
+
stroke-linecap="round"
|
|
279
|
+
stroke-linejoin="round"
|
|
280
|
+
stroke-width="1.5"
|
|
281
|
+
/>
|
|
282
|
+
<path
|
|
283
|
+
id="Vector-2"
|
|
284
|
+
data-name="Vector"
|
|
285
|
+
d="M10.653,0H0"
|
|
286
|
+
transform="translate(0.073 2.682)"
|
|
287
|
+
fill="none"
|
|
288
|
+
stroke="#292d32"
|
|
289
|
+
stroke-linecap="round"
|
|
290
|
+
stroke-linejoin="round"
|
|
291
|
+
stroke-width="1.5"
|
|
292
|
+
/>
|
|
293
|
+
</g>
|
|
294
|
+
<path
|
|
295
|
+
id="Vector-3"
|
|
296
|
+
data-name="Vector"
|
|
297
|
+
d="M8.38,16.76A8.015,8.015,0,0,1,0,8.38,8.015,8.015,0,0,1,8.38,0"
|
|
298
|
+
transform="translate(367.374 447.62)"
|
|
299
|
+
fill="none"
|
|
300
|
+
stroke="#292d32"
|
|
301
|
+
stroke-linecap="round"
|
|
302
|
+
stroke-linejoin="round"
|
|
303
|
+
stroke-width="1.5"
|
|
304
|
+
/>
|
|
305
|
+
<path
|
|
306
|
+
id="Vector-4"
|
|
307
|
+
data-name="Vector"
|
|
308
|
+
d="M0,0H24V24H0Z"
|
|
309
|
+
transform="translate(388 468) rotate(180)"
|
|
310
|
+
fill="none"
|
|
311
|
+
opacity="0"
|
|
312
|
+
/>
|
|
313
|
+
</g>
|
|
314
|
+
</g>
|
|
315
|
+
</svg>
|
|
316
|
+
);
|
|
@@ -5,6 +5,7 @@ import { StyledMenuItem } from "./styles";
|
|
|
5
5
|
export type MenuItemButtonProps = {
|
|
6
6
|
icon?: ReactNode;
|
|
7
7
|
label: ReactNode;
|
|
8
|
+
sx?: any;
|
|
8
9
|
onClick: () => void;
|
|
9
10
|
};
|
|
10
11
|
|
|
@@ -12,14 +13,10 @@ export const MenuItemButton = ({
|
|
|
12
13
|
icon,
|
|
13
14
|
label,
|
|
14
15
|
onClick,
|
|
15
|
-
|
|
16
|
+
sx = {},
|
|
16
17
|
}: MenuItemButtonProps) => {
|
|
17
18
|
return (
|
|
18
|
-
<StyledMenuItem
|
|
19
|
-
sx={{ minWidth: "180px", width: "100%" }}
|
|
20
|
-
onClick={onClick}
|
|
21
|
-
{...props}
|
|
22
|
-
>
|
|
19
|
+
<StyledMenuItem sx={sx} onClick={onClick}>
|
|
23
20
|
{icon && <ListItemIcon>{icon}</ListItemIcon>}
|
|
24
21
|
<Typography variant="subtitle3">{label}</Typography>
|
|
25
22
|
</StyledMenuItem>
|
|
@@ -19,7 +19,7 @@ export const StyledIconButton = styled(IconButton, {
|
|
|
19
19
|
export const StyledMenuItem = styled(MenuItem)(({}) => ({
|
|
20
20
|
display: "flex",
|
|
21
21
|
alignItems: "center",
|
|
22
|
-
|
|
22
|
+
padding: "10px 16px",
|
|
23
23
|
gap: "5px",
|
|
24
24
|
"& .MuiListItemIcon-root": {
|
|
25
25
|
minWidth: "24px",
|
|
@@ -19,6 +19,10 @@ const meta: Meta<typeof AppHeader> = {
|
|
|
19
19
|
control: "text",
|
|
20
20
|
description: "The full name of the user.",
|
|
21
21
|
},
|
|
22
|
+
designation: {
|
|
23
|
+
control: "text",
|
|
24
|
+
description: "The Designation of the user.",
|
|
25
|
+
},
|
|
22
26
|
profileUrl: {
|
|
23
27
|
control: "text",
|
|
24
28
|
description: "The URL of the user's profile photo.",
|
|
@@ -60,6 +64,7 @@ export const Primary: Story = {
|
|
|
60
64
|
args: {
|
|
61
65
|
clientLogo: "https://via.placeholder.com/150",
|
|
62
66
|
fullName: "John Doe",
|
|
67
|
+
designation: "Head of the Department",
|
|
63
68
|
appsMenu: (
|
|
64
69
|
<AppsMenu
|
|
65
70
|
apps={[
|
|
@@ -78,9 +83,6 @@ export const Primary: Story = {
|
|
|
78
83
|
{ label: "Action 1", onClick: () => alert("Action 1 clicked") },
|
|
79
84
|
{ label: "Action 2", onClick: () => alert("Action 2 clicked") },
|
|
80
85
|
],
|
|
81
|
-
headerSx: {
|
|
82
|
-
position: "relative",
|
|
83
|
-
},
|
|
84
86
|
},
|
|
85
87
|
};
|
|
86
88
|
|
|
@@ -90,14 +92,12 @@ export const WithNoAppsMenu: Story = {
|
|
|
90
92
|
args: {
|
|
91
93
|
clientLogo: "https://via.placeholder.com/150",
|
|
92
94
|
fullName: "John Doe",
|
|
95
|
+
designation: "Head of the Department",
|
|
93
96
|
appsMenu: <AppsMenu apps={[]} />,
|
|
94
97
|
userBoxActions: [
|
|
95
98
|
{ label: "Action 1", onClick: () => alert("Action 1 clicked") },
|
|
96
99
|
{ label: "Action 2", onClick: () => alert("Action 2 clicked") },
|
|
97
100
|
],
|
|
98
|
-
headerSx: {
|
|
99
|
-
position: "relative",
|
|
100
|
-
},
|
|
101
101
|
},
|
|
102
102
|
};
|
|
103
103
|
|
|
@@ -107,6 +107,7 @@ export const WithActions: Story = {
|
|
|
107
107
|
args: {
|
|
108
108
|
clientLogo: "https://via.placeholder.com/150",
|
|
109
109
|
fullName: "John Doe",
|
|
110
|
+
designation: "Head of the Department",
|
|
110
111
|
appsMenu: (
|
|
111
112
|
<AppsMenu
|
|
112
113
|
apps={[
|
|
@@ -133,9 +134,6 @@ export const WithActions: Story = {
|
|
|
133
134
|
{ label: "Action 1", onClick: () => alert("Action 1 clicked") },
|
|
134
135
|
{ label: "Action 2", onClick: () => alert("Action 2 clicked") },
|
|
135
136
|
],
|
|
136
|
-
headerSx: {
|
|
137
|
-
position: "relative",
|
|
138
|
-
},
|
|
139
137
|
},
|
|
140
138
|
};
|
|
141
139
|
|
|
@@ -145,6 +143,7 @@ export const WithCustomHeaderActions: Story = {
|
|
|
145
143
|
args: {
|
|
146
144
|
clientLogo: "https://via.placeholder.com/150",
|
|
147
145
|
fullName: "John Doe",
|
|
146
|
+
designation: "Head of the Department",
|
|
148
147
|
appsMenu: (
|
|
149
148
|
<AppsMenu
|
|
150
149
|
apps={[
|
|
@@ -164,9 +163,6 @@ export const WithCustomHeaderActions: Story = {
|
|
|
164
163
|
{ label: "Action 1", onClick: () => alert("Action 1 clicked") },
|
|
165
164
|
{ label: "Action 2", onClick: () => alert("Action 2 clicked") },
|
|
166
165
|
],
|
|
167
|
-
headerSx: {
|
|
168
|
-
position: "relative",
|
|
169
|
-
},
|
|
170
166
|
},
|
|
171
167
|
};
|
|
172
168
|
|
|
@@ -176,6 +172,7 @@ export const WithClogWheel: Story = {
|
|
|
176
172
|
args: {
|
|
177
173
|
clientLogo: "https://via.placeholder.com/150",
|
|
178
174
|
fullName: "John Doe",
|
|
175
|
+
designation: "Head of the Department",
|
|
179
176
|
appsMenu: (
|
|
180
177
|
<AppsMenu
|
|
181
178
|
apps={[
|
|
@@ -15,6 +15,7 @@ export interface AppHeaderProps {
|
|
|
15
15
|
cogWheelMenu?: ReactNode[];
|
|
16
16
|
customHeaderActions?: ReactNode;
|
|
17
17
|
fullName: string;
|
|
18
|
+
designation?: string;
|
|
18
19
|
profileUrl?: string;
|
|
19
20
|
userBoxActions: {
|
|
20
21
|
label: ReactNode;
|
|
@@ -31,6 +32,7 @@ export const AppHeader = ({
|
|
|
31
32
|
actions = [],
|
|
32
33
|
appsMenu,
|
|
33
34
|
clientLogo,
|
|
35
|
+
designation,
|
|
34
36
|
cogWheelMenu = [],
|
|
35
37
|
customHeaderActions,
|
|
36
38
|
fullName,
|
|
@@ -55,6 +57,7 @@ export const AppHeader = ({
|
|
|
55
57
|
<HeaderActions
|
|
56
58
|
cogWheelMenu={cogWheelMenu}
|
|
57
59
|
fullName={fullName}
|
|
60
|
+
designation={designation}
|
|
58
61
|
userBoxActions={userBoxActions}
|
|
59
62
|
profileUrl={profileUrl}
|
|
60
63
|
actions={actions}
|
|
@@ -8,12 +8,14 @@ import { DropDownMenu } from "../../../DropDownMenu/DropDownMenu";
|
|
|
8
8
|
const CogWheelMenu = ({ menu }: { menu: ReactNode[] }) => {
|
|
9
9
|
return (
|
|
10
10
|
<>
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
<div>
|
|
12
|
+
<Divider
|
|
13
|
+
orientation="vertical"
|
|
14
|
+
variant="middle"
|
|
15
|
+
flexItem
|
|
16
|
+
sx={{ height: "20px" }}
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
17
19
|
|
|
18
20
|
<DropDownMenu
|
|
19
21
|
anchor={({ open }) => (
|
|
@@ -9,6 +9,7 @@ import UserBox from "./UserBox";
|
|
|
9
9
|
export interface HeaderActionsProps {
|
|
10
10
|
cogWheelMenu: ReactNode[];
|
|
11
11
|
fullName: string;
|
|
12
|
+
designation?: string;
|
|
12
13
|
userBoxActions: {
|
|
13
14
|
label: ReactNode;
|
|
14
15
|
icon?: ReactNode;
|
|
@@ -22,40 +23,42 @@ export interface HeaderActionsProps {
|
|
|
22
23
|
const HeaderActions = ({
|
|
23
24
|
cogWheelMenu,
|
|
24
25
|
fullName,
|
|
26
|
+
designation,
|
|
25
27
|
userBoxActions,
|
|
26
28
|
profileUrl = "",
|
|
27
29
|
actions = [],
|
|
28
30
|
profileSx = {},
|
|
29
31
|
}: HeaderActionsProps) => {
|
|
30
32
|
return (
|
|
31
|
-
<Stack direction="row" gap={
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
</IconButton>
|
|
33
|
+
<Stack direction="row" gap={1} alignItems={"center"}>
|
|
34
|
+
<IconButton
|
|
35
|
+
href={"https://campx.atlassian.net/servicedesk/customer/portal/2"}
|
|
36
|
+
target="_blank"
|
|
37
|
+
>
|
|
38
|
+
<HelpIcon />
|
|
39
|
+
</IconButton>
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
{actions.map((action, index) => (
|
|
42
|
+
<>
|
|
43
|
+
<div>
|
|
42
44
|
<Divider
|
|
43
45
|
orientation="vertical"
|
|
44
46
|
variant="middle"
|
|
45
47
|
flexItem
|
|
46
|
-
sx={{ height: "
|
|
48
|
+
sx={{ height: "20px" }}
|
|
47
49
|
/>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
</div>
|
|
51
|
+
{action}
|
|
52
|
+
</>
|
|
53
|
+
))}
|
|
54
|
+
{cogWheelMenu?.length ? <CogWheelMenu menu={cogWheelMenu} /> : null}
|
|
55
|
+
<UserBox
|
|
56
|
+
fullName={fullName}
|
|
57
|
+
designation={designation}
|
|
58
|
+
actions={userBoxActions}
|
|
59
|
+
profileUrl={profileUrl}
|
|
60
|
+
profileSx={profileSx}
|
|
61
|
+
/>
|
|
59
62
|
</Stack>
|
|
60
63
|
);
|
|
61
64
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { Stack, Typography } from "@mui/material";
|
|
1
2
|
import { ReactNode } from "react";
|
|
2
3
|
import { DropDownMenu } from "../../../DropDownMenu/DropDownMenu";
|
|
3
|
-
import {
|
|
4
|
+
import { MenuItemButton } from "../../../DropDownMenu/MenuItemButton";
|
|
5
|
+
import { StyledAvatar, StyledTypography } from "../styles/styles";
|
|
4
6
|
// import {
|
|
5
7
|
// activeDevices,
|
|
6
8
|
// changePassword,
|
|
@@ -26,11 +28,13 @@ const getStartingLetters = (text: string) => {
|
|
|
26
28
|
|
|
27
29
|
export default function UserBox({
|
|
28
30
|
fullName,
|
|
31
|
+
designation = "",
|
|
29
32
|
actions,
|
|
30
33
|
profileUrl,
|
|
31
34
|
profileSx = {},
|
|
32
35
|
}: {
|
|
33
36
|
fullName: string;
|
|
37
|
+
designation?: string;
|
|
34
38
|
actions: {
|
|
35
39
|
label: ReactNode;
|
|
36
40
|
icon?: ReactNode;
|
|
@@ -47,71 +51,42 @@ export default function UserBox({
|
|
|
47
51
|
{getStartingLetters(fullName)}
|
|
48
52
|
</StyledAvatar>
|
|
49
53
|
)}
|
|
50
|
-
menu={[
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// padding: 0,
|
|
87
|
-
// },
|
|
88
|
-
// },
|
|
89
|
-
// },
|
|
90
|
-
// },
|
|
91
|
-
// {
|
|
92
|
-
// label: "Change Password",
|
|
93
|
-
// actionType: "dialog",
|
|
94
|
-
// icon: (
|
|
95
|
-
// <img
|
|
96
|
-
// style={{ marginRight: "10px" }}
|
|
97
|
-
// src={changePassword.default}
|
|
98
|
-
// />
|
|
99
|
-
// ),
|
|
100
|
-
// content: ({ close }) => <ChangePassword close={close} />,
|
|
101
|
-
// contentTitle: "Change Password",
|
|
102
|
-
// },
|
|
103
|
-
// {
|
|
104
|
-
// label: "Logout",
|
|
105
|
-
// icon: (
|
|
106
|
-
// <img
|
|
107
|
-
// style={{ marginRight: "10px" }}
|
|
108
|
-
// src={logoutIcon.default}
|
|
109
|
-
// />
|
|
110
|
-
// ),
|
|
111
|
-
// onClick: logout,
|
|
112
|
-
// },
|
|
113
|
-
// ]
|
|
114
|
-
// }
|
|
54
|
+
menu={[
|
|
55
|
+
<MenuItemButton
|
|
56
|
+
label={
|
|
57
|
+
<Stack gap={0.5}>
|
|
58
|
+
<StyledTypography variant="subtitle3">Account</StyledTypography>
|
|
59
|
+
<Stack direction={"row"} gap={1}>
|
|
60
|
+
<StyledAvatar src={profileUrl ?? ""} sx={profileSx}>
|
|
61
|
+
{getStartingLetters(fullName)}
|
|
62
|
+
</StyledAvatar>
|
|
63
|
+
<Stack>
|
|
64
|
+
<Typography variant="subtitle3">{fullName}</Typography>
|
|
65
|
+
<Typography variant="caption">{designation}</Typography>
|
|
66
|
+
</Stack>
|
|
67
|
+
</Stack>
|
|
68
|
+
</Stack>
|
|
69
|
+
}
|
|
70
|
+
onClick={function (): void {
|
|
71
|
+
throw new Error("Function not implemented.");
|
|
72
|
+
}}
|
|
73
|
+
/>,
|
|
74
|
+
<MenuItemButton
|
|
75
|
+
label={
|
|
76
|
+
<Stack gap={0.5}>
|
|
77
|
+
<Typography variant="subtitle3">Account</Typography>
|
|
78
|
+
<Stack>
|
|
79
|
+
<StyledAvatar src={profileUrl ?? ""} sx={profileSx}>
|
|
80
|
+
{getStartingLetters(fullName)}
|
|
81
|
+
</StyledAvatar>
|
|
82
|
+
</Stack>
|
|
83
|
+
</Stack>
|
|
84
|
+
}
|
|
85
|
+
onClick={function (): void {
|
|
86
|
+
throw new Error("Function not implemented.");
|
|
87
|
+
}}
|
|
88
|
+
/>,
|
|
89
|
+
]}
|
|
115
90
|
/>
|
|
116
91
|
);
|
|
117
92
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Avatar, Box, styled } from "@mui/material";
|
|
1
|
+
import { Avatar, Box, Typography, styled } from "@mui/material";
|
|
2
2
|
import { Link } from "react-router-dom";
|
|
3
3
|
|
|
4
4
|
export const StyledContainer = styled(Box)(({ theme }) => ({
|
|
@@ -8,15 +8,7 @@ export const StyledContainer = styled(Box)(({ theme }) => ({
|
|
|
8
8
|
justifyContent: "space-between",
|
|
9
9
|
height: "60px",
|
|
10
10
|
margin: "auto",
|
|
11
|
-
|
|
12
|
-
width: "770px",
|
|
13
|
-
},
|
|
14
|
-
"@media (min-width: 1024px)": {
|
|
15
|
-
width: "1025px",
|
|
16
|
-
},
|
|
17
|
-
"@media (min-width: 1200px)": {
|
|
18
|
-
width: "1280px",
|
|
19
|
-
},
|
|
11
|
+
width: "90%",
|
|
20
12
|
}));
|
|
21
13
|
|
|
22
14
|
export const StyledHeader = styled("header")(({ theme }) => ({
|
|
@@ -62,8 +54,16 @@ export const StyledImageWrapper = styled(Box)(() => ({
|
|
|
62
54
|
}));
|
|
63
55
|
|
|
64
56
|
export const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
background: theme.palette.background.default,
|
|
58
|
+
cursor: "pointer",
|
|
59
|
+
height: "42px",
|
|
60
|
+
width: "42px",
|
|
61
|
+
border: `1px solid ${theme.palette.primary.main}`,
|
|
62
|
+
fontSize: "1rem",
|
|
63
|
+
fontWeight: "600",
|
|
64
|
+
color: theme.palette.primary.main,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
export const StyledTypography = styled(Typography)(({ theme }) => ({
|
|
68
|
+
color: theme.palette.text.secondary,
|
|
69
69
|
}));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { LayoutWrapper, LayoutWrapperProps } from "./LayoutWrapper";
|
|
3
|
+
|
|
4
|
+
// Define the default export with Meta type including the component type
|
|
5
|
+
const meta: Meta<typeof LayoutWrapper> = {
|
|
6
|
+
title: "Layout/LayoutWrapper",
|
|
7
|
+
component: LayoutWrapper,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
// argTypes: {
|
|
10
|
+
// menu: {
|
|
11
|
+
// control: "object",
|
|
12
|
+
// description: "Menu items to be displayed in the side navigation.",
|
|
13
|
+
// },
|
|
14
|
+
// },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof LayoutWrapper>;
|
|
19
|
+
|
|
20
|
+
// Primary story
|
|
21
|
+
export const Primary: Story = {
|
|
22
|
+
render: (args: LayoutWrapperProps) => <LayoutWrapper {...args} />,
|
|
23
|
+
args: {
|
|
24
|
+
menu: [
|
|
25
|
+
{ name: "Item 1", path: "/" },
|
|
26
|
+
{ name: "Item 2", path: "/item2" },
|
|
27
|
+
],
|
|
28
|
+
title: "Home",
|
|
29
|
+
children: <>hi</>,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Box, IconButton, Toolbar, Typography } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
import MenuIcon from "@mui/icons-material/Menu";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { LeftIcon, RightIcon } from "../../../assets/images/icons";
|
|
6
|
+
import { SideNavigation } from "../SideNavigation/SideNavigation";
|
|
7
|
+
|
|
8
|
+
export interface LayoutWrapperProps {
|
|
9
|
+
title?: string;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
showIcon?: boolean;
|
|
12
|
+
menu?: any;
|
|
13
|
+
}
|
|
14
|
+
export const LayoutWrapper = ({
|
|
15
|
+
children,
|
|
16
|
+
title,
|
|
17
|
+
showIcon = true,
|
|
18
|
+
menu,
|
|
19
|
+
}: LayoutWrapperProps) => {
|
|
20
|
+
const [open, setOpen] = useState<boolean>(
|
|
21
|
+
window.innerWidth > 1024 ? true : false
|
|
22
|
+
);
|
|
23
|
+
const [isHovered, setIsHovered] = useState<boolean>(false);
|
|
24
|
+
|
|
25
|
+
const handleDrawer = () => {
|
|
26
|
+
setOpen(!open);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Box width={"100%"}>
|
|
31
|
+
<Toolbar sx={{ paddingLeft: "0px !important" }}>
|
|
32
|
+
{showIcon && (
|
|
33
|
+
<IconButton
|
|
34
|
+
color="inherit"
|
|
35
|
+
aria-label="open drawer"
|
|
36
|
+
onClick={handleDrawer}
|
|
37
|
+
edge="start"
|
|
38
|
+
sx={{ mr: 0.5 }}
|
|
39
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
40
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
41
|
+
>
|
|
42
|
+
{open && isHovered ? (
|
|
43
|
+
<LeftIcon />
|
|
44
|
+
) : !open && isHovered ? (
|
|
45
|
+
<RightIcon />
|
|
46
|
+
) : (
|
|
47
|
+
<MenuIcon />
|
|
48
|
+
)}
|
|
49
|
+
</IconButton>
|
|
50
|
+
)}
|
|
51
|
+
<Typography variant="subtitle1" noWrap>
|
|
52
|
+
{title}
|
|
53
|
+
</Typography>
|
|
54
|
+
</Toolbar>
|
|
55
|
+
|
|
56
|
+
<SideNavigation
|
|
57
|
+
menu={menu}
|
|
58
|
+
children={children}
|
|
59
|
+
open={open}
|
|
60
|
+
handleDrawer={handleDrawer}
|
|
61
|
+
/>
|
|
62
|
+
</Box>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { SideNavigation, SideNavigationProps } from "./SideNavigation";
|
|
4
|
+
|
|
5
|
+
// Define the default export with Meta type including the component type
|
|
6
|
+
const meta: Meta<typeof SideNavigation> = {
|
|
7
|
+
title: "Layout/SideNavigation",
|
|
8
|
+
component: SideNavigation,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {
|
|
11
|
+
menu: {
|
|
12
|
+
control: "object",
|
|
13
|
+
description: "Menu items to be displayed in the side navigation.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof SideNavigation>;
|
|
20
|
+
|
|
21
|
+
// Primary story
|
|
22
|
+
export const Primary: Story = {
|
|
23
|
+
render: (args: SideNavigationProps) => <SideNavigation {...args} />,
|
|
24
|
+
args: {
|
|
25
|
+
menu: [
|
|
26
|
+
{ label: "Item 1", path: "/" },
|
|
27
|
+
{ label: "Item 2", path: "/item2" },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Box, ListItemIcon, ListItemText, Stack } from "@mui/material";
|
|
2
|
+
import { useMatch, useResolvedPath } from "react-router-dom";
|
|
3
|
+
import { Typography } from "../../Typography/Typography";
|
|
4
|
+
import {
|
|
5
|
+
Main,
|
|
6
|
+
StyledDrawer,
|
|
7
|
+
StyledLinkButton,
|
|
8
|
+
StyledList,
|
|
9
|
+
StyledListItem,
|
|
10
|
+
StyledListItemButton,
|
|
11
|
+
} from "./styles/styles";
|
|
12
|
+
|
|
13
|
+
export interface SideNavigationProps {
|
|
14
|
+
menu?: any;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
open?: any;
|
|
17
|
+
handleDrawer?: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MenuItemProps {
|
|
21
|
+
menuItem: {
|
|
22
|
+
name: string;
|
|
23
|
+
path: string;
|
|
24
|
+
icon: any;
|
|
25
|
+
permissionKey: string;
|
|
26
|
+
iconType: string;
|
|
27
|
+
};
|
|
28
|
+
index: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const SideNavigation = ({
|
|
32
|
+
menu,
|
|
33
|
+
children,
|
|
34
|
+
open,
|
|
35
|
+
handleDrawer,
|
|
36
|
+
}: SideNavigationProps) => {
|
|
37
|
+
return (
|
|
38
|
+
<Stack gap="20px" direction={"row"}>
|
|
39
|
+
<StyledDrawer
|
|
40
|
+
variant={window.innerWidth > 1024 ? "persistent" : "temporary"}
|
|
41
|
+
anchor="left"
|
|
42
|
+
open={open}
|
|
43
|
+
onClose={handleDrawer}
|
|
44
|
+
>
|
|
45
|
+
<StyledList>
|
|
46
|
+
{menu?.map((item: any, index: number) => (
|
|
47
|
+
<MenuItem menuItem={item} index={index} key={index} />
|
|
48
|
+
))}
|
|
49
|
+
</StyledList>
|
|
50
|
+
</StyledDrawer>
|
|
51
|
+
<Main open={open}>{children}</Main>
|
|
52
|
+
</Stack>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const MenuItem = ({ menuItem, index }: MenuItemProps) => {
|
|
57
|
+
const { path, icon: Icon, name, permissionKey, iconType } = menuItem;
|
|
58
|
+
|
|
59
|
+
let resolved = useResolvedPath(path);
|
|
60
|
+
// const permissions = PermissionsStore.useState((s) => s).permissions
|
|
61
|
+
let match = useMatch({ path: resolved.pathname, end: false });
|
|
62
|
+
|
|
63
|
+
// const hasAccess = permissionKey ? permissions[permissionKey] : accessIfNoKey
|
|
64
|
+
|
|
65
|
+
// if (!hasAccess) return null
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<StyledListItem key={path} disablePadding match={match}>
|
|
69
|
+
<StyledLinkButton
|
|
70
|
+
to={path}
|
|
71
|
+
style={{ width: "100%" }}
|
|
72
|
+
// onClick={() =>
|
|
73
|
+
// // sideNavStore.update((s) => {
|
|
74
|
+
// // s.active = index
|
|
75
|
+
// // })
|
|
76
|
+
// }
|
|
77
|
+
>
|
|
78
|
+
<StyledListItemButton>
|
|
79
|
+
<ListItemIcon
|
|
80
|
+
sx={{
|
|
81
|
+
minWidth: "16px",
|
|
82
|
+
marginRight: "8px",
|
|
83
|
+
display: "flex",
|
|
84
|
+
alignItems: "center",
|
|
85
|
+
justifyContent: "center",
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
<Box
|
|
89
|
+
sx={{
|
|
90
|
+
minWidth: "16px",
|
|
91
|
+
marginRight: "8px",
|
|
92
|
+
display: "flex",
|
|
93
|
+
alignItems: "center",
|
|
94
|
+
justifyContent: "center",
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{/* <GetSidenavIconByType
|
|
98
|
+
iconType={iconType}
|
|
99
|
+
color={match ? '#323167' : '#000'}
|
|
100
|
+
/> */}
|
|
101
|
+
{/* {getSidenavIconByType(iconType, 'red')} */}
|
|
102
|
+
</Box>
|
|
103
|
+
</ListItemIcon>
|
|
104
|
+
<ListItemText
|
|
105
|
+
primary={<Typography variant="subtitle3">{name}</Typography>}
|
|
106
|
+
/>
|
|
107
|
+
</StyledListItemButton>
|
|
108
|
+
</StyledLinkButton>
|
|
109
|
+
</StyledListItem>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Drawer, List, ListItem, ListItemButton, styled } from "@mui/material";
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
3
|
+
const drawerWidth: number = 240;
|
|
4
|
+
|
|
5
|
+
export const StyledDrawer = styled(Drawer)(() => ({
|
|
6
|
+
width: drawerWidth,
|
|
7
|
+
flexShrink: 0,
|
|
8
|
+
"& .MuiDrawer-paper": {
|
|
9
|
+
width: drawerWidth,
|
|
10
|
+
boxSizing: "border-box",
|
|
11
|
+
position: "unset",
|
|
12
|
+
transition: "none !important",
|
|
13
|
+
borderRight: "none !important",
|
|
14
|
+
borderRadius: "5px",
|
|
15
|
+
},
|
|
16
|
+
"@media (max-width: 1024px)": {
|
|
17
|
+
"& .MuiDrawer-paper": {
|
|
18
|
+
borderRadius: "0px",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
export const StyledList = styled(List)(({ theme }) => ({
|
|
24
|
+
backgroundColor: theme.palette.background.paper,
|
|
25
|
+
height: "calc(100vh - 120px)",
|
|
26
|
+
paddingTop: "20px",
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
interface StyledListItemProps {
|
|
30
|
+
match: any;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const StyledListItem = styled(ListItem)<StyledListItemProps>(
|
|
34
|
+
({ theme, match }) => ({
|
|
35
|
+
backgroundColor: match ? theme.palette.secondary.main : "none",
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
export const StyledListItemButton = styled(ListItemButton)(() => ({
|
|
39
|
+
alignItems: "center",
|
|
40
|
+
display: "flex",
|
|
41
|
+
paddingBottom: "4px",
|
|
42
|
+
paddingTop: "4px",
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
export const StyledLinkButton = styled(Link)({
|
|
46
|
+
textDecoration: "none",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const Main = styled("main", {
|
|
50
|
+
shouldForwardProp: (prop) => prop !== "open",
|
|
51
|
+
})<{
|
|
52
|
+
open?: boolean;
|
|
53
|
+
}>(({ theme, open }) => ({
|
|
54
|
+
padding: "25px",
|
|
55
|
+
transition: theme.transitions.create("margin", {
|
|
56
|
+
easing: theme.transitions.easing.sharp,
|
|
57
|
+
duration: theme.transitions.duration.leavingScreen,
|
|
58
|
+
}),
|
|
59
|
+
marginLeft: `-${drawerWidth}px`,
|
|
60
|
+
...(open && {
|
|
61
|
+
transition: theme.transitions.create("margin", {
|
|
62
|
+
easing: theme.transitions.easing.easeOut,
|
|
63
|
+
duration: theme.transitions.duration.enteringScreen,
|
|
64
|
+
}),
|
|
65
|
+
marginLeft: 0,
|
|
66
|
+
}),
|
|
67
|
+
width: "100%",
|
|
68
|
+
height: "calc(100vh - 120px)",
|
|
69
|
+
overflowY: "auto",
|
|
70
|
+
backgroundColor: theme.palette.background.paper,
|
|
71
|
+
borderRadius: "5px",
|
|
72
|
+
"&::-webkit-scrollbar": {
|
|
73
|
+
width: "0.4em",
|
|
74
|
+
height: "0.4em",
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
"&::-webkit-scrollbar-thumb": {
|
|
78
|
+
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
|
79
|
+
borderRadius: "3px",
|
|
80
|
+
},
|
|
81
|
+
"@media (max-width: 1024px)": {
|
|
82
|
+
marginLeft: 0,
|
|
83
|
+
},
|
|
84
|
+
}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Box, Button } from "@mui/material";
|
|
1
|
+
import { Box, Button, Typography } from "@mui/material";
|
|
2
2
|
import { Meta, StoryObj } from "@storybook/react/*";
|
|
3
3
|
import DialogButton, { DialogButtonProps } from "./DialogButton";
|
|
4
4
|
|
|
@@ -94,12 +94,7 @@ export const WithMaxWidthMd: Story = {
|
|
|
94
94
|
),
|
|
95
95
|
content: ({ close }: { close: (e: any) => void }) => (
|
|
96
96
|
<>
|
|
97
|
-
<
|
|
98
|
-
sx={{
|
|
99
|
-
height: "500px",
|
|
100
|
-
width: "100px",
|
|
101
|
-
}}
|
|
102
|
-
></Box>
|
|
97
|
+
<Typography> Hello</Typography>
|
|
103
98
|
</>
|
|
104
99
|
),
|
|
105
100
|
dialogProps: {
|