From ff72640e76725efa0c52a961eca201e3f68c539e Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Sat, 12 Aug 2023 00:07:47 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(PaginatorComponent):=20fix?= =?UTF-8?q?=20initial=20pageIndex=20value=20to=20start=20from=200=20instea?= =?UTF-8?q?d=20of=201=20for=20consistency=20=E2=9C=A8=20feat(PaginatorComp?= =?UTF-8?q?onent):=20update=20rowsCount=20options=20to=20[10,=2020,=2050,?= =?UTF-8?q?=20100]=20for=20more=20flexibility=20in=20choosing=20page=20siz?= =?UTF-8?q?e=20=F0=9F=90=9B=20fix(PaginatorComponent):=20fix=20maxIndex=20?= =?UTF-8?q?calculation=20to=20always=20be=20100=20for=20now,=20to=20avoid?= =?UTF-8?q?=20incorrect=20pagination=20=F0=9F=90=9B=20fix(PaginatorCompone?= =?UTF-8?q?nt):=20fix=20page=20index=20display=20to=20start=20from=201=20i?= =?UTF-8?q?nstead=20of=200=20for=20better=20user=20experience=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(PaginatorComponent):=20fix=20disabled=20stat?= =?UTF-8?q?e=20of=20first=20and=20previous=20buttons=20to=20be=20disabled?= =?UTF-8?q?=20when=20index=20is=200=20=F0=9F=90=9B=20fix(PaginatorComponen?= =?UTF-8?q?t):=20fix=20disabled=20state=20of=20next=20and=20last=20buttons?= =?UTF-8?q?=20to=20be=20disabled=20when=20index=20is=20equal=20to=20maxInd?= =?UTF-8?q?ex=20=E2=9C=A8=20feat(authGuard):=20add=20new=20ProtectedLoginR?= =?UTF-8?q?oute=20component=20to=20redirect=20authenticated=20users=20to?= =?UTF-8?q?=20home=20page=20=F0=9F=90=9B=20fix(genericIconComponent):=20fi?= =?UTF-8?q?x=20icon=20size=20to=20be=20smaller=20with=20h-3=20and=20w-3=20?= =?UTF-8?q?classes=20=F0=9F=90=9B=20fix(ui/checkbox):=20fix=20checkbox=20i?= =?UTF-8?q?con=20size=20to=20be=20smaller=20with=20h-3=20and=20w-3=20class?= =?UTF-8?q?es=20=E2=9C=A8=20feat(constants):=20add=20CONTROL=5FNEW=5FUSER?= =?UTF-8?q?=20constant=20for=20new=20user=20form=20initialization=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(authContext):=20fix=20getAuthentication=20fu?= =?UTF-8?q?nction=20to=20correctly=20check=20for=20stored=20access=20and?= =?UTF-8?q?=20refresh=20tokens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 fix(api.tsx): remove unused imports and reorganize imports for better readability ✨ feat(api.tsx): add support for retrying failed requests up to 3 times with a 5-second delay between retries 🐛 fix(api.tsx): fix logic for excluding certain URLs from error retries ✨ feat(api.tsx): add support for adding access token to every request as a request interceptor 🐛 fix(api.tsx): fix formatting and remove unnecessary code ✨ feat(index.ts): add support for fetching users, adding a user, fetching users with pagination, deleting a user, and updating a user 🐛 fix(UserManagementModal): fix typo in username state variable name ✨ feat(UserManagementModal): add support for password visibility toggle in password and confirm password fields ✨ feat(UserManagementModal): add support for is_disabled and is_superuser checkboxes 🐛 fix(LoginPage): fix typo in username state variable name ✨ feat(LoginPage): add support for handling input changes and signing in with username and password 🔨 refactor(AdminPage/index.tsx): import Checkbox component to improve code readability and maintainability 🔨 refactor(AdminPage/index.tsx): import API functions separately to improve code readability and maintainability 🔨 refactor(AdminPage/index.tsx): import alertContext from contexts/alertContext to improve code readability and maintainability 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused variables and functions to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused imports to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve code cleanliness and performance 🔨 refactor(AdminPage/index.tsx): remove unused code and dependencies to improve 🐛 fix(AdminPage/index.tsx): update text when there are no users registered to improve clarity and user experience ✨ feat(AdminPage/index.tsx): add loading state when fetching users to provide feedback to the user 🔨 refactor(AdminPage/index.tsx): refactor filter functionality to reset filter when input value is cleared 🔨 refactor(AdminPage/index.tsx): refactor filter functionality to use the current user list instead of the filtered list 🔨 refactor(AdminPage/index.tsx): refactor handleNewUser function to pass the user object instead of index 🔨 refactor(AdminPage/index.tsx): refactor handleEditUser function to pass the user id instead of index 🔨 refactor(AdminPage/index.tsx): refactor handleDeleteUser function to pass the user object instead of index 🔨 refactor(AdminPage/index.tsx): refactor TableRow key to use index instead of user.user 🔨 refactor(AdminPage/index.tsx): refactor TableCell content to use ShadTooltip component for better user experience 🔨 refactor(AdminPage/index.tsx): refactor Checkbox components to use id and checked props for better semantics 🔨 refactor(AdminPage/index.tsx): refactor date formatting to use toISOString and split methods for better readability 🔨 refactor(AdminPage/index.tsx): refactor UserManagementModal titleHeader to use user.id instead of user.user for better clarity 🔨 refactor(AdminPage/index.tsx): refactor handleEditUser function to pass the user id instead of index 🔨 refactor(AdminPage/index.tsx): refactor handleDeleteUser function to pass the user object instead of index 🔨 refactor(AdminPage/index.tsx): refactor PaginatorComponent to use handleChangePagination function for better readability and maintainability 🐛 fix(loginPage/index.tsx): remove unused import statement for 'error' from console module ✨ feat(loginPage/index.tsx): add support for displaying error message when signing in fails 🐛 fix(routes.tsx): add ProtectedLoginRoute component to protect login, signup, and login/admin routes 🐛 fix(api/index.ts): add missing 'is_disabled' and 'is_superuser' properties to Users type 🐛 fix(components/index.ts): change value type of inputHandlerEventType to include boolean ✨ feat(components/index.ts): add UserInputType type for user input data 🐛 fix(styleUtils.ts): add missing Eye and EyeOff icons to nodeIconsLucide object --- .../components/PaginatorComponent/index.tsx | 42 +- .../src/components/authGuard/index.tsx | 19 +- .../src/components/authLoginGuard/index.tsx | 14 + .../components/genericIconComponent/index.tsx | 10 +- src/frontend/src/components/ui/checkbox.tsx | 2 +- src/frontend/src/constants/constants.ts | 8 + src/frontend/src/contexts/authContext.tsx | 10 +- src/frontend/src/controllers/API/api.tsx | 98 ++-- src/frontend/src/controllers/API/index.ts | 76 ++- .../src/modals/UserManagementModal/index.tsx | 169 ++++--- .../src/pages/AdminPage/LoginPage/index.tsx | 60 ++- src/frontend/src/pages/AdminPage/index.tsx | 475 ++++++++---------- src/frontend/src/pages/loginPage/index.tsx | 34 +- src/frontend/src/routes.tsx | 28 +- src/frontend/src/types/api/index.ts | 9 + src/frontend/src/types/components/index.ts | 9 +- src/frontend/src/utils/styleUtils.ts | 4 + 17 files changed, 609 insertions(+), 458 deletions(-) create mode 100644 src/frontend/src/components/authLoginGuard/index.tsx diff --git a/src/frontend/src/components/PaginatorComponent/index.tsx b/src/frontend/src/components/PaginatorComponent/index.tsx index 8fcd8683f..ebad18506 100644 --- a/src/frontend/src/components/PaginatorComponent/index.tsx +++ b/src/frontend/src/components/PaginatorComponent/index.tsx @@ -12,16 +12,16 @@ import { Button } from "../ui/button"; export default function PaginatorComponent({ pageSize = 10, - pageIndex = 1, - rowsCount = [10, 20, 30], + pageIndex = 0, + rowsCount = [10, 20, 50, 100], totalRowsCount = 0, paginate, }: PaginatorComponentType) { + const [size, setPageSize] = useState(pageSize); const [index, setPageIndex] = useState(pageIndex); - const [maxIndex, setMaxPageIndex] = useState( - Math.ceil(totalRowsCount / pageSize) + 100 ); return ( @@ -34,8 +34,8 @@ export default function PaginatorComponent({
- Page {index} of {maxIndex} + Page {index+1} of {maxIndex}
{ - setUserName(input.target.value); + onChange={({ target: { value } }) => { + handleInput({ target: { name: "username", value } }); + setUserName(value); }} value={username} className="primary-input" @@ -104,21 +122,38 @@ export default function UserManagementModal({ justifyContent: "space-between", }} > - + Password{" "} - * + + * + + {pwdVisible && ( + setPwdVisible(!pwdVisible)} + className="h-5 cursor-pointer" strokeWidth={1.5} /> + )} + + {!pwdVisible && ( + setPwdVisible(!pwdVisible)} + className="h-5 cursor-pointer" strokeWidth={1.5} /> + )} + { - setPassword(input.target.value); + onChange={({ target: { value } }) => { + handleInput({ target: { name: "password", value } }); + setPassword(value); }} value={password} className="primary-input" required + type={pwdVisible ? "text" : "password"} /> + Please enter a password @@ -143,9 +178,22 @@ export default function UserManagementModal({ justifyContent: "space-between", }} > - + Confirm password{" "} - * + + * + + {confirmPwdVisible && ( + setConfirmPwdVisible(!confirmPwdVisible)} + className="h-5 cursor-pointer" strokeWidth={1.5} /> + )} + + {!confirmPwdVisible && ( + setConfirmPwdVisible(!confirmPwdVisible)} + className="h-5 cursor-pointer" strokeWidth={1.5} /> + )} @@ -156,6 +204,7 @@ export default function UserManagementModal({ value={confirmPassword} className="primary-input" required + type={confirmPwdVisible ? "text" : "password"} /> @@ -164,57 +213,49 @@ export default function UserManagementModal({ +
+ +
+ + Disabled + + + { + handleInput({ target: { name: "is_disabled", value } }); + setIsDisabled(value); + }} + /> + +
+
- {/* - -
- - Email * - - - Please enter your email - - - Please provide a valid email - -
- - - -
*/} - - {/* - -
- - Date of birth{" "} - * - - - Please enter your date of birth - -
- - - -
*/} + +
+ + Superuser + + + { + handleInput({ + target: { name: "is_superuser", value }, + }); + setIsSuperUser(value); + }} + /> + +
+
+
diff --git a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx index 74cc75d07..bcc545e9b 100644 --- a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx @@ -1,12 +1,49 @@ +import { useContext, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Button } from "../../../components/ui/button"; import { Input } from "../../../components/ui/input"; +import { CONTROL_LOGIN_STATE } from "../../../constants/constants"; +import { alertContext } from "../../../contexts/alertContext"; +import { AuthContext } from "../../../contexts/authContext"; +import { onLogin } from "../../../controllers/API"; +import { LoginType } from "../../../types/api"; +import { + inputHandlerEventType, + loginInputStateType, +} from "../../../types/components"; export default function LoginAdminPage() { const navigate = useNavigate(); - function loginAdmin() { - navigate("/admin/"); + const [inputState, setInputState] = + useState(CONTROL_LOGIN_STATE); + const { login } = useContext(AuthContext); + + const { password, username } = inputState; + const { setErrorData } = useContext(alertContext); + + function handleInput({ + target: { name, value }, + }: inputHandlerEventType): void { + setInputState((prev) => ({ ...prev, [name]: value })); + } + + function signIn() { + const user: LoginType = { + username: username, + password: password, + }; + onLogin(user) + .then((user) => { + login(user.access_token, user.refresh_token); + navigate("/admin/"); + }) + .catch((error) => { + setErrorData({ + title: "Error signing in", + list: [error["response"]["data"]["detail"]], + }); + }); } return ( @@ -14,11 +51,24 @@ export default function LoginAdminPage() {
⛓️ Admin - - + { + handleInput({ target: { name: "username", value } }); + }} + className="bg-background" + placeholder="Username" + /> + { + handleInput({ target: { name: "password", value } }); + }} + className="bg-background" + placeholder="Password" + />
- {userList.current.length === 0 && ( + {userList.current.length === 0 && !loadingUsers && ( <>
-

There's no users left :)

+

There's no users registered :)

)} - {userList.current.length > 0 && ( - <> -
-
- handleFilterUsers(e.target.value)} - /> - {inputValue.length > 0 && ( - - )} -
-
- { - handleNewUser(user); + <> +
+
+ handleFilterUsers(e.target.value)} + /> + {inputValue.length > 0 && ( + - -
+ Reset + + + )}
-
- - - - User - Password - - - +
+ { + handleNewUser(user); + }} + > + + +
+ + {loadingUsers && ( +
+ Loading... +
+ )} +
+
+ + + Id + Username + Disabled + Superuser + Created At + Updated At + + + + {!loadingUsers && ( {filterUserList.map((user, index) => ( - + - {user.user} + + + {user.id} + + - {user.password} + + + {user.username} + + + + + + + + + + + { + new Date(user.create_at) + .toISOString() + .split("T")[0] + } + + + { + new Date(user.updated_at) + .toISOString() + .split("T")[0] + }
{ - handleEditUser(index, user); + onConfirm={(index, editUser) => { + handleEditUser(user.id, editUser); }} > @@ -365,7 +307,7 @@ export default function AdminPage() { data={user} index={index} onConfirm={(index, user) => { - handleDeleteUser(index); + handleDeleteUser(user); }} > @@ -380,18 +322,19 @@ export default function AdminPage() { ))} -
-
- { - handleChangePagination(pageSize, pageIndex); - }} - > - - )} + )} + +
+ + { + handleChangePagination(pageSize, pageIndex); + }} + > +
diff --git a/src/frontend/src/pages/loginPage/index.tsx b/src/frontend/src/pages/loginPage/index.tsx index de9f9342f..aaa07096a 100644 --- a/src/frontend/src/pages/loginPage/index.tsx +++ b/src/frontend/src/pages/loginPage/index.tsx @@ -6,15 +6,14 @@ import InputComponent from "../../components/inputComponent"; import { Button } from "../../components/ui/button"; import { Input } from "../../components/ui/input"; import { CONTROL_LOGIN_STATE } from "../../constants/constants"; +import { alertContext } from "../../contexts/alertContext"; +import { AuthContext } from "../../contexts/authContext"; +import { onLogin } from "../../controllers/API"; +import { LoginType } from "../../types/api"; import { inputHandlerEventType, loginInputStateType, } from "../../types/components"; -import { onLogin } from "../../controllers/API"; -import { LoginType } from "../../types/api"; -import { AuthContext } from "../../contexts/authContext"; -import { alertContext } from "../../contexts/alertContext"; -import { error } from "console"; export default function LoginPage(): JSX.Element { const [inputState, setInputState] = @@ -31,25 +30,22 @@ export default function LoginPage(): JSX.Element { setInputState((prev) => ({ ...prev, [name]: value })); } - function signIn(){ - + function signIn() { const user: LoginType = { username: username, - password: password + password: password, }; - - onLogin( - user - ).then((user) => { + onLogin(user) + .then((user) => { login(user.access_token, user.refresh_token); navigate("/"); - }).catch(error => { + }) + .catch((error) => { setErrorData({ title: "Error signing in", - list: [error['response']['data']['detail']], - }) + list: [error["response"]["data"]["detail"]], + }); }); - } return ( @@ -137,9 +133,9 @@ export default function LoginPage(): JSX.Element {
- +
diff --git a/src/frontend/src/routes.tsx b/src/frontend/src/routes.tsx index db0c47770..4875478f9 100644 --- a/src/frontend/src/routes.tsx +++ b/src/frontend/src/routes.tsx @@ -1,5 +1,6 @@ import { Route, Routes } from "react-router-dom"; import { ProtectedRoute } from "./components/authGuard"; +import { ProtectedLoginRoute } from "./components/authLoginGuard"; import AdminPage from "./pages/AdminPage"; import LoginAdminPage from "./pages/AdminPage/LoginPage"; import CommunityPage from "./pages/CommunityPage"; @@ -47,9 +48,30 @@ const Router = () => { } /> - } /> - } /> - } /> + + + + } + /> + + + + } + /> + + + + } + />