ChangeEmail.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import { wait } from "@/utils/promise";
  2. import { changeEmail, sendOTTForEmailChange } from "@ente/accounts/api/user";
  3. import { APP_HOMES } from "@ente/shared/apps/constants";
  4. import { PageProps } from "@ente/shared/apps/types";
  5. import { VerticallyCentered } from "@ente/shared/components/Container";
  6. import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer";
  7. import LinkButton from "@ente/shared/components/LinkButton";
  8. import SubmitButton from "@ente/shared/components/SubmitButton";
  9. import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
  10. import { Alert, Box, TextField } from "@mui/material";
  11. import { Formik, FormikHelpers } from "formik";
  12. import { t } from "i18next";
  13. import { useRouter } from "next/router";
  14. import { useRef, useState } from "react";
  15. import { Trans } from "react-i18next";
  16. import * as Yup from "yup";
  17. interface formValues {
  18. email: string;
  19. ott?: string;
  20. }
  21. function ChangeEmailForm({ appName }: PageProps) {
  22. const [loading, setLoading] = useState(false);
  23. const [ottInputVisible, setShowOttInputVisibility] = useState(false);
  24. const ottInputRef = useRef(null);
  25. const [email, setEmail] = useState(null);
  26. const [showMessage, setShowMessage] = useState(false);
  27. const [success, setSuccess] = useState(false);
  28. const router = useRouter();
  29. const requestOTT = async (
  30. { email }: formValues,
  31. { setFieldError }: FormikHelpers<formValues>,
  32. ) => {
  33. try {
  34. setLoading(true);
  35. await sendOTTForEmailChange(email);
  36. setEmail(email);
  37. setShowOttInputVisibility(true);
  38. setShowMessage(true);
  39. setTimeout(() => {
  40. ottInputRef.current?.focus();
  41. }, 250);
  42. } catch (e) {
  43. setFieldError("email", t("EMAIl_ALREADY_OWNED"));
  44. }
  45. setLoading(false);
  46. };
  47. const requestEmailChange = async (
  48. { email, ott }: formValues,
  49. { setFieldError }: FormikHelpers<formValues>,
  50. ) => {
  51. try {
  52. setLoading(true);
  53. await changeEmail(email, ott);
  54. setData(LS_KEYS.USER, { ...getData(LS_KEYS.USER), email });
  55. setLoading(false);
  56. setSuccess(true);
  57. await wait(1000);
  58. goToApp();
  59. } catch (e) {
  60. setLoading(false);
  61. setFieldError("ott", t("INCORRECT_CODE"));
  62. }
  63. };
  64. const goToApp = () => {
  65. router.push(APP_HOMES.get(appName));
  66. };
  67. return (
  68. <Formik<formValues>
  69. initialValues={{ email: "" }}
  70. validationSchema={Yup.object().shape({
  71. email: Yup.string()
  72. .email(t("EMAIL_ERROR"))
  73. .required(t("REQUIRED")),
  74. ott: ottInputVisible && Yup.string().required(t("REQUIRED")),
  75. })}
  76. validateOnChange={false}
  77. validateOnBlur={false}
  78. onSubmit={!ottInputVisible ? requestOTT : requestEmailChange}
  79. >
  80. {({ values, errors, handleChange, handleSubmit }) => (
  81. <>
  82. {showMessage && (
  83. <Alert
  84. color="success"
  85. onClose={() => setShowMessage(false)}
  86. >
  87. <Trans
  88. i18nKey="EMAIL_SENT"
  89. components={{
  90. a: (
  91. <Box
  92. color="text.muted"
  93. component={"span"}
  94. />
  95. ),
  96. }}
  97. values={{ email }}
  98. />
  99. </Alert>
  100. )}
  101. <form noValidate onSubmit={handleSubmit}>
  102. <VerticallyCentered>
  103. <TextField
  104. fullWidth
  105. InputProps={{
  106. readOnly: ottInputVisible,
  107. }}
  108. type="email"
  109. label={t("ENTER_EMAIL")}
  110. value={values.email}
  111. onChange={handleChange("email")}
  112. error={Boolean(errors.email)}
  113. helperText={errors.email}
  114. autoFocus
  115. disabled={loading}
  116. />
  117. {ottInputVisible && (
  118. <TextField
  119. fullWidth
  120. type="text"
  121. label={t("ENTER_OTT")}
  122. value={values.ott}
  123. onChange={handleChange("ott")}
  124. error={Boolean(errors.ott)}
  125. helperText={errors.ott}
  126. disabled={loading}
  127. />
  128. )}
  129. <SubmitButton
  130. success={success}
  131. sx={{ mt: 2 }}
  132. loading={loading}
  133. buttonText={
  134. !ottInputVisible
  135. ? t("SEND_OTT")
  136. : t("VERIFY")
  137. }
  138. />
  139. </VerticallyCentered>
  140. </form>
  141. <FormPaperFooter
  142. style={{
  143. justifyContent: ottInputVisible && "space-between",
  144. }}
  145. >
  146. {ottInputVisible && (
  147. <LinkButton
  148. onClick={() => setShowOttInputVisibility(false)}
  149. >
  150. {t("CHANGE_EMAIL")}?
  151. </LinkButton>
  152. )}
  153. <LinkButton onClick={goToApp}>
  154. {t("GO_BACK")}
  155. </LinkButton>
  156. </FormPaperFooter>
  157. </>
  158. )}
  159. </Formik>
  160. );
  161. }
  162. export default ChangeEmailForm;