Skip to content

Commit aebbd16

Browse files
[feat] add reset password API support (#119)
Also make sure to verify permission on reload
1 parent 40755d9 commit aebbd16

File tree

9 files changed

+170
-40
lines changed

9 files changed

+170
-40
lines changed

Diff for: src/api/constants.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export const ABOUT_URL = `${API_V1}/about`;
1616
// Users Management
1717
export const USERS_LIST_URL = `${API_V1}/user`;
1818
export const USER_URL = (username: string) => `${USERS_LIST_URL}/${username}`;
19-
export const USER_ROLES_URL = (username: string) => `${USER_URL(username)}/role`;
19+
export const USER_ROLES_URL = (username: string) => `${USER_URL(username)}/role`;
20+
export const USER_PASSWORD_URL = (username: string) => `${USER_URL(username)}/generate-new-password`;

Diff for: src/api/users.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { Axios } from "./axios";
2-
import { USERS_LIST_URL, USER_ROLES_URL, USER_URL } from "./constants";
2+
import { USERS_LIST_URL, USER_PASSWORD_URL, USER_ROLES_URL, USER_URL } from "./constants";
33

44
export const getUsers = () => {
55
return Axios().get(USERS_LIST_URL);
66
}
77

8-
export const putUser = (username: string, roles?: object[]) => {
9-
return Axios().put(USER_URL(username), roles );
8+
export const postUser = (username: string, roles?: object[]) => {
9+
return Axios().post(USER_URL(username), roles );
1010
}
1111

1212
export const deleteUser = (username: string) => {
@@ -19,4 +19,8 @@ export const putUserRoles = (username: string, roles: object[]) => {
1919

2020
export const getUserRoles = (username: string) => {
2121
return Axios().get(USER_ROLES_URL(username));
22+
}
23+
24+
export const postUserResetPassword = (username: string) => {
25+
return Axios().post(USER_PASSWORD_URL(username));
2226
}

Diff for: src/components/Navbar/index.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ const Navbar: FC<NavbarProps> = (props) => {
118118
} else if (userSepecficStreams && Boolean(userSepecficStreams.length)) {
119119
if (location.pathname === USERS_MANAGEMENT_ROUTE) {
120120
handleChangeWithoutRiderection(userSepecficStreams[0].name, location.pathname);
121+
navigate(`/users`);
121122
} else {
122123
handleChange(userSepecficStreams[0].name);
123124
}

Diff for: src/hooks/useGetLogStreamList.tsx

+32-4
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ import { useEffect } from 'react';
66
import useMountedState from './useMountedState';
77
import { notifications } from '@mantine/notifications';
88
import { IconFileAlert, IconCheck } from '@tabler/icons-react';
9+
import { useLocalStorage } from '@mantine/hooks';
10+
import { useNavigate } from 'react-router-dom';
11+
import { LOGIN_ROUTE } from '@/constants/routes';
912

1013
export const useGetLogStreamList = () => {
1114
const [data, setData] = useMountedState<LogStreamData | null>(null);
1215
const [error, setError] = useMountedState<string | null>(null);
1316
const [loading, setLoading] = useMountedState<boolean>(false);
17+
const [, , removeCredentials] = useLocalStorage({ key: 'credentials' });
18+
const [, , removeUsername] = useLocalStorage({ key: 'username' });
19+
const navigate = useNavigate();
1420

1521
const getData = async () => {
1622
try {
@@ -38,23 +44,45 @@ export const useGetLogStreamList = () => {
3844
color: 'green',
3945
title: 'Streams was loaded',
4046
message: 'Successfully Loaded!!',
41-
icon: <IconCheck size="1rem" />,
47+
icon: <IconCheck size="1rem" />,
4248
autoClose: 1000,
4349
});
4450
}
4551

46-
if(streams && streams.length===0){
52+
if (streams && streams.length === 0) {
4753
notifications.update({
4854
id: 'load-data',
4955
color: 'red',
5056
title: 'No Streams',
5157
message: 'No Streams Found in your account',
52-
icon: <IconFileAlert size="1rem" />,
58+
icon: <IconFileAlert size="1rem" />,
5359
autoClose: 2000,
5460
});
5561
}
5662
break;
5763
}
64+
case StatusCodes.UNAUTHORIZED: {
65+
setError('Unauthorized');
66+
notifications.update({
67+
id: 'load-data',
68+
color: 'red',
69+
title: 'Error Occured',
70+
message: 'Unauthorized',
71+
icon: <IconFileAlert size="1rem" />,
72+
autoClose: 2000,
73+
});
74+
75+
removeCredentials();
76+
removeUsername();
77+
navigate(
78+
{
79+
pathname: LOGIN_ROUTE,
80+
},
81+
{ replace: true },
82+
);
83+
84+
break;
85+
}
5886
default: {
5987
setError('Failed to get log streams');
6088
notifications.update({
@@ -89,5 +117,5 @@ export const useGetLogStreamList = () => {
89117
getData();
90118
}, []);
91119

92-
return { data, error, loading, getData ,resetData};
120+
return { data, error, loading, getData, resetData };
93121
};

Diff for: src/hooks/useGetUserRoles.ts

+19
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { StatusCodes } from 'http-status-codes';
22
import useMountedState from './useMountedState';
33
import { getUserRoles } from '@/api/users';
4+
import { useLocalStorage } from '@mantine/hooks';
5+
import { useNavigate } from 'react-router-dom';
6+
import { LOGIN_ROUTE } from '@/constants/routes';
47

58
export const useGetUserRole = () => {
69
const [data, setData] = useMountedState<any | null>(null);
710
const [error, setError] = useMountedState<string | null>(null);
811
const [loading, setLoading] = useMountedState<boolean>(false);
12+
const [, , removeCredentials] = useLocalStorage({ key: 'credentials' });
13+
const [, , removeUsername] = useLocalStorage({ key: 'username' });
14+
const navigate = useNavigate();
915

1016
const getRoles = async (userName:string) => {
1117
try {
@@ -18,6 +24,19 @@ export const useGetUserRole = () => {
1824
setData(res.data);
1925
break;
2026
}
27+
case StatusCodes.UNAUTHORIZED: {
28+
setError('Unauthorized');
29+
removeCredentials();
30+
removeUsername();
31+
navigate(
32+
{
33+
pathname: LOGIN_ROUTE,
34+
},
35+
{ replace: true },
36+
);
37+
38+
break;
39+
}
2140
default: {
2241
setError('Failed to get Roles');
2342
console.error(res);

Diff for: src/hooks/usePostResetPassword.tsx

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { StatusCodes } from 'http-status-codes';
2+
import useMountedState from './useMountedState';
3+
import { postUserResetPassword } from '@/api/users';
4+
import { notifications } from '@mantine/notifications';
5+
import { IconCheck, IconFileAlert } from '@tabler/icons-react';
6+
7+
export const usePostUserResetPassword = () => {
8+
const [data, setData] = useMountedState<any | null>(null);
9+
const [error, setError] = useMountedState<string | null>(null);
10+
const [loading, setLoading] = useMountedState<boolean>(false);
11+
12+
const resetPasswordUser = async (userName:string) => {
13+
try {
14+
setLoading(true);
15+
notifications.show({
16+
id: 'load-data',
17+
loading: true,
18+
color: '#545BEB',
19+
title: 'Changing Password',
20+
message: 'Password will be Changed.',
21+
autoClose: false,
22+
withCloseButton: false,
23+
});
24+
setError(null);
25+
const res = await postUserResetPassword(userName);
26+
27+
switch (res.status) {
28+
case StatusCodes.OK: {
29+
setData(res.data);
30+
notifications.update({
31+
id: 'load-data',
32+
color: 'green',
33+
title: 'Password was Changed',
34+
message: 'Successfully Changed!!',
35+
icon: <IconCheck size="1rem" />,
36+
autoClose: 3000,
37+
});
38+
break;
39+
40+
}
41+
default: {
42+
setError(res.data);
43+
console.error(res);
44+
notifications.update({
45+
id: 'load-data',
46+
color: 'red',
47+
title: 'Error Occured',
48+
message: res.data,
49+
icon: <IconFileAlert size="1rem" />,
50+
autoClose: 2000,
51+
});
52+
}
53+
}
54+
} catch(error) {
55+
setError('Failed to get Create User');
56+
notifications.update({
57+
id: 'load-data',
58+
color: 'red',
59+
title: 'Error Occured',
60+
message: 'Error Occured while Creating User',
61+
icon: <IconFileAlert size="1rem" />,
62+
autoClose: 2000,
63+
});
64+
console.error(error);
65+
} finally {
66+
setLoading(false);
67+
}
68+
};
69+
70+
const resetData = () => {
71+
setData(null);
72+
};
73+
74+
return { data, error, loading, resetPasswordUser, resetData };
75+
};
76+

Diff for: src/hooks/usePutUser.tsx renamed to src/hooks/usePostUser.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { StatusCodes } from 'http-status-codes';
22
import useMountedState from './useMountedState';
3-
import { putUser } from '@/api/users';
3+
import { postUser } from '@/api/users';
44
import { notifications } from '@mantine/notifications';
55
import { IconCheck, IconFileAlert } from '@tabler/icons-react';
66

7-
export const usePutUser = () => {
7+
export const usePostUser = () => {
88
const [data, setData] = useMountedState<any | null>(null);
99
const [error, setError] = useMountedState<string | null>(null);
1010
const [loading, setLoading] = useMountedState<boolean>(false);
@@ -22,7 +22,7 @@ export const usePutUser = () => {
2222
withCloseButton: false,
2323
});
2424
setError(null);
25-
const res = await putUser(userName,roles);
25+
const res = await postUser(userName,roles);
2626

2727
switch (res.status) {
2828
case StatusCodes.OK: {

Diff for: src/pages/Users/index.tsx

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { Box, Button, Modal, ScrollArea, Select, Table, Text, TextInput} from '@mantine/core';
1+
import { Box, Button, Modal, ScrollArea, Select, Table, Text, TextInput } from '@mantine/core';
22
import { useDocumentTitle } from '@mantine/hooks';
33
import { FC, useEffect, useState } from 'react';
44

55
import { useGetUsers } from '@/hooks/useGetUsers';
66
import { useUsersStyles } from './styles';
7-
import { usePutUser } from '@/hooks/usePutUser';
7+
import { usePostUser } from '@/hooks/usePostUser';
88
import { Prism } from '@mantine/prism';
99
import RoleTd from './row';
1010
import { useGetLogStreamList } from '@/hooks/useGetLogStreamList';
@@ -15,15 +15,13 @@ const Users: FC = () => {
1515
state: { subCreateUserModalTogle },
1616
} = useHeaderContext();
1717

18-
1918
useEffect(() => {
2019
const listener = subCreateUserModalTogle.subscribe(setModalOpen);
2120
return () => {
2221
listener();
2322
};
2423
}, [subCreateUserModalTogle.get()]);
2524

26-
2725
const [modalOpen, setModalOpen] = useState<boolean>(false);
2826
const [createUserInput, setCreateUserInput] = useState<string>('');
2927
const [tagInput, setTagInput] = useState<string>('');
@@ -39,7 +37,7 @@ const Users: FC = () => {
3937
loading: CreatedUserLoading,
4038
createUser,
4139
resetData: resetCreateUser,
42-
} = usePutUser();
40+
} = usePostUser();
4341
const { data: users, error: usersError, loading: usersLoading, getUsersList, resetData: usersReset } = useGetUsers();
4442

4543
const [tableRows, setTableRows] = useState<any>([]);
@@ -102,9 +100,7 @@ const Users: FC = () => {
102100
});
103101
}
104102
if (selectedPrivilege === 'reader' || selectedPrivilege === 'writer') {
105-
if (
106-
streams?.find((stream) => stream.name === SelectedStream)
107-
) {
103+
if (streams?.find((stream) => stream.name === SelectedStream)) {
108104
if (tagInput !== '' && tagInput !== undefined && selectedPrivilege !== 'writer') {
109105
userRole?.push({
110106
privilege: selectedPrivilege,
@@ -127,7 +123,7 @@ const Users: FC = () => {
127123
};
128124

129125
const createVaildtion = () => {
130-
if (users?.includes(createUserInput) || createUserInput.length <3) {
126+
if (users?.includes(createUserInput) || createUserInput.length < 3) {
131127
return true;
132128
}
133129
if (selectedPrivilege !== '') {
@@ -163,7 +159,7 @@ const Users: FC = () => {
163159
<th style={{ textAlign: 'center' }}>Reset Password</th>
164160
</tr>
165161
</thead>
166-
<tbody >{tableRows}</tbody>
162+
<tbody>{tableRows}</tbody>
167163
</Table>
168164
</ScrollArea>
169165
<Modal

0 commit comments

Comments
 (0)