[web] General refactoring - Update the OTP input component package (#3884)

This commit is contained in:
Manav Rathi
2024-10-29 19:37:21 +05:30
committed by GitHub
6 changed files with 52 additions and 56 deletions

View File

@@ -27,7 +27,6 @@
"piexifjs": "^1.0.6",
"pure-react-carousel": "^1.30.1",
"react-dropzone": "^14.2",
"react-otp-input": "^2.3.1",
"react-select": "^5.8.0",
"react-top-loading-bar": "^2.3.1",
"react-virtualized-auto-sizer": "^1.0",

View File

@@ -124,37 +124,3 @@ body {
.pswp__caption--empty {
display: none;
}
.carousel-inner {
padding-bottom: 50px !important;
}
.carousel-indicators li {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 12px;
}
.carousel-indicators .active {
background-color: #51cd7c;
}
div.otp-input input {
width: 36px !important;
height: 36px;
margin: 0 10px;
}
div.otp-input input::placeholder {
opacity: 0;
}
div.otp-input input:not(:placeholder-shown),
div.otp-input input:focus {
border: 2px solid #51cd7c;
border-radius: 1px;
-webkit-transition: 0.5s;
transition: 0.5s;
outline: none;
}

View File

@@ -132,7 +132,7 @@ with Next.js.
For more details, see [translations.md](translations.md).
### Others
### Other UI components
- [formik](https://github.com/jaredpalmer/formik) provides an easier to use
abstraction for dealing with form state, validation and submission states
@@ -140,6 +140,9 @@ For more details, see [translations.md](translations.md).
- [react-select](https://react-select.com/) is used for search dropdowns.
- [react-otp-input](https://github.com/devfolioco/react-otp-input) is used to
render a segmented OTP input field for 2FA authentication.
## Utilities
- [comlink](https://github.com/GoogleChromeLabs/comlink) provides a minimal
@@ -191,15 +194,20 @@ For more details, see [translations.md](translations.md).
- [chrono-node](https://github.com/wanasit/chrono) is used for parsing natural
language queries into dates for showing search results.
- [matrix](https://github.com/mljs/matrix) is mathematical matrix abstraction
by the machine learning code. It is used alongwith
[similarity-transformation](https://github.com/shaileshpandit/similarity-transformation-js)
during face alignment.
### UI
- [react-top-loading-bar](https://github.com/klendi/react-top-loading-bar) is
used for showing a progress indicator for global actions (This shouldn't be
used always, it is only meant as a fallback when there isn't an otherwise
suitable place for showing a local activity indicator).
- [matrix](https://github.com/mljs/matrix) is mathematical matrix abstraction
by the machine learning code. It is used alongwith
[similarity-transformation](https://github.com/shaileshpandit/similarity-transformation-js)
during face alignment.
- [pure-react-carousel](https://github.com/express-labs/pure-react-carousel)
is used for the feature carousel on the welcome (login / signup) screen.
## Auth app specific

View File

@@ -4,10 +4,10 @@ import {
CenteredFlex,
VerticallyCentered,
} from "@ente/shared/components/Container";
import { Box, Typography } from "@mui/material";
import { Box, Typography, styled } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
import { t } from "i18next";
import { useRef, useState } from "react";
import { useState } from "react";
import OtpInput from "react-otp-input";
interface formValues {
@@ -25,7 +25,7 @@ export type VerifyTwoFactorCallback = (
export default function VerifyTwoFactor(props: Props) {
const [waiting, setWaiting] = useState(false);
const otpInputRef = useRef<OtpInput>(null);
const [shouldAutoFocus, setShouldAutoFocus] = useState(true);
const markSuccessful = async () => {
setWaiting(false);
@@ -40,11 +40,13 @@ export default function VerifyTwoFactor(props: Props) {
await props.onSubmit(otp, markSuccessful);
} catch (e) {
resetForm();
for (let i = 0; i < 6; i++) {
otpInputRef.current?.focusPrevInput();
}
const message = e instanceof Error ? e.message : "";
setFieldError("otp", `${t("generic_error_retry")} ${message}`);
// Workaround (toggling shouldAutoFocus) to reset the focus back to
// the first input field in case of errors.
// https://github.com/devfolioco/react-otp-input/issues/420
setShouldAutoFocus(false);
setTimeout(() => setShouldAutoFocus(true), 100);
}
setWaiting(false);
};
@@ -71,17 +73,17 @@ export default function VerifyTwoFactor(props: Props) {
</Typography>
<Box my={2}>
<OtpInput
ref={otpInputRef}
shouldAutoFocus
shouldAutoFocus={shouldAutoFocus}
value={values.otp}
onChange={onChange(
handleChange("otp"),
submitForm,
)}
numInputs={6}
separator={"-"}
isInputNum
className={"otp-input"}
renderSeparator={<span>-</span>}
renderInput={(props) => (
<IndividualInput {...props} />
)}
/>
{errors.otp && (
<CenteredFlex sx={{ mt: 1 }}>
@@ -107,3 +109,23 @@ export default function VerifyTwoFactor(props: Props) {
</Formik>
);
}
const IndividualInput = styled("input")(
({ theme }) => `
font-size: 1.5rem;
padding: 4px;
width: 40px !important;
aspect-ratio: 1;
margin-inline: 8px;
border: 1px solid ${theme.colors.accent.A700};
border-radius: 1px;
outline-color: ${theme.colors.accent.A300};
transition: 0.5s;
${theme.breakpoints.down("sm")} {
font-size: 1rem;
padding: 4px;
width: 32px !important;
}
`,
);

View File

@@ -5,6 +5,7 @@
"dependencies": {
"@/base": "*",
"@ente/eslint-config": "*",
"@ente/shared": "*"
"@ente/shared": "*",
"react-otp-input": "^3.1.1"
}
}

View File

@@ -3743,10 +3743,10 @@ react-is@^18.3.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react-otp-input@^2.3.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/react-otp-input/-/react-otp-input-2.4.0.tgz#0f0a3de1d8c8d564e2e4fbe5d6b7b56e29e3a6e6"
integrity sha512-AIgl7u4sS9BTNCxX1xlaS5fPWay/Zml8Ho5LszXZKXrH1C/TiFsTQGmtl13UecQYO3mSF3HUzG2rrDf0sjEFmg==
react-otp-input@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/react-otp-input/-/react-otp-input-3.1.1.tgz#910169629812c40a614e6c175cc2c5f36102bb61"
integrity sha512-bjPavgJ0/Zmf/AYi4onj8FbH93IjeD+e8pWwxIJreDEWsU1ILR5fs8jEJmMGWSBe/yyvPP6X/W6Mk9UkOCkTPw==
react-refresh@^0.14.2:
version "0.14.2"