選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

EditUser.tsx 5.9 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年前
1年前
1年前
1年前
1年前
1年前
1年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. user: UserResult,
  36. rules: passwordRule,
  37. auths: auth[]
  38. }
  39. const EditUser: React.FC<Props> = async ({
  40. user,
  41. rules,
  42. auths
  43. }) => {
  44. const { t } = useTranslation();
  45. const formProps = useForm<UserInputs>();
  46. const searchParams = useSearchParams();
  47. const id = parseInt(searchParams.get("id") || "0");
  48. const [tabIndex, setTabIndex] = useState(0);
  49. const router = useRouter();
  50. const [serverError, setServerError] = useState("");
  51. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  52. (_e, newValue) => {
  53. setTabIndex(newValue);
  54. },
  55. []
  56. );
  57. const errors = formProps.formState.errors;
  58. useEffect(() => {
  59. try {
  60. const addAuthIds = auths && auths.length > 0
  61. ? auths.filter((item) => item.v === 1).map((item) => item.id).sort((a, b) => a - b)
  62. : []
  63. formProps.reset({
  64. name: user.username,
  65. email: user.email,
  66. addAuthIds: addAuthIds
  67. });
  68. } catch (error) {
  69. console.log(error);
  70. setServerError(t("An error has occurred. Please try again later."));
  71. }
  72. }, [user, auths]);
  73. const hasErrorsInTab = (
  74. tabIndex: number,
  75. errors: FieldErrors<UserResult>
  76. ) => {
  77. switch (tabIndex) {
  78. case 0:
  79. return Object.keys(errors).length > 0;
  80. default:
  81. false;
  82. }
  83. };
  84. const handleCancel = () => {
  85. router.back();
  86. };
  87. const onSubmit = useCallback<SubmitHandler<UserInputs>>(
  88. async (data) => {
  89. try {
  90. let haveError = false
  91. let regex_pw = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,20}$/
  92. let pw = ''
  93. if (data.password && data.password.length > 0) {
  94. pw = data.password
  95. if (pw.length < rules.min) {
  96. haveError = true
  97. formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" })
  98. }
  99. if (pw.length > rules.max) {
  100. haveError = true
  101. formProps.setError("password", { message: t("The password requires 8-20 characters."), type: "required" })
  102. }
  103. if (!regex_pw.test(pw)) {
  104. haveError = true
  105. formProps.setError("password", { message: "A combination of uppercase letters, lowercase letters, numbers, and symbols is required.", type: "required" })
  106. }
  107. }
  108. const userData = {
  109. name: data.name,
  110. locked: false,
  111. addAuthIds: data.addAuthIds || [],
  112. removeAuthIds: data.removeAuthIds || [],
  113. }
  114. const pwData = {
  115. id: id,
  116. password: "",
  117. newPassword: pw
  118. }
  119. if (haveError) {
  120. return
  121. }
  122. console.log("passed")
  123. await editUser(id, userData);
  124. if (data.password && data.password.length > 0) {
  125. await adminChangePassword(pwData);
  126. }
  127. router.replace("/settings/staff");
  128. } catch (e) {
  129. console.log(e);
  130. setServerError(t("An error has occurred. Please try again later."));
  131. }
  132. },
  133. [router]
  134. );
  135. const onSubmitError = useCallback<SubmitErrorHandler<UserInputs>>(
  136. (errors) => {
  137. console.log(errors);
  138. },
  139. []
  140. );
  141. return (
  142. <>
  143. {serverError && (
  144. <Typography variant="body2" color="error" alignSelf="flex-end">
  145. {serverError}
  146. </Typography>
  147. )}
  148. <FormProvider {...formProps}>
  149. <Stack
  150. spacing={2}
  151. component="form"
  152. onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  153. >
  154. <Stack
  155. direction="row"
  156. justifyContent="space-between"
  157. flexWrap="wrap"
  158. rowGap={2}
  159. >
  160. <Tabs
  161. value={tabIndex}
  162. onChange={handleTabChange}
  163. variant="scrollable"
  164. >
  165. <Tab
  166. label={t("User Detail")}
  167. icon={
  168. hasErrorsInTab(0, errors) ? (
  169. <Error sx={{ marginInlineEnd: 1 }} color="error" />
  170. ) : undefined
  171. }
  172. iconPosition="end"
  173. />
  174. <Tab label={t("User Authority")} iconPosition="end" />
  175. </Tabs>
  176. </Stack>
  177. {tabIndex == 0 && <UserDetail />}
  178. {tabIndex === 1 && <AuthAllocation auths={auths!}/>}
  179. <Stack direction="row" justifyContent="flex-end" gap={1}>
  180. <Button
  181. variant="text"
  182. startIcon={<RestartAlt />}
  183. // onClick={() => console.log("asdasd")}
  184. >
  185. {t("Reset")}
  186. </Button>
  187. <Button
  188. variant="outlined"
  189. startIcon={<Close />}
  190. onClick={handleCancel}
  191. >
  192. {t("Cancel")}
  193. </Button>
  194. <Button variant="contained" startIcon={<Check />} type="submit">
  195. {t("Confirm")}
  196. </Button>
  197. </Stack>
  198. </Stack>
  199. </FormProvider>
  200. </>
  201. );
  202. };
  203. export default EditUser;