SetPasswordForm.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { isWeakPassword } from "@ente/accounts/utils";
  2. import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
  3. import SubmitButton from "@ente/shared/components/SubmitButton";
  4. import { Box, Input, TextField, Typography } from "@mui/material";
  5. import { Formik } from "formik";
  6. import { t } from "i18next";
  7. import React, { useState } from "react";
  8. import { Trans } from "react-i18next";
  9. import * as Yup from "yup";
  10. import { PasswordStrengthHint } from "./PasswordStrength";
  11. export interface SetPasswordFormProps {
  12. userEmail: string;
  13. callback: (
  14. passphrase: string,
  15. setFieldError: (
  16. field: keyof SetPasswordFormValues,
  17. message: string,
  18. ) => void,
  19. ) => Promise<void>;
  20. buttonText: string;
  21. }
  22. export interface SetPasswordFormValues {
  23. passphrase: string;
  24. confirm: string;
  25. }
  26. function SetPasswordForm(props: SetPasswordFormProps) {
  27. const [loading, setLoading] = useState(false);
  28. const [showPassword, setShowPassword] = useState(false);
  29. const handleClickShowPassword = () => {
  30. setShowPassword(!showPassword);
  31. };
  32. const handleMouseDownPassword = (
  33. event: React.MouseEvent<HTMLButtonElement>,
  34. ) => {
  35. event.preventDefault();
  36. };
  37. const onSubmit = async (
  38. values: SetPasswordFormValues,
  39. {
  40. setFieldError,
  41. }: {
  42. setFieldError: (
  43. field: keyof SetPasswordFormValues,
  44. message: string,
  45. ) => void;
  46. },
  47. ) => {
  48. setLoading(true);
  49. try {
  50. const { passphrase, confirm } = values;
  51. if (passphrase === confirm) {
  52. await props.callback(passphrase, setFieldError);
  53. } else {
  54. setFieldError("confirm", t("PASSPHRASE_MATCH_ERROR"));
  55. }
  56. } catch (e) {
  57. setFieldError("confirm", `${t("UNKNOWN_ERROR")} ${e.message}`);
  58. } finally {
  59. setLoading(false);
  60. }
  61. };
  62. return (
  63. <Formik<SetPasswordFormValues>
  64. initialValues={{ passphrase: "", confirm: "" }}
  65. validationSchema={Yup.object().shape({
  66. passphrase: Yup.string().required(t("REQUIRED")),
  67. confirm: Yup.string().required(t("REQUIRED")),
  68. })}
  69. validateOnChange={false}
  70. validateOnBlur={false}
  71. onSubmit={onSubmit}
  72. >
  73. {({ values, errors, handleChange, handleSubmit }) => (
  74. <form noValidate onSubmit={handleSubmit}>
  75. <Typography mb={2} color="text.muted" variant="small">
  76. {t("ENTER_ENC_PASSPHRASE")}
  77. </Typography>
  78. <Input
  79. sx={{ display: "none" }}
  80. name="email"
  81. id="email"
  82. autoComplete="username"
  83. type="email"
  84. value={props.userEmail}
  85. />
  86. <TextField
  87. fullWidth
  88. name="password"
  89. id="password"
  90. autoComplete="new-password"
  91. type={showPassword ? "text" : "password"}
  92. label={t("PASSPHRASE_HINT")}
  93. value={values.passphrase}
  94. onChange={handleChange("passphrase")}
  95. error={Boolean(errors.passphrase)}
  96. helperText={errors.passphrase}
  97. autoFocus
  98. disabled={loading}
  99. InputProps={{
  100. endAdornment: (
  101. <ShowHidePassword
  102. showPassword={showPassword}
  103. handleClickShowPassword={
  104. handleClickShowPassword
  105. }
  106. handleMouseDownPassword={
  107. handleMouseDownPassword
  108. }
  109. />
  110. ),
  111. }}
  112. />
  113. <TextField
  114. fullWidth
  115. name="confirm-password"
  116. id="confirm-password"
  117. autoComplete="new-password"
  118. type="password"
  119. label={t("CONFIRM_PASSPHRASE")}
  120. value={values.confirm}
  121. onChange={handleChange("confirm")}
  122. disabled={loading}
  123. error={Boolean(errors.confirm)}
  124. helperText={errors.confirm}
  125. />
  126. <PasswordStrengthHint password={values.passphrase} />
  127. <Typography my={2} variant="small">
  128. <Trans i18nKey={"PASSPHRASE_DISCLAIMER"} />
  129. </Typography>
  130. <Box my={4}>
  131. <SubmitButton
  132. sx={{ my: 0 }}
  133. loading={loading}
  134. buttonText={props.buttonText}
  135. disabled={isWeakPassword(values.passphrase)}
  136. />
  137. {loading && (
  138. <Typography
  139. textAlign="center"
  140. mt={1}
  141. color="text.muted"
  142. variant="small"
  143. >
  144. {t("KEY_GENERATION_IN_PROGRESS_MESSAGE")}
  145. </Typography>
  146. )}
  147. </Box>
  148. </form>
  149. )}
  150. </Formik>
  151. );
  152. }
  153. export default SetPasswordForm;