You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
10 KiB

  1. // import { Link } from 'react-router-dom';
  2. import React, {
  3. useState,
  4. useRef,
  5. } from 'react';
  6. // material-ui
  7. import {
  8. Stepper,
  9. Step,
  10. StepButton,
  11. // Grid,
  12. Stack,
  13. Typography,
  14. Button, StepLabel,
  15. CircularProgress,
  16. } from '@mui/material';
  17. import VisibilityIcon from '@mui/icons-material/Visibility';
  18. import { POST_USERNAME, POST_VERIFY_CAPTCHA } from "utils/ApiPathConst";
  19. // project import
  20. import Loadable from 'components/Loadable';
  21. import { lazy } from 'react';
  22. import { notifyActionError } from 'utils/CommonFunction';
  23. import axios from "axios";
  24. import {FormattedMessage, useIntl} from "react-intl";
  25. import usePageTitle from "components/usePageTitle";
  26. const CustomFormWizard = Loadable(lazy(() => import('./auth-forms/CustomFormWizard')));
  27. const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom')));
  28. // ================================|| REGISTER ||================================ //
  29. const Register = () => {
  30. const [activeStep, setActiveStep] = useState(0);
  31. const [completed, setCompleted] = useState([false]);
  32. const [updateValid, setUpdateValid] = useState(false);
  33. const step0GuardRef = useRef(null);
  34. const [username, setUsername] = useState("");
  35. const [base64Url, setBase64Url] = useState("")
  36. const [checkCode, setCheckCode] = useState("")
  37. const [isNextBusy, setIsNextBusy] = useState(false);
  38. const nextBusyRef = useRef(false);
  39. const intl = useIntl();
  40. // Localized document title/meta for register flow
  41. usePageTitle("register");
  42. const steps = [
  43. intl.formatMessage({id: 'personalInformation'}),
  44. intl.formatMessage({id: 'preview'}),
  45. intl.formatMessage({id: 'finishSubmission'})
  46. ];
  47. const stepStyle = {
  48. width: { lg: "40%", md: "70%", xs: "100%" },
  49. boxShadow: 1,
  50. backgroundColor: "#FFFFFF",
  51. padding: 2,
  52. /* Inactive (default) */
  53. "& .MuiStepIcon-root": { color: "#757575", fontSize: "2rem" }, // darker grey
  54. "& .MuiStepLabel-label": { color: "#424242" }, // label darker
  55. "& .MuiStepConnector-line": { borderColor: "#9E9E9E" }, // connector darker
  56. /* Active */
  57. "& .Mui-active": {
  58. "&.MuiStepIcon-root": { color: "warning.main", fontSize: "2rem" },
  59. "& .MuiStepConnector-line": { borderColor: "warning.main" }
  60. },
  61. /* Completed */
  62. "& .Mui-completed": {
  63. "&.MuiStepIcon-root": { color: "#1976d2", fontSize: "2rem" }, // use your strong blue
  64. "& .MuiStepConnector-line": { borderColor: "#1976d2" }
  65. }
  66. };
  67. const totalSteps = () => {
  68. return steps.length;
  69. };
  70. const completedSteps = () => {
  71. return Object.keys(completed).length;
  72. };
  73. const isLastStep = () => {
  74. return activeStep === totalSteps() - 1;
  75. };
  76. const allStepsCompleted = () => {
  77. return completedSteps() === totalSteps();
  78. };
  79. const handleCheckUsername = async () => {
  80. const response = await axios.post(`${POST_USERNAME}`, {
  81. u1: username,
  82. })
  83. return Number(response.data[0]) > 0
  84. }
  85. const handleCaptcha = async () => {
  86. const response = await axios.post(`${POST_VERIFY_CAPTCHA}`, {
  87. captcha: base64Url,
  88. checkCode: checkCode,
  89. })
  90. return Boolean(response.data["success"]);
  91. }
  92. const handleNext = async () => {
  93. if (nextBusyRef.current) return;
  94. nextBusyRef.current = true;
  95. setIsNextBusy(true);
  96. try {
  97. if (activeStep === 0 && step0GuardRef.current) {
  98. const step0Ok = await Promise.resolve(step0GuardRef.current());
  99. if (!step0Ok) {
  100. return;
  101. }
  102. }
  103. const captchaTest = await handleCaptcha();
  104. if (!captchaTest) {
  105. notifyActionError(intl.formatMessage({id: 'validVerify'}))
  106. return;
  107. }
  108. const test = await handleCheckUsername()
  109. if (test) {
  110. notifyActionError(intl.formatMessage({id: 'usernameTaken'}))
  111. } else {
  112. const newActiveStep =
  113. isLastStep() && !allStepsCompleted()
  114. ? // It's the last step, but not all steps have been completed,
  115. // find the first step that has been completed
  116. steps.findIndex((step, i) => !(i in completed))
  117. : activeStep + 1;
  118. setActiveStep(newActiveStep);
  119. scrollToTop();
  120. }
  121. } finally {
  122. nextBusyRef.current = false;
  123. setIsNextBusy(false);
  124. }
  125. };
  126. const handleBack = () => {
  127. scrollToTop();
  128. setActiveStep((prevActiveStep) => prevActiveStep - 1);
  129. };
  130. const scrollToTop = () => {
  131. window.scrollTo(0, 0);
  132. };
  133. const handleReset = () => {
  134. setActiveStep(0);
  135. setCompleted({});
  136. };
  137. return (
  138. // <AuthWrapper>
  139. <Stack sx={{ width: '100%', fontSize: '2rem', paddingTop: '35px', bgcolor: 'backgroundColor.default' }} alignItems="center">
  140. <Stepper activeStep={activeStep} sx={stepStyle}>
  141. {steps.map((label, index) => (
  142. <Step key={label} completed={completed[index]} readOnly={true}>
  143. {index < 2 ? (
  144. <StepButton
  145. aria-current={activeStep === index ? 'step' : undefined}
  146. // onClick={handleStep(index)}
  147. >
  148. <StepLabel
  149. sx={{
  150. flexDirection: 'column',
  151. "& .MuiStepLabel-iconContainer": { paddingRight: 0 }
  152. }}
  153. >
  154. <Typography variant="step1">{label}</Typography>
  155. </StepLabel>
  156. </StepButton>
  157. ) : (
  158. <StepButton
  159. aria-current={activeStep === index ? 'step' : undefined}
  160. sx={
  161. activeStep === 2
  162. ? { "& .MuiSvgIcon-root": { color: "warning.main", fontSize: "2rem" } }
  163. : allStepsCompleted()
  164. ? { "& .MuiSvgIcon-root": { color: "#1976d2", fontSize: "2rem" } }
  165. : { color: "rgba(0,0,0,0.6)" }
  166. }
  167. icon={<VisibilityIcon />}
  168. // onClick={handleStep(index)}
  169. >
  170. <StepLabel
  171. sx={{
  172. flexDirection: 'column',
  173. "& .MuiStepLabel-iconContainer": { paddingRight: 0 }
  174. }}
  175. >
  176. <Typography variant="step1">{label}</Typography>
  177. </StepLabel>
  178. </StepButton>
  179. )}
  180. </Step>
  181. ))}
  182. </Stepper>
  183. {allStepsCompleted() ? (
  184. <React.Fragment>
  185. <Typography variant="h4" sx={{ mt: 2, mb: 1 }}>
  186. All steps completed - you&apos;re finished
  187. </Typography>
  188. <Stack direction="row" sx={{ pt: 2 }}>
  189. <Stack sx={{ flex: '1 1 auto' }} />
  190. <Button onClick={handleReset}><Typography variant="h5">Reset</Typography></Button>
  191. </Stack>
  192. </React.Fragment>
  193. ) : (
  194. <React.Fragment>
  195. <AuthWrapper>
  196. <CustomFormWizard
  197. setUpdateValid={setUpdateValid}
  198. step0GuardRef={step0GuardRef}
  199. step={activeStep}
  200. setUsername={setUsername}
  201. setBase64Url={setBase64Url}
  202. setCheckCode={setCheckCode}
  203. />
  204. {/* <CustomFormWizard step={activeStep} /> */}
  205. </AuthWrapper>
  206. <Stack direction="row" sx={{ pb: 2, mt:-4, mb:2 }}>
  207. {activeStep === 2 || activeStep === 0 ? (
  208. <Button
  209. color="inherit"
  210. disabled={true}
  211. onClick={handleBack}
  212. sx={{ mr: 1 }}
  213. variant="h5"
  214. >
  215. <Typography variant="h5">
  216. <FormattedMessage id="back"/>
  217. </Typography>
  218. </Button>
  219. ) : (
  220. <Button
  221. color="inherit"
  222. disabled={activeStep === 0 || isNextBusy}
  223. onClick={handleBack}
  224. sx={{ mr: 1 }}
  225. variant="h5"
  226. >
  227. <Typography variant="h5">
  228. <FormattedMessage id="back"/>
  229. </Typography>
  230. </Button>
  231. )
  232. }
  233. <Stack sx={{ flex: '1 1 auto' }} />
  234. {activeStep === totalSteps() - 2 ?
  235. (
  236. <Button
  237. variant="outlined"
  238. disabled={isNextBusy}
  239. onClick={handleNext}
  240. aria-busy={isNextBusy}
  241. sx={{ mr: 1, minWidth: 120 }}
  242. >
  243. {isNextBusy ? (
  244. <CircularProgress size={22} color="inherit" aria-hidden />
  245. ) : (
  246. <Typography variant="h5">
  247. <FormattedMessage id="submit"/>
  248. </Typography>
  249. )}
  250. </Button>
  251. ) : (activeStep === totalSteps() - 1 ?
  252. (
  253. <Button variant="outlined" color="inherit"
  254. disabled={true} sx={{ mr: 1 }}>
  255. <Typography variant="h5">
  256. <FormattedMessage id="submit"/>
  257. </Typography>
  258. </Button>
  259. ) :
  260. (
  261. // <Button disabled={updateValid} variant="outlined" onClick={handleNext} sx={{ mr: 1 }}>
  262. <Button disabled={!updateValid || isNextBusy} variant="outlined" onClick={handleNext} sx={{ mr: 1 }}>
  263. <Typography variant="h5">
  264. <FormattedMessage id="continue"/>
  265. </Typography>
  266. </Button>
  267. )
  268. )}
  269. {/* {activeStep !== steps.length &&
  270. (completed[activeStep] ? (
  271. <Typography variant="caption" sx={{ display: 'inline-block' }}>
  272. Step {activeStep + 1} already completed
  273. </Typography>
  274. ) : (
  275. <Button onClick={handleComplete}>
  276. {completedSteps() === totalSteps() - 1
  277. ? 'Finish'
  278. : 'Complete Step'}
  279. </Button>
  280. ))} */}
  281. </Stack>
  282. </React.Fragment>
  283. )}
  284. </Stack >
  285. // </AuthWrapper>
  286. );
  287. };
  288. export default Register;