SetPasswordForm.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import React, { useState } from 'react';
  2. import { Formik } from 'formik';
  3. import * as Yup from 'yup';
  4. import SubmitButton from '@ente/shared/components/SubmitButton';
  5. import { Box, Input, TextField, Typography } from '@mui/material';
  6. import { PasswordStrengthHint } from './PasswordStrength';
  7. import { isWeakPassword } from '@ente/accounts/utils';
  8. import { Trans } from 'react-i18next';
  9. import { t } from 'i18next';
  10. import ShowHidePassword from '@ente/shared/components/Form/ShowHidePassword';
  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. {({ values, errors, handleChange, handleSubmit }) => (
  73. <form noValidate onSubmit={handleSubmit}>
  74. <Typography mb={2} color="text.muted" variant="small">
  75. {t('ENTER_ENC_PASSPHRASE')}
  76. </Typography>
  77. <Input
  78. sx={{ display: 'none' }}
  79. name="email"
  80. id="email"
  81. autoComplete="username"
  82. type="email"
  83. value={props.userEmail}
  84. />
  85. <TextField
  86. fullWidth
  87. name="password"
  88. id="password"
  89. autoComplete="new-password"
  90. type={showPassword ? 'text' : 'password'}
  91. label={t('PASSPHRASE_HINT')}
  92. value={values.passphrase}
  93. onChange={handleChange('passphrase')}
  94. error={Boolean(errors.passphrase)}
  95. helperText={errors.passphrase}
  96. autoFocus
  97. disabled={loading}
  98. InputProps={{
  99. endAdornment: (
  100. <ShowHidePassword
  101. showPassword={showPassword}
  102. handleClickShowPassword={
  103. handleClickShowPassword
  104. }
  105. handleMouseDownPassword={
  106. handleMouseDownPassword
  107. }
  108. />
  109. ),
  110. }}
  111. />
  112. <TextField
  113. fullWidth
  114. name="confirm-password"
  115. id="confirm-password"
  116. autoComplete="new-password"
  117. type="password"
  118. label={t('CONFIRM_PASSPHRASE')}
  119. value={values.confirm}
  120. onChange={handleChange('confirm')}
  121. disabled={loading}
  122. error={Boolean(errors.confirm)}
  123. helperText={errors.confirm}
  124. />
  125. <PasswordStrengthHint password={values.passphrase} />
  126. <Typography my={2} variant="small">
  127. <Trans i18nKey={'PASSPHRASE_DISCLAIMER'} />
  128. </Typography>
  129. <Box my={4}>
  130. <SubmitButton
  131. sx={{ my: 0 }}
  132. loading={loading}
  133. buttonText={props.buttonText}
  134. disabled={isWeakPassword(values.passphrase)}
  135. />
  136. {loading && (
  137. <Typography
  138. textAlign="center"
  139. mt={1}
  140. color="text.muted"
  141. variant="small">
  142. {t('KEY_GENERATION_IN_PROGRESS_MESSAGE')}
  143. </Typography>
  144. )}
  145. </Box>
  146. </form>
  147. )}
  148. </Formik>
  149. );
  150. }
  151. export default SetPasswordForm;