Skip to content

Commit ea933c8

Browse files
Merge pull request #1342 from Code-A2Z/avdhesh/settings-page
Create & Setup Settings page
2 parents 5648699 + d8f043e commit ea933c8

33 files changed

Lines changed: 1753 additions & 566 deletions

File tree

client/src/App.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { memo, useEffect, useState, useMemo } from 'react';
2-
import { Provider } from 'jotai';
1+
import { memo, useEffect, useMemo } from 'react';
32
import { setupTokenRefresh } from './shared/utils/api-interceptor';
43
import { AppUnProtectedRoutes } from './modules/app/routes';
54
import { AppProtectedRoutes } from './modules/app/routes/auth-routes';
@@ -8,18 +7,13 @@ import { useAuth } from './shared/hooks/use-auth';
87

98
const App = memo(() => {
109
const { GlobalScrollbar } = useScrollbar();
11-
const [cacheKey, setCacheKey] = useState<string>('');
1210
const { token } = useAuth();
1311
const isAuth = useMemo(() => !!token, [token]);
1412

1513
useEffect(() => {
1614
setupTokenRefresh();
1715
}, []);
1816

19-
useEffect(() => {
20-
setCacheKey(Date.now().toString());
21-
}, [isAuth]);
22-
2317
if (!isAuth) {
2418
return (
2519
<>
@@ -30,10 +24,10 @@ const App = memo(() => {
3024
}
3125

3226
return (
33-
<Provider key={cacheKey}>
27+
<>
3428
<GlobalScrollbar />
3529
<AppProtectedRoutes />
36-
</Provider>
30+
</>
3731
);
3832
});
3933

client/src/infra/rest/apis/user/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { get, patch } from '../..';
22
import { ApiResponse } from '../../typings';
3+
import { USER_DB_STATE } from '../../typings';
34
import {
45
getUserProfileResponse,
56
searchUserResponse,
@@ -18,6 +19,10 @@ export const userProfile = async (username: string) => {
1819
);
1920
};
2021

22+
export const getCurrentUser = async () => {
23+
return get<undefined, ApiResponse<USER_DB_STATE>>(`/api/user/me`, true);
24+
};
25+
2126
export const updateProfileImg = async (imageUrl: string) => {
2227
return patch<{ url: string }, ApiResponse<{ profile_img: string }>>(
2328
`/api/user/update-profile-img`,

client/src/main.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { StrictMode } from 'react';
22
import { createRoot } from 'react-dom/client';
3+
import { Provider } from 'jotai';
34
import App from './App';
45
import createCache from '@emotion/cache';
56
import { CacheProvider } from '@emotion/react';
@@ -14,13 +15,15 @@ const cache = createCache({
1415

1516
createRoot(document.getElementById('root')!).render(
1617
<StrictMode>
17-
<CacheProvider value={cache}>
18-
<MuiThemeProvider>
19-
<BrowserRouter>
20-
<A2ZNotifications />
21-
<App />
22-
</BrowserRouter>
23-
</MuiThemeProvider>
24-
</CacheProvider>
18+
<Provider>
19+
<CacheProvider value={cache}>
20+
<MuiThemeProvider>
21+
<BrowserRouter>
22+
<A2ZNotifications />
23+
<App />
24+
</BrowserRouter>
25+
</MuiThemeProvider>
26+
</CacheProvider>
27+
</Provider>
2528
</StrictMode>
2629
);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentType, LazyExoticComponent, Suspense } from 'react';
2+
import Loader from '../../../../../shared/components/molecules/loader';
3+
import { LOADING } from '../../constants';
4+
import ProtectedPlaceholder from './protected';
5+
6+
export const ProtectedRoute = ({
7+
component: LazyComponent,
8+
hasAccess,
9+
}: {
10+
component: LazyExoticComponent<ComponentType<Record<string, unknown>>>;
11+
hasAccess: boolean;
12+
}) => {
13+
if (hasAccess) {
14+
return (
15+
<Suspense fallback={<Loader size={32} secondary={LOADING} />}>
16+
<LazyComponent />
17+
</Suspense>
18+
);
19+
}
20+
21+
return <ProtectedPlaceholder />;
22+
};
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { FC } from 'react';
2+
import { Box, Typography, useTheme } from '@mui/material';
3+
import { useCustomNavigate } from '../../../../../shared/hooks/use-custom-navigate';
4+
import A2ZButton from '../../../../../shared/components/atoms/button';
5+
import { ROUTES_V1 } from '../../constants/routes';
6+
7+
interface ProtectedPlaceholderProps {
8+
onClick?: () => void;
9+
heading?: string;
10+
description?: string;
11+
buttonText?: string;
12+
showButton?: boolean;
13+
}
14+
15+
const ProtectedPlaceholder: FC<ProtectedPlaceholderProps> = ({
16+
heading = 'Access Denied',
17+
description = 'You do not have access to this content.',
18+
onClick,
19+
buttonText = 'Go to Home',
20+
showButton = true,
21+
}) => {
22+
const theme = useTheme();
23+
const navigate = useCustomNavigate();
24+
25+
return (
26+
<Box
27+
sx={{
28+
display: 'flex',
29+
justifyContent: 'center',
30+
alignItems: 'center',
31+
height: '100%',
32+
width: '100%',
33+
}}
34+
>
35+
<Box
36+
sx={{
37+
display: 'flex',
38+
justifyContent: 'center',
39+
alignItems: 'center',
40+
flexDirection: 'column',
41+
p: { xs: 3, sm: '36px 72px' },
42+
borderRadius: 2,
43+
bgcolor:
44+
theme.palette.mode === 'dark'
45+
? 'background.paper'
46+
: theme.palette.grey[50],
47+
boxShadow: theme.shadows[2],
48+
maxWidth: { xs: '90%', sm: 'auto' },
49+
}}
50+
>
51+
<Typography
52+
variant="h4"
53+
component="h1"
54+
sx={{
55+
m: 0,
56+
fontWeight: 600,
57+
color: 'text.primary',
58+
textAlign: 'center',
59+
}}
60+
>
61+
{heading}
62+
</Typography>
63+
<Typography
64+
variant="body1"
65+
component="p"
66+
sx={{
67+
mt: 2,
68+
color: 'text.secondary',
69+
textAlign: 'center',
70+
maxWidth: 400,
71+
}}
72+
>
73+
{description}
74+
</Typography>
75+
76+
{showButton && (
77+
<A2ZButton
78+
variant="contained"
79+
sx={{
80+
mt: 6,
81+
px: 3,
82+
py: 1.5,
83+
fontSize: 16,
84+
transition: 'all 0.2s ease-in-out',
85+
bgcolor: 'primary.main',
86+
color: 'primary.contrastText',
87+
'&:hover': {
88+
transform: 'scale(1.05)',
89+
bgcolor: 'primary.dark',
90+
},
91+
}}
92+
onClick={() => {
93+
if (onClick) {
94+
onClick();
95+
} else {
96+
navigate({ pathname: ROUTES_V1.HOME.replace('/*', '/') });
97+
}
98+
}}
99+
>
100+
{buttonText}
101+
</A2ZButton>
102+
)}
103+
</Box>
104+
</Box>
105+
);
106+
};
107+
108+
export default ProtectedPlaceholder;

client/src/modules/app/routes/auth-routes/v1/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export default function getRoutesV1() {
2020
}
2121
/>,
2222
<Route
23-
key={ROUTES_V1.SETTINGS}
24-
path={ROUTES_V1.SETTINGS}
23+
key={`${ROUTES_V1.SETTINGS}/*`}
24+
path={`${ROUTES_V1.SETTINGS}/*`}
2525
element={
2626
<Suspense fallback={<Loader size={32} secondary={LOADING} />}>
2727
<SettingsPageLazyComponent />

client/src/modules/app/routes/constants/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export enum ROUTES_V1 {
22
HOME = '/v1/home',
33
SETTINGS = '/v1/settings',
4+
SETTINGS_PROFILE = '/profile',
45
}
56

67
export enum ROUTES_PAGE_V1 {

client/src/modules/edit-profile/constants/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

client/src/modules/edit-profile/hooks/index.ts

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)