fix(mobile): fix OTPWindow and integrate verification function
- Updated OTPWindow component to accept a generic verification function and handle success callbacks more flexibly. - Refactored useTOTPModalWrapper to utilize the new OTPWindow for improved modal presentation and verification handling. - Enhanced the animation settings for the modal to maintain consistency in user experience. These changes streamline the two-factor authentication process and improve the overall usability of the OTP modal. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
9be249dba7
commit
e2cc31d4ba
|
|
@ -1,5 +1,4 @@
|
|||
import { useMutation } from "@tanstack/react-query"
|
||||
import type { FC } from "react"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { Keyboard, Modal, StyleSheet, Text, useWindowDimensions, View } from "react-native"
|
||||
import type { OtpInputRef } from "react-native-otp-entry"
|
||||
|
|
@ -8,13 +7,16 @@ import Animated, { FadeIn, FadeOut, useSharedValue, withSpring } from "react-nat
|
|||
import { useSafeAreaInsets } from "react-native-safe-area-context"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
|
||||
import { isAuthCodeValid, twoFactor } from "@/src/lib/auth"
|
||||
import { isAuthCodeValid } from "@/src/lib/auth"
|
||||
import { toast } from "@/src/lib/toast"
|
||||
import { accentColor } from "@/src/theme/colors"
|
||||
|
||||
export const OTPWindow: FC<{
|
||||
onSuccess: (token: string) => void
|
||||
}> = ({ onSuccess }) => {
|
||||
type OTPWindowProps<T> = {
|
||||
onSuccess: (data: T) => void
|
||||
verifyFn: (code: string) => Promise<T>
|
||||
}
|
||||
|
||||
export const OTPWindow = <T,>({ onSuccess, verifyFn }: OTPWindowProps<T>) => {
|
||||
const otpInputRef = useRef<OtpInputRef>(null)
|
||||
const label = useColor("label")
|
||||
const tertiaryLabel = useColor("tertiaryLabel")
|
||||
|
|
@ -26,21 +28,12 @@ export const OTPWindow: FC<{
|
|||
toast.error(`Failed to verify: ${error.message}`)
|
||||
},
|
||||
onSuccess(data) {
|
||||
onSuccess(data.token)
|
||||
onSuccess(data)
|
||||
},
|
||||
onSettled() {
|
||||
setOpen(false)
|
||||
},
|
||||
mutationFn: async ({ code }: { code: string }) => {
|
||||
const { data, error } = await twoFactor.verifyTotp({ code })
|
||||
if (!data || error) {
|
||||
const errorMessage = error?.message ?? "Invalid TOTP code"
|
||||
toast.error(errorMessage)
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
mutationFn: ({ code }: { code: string }) => verifyFn(code),
|
||||
})
|
||||
|
||||
const windowScaleValue = useSharedValue(0.9)
|
||||
|
|
@ -53,12 +46,13 @@ export const OTPWindow: FC<{
|
|||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const preset = { stiffness: 100, damping: 10 }
|
||||
if (open) {
|
||||
windowScaleValue.value = withSpring(1, { stiffness: 100, damping: 10 })
|
||||
windowOpacityValue.value = withSpring(1, { stiffness: 100, damping: 10 })
|
||||
windowScaleValue.value = withSpring(1, preset)
|
||||
windowOpacityValue.value = withSpring(1, preset)
|
||||
} else {
|
||||
windowOpacityValue.value = withSpring(0, { stiffness: 100, damping: 10 })
|
||||
windowScaleValue.value = withSpring(0.9, { stiffness: 100, damping: 10 })
|
||||
windowOpacityValue.value = withSpring(0, preset)
|
||||
windowScaleValue.value = withSpring(0.9, preset)
|
||||
}
|
||||
}, [open, windowOpacityValue, windowScaleValue])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useCallback } from "react"
|
||||
import Siblings from "react-native-root-siblings"
|
||||
|
||||
import { getFetchErrorInfo } from "@/src/lib/error-parser"
|
||||
import { useNavigation } from "@/src/lib/navigation/hooks"
|
||||
|
|
@ -6,6 +7,8 @@ import { toast } from "@/src/lib/toast"
|
|||
import { TwoFactorAuthScreen } from "@/src/screens/(modal)/2fa"
|
||||
import { useWhoami } from "@/src/store/user/hooks"
|
||||
|
||||
import { OTPWindow } from "../compoents/OTPWindow"
|
||||
|
||||
export const useTOTPModalWrapper = <T extends { TOTPCode?: string }>(
|
||||
callback: (input: T) => Promise<any>,
|
||||
options?: { force?: boolean; dismiss?: () => any },
|
||||
|
|
@ -24,20 +27,23 @@ export const useTOTPModalWrapper = <T extends { TOTPCode?: string }>(
|
|||
return
|
||||
}
|
||||
|
||||
// present({
|
||||
// title: t("profile.totp_code.title"),
|
||||
// content: ({ dismiss }) => {
|
||||
// return createElement(TOTPForm, {
|
||||
// async onSubmitMutationFn(values) {
|
||||
// await callback({
|
||||
// ...input,
|
||||
// TOTPCode: values.code,
|
||||
// })
|
||||
// dismiss()
|
||||
// },
|
||||
// })
|
||||
// },
|
||||
// })
|
||||
const root = new Siblings(
|
||||
(
|
||||
<OTPWindow
|
||||
verifyFn={async (TOTPCode) => {
|
||||
await callback({
|
||||
...input,
|
||||
TOTPCode,
|
||||
})
|
||||
|
||||
root.destroy()
|
||||
}}
|
||||
onSuccess={async () => {
|
||||
root.destroy()
|
||||
}}
|
||||
/>
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (options?.force) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue