From b91acd66758870f55af6ff5db545d5e4b6259f8f Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Wed, 22 May 2024 16:05:31 +0800 Subject: [PATCH] update --- src/components/EditTeam/Allocation.tsx | 24 ++- src/components/EditUser/AuthAllocation.tsx | 196 +++++++++++---------- src/components/EditUser/EditUser.tsx | 100 +++++++---- src/components/EditUser/UserDetail.tsx | 41 ++++- 4 files changed, 214 insertions(+), 147 deletions(-) diff --git a/src/components/EditTeam/Allocation.tsx b/src/components/EditTeam/Allocation.tsx index 2376ece..b9762f5 100644 --- a/src/components/EditTeam/Allocation.tsx +++ b/src/components/EditTeam/Allocation.tsx @@ -60,24 +60,20 @@ const Allocation: React.FC = ({ allStaffs: staff, teamLead }) => { return rearrangedStaff.filter((s) => getValues("addStaffIds")?.includes(s.id)) } ); - const [seletedTeamLead, setSeletedTeamLead] = useState(); const [deletedStaffIds, setDeletedStaffIds] = useState([]); // Adding / Removing staff const addStaff = useCallback((staff: StaffResult) => { setSelectedStaff((s) => [...s, staff]); - // setDeletedStaffIds((s) => s.filter((s) => s === selectedStaff.id)) }, []); const removeStaff = useCallback((staff: StaffResult) => { setSelectedStaff((s) => s.filter((s) => s.id !== staff.id)); - // setDeletedStaffIds((s) => s) setDeletedStaffIds((prevIds) => [...prevIds, staff.id]); }, []); const setTeamLead = useCallback( (staff: StaffResult) => { - setSeletedTeamLead(staff.id); const rearrangedList = getValues("addStaffIds").reduce( (acc, num, index) => { if (num === staff.id && index !== 0) { @@ -171,16 +167,16 @@ const Allocation: React.FC = ({ allStaffs: staff, teamLead }) => { }, []); React.useEffect(() => { - // setFilteredStaff( - // initialStaffs.filter((s) => { - // const q = query.toLowerCase(); - // // s.staffId.toLowerCase().includes(q) - // // const q = query.toLowerCase(); - // // return s.name.toLowerCase().includes(q); - // // s.code.toString().includes(q) || - // // (s.brNo != null && s.brNo.toLowerCase().includes(q)) - // }) - // ); + setFilteredStaff( + initialStaffs.filter((i) => { + const q = query.toLowerCase(); + return ( + i.staffId.toLowerCase().includes(q) || + i.name.toLowerCase().includes(q) || + i.currentPosition.toLowerCase().includes(q) + ); + }) + ); }, [staff, query]); useEffect(() => { diff --git a/src/components/EditUser/AuthAllocation.tsx b/src/components/EditUser/AuthAllocation.tsx index afb44d5..fe6c5a9 100644 --- a/src/components/EditUser/AuthAllocation.tsx +++ b/src/components/EditUser/AuthAllocation.tsx @@ -1,93 +1,97 @@ "use client"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; -import { Add, Clear, PersonAdd, PersonRemove, Remove, Search } from "@mui/icons-material"; +import { + Add, + Clear, + PersonAdd, + PersonRemove, + Remove, + Search, +} from "@mui/icons-material"; import { useTranslation } from "react-i18next"; import { - FieldErrors, - FormProvider, - SubmitErrorHandler, - SubmitHandler, - useForm, - useFormContext, - } from "react-hook-form"; + FieldErrors, + FormProvider, + SubmitErrorHandler, + SubmitHandler, + useForm, + useFormContext, +} from "react-hook-form"; import { - Box, - Card, - CardContent, - Grid, - IconButton, - InputAdornment, - Stack, - Tab, - Tabs, - TabsProps, - TextField, - Typography, - } from "@mui/material"; - import { differenceBy } from "lodash"; + Box, + Card, + CardContent, + Grid, + IconButton, + InputAdornment, + Stack, + Tab, + Tabs, + TabsProps, + TextField, + Typography, +} from "@mui/material"; +import { differenceBy } from "lodash"; import { UserInputs } from "@/app/api/user/actions"; import { auth } from "@/app/api/group/actions"; import SearchResults, { Column } from "../SearchResults"; export interface Props { - auths: auth[] - - } + auths: auth[]; +} const AuthAllocation: React.FC = ({ auths }) => { - const { t } = useTranslation(); - const searchParams = useSearchParams(); - const id = parseInt(searchParams.get("id") || "0"); - const { - setValue, - getValues, - formState: { defaultValues }, - reset, - resetField, - } = useFormContext(); - const initialAuths = auths.map((u) => ({ ...u })).sort((a, b) => a.id - b.id); - const [filteredAuths, setFilteredAuths] = useState(initialAuths); - const [selectedAuths, setSelectedAuths] = useState( - () => { - return filteredAuths.filter( - (s) => getValues("addAuthIds")?.includes(s.id) - ); - } + const { t } = useTranslation(); + const searchParams = useSearchParams(); + const id = parseInt(searchParams.get("id") || "0"); + const { + setValue, + getValues, + formState: { defaultValues }, + reset, + resetField, + } = useFormContext(); + const initialAuths = auths.map((u) => ({ ...u })).sort((a, b) => a.id - b.id); + const [filteredAuths, setFilteredAuths] = useState(initialAuths); + const [selectedAuths, setSelectedAuths] = useState( + () => { + return filteredAuths.filter( + (s) => getValues("addAuthIds")?.includes(s.id) ); - const [removeAuthIds, setRemoveAuthIds] = useState([]); + } + ); + const [removeAuthIds, setRemoveAuthIds] = useState([]); - // Adding / Removing Auth - const addAuth = useCallback((auth: auth) => { - setSelectedAuths((a) => [...a, auth]); - }, []); - const removeAuth = useCallback((auth: auth) => { - setSelectedAuths((a) => a.filter((a) => a.id !== auth.id)); - setRemoveAuthIds((prevIds) => [...prevIds, auth.id]); - }, []); + // Adding / Removing Auth + const addAuth = useCallback((auth: auth) => { + setSelectedAuths((a) => [...a, auth]); + }, []); + const removeAuth = useCallback((auth: auth) => { + setSelectedAuths((a) => a.filter((a) => a.id !== auth.id)); + setRemoveAuthIds((prevIds) => [...prevIds, auth.id]); + }, []); - const clearAuth = useCallback(() => { - if (defaultValues !== undefined) { - resetField("addAuthIds"); - setSelectedAuths( - initialAuths.filter((auth) => defaultValues.addAuthIds?.includes(auth.id)) - ); - } - }, [defaultValues]); + const clearAuth = useCallback(() => { + if (defaultValues !== undefined) { + resetField("addAuthIds"); + setSelectedAuths( + initialAuths.filter( + (auth) => defaultValues.addAuthIds?.includes(auth.id) + ) + ); + } + }, [defaultValues]); - // Sync with form + // Sync with form useEffect(() => { setValue( "addAuthIds", selectedAuths.map((a) => a.id) ); - setValue( - "removeAuthIds", - removeAuthIds - ); + setValue("removeAuthIds", removeAuthIds); }, [selectedAuths, removeAuthIds, setValue]); - const AuthPoolColumns = useMemo[]>( () => [ { @@ -97,8 +101,7 @@ const AuthAllocation: React.FC = ({ auths }) => { buttonIcon: , }, { label: t("authority"), name: "authority" }, - { label: t("Auth Name"), name: "name" }, - // { label: t("Current Position"), name: "currentPosition" }, + { label: t("description"), name: "name" }, ], [addAuth, t] ); @@ -109,10 +112,10 @@ const AuthAllocation: React.FC = ({ auths }) => { label: t("Remove"), name: "id", onClick: removeAuth, - buttonIcon: , + buttonIcon: , }, { label: t("authority"), name: "authority" }, - { label: t("Auth Name"), name: "name" }, + { label: t("description"), name: "name" }, ], [removeAuth, selectedAuths, t] ); @@ -128,16 +131,14 @@ const AuthAllocation: React.FC = ({ auths }) => { }, []); React.useEffect(() => { - // setFilteredStaff( - // initialStaffs.filter((s) => { - // const q = query.toLowerCase(); - // // s.staffId.toLowerCase().includes(q) - // // const q = query.toLowerCase(); - // // return s.name.toLowerCase().includes(q); - // // s.code.toString().includes(q) || - // // (s.brNo != null && s.brNo.toLowerCase().includes(q)) - // }) - // ); + setFilteredAuths( + initialAuths.filter((a) => + ( + a.authority.toLowerCase().includes(query.toLowerCase()) || + a.name?.toLowerCase().includes(query.toLowerCase()) + ) + ) + ); }, [auths, query]); const resetAuth = React.useCallback(() => { @@ -147,16 +148,16 @@ const AuthAllocation: React.FC = ({ auths }) => { const formProps = useForm({}); - // Tab related - const [tabIndex, setTabIndex] = React.useState(0); - const handleTabChange = React.useCallback>( - (_e, newValue) => { - setTabIndex(newValue); - }, - [] - ); + // Tab related + const [tabIndex, setTabIndex] = React.useState(0); + const handleTabChange = React.useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [] + ); -return ( + return ( <> @@ -175,7 +176,9 @@ return ( fullWidth onChange={onQueryInputChange} value={query} - placeholder={t("Search by staff ID, name or position.")} + placeholder={t( + "Search by Authority or description or position." + )} InputProps={{ endAdornment: query && ( @@ -191,18 +194,20 @@ return ( - {tabIndex === 0 && ( + {tabIndex === 0 && ( )} - {tabIndex === 1 && ( + {tabIndex === 1 && ( ); - -} -export default AuthAllocation \ No newline at end of file +}; +export default AuthAllocation; diff --git a/src/components/EditUser/EditUser.tsx b/src/components/EditUser/EditUser.tsx index bbbd174..947a116 100644 --- a/src/components/EditUser/EditUser.tsx +++ b/src/components/EditUser/EditUser.tsx @@ -1,6 +1,12 @@ "use client"; import { useRouter, useSearchParams } from "next/navigation"; -import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react"; +import React, { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useState, +} from "react"; import SearchResults, { Column } from "../SearchResults"; // import { TeamResult } from "@/app/api/team"; import { useTranslation } from "react-i18next"; @@ -26,23 +32,24 @@ import { } from "react-hook-form"; import { Check, Close, Error, RestartAlt } from "@mui/icons-material"; import { StaffResult } from "@/app/api/staff"; -import { UserInputs, adminChangePassword, editUser, fetchUserDetails } from "@/app/api/user/actions"; +import { + UserInputs, + adminChangePassword, + editUser, + fetchUserDetails, +} from "@/app/api/user/actions"; import UserDetail from "./UserDetail"; import { UserResult, passwordRule } from "@/app/api/user"; import { auth, fetchAuth } from "@/app/api/group/actions"; import AuthAllocation from "./AuthAllocation"; interface Props { - user: UserResult, - rules: passwordRule, - auths: auth[] -} + user: UserResult; + rules: passwordRule; + auths: auth[]; +} -const EditUser: React.FC = async ({ - user, - rules, - auths -}) => { +const EditUser: React.FC = async ({ user, rules, auths }) => { const { t } = useTranslation(); const formProps = useForm(); const searchParams = useSearchParams(); @@ -50,6 +57,13 @@ const EditUser: React.FC = async ({ const [tabIndex, setTabIndex] = useState(0); const router = useRouter(); const [serverError, setServerError] = useState(""); + const addAuthIds = + auths && auths.length > 0 + ? auths + .filter((item) => item.v === 1) + .map((item) => item.id) + .sort((a, b) => a - b) + : []; const handleTabChange = useCallback>( (_e, newValue) => { @@ -60,22 +74,27 @@ const EditUser: React.FC = async ({ const errors = formProps.formState.errors; - useEffect(() => { + const resetForm = React.useCallback(() => { + console.log("triggerred"); + console.log(addAuthIds); try { - const addAuthIds = auths && auths.length > 0 - ? auths.filter((item) => item.v === 1).map((item) => item.id).sort((a, b) => a - b) - : [] - formProps.reset({ name: user.username, email: user.email, - addAuthIds: addAuthIds + addAuthIds: addAuthIds, + removeAuthIds: [], + password: "", }); + console.log(formProps.formState.defaultValues); } catch (error) { console.log(error); setServerError(t("An error has occurred. Please try again later.")); } - }, [user, auths]); + }, [auths, user]); + + useEffect(() => { + resetForm(); + }, []); const hasErrorsInTab = ( tabIndex: number, @@ -96,22 +115,33 @@ const EditUser: React.FC = async ({ const onSubmit = useCallback>( async (data) => { try { - let haveError = false - let regex_pw = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,20}$/ - let pw = '' + let haveError = false; + let regex_pw = + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,20}$/; + let pw = ""; if (data.password && data.password.length > 0) { - pw = data.password + pw = data.password; if (pw.length < rules.min) { - haveError = true - formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" }) + haveError = true; + formProps.setError("password", { + message: t("The password requires 8-20 characters."), + type: "required", + }); } if (pw.length > rules.max) { - haveError = true - formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" }) + haveError = true; + formProps.setError("password", { + message: t("The password requires 8-20 characters."), + type: "required", + }); } if (!regex_pw.test(pw)) { - haveError = true - formProps.setError("password", { message: "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", type: "required" }) + haveError = true; + formProps.setError("password", { + message: + "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", + type: "required", + }); } } const userData = { @@ -119,16 +149,16 @@ const EditUser: React.FC = async ({ locked: false, addAuthIds: data.addAuthIds || [], removeAuthIds: data.removeAuthIds || [], - } + }; const pwData = { id: id, password: "", - newPassword: pw - } + newPassword: pw, + }; if (haveError) { - return + return; } - console.log("passed") + console.log("passed"); await editUser(id, userData); if (data.password && data.password.length > 0) { await adminChangePassword(pwData); @@ -185,12 +215,12 @@ const EditUser: React.FC = async ({ {tabIndex == 0 && } - {tabIndex === 1 && } + {tabIndex === 1 && } diff --git a/src/components/EditUser/UserDetail.tsx b/src/components/EditUser/UserDetail.tsx index fc2f419..1d251c4 100644 --- a/src/components/EditUser/UserDetail.tsx +++ b/src/components/EditUser/UserDetail.tsx @@ -9,13 +9,13 @@ import { Stack, TextField, Typography, + makeStyles, } from "@mui/material"; import { useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; - - const UserDetail: React.FC = () => { + const { t } = useTranslation(); const { register, @@ -45,6 +45,30 @@ const UserDetail: React.FC = () => { label={t("password")} fullWidth {...register("password")} + // helperText={ + // Boolean(errors.password) && + // (errors.password?.message + // ? t(errors.password.message) + // : + // (<> + // - 8-20 characters + //
+ // - Uppercase letters + //
+ // - Lowercase letters + //
+ // - Numbers + //
+ // - Symbols + // ) + // ) + // } + helperText={ + Boolean(errors.password) && + (errors.password?.message + ? t(errors.password.message) + : t("Please input correct password")) + } error={Boolean(errors.password)} /> @@ -55,3 +79,16 @@ const UserDetail: React.FC = () => { }; export default UserDetail; + + +{/* <> + - 8-20 characters +
+ - Uppercase letters +
+ - Lowercase letters +
+ - Numbers +
+ - Symbols + */} \ No newline at end of file