FPSMS-frontend
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

CreateUser.tsx 6.5 KiB

hace 2 días
hace 2 días
hace 2 días
hace 2 días
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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 = {
  138. username: data.username,
  139. // name: data.name,
  140. locked: false,
  141. addAuthIds: data.addAuthIds || [],
  142. removeAuthIds: data.removeAuthIds || [],
  143. password: pw,
  144. };
  145. const pwData = {
  146. id: id,
  147. password: pw,
  148. newPassword: "",
  149. };
  150. if (haveError) {
  151. return;
  152. }
  153. console.log("passed");
  154. console.log(userData);
  155. await createUser(userData);
  156. // if (data.password && data.password.length > 0) {
  157. // await adminChangePassword(pwData);
  158. // }
  159. router.replace("/settings/user");
  160. } catch (e) {
  161. console.log(e);
  162. setServerError(t("An error has occurred. Please try again later."));
  163. }
  164. },
  165. [router],
  166. );
  167. const onSubmitError = useCallback<SubmitErrorHandler<UserInputs>>(
  168. (errors) => {
  169. console.log(errors);
  170. },
  171. [],
  172. );
  173. return (
  174. <>
  175. {serverError && (
  176. <Typography variant="body2" color="error" alignSelf="flex-end">
  177. {serverError}
  178. </Typography>
  179. )}
  180. <FormProvider {...formProps}>
  181. <Stack
  182. spacing={2}
  183. component="form"
  184. onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
  185. >
  186. <Stack
  187. direction="row"
  188. justifyContent="space-between"
  189. flexWrap="wrap"
  190. rowGap={2}
  191. >
  192. <Tabs
  193. value={tabIndex}
  194. onChange={handleTabChange}
  195. variant="scrollable"
  196. >
  197. <Tab
  198. label={t("User Detail")}
  199. icon={
  200. hasErrorsInTab(0, errors) ? (
  201. <Error sx={{ marginInlineEnd: 1 }} color="error" />
  202. ) : undefined
  203. }
  204. iconPosition="end"
  205. />
  206. <Tab label={t("User Authority")} iconPosition="end" />
  207. </Tabs>
  208. </Stack>
  209. {tabIndex == 0 && <UserDetail />}
  210. {tabIndex === 1 && <AuthAllocation auths={auths!} />}
  211. <Stack direction="row" justifyContent="flex-end" gap={1}>
  212. <Button
  213. variant="text"
  214. startIcon={<RestartAlt />}
  215. onClick={(e) => {
  216. e.preventDefault();
  217. e.stopPropagation();
  218. resetForm(e);
  219. }}
  220. type="button"
  221. >
  222. {t("Reset")}
  223. </Button>
  224. <Button
  225. variant="outlined"
  226. startIcon={<Close />}
  227. onClick={handleCancel}
  228. type="button"
  229. >
  230. {t("Cancel")}
  231. </Button>
  232. <Button variant="contained" startIcon={<Check />} type="submit">
  233. {t("Confirm")}
  234. </Button>
  235. </Stack>
  236. </Stack>
  237. </FormProvider>
  238. </>
  239. );
  240. };
  241. export default CreateUser;