ChangeEmail.tsx 6.4 KB

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