FPSMS-frontend
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 

253 lignes
6.6 KiB

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