Files
bsky-social-app/src/features/inviteFriends/components/AddToWalletButton.tsx
T

98 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {useEffect, useState} from 'react'
import {Platform, View} from 'react-native'
import {useLingui} from '@lingui/react/macro'
import * as RNWallet from '@premieroctet/react-native-wallet'
import {logger} from '#/logger'
import {useAgent} from '#/state/session'
import * as Toast from '#/components/Toast'
import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
const BSKY_WEB = 'https://bsky.app'
export function AddToWalletButton({handle}: {handle: string}) {
const {t: l} = useLingui()
const ax = useAnalytics()
const agent = useAgent()
const [canAdd, setCanAdd] = useState<boolean | null>(null)
const [isAdding, setIsAdding] = useState(false)
useEffect(() => {
if (IS_WEB) return
// Skip the native check if the handle is already known to be unusable.
if (!handle || handle === 'handle.invalid') return
let cancelled = false
;(RNWallet.canAddPasses() as Promise<boolean>)
.then((ok: boolean) => {
if (!cancelled) setCanAdd(ok)
})
.catch(() => {
if (!cancelled) setCanAdd(false)
})
return () => {
cancelled = true
}
}, [handle])
if (IS_WEB) return null
// iOS-only launch: Google Wallet backend is not yet provisioned. Once
// the Google Wallet API issuer + service account land, drop this gate.
if (Platform.OS !== 'ios') return null
if (!handle || handle === 'handle.invalid') return null
if (canAdd !== true) return null
const onPress = async () => {
if (isAdding) return
setIsAdding(true)
ax.metric('invite:action:wallet', {platform: Platform.OS})
try {
const accessJwt = agent.session?.accessJwt
if (!accessJwt) throw new Error('no session')
let added: boolean
if (Platform.OS === 'ios') {
const res = await fetch(`${BSKY_WEB}/invite/pass.url`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessJwt}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
})
if (!res.ok) throw new Error(`pass.url ${res.status}`)
const {url} = (await res.json()) as {url: string}
added = await RNWallet.addPass(url)
} else {
const res = await fetch(`${BSKY_WEB}/invite/wallet/jwt`, {
headers: {Authorization: `Bearer ${accessJwt}`},
})
if (!res.ok) throw new Error(`wallet/jwt ${res.status}`)
const {jwt} = (await res.json()) as {jwt: string}
added = await RNWallet.addPassWithSignedJwt(jwt)
}
if (added) {
Toast.show(l`Added to your wallet`)
}
} catch (err) {
Toast.show(l`Could not add to wallet – please try again`, {type: 'error'})
logger.error('InviteWallet: addPass failed', {safeMessage: err})
} finally {
setIsAdding(false)
}
}
return (
<View
style={[{alignItems: 'center'}, isAdding ? {opacity: 0.6} : null]}
pointerEvents={isAdding ? 'none' : 'auto'}>
<RNWallet.RNWalletView
buttonStyle={RNWallet.ButtonStyle.BLACK}
buttonType={RNWallet.ButtonType.PRIMARY}
onPress={() => {
void onPress()
}}
/>
</View>
)
}