Bunch of contract updates
This commit is contained in:
@@ -9,11 +9,14 @@ import {
|
||||
useMainSubscriptions,
|
||||
usePurchaseSubscription,
|
||||
} from '#/state/purchases/subscriptions'
|
||||
// import {useEntitlements} from '#/state/purchases/subscriptions/useEntitlements'
|
||||
import {Subscriptions as SubscriptionsResponse} from '#/state/purchases/subscriptions/types'
|
||||
import {ViewHeader} from '#/view/com/util/ViewHeader'
|
||||
import {CenteredView} from '#/view/com/util/Views'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export type ScreenProps = NativeStackScreenProps<
|
||||
@@ -24,54 +27,110 @@ export type ScreenProps = NativeStackScreenProps<
|
||||
export function Subscriptions(_props: ScreenProps) {
|
||||
const {_} = useLingui()
|
||||
|
||||
const {data: subscriptions} = useMainSubscriptions()
|
||||
const {mutateAsync: purchaseSubscription} = usePurchaseSubscription()
|
||||
// const {data: entitlements} = useEntitlements()
|
||||
const {data: subscriptions, isError} = useMainSubscriptions()
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
<CenteredView sideBorders={true}>
|
||||
<ViewHeader title={_(msg`Liked By`)} />
|
||||
<ViewHeader title={_(msg`Subscriptions`)} />
|
||||
<View style={[a.px_xl, a.py_xl, a.gap_lg]}>
|
||||
<Text style={[a.text_2xl]}>Subs</Text>
|
||||
|
||||
<View style={[a.gap_sm]}>
|
||||
{subscriptions?.monthly.map(s => (
|
||||
<View key={s.id}>
|
||||
<Button
|
||||
label={s.id}
|
||||
size="small"
|
||||
variant="solid"
|
||||
color={s.status === 'active' ? 'primary' : 'secondary'}
|
||||
onPress={() => {
|
||||
purchaseSubscription(s.product)
|
||||
}}>
|
||||
<ButtonText>
|
||||
{s.id} ({s.price.formatted})
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<View style={[a.gap_sm]}>
|
||||
{subscriptions?.annual.map(s => (
|
||||
<View key={s.id}>
|
||||
<Button
|
||||
label={s.id}
|
||||
size="small"
|
||||
variant="solid"
|
||||
color={s.status === 'active' ? 'primary' : 'secondary'}
|
||||
onPress={() => {
|
||||
purchaseSubscription(s.product)
|
||||
}}>
|
||||
<ButtonText>
|
||||
{s.id} ({s.price.formatted})
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
{isError ? (
|
||||
<Text>Error</Text>
|
||||
) : !subscriptions ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<MainSubscription subscriptions={subscriptions} />
|
||||
)}
|
||||
</View>
|
||||
</CenteredView>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
export function MainSubscription({
|
||||
subscriptions,
|
||||
}: {
|
||||
subscriptions: SubscriptionsResponse
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
const active = subscriptions.active.at(0)
|
||||
const {mutateAsync: purchaseSubscription} = usePurchaseSubscription()
|
||||
|
||||
if (active) {
|
||||
const contents = (
|
||||
<View style={[a.gap_sm]}>
|
||||
<View style={[a.flex_row, a.align_center, a.justify_between]}>
|
||||
<Text style={[a.text_xl, a.font_heavy]}>Bluesky Plus</Text>
|
||||
<Text
|
||||
style={[
|
||||
a.text_md,
|
||||
a.font_bold,
|
||||
a.p_xs,
|
||||
a.rounded_xs,
|
||||
{
|
||||
color: t.palette.white,
|
||||
backgroundColor: t.palette.primary_500,
|
||||
},
|
||||
]}>
|
||||
Supporter
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={[a.text_md]}>Managed via: {active?.platform}</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[a.p_lg, a.rounded_md, a.border, t.atoms.border_contrast_low]}>
|
||||
{contents}
|
||||
</View>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<View
|
||||
style={[a.p_lg, a.rounded_md, a.border, t.atoms.border_contrast_low]}>
|
||||
<View style={[a.gap_sm, a.pb_xl]}>
|
||||
{subscriptions.available.monthly.map(s => (
|
||||
<View key={s.id}>
|
||||
<Button
|
||||
label={s.id}
|
||||
size="small"
|
||||
variant="solid"
|
||||
color={s.status === 'active' ? 'primary' : 'secondary'}
|
||||
onPress={() => {
|
||||
purchaseSubscription(s.product)
|
||||
}}>
|
||||
<ButtonText>
|
||||
{s.id} ({s.price.formatted})
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<View style={[a.gap_sm]}>
|
||||
{subscriptions.available.annual.map(s => (
|
||||
<View key={s.id}>
|
||||
<Button
|
||||
label={s.id}
|
||||
size="small"
|
||||
variant="solid"
|
||||
color={s.status === 'active' ? 'primary' : 'secondary'}
|
||||
onPress={() => {
|
||||
purchaseSubscription(s.product)
|
||||
}}>
|
||||
<ButtonText>
|
||||
{s.id} ({s.price.formatted})
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {RawSubscriptionObject} from '#/state/purchases/subscriptions/api/types'
|
||||
import {EntitlementId} from '#/state/purchases/subscriptions/types'
|
||||
|
||||
export async function getMainSubscriptions({
|
||||
did,
|
||||
@@ -13,10 +14,31 @@ export async function getMainSubscriptions({
|
||||
|
||||
if (!res.ok) {
|
||||
console.error('error fetching subscriptions', res.status, await res.text())
|
||||
return {
|
||||
active: [],
|
||||
available: [],
|
||||
}
|
||||
}
|
||||
|
||||
const json = await res.json()
|
||||
|
||||
return json as {
|
||||
active: RawSubscriptionObject[]
|
||||
available: RawSubscriptionObject[]
|
||||
}
|
||||
}
|
||||
|
||||
export async function getEntitlements({did}: {did: string}) {
|
||||
const res = await fetch(
|
||||
`https://bsky-purchases.ngrok.io/entitlements?user=${did}`,
|
||||
)
|
||||
|
||||
if (!res.ok) {
|
||||
console.error('error fetching entitlements', res.status, await res.text())
|
||||
return []
|
||||
}
|
||||
|
||||
const {subscriptions} = await res.json()
|
||||
const {entitlements} = await res.json()
|
||||
|
||||
return subscriptions as RawSubscriptionObject[]
|
||||
return entitlements as {id: EntitlementId}[]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,15 @@ export type RawSubscriptionObjectBase<T> = T & {
|
||||
lookupKey: string
|
||||
checkoutId: string
|
||||
interval: 'monthly' | 'annual'
|
||||
autoRenew: boolean
|
||||
active: boolean
|
||||
autoRenewStatus:
|
||||
| 'will_renew'
|
||||
| 'will_not_renew'
|
||||
| 'will_change_product'
|
||||
| 'will_pause'
|
||||
| 'requires_price_increase_consent'
|
||||
| 'has_already_renewed'
|
||||
| null
|
||||
status:
|
||||
| 'trialing'
|
||||
| 'active'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Purchases from 'react-native-purchases'
|
||||
import {useMutation, useQuery} from '@tanstack/react-query'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {isAndroid} from '#/platform/detection'
|
||||
import {getMainSubscriptions} from '#/state/purchases/subscriptions/api'
|
||||
@@ -17,15 +17,12 @@ export function useMainSubscriptions() {
|
||||
return useQuery<Subscriptions>({
|
||||
queryKey: ['availableSubscriptions', did],
|
||||
async queryFn() {
|
||||
Purchases.logIn(did)
|
||||
Purchases.setEmail(currentAccount!.email!)
|
||||
|
||||
const platform = isAndroid ? 'android' : ('ios' as const)
|
||||
const platform = isAndroid ? 'android' : 'ios'
|
||||
const rawSubscriptions = await getMainSubscriptions({
|
||||
did: currentAccount!.did,
|
||||
platform,
|
||||
})
|
||||
const platformSubscriptions = rawSubscriptions
|
||||
const platformSubscriptions = rawSubscriptions.available
|
||||
.filter(s => s.platform !== 'web')
|
||||
.filter(s => s.platform === platform)
|
||||
const lookupKeys = Array.from(
|
||||
@@ -51,17 +48,29 @@ export function useMainSubscriptions() {
|
||||
})
|
||||
.filter(Boolean) as Subscription[]
|
||||
|
||||
return organizeMainSubscriptionsByTier(subscriptions)
|
||||
return {
|
||||
active: rawSubscriptions.active,
|
||||
available: organizeMainSubscriptionsByTier(subscriptions),
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function usePurchaseSubscription() {
|
||||
const {currentAccount} = useSession()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
async mutationFn(product: Subscription['product']) {
|
||||
if (product.platform === 'web') {
|
||||
throw new Error('Cannot purchase web subscription on native')
|
||||
}
|
||||
// TODO don't do this here
|
||||
Purchases.addCustomerInfoUpdateListener(_info => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['availableSubscriptions', currentAccount!.did],
|
||||
})
|
||||
})
|
||||
return Purchases.purchaseStoreProduct(product.data)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -22,7 +22,7 @@ export function useMainSubscriptions() {
|
||||
did: currentAccount!.did,
|
||||
platform: 'web',
|
||||
})
|
||||
const platformSubscriptions = rawSubscriptions.filter(
|
||||
const platformSubscriptions = rawSubscriptions.available.filter(
|
||||
s => s.platform === 'web',
|
||||
)
|
||||
const subscriptions = platformSubscriptions.map(sub => {
|
||||
@@ -40,7 +40,10 @@ export function useMainSubscriptions() {
|
||||
return subscription
|
||||
})
|
||||
|
||||
return organizeMainSubscriptionsByTier(subscriptions)
|
||||
return {
|
||||
active: rawSubscriptions.active,
|
||||
available: organizeMainSubscriptionsByTier(subscriptions),
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import {PurchasesStoreProduct} from 'react-native-purchases'
|
||||
|
||||
import {RawSubscriptionObjectBase} from '#/state/purchases/subscriptions/api/types'
|
||||
import {
|
||||
RawSubscriptionObject,
|
||||
RawSubscriptionObjectBase,
|
||||
} from '#/state/purchases/subscriptions/api/types'
|
||||
|
||||
export enum SubscriptionId {
|
||||
Main0MonthlyAuto = 'main:0:monthly:auto',
|
||||
@@ -11,6 +14,12 @@ export enum SubscriptionId {
|
||||
Main2AnnualAuto = 'main:2:annual:auto',
|
||||
}
|
||||
|
||||
export enum EntitlementId {
|
||||
Main0 = 'main:0',
|
||||
Main1 = 'main:1',
|
||||
Main2 = 'main:2',
|
||||
}
|
||||
|
||||
export type Subscription =
|
||||
| RawSubscriptionObjectBase<{
|
||||
platform: 'android'
|
||||
@@ -50,6 +59,9 @@ export type Subscription =
|
||||
}>
|
||||
|
||||
export type Subscriptions = {
|
||||
monthly: Subscription[]
|
||||
annual: Subscription[]
|
||||
active: RawSubscriptionObject[]
|
||||
available: {
|
||||
monthly: Subscription[]
|
||||
annual: Subscription[]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {getEntitlements} from '#/state/purchases/subscriptions/api'
|
||||
import {useSession} from '#/state/session'
|
||||
|
||||
export function useEntitlements() {
|
||||
const {currentAccount} = useSession()
|
||||
return useQuery({
|
||||
queryKey: ['entitlements', currentAccount!.did],
|
||||
async queryFn() {
|
||||
return getEntitlements({did: currentAccount!.did})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import {Subscription, Subscriptions} from './types'
|
||||
|
||||
export function organizeMainSubscriptionsByTier(
|
||||
subscriptions: Subscription[],
|
||||
): Subscriptions {
|
||||
const result: Subscriptions = {
|
||||
): Subscriptions['subscriptions'] {
|
||||
const result: Subscriptions['subscriptions'] = {
|
||||
monthly: [],
|
||||
annual: [],
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {IS_INTERNAL} from '#/lib/app-info'
|
||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
|
||||
@@ -276,12 +275,10 @@ let DrawerContent = ({}: {}): React.ReactNode => {
|
||||
onPress={onPressProfile}
|
||||
/>
|
||||
<SettingsMenuItem onPress={onPressSettings} />
|
||||
{IS_INTERNAL && (
|
||||
<SubscriptionsMenuItem
|
||||
isActive={false}
|
||||
onPress={onPressSubscriptions}
|
||||
/>
|
||||
)}
|
||||
<SubscriptionsMenuItem
|
||||
isActive={false}
|
||||
onPress={onPressSubscriptions}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user