2
0

InvitedForm.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import React, { useCallback, useState, type JSX } from 'react';
  2. import { LoadingSpinner } from '@growi/ui/dist/components';
  3. import { useTranslation } from 'next-i18next';
  4. import { useRouter } from 'next/router';
  5. import { useForm } from 'react-hook-form';
  6. import { apiv3Post } from '~/client/util/apiv3-client';
  7. import { useCurrentUser } from '~/states/global';
  8. type InvitedFormProps = {
  9. invitedFormUsername: string,
  10. invitedFormName: string,
  11. }
  12. type InvitedFormValues = {
  13. name: string,
  14. username: string,
  15. password: string,
  16. };
  17. export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
  18. const { t } = useTranslation();
  19. const router = useRouter();
  20. const user = useCurrentUser();
  21. const [loginErrors, setLoginErrors] = useState<Error[]>([]);
  22. const [isLoading, setIsLoading] = useState(false);
  23. const { invitedFormUsername, invitedFormName } = props;
  24. const {
  25. register,
  26. handleSubmit,
  27. formState: { isSubmitting },
  28. } = useForm<InvitedFormValues>({
  29. defaultValues: {
  30. name: invitedFormName,
  31. username: invitedFormUsername,
  32. },
  33. });
  34. const submitHandler = useCallback(async(values: InvitedFormValues) => {
  35. setIsLoading(true);
  36. const invitedForm = {
  37. name: values.name,
  38. username: values.username,
  39. password: values.password,
  40. };
  41. try {
  42. const res = await apiv3Post('/invited', { invitedForm });
  43. const { redirectTo } = res.data;
  44. router.push(redirectTo ?? '/');
  45. }
  46. catch (err) {
  47. setLoginErrors(err);
  48. setIsLoading(false);
  49. }
  50. }, [router]);
  51. const formNotification = useCallback(() => {
  52. return (
  53. <>
  54. { loginErrors != null && loginErrors.length > 0 ? (
  55. <p className="alert alert-danger">
  56. { loginErrors.map((err) => {
  57. return <span>{ t(err.message) }<br /></span>;
  58. }) }
  59. </p>
  60. ) : (
  61. <p className="alert alert-success">
  62. <strong>{ t('invited.discription_heading') }</strong><br></br>
  63. <small>{ t('invited.discription') }</small>
  64. </p>
  65. ) }
  66. </>
  67. );
  68. }, [loginErrors, t]);
  69. if (user == null) {
  70. return <></>;
  71. }
  72. return (
  73. <div className="nologin-dialog px-3 pb-3 mx-auto" id="nologin-dialog">
  74. { formNotification() }
  75. <form role="form" onSubmit={handleSubmit(submitHandler)} id="invited-form">
  76. {/* Email Form */}
  77. <div className="input-group">
  78. <span className="input-group-text">
  79. <span className="material-symbols-outlined">mail</span>
  80. </span>
  81. <input
  82. type="text"
  83. className="form-control"
  84. disabled
  85. placeholder={t('Email')}
  86. name="invitedForm[email]"
  87. defaultValue={user.email}
  88. required
  89. />
  90. </div>
  91. {/* UserID Form */}
  92. <div className="input-group" id="input-group-username">
  93. <span className="input-group-text">
  94. <span className="material-symbols-outlined">person</span>
  95. </span>
  96. <input
  97. type="text"
  98. className="form-control"
  99. placeholder={t('User ID')}
  100. required
  101. {...register('username', { required: true })}
  102. />
  103. </div>
  104. {/* Name Form */}
  105. <div className="input-group">
  106. <span className="input-group-text">
  107. <span className="material-symbols-outlined">sell</span>
  108. </span>
  109. <input
  110. type="text"
  111. className="form-control"
  112. placeholder={t('Name')}
  113. required
  114. {...register('name', { required: true })}
  115. />
  116. </div>
  117. {/* Password Form */}
  118. <div className="input-group">
  119. <span className="input-group-text">
  120. <span className="material-symbols-outlined">lock</span>
  121. </span>
  122. <input
  123. type="password"
  124. className="form-control"
  125. placeholder={t('Password')}
  126. required
  127. minLength={6}
  128. {...register('password', { required: true, minLength: 6 })}
  129. />
  130. </div>
  131. {/* Create Button */}
  132. <div className="input-group justify-content-center d-flex mt-4">
  133. <button type="submit" className="btn btn-fill" id="register" disabled={isLoading || isSubmitting}>
  134. <span className="btn-label">
  135. {isLoading ? (
  136. <LoadingSpinner />
  137. ) : (
  138. <span className="material-symbols-outlined">person_add</span>
  139. )}
  140. </span>
  141. <span className="btn-label-text">{t('Create')}</span>
  142. </button>
  143. </div>
  144. </form>
  145. <div className="input-group mt-4 d-flex justify-content-center">
  146. <a href="https://growi.org" className="link-growi-org">
  147. <span className="growi">GROWI</span><span className="org">.ORG</span>
  148. </a>
  149. </div>
  150. </div>
  151. );
  152. };