Use listeners for easier to grok logic
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import {useCallback, useState} from 'react'
|
||||
import {useCallback, useEffect, useState} from 'react'
|
||||
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useAgent} from '#/state/session'
|
||||
import {emitEmailVerified} from '#/components/dialogs/EmailDialog/events'
|
||||
|
||||
export type AccountEmailState = {
|
||||
isEmailVerified: boolean
|
||||
email2FAEnabled: boolean
|
||||
}
|
||||
|
||||
export const accountEmailStateQueryKey = ['isEmailVerified'] as const
|
||||
export const accountEmailStateQueryKey = ['accountEmailState'] as const
|
||||
|
||||
export function useInvalidateAccountEmailState() {
|
||||
const qc = useQueryClient()
|
||||
@@ -36,21 +37,17 @@ export function useUpdateAccountEmailStateQueryCache() {
|
||||
)
|
||||
}
|
||||
|
||||
export function useAccountEmailState({
|
||||
onVerify,
|
||||
}: {
|
||||
onVerify?: () => void
|
||||
} = {}) {
|
||||
export function useAccountEmailState() {
|
||||
const agent = useAgent()
|
||||
const [prevIsEmailVerified, setPrevEmailIsVerified] = useState(
|
||||
!!agent.session?.emailConfirmed,
|
||||
)
|
||||
const fallbackData: AccountEmailState = {
|
||||
isEmailVerified: !!agent.session?.emailConfirmed,
|
||||
email2FAEnabled: !!agent.session?.emailAuthFactor,
|
||||
}
|
||||
const query = useQuery<AccountEmailState>({
|
||||
enabled: !!agent.session,
|
||||
initialData: {
|
||||
isEmailVerified: !!agent.session?.emailConfirmed,
|
||||
email2FAEnabled: !!agent.session?.emailAuthFactor,
|
||||
},
|
||||
refetchOnWindowFocus: true,
|
||||
queryKey: accountEmailStateQueryKey,
|
||||
queryFn: async () => {
|
||||
@@ -63,12 +60,20 @@ export function useAccountEmailState({
|
||||
},
|
||||
})
|
||||
|
||||
if (query.data.isEmailVerified && !prevIsEmailVerified) {
|
||||
setPrevEmailIsVerified(true)
|
||||
onVerify?.()
|
||||
} else if (!query.data.isEmailVerified && prevIsEmailVerified) {
|
||||
setPrevEmailIsVerified(false)
|
||||
}
|
||||
const state = query.data ?? fallbackData
|
||||
|
||||
return query.data
|
||||
/*
|
||||
* This will emit `n` times for each instance of this hook. So the listeners
|
||||
* all use `once` to prevent multiple handlers firing.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (state.isEmailVerified && !prevIsEmailVerified) {
|
||||
setPrevEmailIsVerified(true)
|
||||
emitEmailVerified()
|
||||
} else if (!state.isEmailVerified && prevIsEmailVerified) {
|
||||
setPrevEmailIsVerified(false)
|
||||
}
|
||||
}, [state, prevIsEmailVerified])
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import {useEffect} from 'react'
|
||||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
const events = new EventEmitter<{
|
||||
emailVerified: void
|
||||
}>()
|
||||
|
||||
export function emitEmailVerified() {
|
||||
events.emit('emailVerified')
|
||||
}
|
||||
|
||||
export function useOnEmailVerified(cb: () => void) {
|
||||
useEffect(() => {
|
||||
/*
|
||||
* N.B. Use `once` here, since the event can fire multiple times for each
|
||||
* instance of `useAccountEmailState`
|
||||
*/
|
||||
events.once('emailVerified', cb)
|
||||
return () => {
|
||||
events.off('emailVerified', cb)
|
||||
}
|
||||
}, [cb])
|
||||
}
|
||||
@@ -207,6 +207,7 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
|
||||
}
|
||||
keyboardType="email-address"
|
||||
autoComplete="email"
|
||||
autoCapitalize="none"
|
||||
onSubmitEditing={handleUpdateEmail}
|
||||
/>
|
||||
</TextField.Root>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useCallback, useReducer} from 'react'
|
||||
import {useReducer} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -11,9 +11,9 @@ import {Admonition} from '#/components/Admonition'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {ResendEmailText} from '#/components/dialogs/EmailDialog/components/ResendEmailText'
|
||||
import {TokenField} from '#/components/dialogs/EmailDialog/components/TokenField'
|
||||
import {useAccountEmailState} from '#/components/dialogs/EmailDialog/data/useAccountEmailState'
|
||||
import {useConfirmEmail} from '#/components/dialogs/EmailDialog/data/useConfirmEmail'
|
||||
import {useRequestEmailVerification} from '#/components/dialogs/EmailDialog/data/useRequestEmailVerification'
|
||||
import {useOnEmailVerified} from '#/components/dialogs/EmailDialog/events'
|
||||
import {
|
||||
type ScreenID,
|
||||
type ScreenProps,
|
||||
@@ -98,7 +98,7 @@ export function Verify({config}: ScreenProps<ScreenID.Verify>) {
|
||||
const {mutateAsync: requestEmailVerification} = useRequestEmailVerification()
|
||||
const {mutateAsync: confirmEmail} = useConfirmEmail()
|
||||
|
||||
const onVerify = useCallback(() => {
|
||||
useOnEmailVerified(() => {
|
||||
if (config.onVerify) {
|
||||
config.onVerify()
|
||||
} else {
|
||||
@@ -107,8 +107,7 @@ export function Verify({config}: ScreenProps<ScreenID.Verify>) {
|
||||
step: 'success',
|
||||
})
|
||||
}
|
||||
}, [config, dispatch])
|
||||
useAccountEmailState({onVerify})
|
||||
})
|
||||
|
||||
const handleRequestEmailVerification = async () => {
|
||||
dispatch({
|
||||
|
||||
Reference in New Issue
Block a user