您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

EditUser.tsx 6.6 KiB

1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
1年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. "use client";
  2. import { useRouter, useSearchParams } from "next/navigation";
  3. import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
  4. import SearchResults, { Column } from "../SearchResults";
  5. // import { TeamResult } from "@/app/api/team";
  6. import { useTranslation } from "react-i18next";
  7. import {
  8. Button,
  9. Card,
  10. CardContent,
  11. Grid,
  12. Stack,
  13. Tab,
  14. Tabs,
  15. TabsProps,
  16. TextField,
  17. Typography,
  18. } from "@mui/material";
  19. import {
  20. FieldErrors,
  21. FormProvider,
  22. SubmitErrorHandler,
  23. SubmitHandler,
  24. useForm,
  25. useFormContext,
  26. } from "react-hook-form";
  27. import { Check, Close, Error, RestartAlt } from "@mui/icons-material";
  28. import { StaffResult } from "@/app/api/staff";
  29. import { UserInputs, adminChangePassword, editUser, fetchUserDetails } from "@/app/api/user/actions";
  30. import UserDetail from "./UserDetail";
  31. import { UserResult, passwordRule } from "@/app/api/user";
  32. import { auth, fetchAuth } from "@/app/api/group/actions";
  33. import AuthAllocation from "./AuthAllocation";
  34. interface Props {
  35. rules: passwordRule
  36. }
  37. const EditUser: React.FC<Props> = async ({
  38. rules
  39. }) => {
  40. const { t } = useTranslation();
  41. const formProps = useForm<UserInputs>();
  42. const searchParams = useSearchParams();
  43. const id = parseInt(searchParams.get("id") || "0");
  44. const [tabIndex, setTabIndex] = useState(0);
  45. const router = useRouter();
  46. const [serverError, setServerError] = useState("");
  47. const [data, setData] = useState<UserResult>();
  48. const [auths, setAuths] = useState<auth[]>();
  49. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  50. (_e, newValue) => {
  51. setTabIndex(newValue);
  52. },
  53. []
  54. );
  55. console.log(rules);
  56. const errors = formProps.formState.errors;
  57. const fetchUserDetail = async () => {
  58. try {
  59. // fetch user info
  60. const userDetail = await fetchUserDetails(id);
  61. console.log(userDetail);
  62. const _data = userDetail.data as UserResult;
  63. console.log(_data);
  64. setData(_data);
  65. //fetch user auths
  66. const authDetail = await fetchAuth("user", id);
  67. setAuths(authDetail.records)
  68. const addAuthIds = authDetail.records.filter((item) => item.v === 1).map((item) => item.id).sort((a, b) => a - b);
  69. formProps.reset({
  70. name: _data.username,
  71. email: _data.email,
  72. addAuthIds: addAuthIds || []
  73. });
  74. } catch (error) {
  75. console.log(error);
  76. setServerError(t("An error has occurred. Please try again later."));
  77. }
  78. }
  79. useEffect(() => {
  80. fetchUserDetail();
  81. }, []);
  82. // useEffect(() => {
  83. // const thisUser = users.filter((item) => item.id === id)
  84. // formProps.reset({
  85. // username: thisUser[0].username,
  86. // email: thisUser[0].email,
  87. // });
  88. // }, []);
  89. const hasErrorsInTab = (
  90. tabIndex: number,
  91. errors: FieldErrors<UserResult>
  92. ) => {
  93. switch (tabIndex) {
  94. case 0:
  95. return Object.keys(errors).length > 0;
  96. default:
  97. false;
  98. }
  99. };
  100. const handleCancel = () => {
  101. router.back();
  102. };
  103. const onSubmit = useCallback<SubmitHandler<UserInputs>>(
  104. async (data) => {
  105. try {
  106. let haveError = false
  107. let regex_pw = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
  108. let pw = ''
  109. if (data.password && data.password.length > 0) {
  110. pw = data.password
  111. if (pw.length < rules.min) {
  112. haveError = true
  113. formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" })
  114. }
  115. if (pw.length > rules.max) {
  116. haveError = true
  117. formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" })
  118. }
  119. if (!regex_pw.test(pw)) {
  120. haveError = true
  121. formProps.setError("password", { message: "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", type: "required" })
  122. }
  123. }
  124. console.log(data);
  125. const userData = {
  126. name: data.name,
  127. email: '',
  128. locked: false,
  129. addAuthIds: data.addAuthIds || [],
  130. removeAuthIds: data.removeAuthIds || [],
  131. }
  132. const pwData = {
  133. id: id,
  134. password: "",
  135. newPassword: pw
  136. }
  137. console.log(userData);
  138. if (haveError) {
  139. return
  140. }
  141. await editUser(id, userData);
  142. if (data.password && data.password.length > 0) {
  143. await adminChangePassword(pwData);
  144. }
  145. router.replace("/settings/staff");
  146. } catch (e) {
  147. console.log(e);
  148. setServerError(t("An error has occurred. Please try again later."));
  149. }
  150. },
  151. [router]
  152. );
  153. const onSubmitError = useCallback<SubmitErrorHandler<UserInputs>>(
  154. (errors) => {
  155. console.log(errors);
  156. },
  157. []
  158. );
  159. return (
  160. <>
  161. {serverError && (
  162. <Typography variant="body2" color="error" alignSelf="flex-end">
  163. {serverError}
  164. </Typography>
  165. )}
  166. <FormProvider {...formProps}>
  167. <Stack
  168. spacing={2}
  169. component="form"
  170. onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  171. >
  172. <Stack
  173. direction="row"
  174. justifyContent="space-between"
  175. flexWrap="wrap"
  176. rowGap={2}
  177. >
  178. <Tabs
  179. value={tabIndex}
  180. onChange={handleTabChange}
  181. variant="scrollable"
  182. >
  183. <Tab
  184. label={t("User Detail")}
  185. icon={
  186. hasErrorsInTab(0, errors) ? (
  187. <Error sx={{ marginInlineEnd: 1 }} color="error" />
  188. ) : undefined
  189. }
  190. iconPosition="end"
  191. />
  192. <Tab label={t("User Authority")} iconPosition="end" />
  193. </Tabs>
  194. </Stack>
  195. {tabIndex == 0 && <UserDetail data={data!} />}
  196. {tabIndex === 1 && <AuthAllocation auths={auths!}/>}
  197. <Stack direction="row" justifyContent="flex-end" gap={1}>
  198. <Button
  199. variant="text"
  200. startIcon={<RestartAlt />}
  201. // onClick={() => console.log("asdasd")}
  202. >
  203. {t("Reset")}
  204. </Button>
  205. <Button
  206. variant="outlined"
  207. startIcon={<Close />}
  208. onClick={handleCancel}
  209. >
  210. {t("Cancel")}
  211. </Button>
  212. <Button variant="contained" startIcon={<Check />} type="submit">
  213. {t("Confirm")}
  214. </Button>
  215. </Stack>
  216. </Stack>
  217. </FormProvider>
  218. </>
  219. );
  220. };
  221. export default EditUser;