Hook up dialog to fake mutation

This commit is contained in:
Eric Bailey
2025-06-26 15:27:08 -05:00
parent 2bf1c1e0d7
commit f25eb23e95
2 changed files with 183 additions and 94 deletions
@@ -4,11 +4,14 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {validate as validateEmail} from 'email-validator' import {validate as validateEmail} from 'email-validator'
import {useCleanError} from '#/lib/hooks/useCleanError'
import {useLanguagePrefs} from '#/state/preferences' import {useLanguagePrefs} from '#/state/preferences'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge' import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
import {urls} from '#/components/ageAssurance/const' import {urls} from '#/components/ageAssurance/const'
import {useInitAgeAssurance} from '#/components/ageAssurance/useInitAgeAssurance'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog' import * as Dialog from '#/components/Dialog'
import {Divider} from '#/components/Divider' import {Divider} from '#/components/Divider'
@@ -16,6 +19,7 @@ import * as TextField from '#/components/forms/TextField'
import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '#/components/icons/Envelope' import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '#/components/icons/Envelope'
import {LanguageSelect} from '#/components/LanguageSelect' import {LanguageSelect} from '#/components/LanguageSelect'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
export {useDialogControl} from '#/components/Dialog/context' export {useDialogControl} from '#/components/Dialog/context'
@@ -51,10 +55,16 @@ function Inner() {
const {_} = useLingui() const {_} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const cleanError = useCleanError()
const {close} = Dialog.useDialogContext()
const [success, setSuccess] = useState(false)
const [email, setEmail] = useState(currentAccount?.email || '') const [email, setEmail] = useState(currentAccount?.email || '')
const [emailValid, setEmailValid] = useState(validateEmail(email)) const [emailValid, setEmailValid] = useState(validateEmail(email))
const [language, setLanguage] = useState(langPrefs.appLanguage) const [language, setLanguage] = useState(langPrefs.appLanguage)
const [error, setError] = useState<string>('')
const {mutateAsync: init, isPending} = useInitAgeAssurance()
const onSubmit = async () => { const onSubmit = async () => {
try { try {
@@ -62,7 +72,17 @@ function Inner() {
setEmailValid(false) setEmailValid(false)
return return
} }
} catch (e) {}
await init({
email,
language,
})
setSuccess(true)
} catch (e) {
const {clean} = cleanError(e)
setError(clean || _(msg`Something went wrong, please try again`))
}
} }
return ( return (
@@ -71,10 +91,16 @@ function Inner() {
<AgeAssuranceBadge /> <AgeAssuranceBadge />
<Text style={[a.text_xl, a.font_heavy, a.pt_xl, a.pb_md]}> <Text style={[a.text_xl, a.font_heavy, a.pt_xl, a.pb_md]}>
<Trans>Verify your age</Trans> {success ? <Trans>Success!</Trans> : <Trans>Verify your age</Trans>}
</Text> </Text>
<View style={[a.pb_xl, a.gap_sm]}> <View style={[a.pb_xl, a.gap_sm]}>
{success ? (
<Text style={[a.text_sm, a.leading_snug]}>
<Trans>Please check your email to contine the process.</Trans>
</Text>
) : (
<>
<Text style={[a.text_sm, a.leading_snug]}> <Text style={[a.text_sm, a.leading_snug]}>
<Trans> <Trans>
We use{' '} We use{' '}
@@ -91,15 +117,32 @@ function Inner() {
<Text style={[a.text_sm, a.leading_snug]}> <Text style={[a.text_sm, a.leading_snug]}>
<Trans> <Trans>
If KWS cannot use your email address to confirm that you If KWS cannot use your email address to confirm that you
previously verified your age, youll be taken to the KWS website previously verified your age, youll be taken to the KWS
to provide more details. website to provide more details.
</Trans> </Trans>
</Text> </Text>
<Text style={[a.text_sm, a.leading_snug]}> <Text style={[a.text_sm, a.leading_snug]}>
<Trans>This should only take a few minutes.</Trans> <Trans>This should only take a few minutes.</Trans>
</Text> </Text>
</>
)}
</View> </View>
{success ? (
<View style={[a.w_full]}>
<Button
label={_(msg`Close dialog`)}
size="large"
variant="solid"
color="secondary"
onPress={() => close()}>
<ButtonText>
<Trans>Close dialog</Trans>
</ButtonText>
</Button>
</View>
) : (
<>
<Divider /> <Divider />
<View style={[a.w_full, a.pt_xl, a.gap_md]}> <View style={[a.w_full, a.pt_xl, a.gap_md]}>
@@ -133,15 +176,21 @@ function Inner() {
<LanguageSelect value={language} onChange={setLanguage} /> <LanguageSelect value={language} onChange={setLanguage} />
</View> </View>
{error && <Admonition type="error">{error}</Admonition>}
<Button <Button
label={_(msg`Get an email`)} label={_(msg`Get an email`)}
size="large" size="large"
variant="solid" variant="solid"
color="primary"> color="primary"
onPress={onSubmit}>
<ButtonText> <ButtonText>
<Trans>Get an email</Trans> <Trans>Get an email</Trans>
</ButtonText> </ButtonText>
<ButtonIcon icon={Envelope} position="right" /> <ButtonIcon
icon={isPending ? Loader : Envelope}
position="right"
/>
</Button> </Button>
</View> </View>
@@ -160,19 +209,21 @@ function Inner() {
style={[a.text_xs, a.leading_snug]}> style={[a.text_xs, a.leading_snug]}>
KWS Terms of Use KWS Terms of Use
</InlineLinkText>{' '} </InlineLinkText>{' '}
and acknowledge that KWS will store your verified status alongside and acknowledge that KWS will store your verified status
your hashed email address in accordance with the{' '} alongside your hashed email address in accordance with the{' '}
<InlineLinkText <InlineLinkText
label={urls.kwsPrivacyPolicy} label={urls.kwsPrivacyPolicy}
to={urls.kwsPrivacyPolicy} to={urls.kwsPrivacyPolicy}
style={[a.text_xs, a.leading_snug]}> style={[a.text_xs, a.leading_snug]}>
KWS Privacy Policy KWS Privacy Policy
</InlineLinkText> </InlineLinkText>
. This means you wont need to verify again the next time you use . This means you wont need to verify again the next time you
this email for other apps, games, and services powered by KWS use this email for other apps, games, and services powered by
technology. KWS technology.
</Trans> </Trans>
</Text> </Text>
</>
)}
</View> </View>
</View> </View>
) )
@@ -0,0 +1,38 @@
import {useMutation} from '@tanstack/react-query'
import {wait} from '#/lib/async/wait'
import {isNetworkError} from '#/lib/hooks/useCleanError'
import {logger} from '#/logger'
// import {useAgent} from '#/state/session';
type TempInputSchema = {
email: string
language: string
}
export function useInitAgeAssurance() {
// const agent = useAgent()
return useMutation({
async mutationFn(_props: TempInputSchema) {
// 2s wait is good actually, email sending takes a hot sec
// const {data} = await wait(2e3, agent.app.bsky.unspecced.initAgeAssurance(props))
await wait(
2e3,
(() => ({
data: {
$type: 'app.bsky.unspecced.defs#ageAssuranceState',
lastInitiatedAt: new Date().toISOString(),
status: 'pending',
},
}))(),
)
},
onError(e) {
if (!isNetworkError(e)) {
logger.error(`useInitAgeAssurance failed`, {
safeMessage: e,
})
}
},
})
}