SignUp.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { useIntl } from "react-intl";
  2. import {
  3. ProForm,
  4. ProFormDependency,
  5. type ProFormInstance,
  6. ProFormText,
  7. } from "@ant-design/pro-components";
  8. import { Button, message, Modal, Result } from "antd";
  9. import { useNavigate } from "react-router";
  10. import { EyeInvisibleOutlined, EyeTwoTone } from "@ant-design/icons";
  11. import { get, post } from "../../../request";
  12. import LangSelect from "../../general/LangSelect";
  13. import { useRef, useState } from "react";
  14. import type {
  15. IInviteResponse,
  16. ISignInResponse,
  17. ISignUpRequest,
  18. } from "../../../api/Auth";
  19. export interface IAccountForm {
  20. email: string;
  21. username: string;
  22. nickname: string;
  23. password: string;
  24. password2: string;
  25. lang: string;
  26. }
  27. interface IAccountInfo {
  28. email?: boolean;
  29. }
  30. export const AccountInfo = ({ email = true }: IAccountInfo) => {
  31. const intl = useIntl();
  32. const [nickname, setNickname] = useState<string>();
  33. return (
  34. <>
  35. {email ? (
  36. <ProForm.Group>
  37. <ProFormText
  38. width="md"
  39. name="email"
  40. required
  41. label={intl.formatMessage({
  42. id: "forms.fields.email.label",
  43. })}
  44. rules={[{ required: true, max: 255, min: 4 }]}
  45. disabled
  46. />
  47. </ProForm.Group>
  48. ) : (
  49. <></>
  50. )}
  51. <ProForm.Group>
  52. <ProFormText
  53. width="md"
  54. name="username"
  55. required
  56. fieldProps={{
  57. onChange: (event) => {
  58. setNickname(event.target.value);
  59. },
  60. }}
  61. label={intl.formatMessage({
  62. id: "forms.fields.username.label",
  63. })}
  64. rules={[
  65. { required: true, max: 32, min: 6 },
  66. {
  67. pattern: new RegExp("^[0-9a-zA-Z_]{1,}", "g"),
  68. message: "只允许数字,字母,下划线",
  69. },
  70. ]}
  71. />
  72. </ProForm.Group>
  73. <ProForm.Group>
  74. <ProFormText.Password
  75. width="md"
  76. name="password"
  77. fieldProps={{
  78. type: "password",
  79. iconRender: (visible) =>
  80. visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />,
  81. }}
  82. required
  83. label={intl.formatMessage({
  84. id: "forms.fields.password.label",
  85. })}
  86. rules={[{ required: true, max: 32, min: 6 }]}
  87. />
  88. </ProForm.Group>
  89. <ProForm.Group>
  90. <ProFormText.Password
  91. width="md"
  92. name="password2"
  93. fieldProps={{
  94. type: "password",
  95. iconRender: (visible) =>
  96. visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />,
  97. }}
  98. required
  99. label={intl.formatMessage({
  100. id: "forms.fields.confirm-password.label",
  101. })}
  102. rules={[{ required: true, max: 32, min: 6 }]}
  103. />
  104. </ProForm.Group>
  105. <ProForm.Group>
  106. <ProFormDependency name={["username"]}>
  107. {({ username }) => {
  108. return (
  109. <ProFormText
  110. width="md"
  111. fieldProps={{
  112. placeholder: username,
  113. value: nickname ? nickname : username,
  114. onChange: (event) => {
  115. setNickname(event.target.value);
  116. },
  117. }}
  118. name="nickname"
  119. required
  120. label={intl.formatMessage({
  121. id: "forms.fields.nickname.label",
  122. })}
  123. rules={[{ required: false, max: 32, min: 4 }]}
  124. />
  125. );
  126. }}
  127. </ProFormDependency>
  128. </ProForm.Group>
  129. <ProForm.Group>
  130. <LangSelect label="常用的译文语言" />
  131. </ProForm.Group>
  132. </>
  133. );
  134. };
  135. export const SignUpSuccess = () => {
  136. const intl = useIntl();
  137. const navigate = useNavigate();
  138. return (
  139. <Result
  140. status="success"
  141. title="注册成功"
  142. subTitle={
  143. <Button
  144. type="primary"
  145. onClick={() => navigate("/anonymous/users/sign-in")}
  146. >
  147. {intl.formatMessage({
  148. id: "nut.users.sign-in.title",
  149. })}
  150. </Button>
  151. }
  152. />
  153. );
  154. };
  155. export const onSignIn = async (token: string, values: IAccountForm) => {
  156. if (values.password !== values.password2) {
  157. Modal.error({ title: "两次密码不同" });
  158. return false;
  159. }
  160. const url = "/v2/sign-up";
  161. const data = {
  162. token: token,
  163. username: values.username,
  164. nickname:
  165. values.nickname && values.nickname.trim() !== ""
  166. ? values.nickname
  167. : values.username,
  168. email: values.email,
  169. password: values.password,
  170. lang: values.lang,
  171. };
  172. console.info("api request", url, data);
  173. const signUp = await post<ISignUpRequest, ISignInResponse>(
  174. "/v2/sign-up",
  175. data
  176. );
  177. console.info("api response", signUp);
  178. return signUp;
  179. };
  180. interface IWidget {
  181. token?: string;
  182. }
  183. const SignUpWidget = ({ token }: IWidget) => {
  184. const [success, setSuccess] = useState(false);
  185. const formRef = useRef<ProFormInstance | undefined>(undefined);
  186. return success ? (
  187. <SignUpSuccess />
  188. ) : (
  189. <ProForm<IAccountForm>
  190. formRef={formRef}
  191. onFinish={async (values: IAccountForm) => {
  192. if (typeof token === "undefined") {
  193. return;
  194. }
  195. const signUp = await onSignIn(token, values);
  196. if (signUp) {
  197. if (signUp.ok) {
  198. setSuccess(true);
  199. } else {
  200. message.error(signUp.message);
  201. }
  202. }
  203. }}
  204. request={async () => {
  205. const url = `/v2/invite/${token}`;
  206. console.info("api request", url);
  207. const res = await get<IInviteResponse>(url);
  208. console.debug("api response", res.data);
  209. return {
  210. id: res.data.id,
  211. username: "",
  212. nickname: "",
  213. password: "",
  214. password2: "",
  215. email: res.data.email,
  216. lang: "zh-Hans",
  217. };
  218. }}
  219. >
  220. <AccountInfo />
  221. </ProForm>
  222. );
  223. };
  224. export default SignUpWidget;