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,108 +91,139 @@ 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]}>
<Text style={[a.text_sm, a.leading_snug]}> {success ? (
<Trans> <Text style={[a.text_sm, a.leading_snug]}>
We use{' '} <Trans>Please check your email to contine the process.</Trans>
<InlineLinkText </Text>
label={urls.kwsHome} ) : (
to={urls.kwsHome} <>
style={[a.text_sm, a.leading_snug]}> <Text style={[a.text_sm, a.leading_snug]}>
KWS <Trans>
</InlineLinkText>{' '} We use{' '}
to verify that youre an adult. When you click "Get an email" <InlineLinkText
below, Bluesky will share your email address with KWS. label={urls.kwsHome}
</Trans> to={urls.kwsHome}
</Text> style={[a.text_sm, a.leading_snug]}>
<Text style={[a.text_sm, a.leading_snug]}> KWS
<Trans> </InlineLinkText>{' '}
If KWS cannot use your email address to confirm that you to verify that youre an adult. When you click "Get an email"
previously verified your age, youll be taken to the KWS website below, Bluesky will share your email address with KWS.
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>
<Trans>This should only take a few minutes.</Trans> If KWS cannot use your email address to confirm that you
</Text> previously verified your age, youll be taken to the KWS
website to provide more details.
</Trans>
</Text>
<Text style={[a.text_sm, a.leading_snug]}>
<Trans>This should only take a few minutes.</Trans>
</Text>
</>
)}
</View> </View>
<Divider /> {success ? (
<View style={[a.w_full]}>
<View style={[a.w_full, a.pt_xl, a.gap_md]}> <Button
<View> label={_(msg`Close dialog`)}
<TextField.LabelText> size="large"
<Trans>Your email</Trans> variant="solid"
</TextField.LabelText> color="secondary"
<TextField.Root isInvalid={!emailValid}> onPress={() => close()}>
<TextField.Input <ButtonText>
label={_(msg`Your email`)} <Trans>Close dialog</Trans>
placeholder={_(msg`Your email`)} </ButtonText>
value={email} </Button>
onChangeText={setEmail}
onFocus={() => setEmailValid(true)}
onBlur={() => {
setEmailValid(validateEmail(email))
}}
returnKeyType="done"
autoCapitalize="none"
autoComplete="off"
autoCorrect={false}
onSubmitEditing={onSubmit}
/>
</TextField.Root>
</View> </View>
) : (
<>
<Divider />
<View> <View style={[a.w_full, a.pt_xl, a.gap_md]}>
<TextField.LabelText> <View>
<Trans>Your preferred language</Trans> <TextField.LabelText>
</TextField.LabelText> <Trans>Your email</Trans>
<LanguageSelect value={language} onChange={setLanguage} /> </TextField.LabelText>
</View> <TextField.Root isInvalid={!emailValid}>
<TextField.Input
label={_(msg`Your email`)}
placeholder={_(msg`Your email`)}
value={email}
onChangeText={setEmail}
onFocus={() => setEmailValid(true)}
onBlur={() => {
setEmailValid(validateEmail(email))
}}
returnKeyType="done"
autoCapitalize="none"
autoComplete="off"
autoCorrect={false}
onSubmitEditing={onSubmit}
/>
</TextField.Root>
</View>
<Button <View>
label={_(msg`Get an email`)} <TextField.LabelText>
size="large" <Trans>Your preferred language</Trans>
variant="solid" </TextField.LabelText>
color="primary"> <LanguageSelect value={language} onChange={setLanguage} />
<ButtonText> </View>
<Trans>Get an email</Trans>
</ButtonText>
<ButtonIcon icon={Envelope} position="right" />
</Button>
</View>
<Text {error && <Admonition type="error">{error}</Admonition>}
style={[
a.text_xs, <Button
a.leading_snug, label={_(msg`Get an email`)}
a.pt_lg, size="large"
t.atoms.text_contrast_medium, variant="solid"
]}> color="primary"
<Trans> onPress={onSubmit}>
By continuing, you agree to the{' '} <ButtonText>
<InlineLinkText <Trans>Get an email</Trans>
label={urls.kwsTermsOfUse} </ButtonText>
to={urls.kwsTermsOfUse} <ButtonIcon
style={[a.text_xs, a.leading_snug]}> icon={isPending ? Loader : Envelope}
KWS Terms of Use position="right"
</InlineLinkText>{' '} />
and acknowledge that KWS will store your verified status alongside </Button>
your hashed email address in accordance with the{' '} </View>
<InlineLinkText
label={urls.kwsPrivacyPolicy} <Text
to={urls.kwsPrivacyPolicy} style={[
style={[a.text_xs, a.leading_snug]}> a.text_xs,
KWS Privacy Policy a.leading_snug,
</InlineLinkText> a.pt_lg,
. This means you wont need to verify again the next time you use t.atoms.text_contrast_medium,
this email for other apps, games, and services powered by KWS ]}>
technology. <Trans>
</Trans> By continuing, you agree to the{' '}
</Text> <InlineLinkText
label={urls.kwsTermsOfUse}
to={urls.kwsTermsOfUse}
style={[a.text_xs, a.leading_snug]}>
KWS Terms of Use
</InlineLinkText>{' '}
and acknowledge that KWS will store your verified status
alongside your hashed email address in accordance with the{' '}
<InlineLinkText
label={urls.kwsPrivacyPolicy}
to={urls.kwsPrivacyPolicy}
style={[a.text_xs, a.leading_snug]}>
KWS Privacy Policy
</InlineLinkText>
. This means you wont need to verify again the next time you
use this email for other apps, games, and services powered by
KWS technology.
</Trans>
</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,
})
}
},
})
}