Set up other products, web done
This commit is contained in:
@@ -1,260 +0,0 @@
|
|||||||
/**
|
|
||||||
* From react-native-localize
|
|
||||||
*
|
|
||||||
* MIT License
|
|
||||||
* Copyright (c) 2017-present, Mathieu Acthernoene
|
|
||||||
*
|
|
||||||
* @see https://github.com/zoontek/react-native-localize/blob/master/LICENSE
|
|
||||||
* @see https://github.com/zoontek/react-native-localize/blob/ee5bf25e0bb8f3b8e4f3fd055f67ad46269c81ea/src/constants.ts
|
|
||||||
*/
|
|
||||||
export const countryCodeToCurrency: Record<string, string> = {
|
|
||||||
ad: 'eur',
|
|
||||||
ae: 'aed',
|
|
||||||
af: 'afn',
|
|
||||||
ag: 'xcd',
|
|
||||||
ai: 'xcd',
|
|
||||||
al: 'all',
|
|
||||||
am: 'amd',
|
|
||||||
an: 'ang',
|
|
||||||
ao: 'aoa',
|
|
||||||
ar: 'ars',
|
|
||||||
as: 'usd',
|
|
||||||
at: 'eur',
|
|
||||||
au: 'aud',
|
|
||||||
aw: 'awg',
|
|
||||||
ax: 'eur',
|
|
||||||
az: 'azn',
|
|
||||||
ba: 'bam',
|
|
||||||
bb: 'bbd',
|
|
||||||
bd: 'bdt',
|
|
||||||
be: 'eur',
|
|
||||||
bf: 'xof',
|
|
||||||
bg: 'bgn',
|
|
||||||
bh: 'bhd',
|
|
||||||
bi: 'bif',
|
|
||||||
bj: 'xof',
|
|
||||||
bl: 'eur',
|
|
||||||
bm: 'bmd',
|
|
||||||
bn: 'bnd',
|
|
||||||
bo: 'bob',
|
|
||||||
bq: 'usd',
|
|
||||||
br: 'brl',
|
|
||||||
bs: 'bsd',
|
|
||||||
bt: 'btn',
|
|
||||||
bv: 'nok',
|
|
||||||
bw: 'bwp',
|
|
||||||
by: 'byn',
|
|
||||||
bz: 'bzd',
|
|
||||||
ca: 'cad',
|
|
||||||
cc: 'aud',
|
|
||||||
cd: 'cdf',
|
|
||||||
cf: 'xaf',
|
|
||||||
cg: 'xaf',
|
|
||||||
ch: 'chf',
|
|
||||||
ci: 'xof',
|
|
||||||
ck: 'nzd',
|
|
||||||
cl: 'clp',
|
|
||||||
cm: 'xaf',
|
|
||||||
cn: 'cny',
|
|
||||||
co: 'cop',
|
|
||||||
cr: 'crc',
|
|
||||||
cu: 'cup',
|
|
||||||
cv: 'cve',
|
|
||||||
cw: 'ang',
|
|
||||||
cx: 'aud',
|
|
||||||
cy: 'eur',
|
|
||||||
cz: 'czk',
|
|
||||||
de: 'eur',
|
|
||||||
dj: 'djf',
|
|
||||||
dk: 'dkk',
|
|
||||||
dm: 'xcd',
|
|
||||||
do: 'dop',
|
|
||||||
dz: 'dzd',
|
|
||||||
ec: 'usd',
|
|
||||||
ee: 'eur',
|
|
||||||
eg: 'egp',
|
|
||||||
eh: 'mad',
|
|
||||||
er: 'ern',
|
|
||||||
es: 'eur',
|
|
||||||
et: 'etb',
|
|
||||||
fi: 'eur',
|
|
||||||
fj: 'fjd',
|
|
||||||
fk: 'fkp',
|
|
||||||
fm: 'usd',
|
|
||||||
fo: 'dkk',
|
|
||||||
fr: 'eur',
|
|
||||||
ga: 'xaf',
|
|
||||||
gb: 'gbp',
|
|
||||||
gd: 'xcd',
|
|
||||||
ge: 'gel',
|
|
||||||
gf: 'eur',
|
|
||||||
gg: 'gbp',
|
|
||||||
gh: 'ghs',
|
|
||||||
gi: 'gip',
|
|
||||||
gl: 'dkk',
|
|
||||||
gm: 'gmd',
|
|
||||||
gn: 'gnf',
|
|
||||||
gp: 'eur',
|
|
||||||
gq: 'xaf',
|
|
||||||
gr: 'eur',
|
|
||||||
gs: 'gbp',
|
|
||||||
gt: 'gtq',
|
|
||||||
gu: 'usd',
|
|
||||||
gw: 'xof',
|
|
||||||
gy: 'gyd',
|
|
||||||
hk: 'hkd',
|
|
||||||
hm: 'aud',
|
|
||||||
hn: 'hnl',
|
|
||||||
hr: 'hrk',
|
|
||||||
ht: 'htg',
|
|
||||||
hu: 'huf',
|
|
||||||
id: 'idr',
|
|
||||||
ie: 'eur',
|
|
||||||
il: 'ils',
|
|
||||||
im: 'gbp',
|
|
||||||
in: 'inr',
|
|
||||||
io: 'usd',
|
|
||||||
iq: 'iqd',
|
|
||||||
ir: 'irr',
|
|
||||||
is: 'isk',
|
|
||||||
it: 'eur',
|
|
||||||
je: 'gbp',
|
|
||||||
jm: 'jmd',
|
|
||||||
jo: 'jod',
|
|
||||||
jp: 'jpy',
|
|
||||||
ke: 'kes',
|
|
||||||
kg: 'kgs',
|
|
||||||
kh: 'khr',
|
|
||||||
ki: 'aud',
|
|
||||||
km: 'kmf',
|
|
||||||
kn: 'xcd',
|
|
||||||
kp: 'kpw',
|
|
||||||
kr: 'krw',
|
|
||||||
kw: 'kwd',
|
|
||||||
ky: 'kyd',
|
|
||||||
kz: 'kzt',
|
|
||||||
la: 'lak',
|
|
||||||
lb: 'lbp',
|
|
||||||
lc: 'xcd',
|
|
||||||
li: 'chf',
|
|
||||||
lk: 'lkr',
|
|
||||||
lr: 'lrd',
|
|
||||||
ls: 'lsl',
|
|
||||||
lt: 'eur',
|
|
||||||
lu: 'eur',
|
|
||||||
lv: 'eur',
|
|
||||||
ly: 'lyd',
|
|
||||||
ma: 'mad',
|
|
||||||
mc: 'eur',
|
|
||||||
md: 'mdl',
|
|
||||||
me: 'eur',
|
|
||||||
mf: 'eur',
|
|
||||||
mg: 'mga',
|
|
||||||
mh: 'usd',
|
|
||||||
mk: 'mkd',
|
|
||||||
ml: 'xof',
|
|
||||||
mm: 'mmk',
|
|
||||||
mn: 'mnt',
|
|
||||||
mo: 'mop',
|
|
||||||
mp: 'usd',
|
|
||||||
mq: 'eur',
|
|
||||||
mr: 'mro',
|
|
||||||
ms: 'xcd',
|
|
||||||
mt: 'eur',
|
|
||||||
mu: 'mur',
|
|
||||||
mv: 'mvr',
|
|
||||||
mw: 'mwk',
|
|
||||||
mx: 'mxn',
|
|
||||||
my: 'myr',
|
|
||||||
mz: 'mzn',
|
|
||||||
na: 'nad',
|
|
||||||
nc: 'xpf',
|
|
||||||
ne: 'xof',
|
|
||||||
nf: 'aud',
|
|
||||||
ng: 'ngn',
|
|
||||||
ni: 'nio',
|
|
||||||
nl: 'eur',
|
|
||||||
no: 'nok',
|
|
||||||
np: 'npr',
|
|
||||||
nr: 'aud',
|
|
||||||
nu: 'nzd',
|
|
||||||
nz: 'nzd',
|
|
||||||
om: 'omr',
|
|
||||||
pa: 'pab',
|
|
||||||
pe: 'pen',
|
|
||||||
pf: 'xpf',
|
|
||||||
pg: 'pgk',
|
|
||||||
ph: 'php',
|
|
||||||
pk: 'pkr',
|
|
||||||
pl: 'pln',
|
|
||||||
pm: 'eur',
|
|
||||||
pn: 'nzd',
|
|
||||||
pr: 'usd',
|
|
||||||
ps: 'ils',
|
|
||||||
pt: 'eur',
|
|
||||||
pw: 'usd',
|
|
||||||
py: 'pyg',
|
|
||||||
qa: 'qar',
|
|
||||||
re: 'eur',
|
|
||||||
ro: 'ron',
|
|
||||||
rs: 'rsd',
|
|
||||||
ru: 'rub',
|
|
||||||
rw: 'rwf',
|
|
||||||
sa: 'sar',
|
|
||||||
sb: 'sbd',
|
|
||||||
sc: 'scr',
|
|
||||||
sd: 'sdg',
|
|
||||||
se: 'sek',
|
|
||||||
sg: 'sgd',
|
|
||||||
sh: 'shp',
|
|
||||||
si: 'eur',
|
|
||||||
sj: 'nok',
|
|
||||||
sk: 'eur',
|
|
||||||
sl: 'sll',
|
|
||||||
sm: 'eur',
|
|
||||||
sn: 'xof',
|
|
||||||
so: 'sos',
|
|
||||||
sr: 'srd',
|
|
||||||
ss: 'ssp',
|
|
||||||
st: 'std',
|
|
||||||
sv: 'svc',
|
|
||||||
sx: 'ang',
|
|
||||||
sy: 'syp',
|
|
||||||
sz: 'szl',
|
|
||||||
tc: 'usd',
|
|
||||||
td: 'xaf',
|
|
||||||
tf: 'eur',
|
|
||||||
tg: 'xof',
|
|
||||||
th: 'thb',
|
|
||||||
tj: 'tjs',
|
|
||||||
tk: 'nzd',
|
|
||||||
tl: 'usd',
|
|
||||||
tm: 'tmt',
|
|
||||||
tn: 'tnd',
|
|
||||||
to: 'top',
|
|
||||||
tr: 'try',
|
|
||||||
tt: 'ttd',
|
|
||||||
tv: 'aud',
|
|
||||||
tw: 'twd',
|
|
||||||
tz: 'tzs',
|
|
||||||
ua: 'uah',
|
|
||||||
ug: 'ugx',
|
|
||||||
um: 'usd',
|
|
||||||
us: 'usd',
|
|
||||||
uy: 'uyu',
|
|
||||||
uz: 'uzs',
|
|
||||||
va: 'eur',
|
|
||||||
vc: 'xcd',
|
|
||||||
ve: 'vef',
|
|
||||||
vg: 'usd',
|
|
||||||
vi: 'usd',
|
|
||||||
vn: 'vnd',
|
|
||||||
vu: 'vuv',
|
|
||||||
wf: 'xpf',
|
|
||||||
ws: 'wst',
|
|
||||||
ye: 'yer',
|
|
||||||
yt: 'eur',
|
|
||||||
za: 'zar',
|
|
||||||
zm: 'zmw',
|
|
||||||
zw: 'zwl',
|
|
||||||
}
|
|
||||||
+19
-15
@@ -1,29 +1,32 @@
|
|||||||
import Purchases, {PurchasesPackage} from 'react-native-purchases'
|
import Purchases, {PurchasesPackage} from 'react-native-purchases'
|
||||||
import {msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {useMutation, useQuery} from '@tanstack/react-query'
|
import {useMutation, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {Subscription} from '#/state/purchases/useSubscriptions/types'
|
import {
|
||||||
import {identifierToSubscriptionInfo} from '#/state/purchases/useSubscriptions/util'
|
Subscription,
|
||||||
|
Subscriptions,
|
||||||
|
} from '#/state/purchases/subscriptions/types'
|
||||||
|
import {
|
||||||
|
identifierToSubscriptionInfo,
|
||||||
|
organizeSubscriptionsByTier,
|
||||||
|
} from '#/state/purchases/subscriptions/util'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
export function useAvailableSubscriptions() {
|
export function useAvailableSubscriptions() {
|
||||||
const {_} = useLingui()
|
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const did = currentAccount!.did
|
const did = currentAccount!.did
|
||||||
|
|
||||||
return useQuery<Subscription[]>({
|
return useQuery<Subscriptions>({
|
||||||
queryKey: ['availableSubscriptions', did],
|
queryKey: ['availableSubscriptions', did],
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
Purchases.logIn(did)
|
Purchases.logIn(did)
|
||||||
const offerings = await Purchases.getOfferings()
|
const offerings = await Purchases.getOfferings()
|
||||||
if (
|
const tierOfferings = Object.values(offerings.all).filter(offering => {
|
||||||
offerings.current !== null &&
|
return offering.identifier.includes('bsky_tier')
|
||||||
offerings.current.availablePackages.length !== 0
|
})
|
||||||
) {
|
const packages = tierOfferings.flatMap(
|
||||||
return normalizePackages(offerings.current.availablePackages)
|
offering => offering.availablePackages,
|
||||||
}
|
)
|
||||||
throw new Error(_(msg`Error loading subscriptions`))
|
return organizeSubscriptionsByTier(normalizePackages(packages))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -41,14 +44,15 @@ function normalizePackages(pkgs: PurchasesPackage[]): Subscription[] {
|
|||||||
.map(p => {
|
.map(p => {
|
||||||
const info = identifierToSubscriptionInfo(p.product.identifier)
|
const info = identifierToSubscriptionInfo(p.product.identifier)
|
||||||
if (!info) return
|
if (!info) return
|
||||||
return {
|
const subscription: Subscription = {
|
||||||
info,
|
info,
|
||||||
pricing: {
|
price: {
|
||||||
formatted: p.product.priceString,
|
formatted: p.product.priceString,
|
||||||
value: p.product.price,
|
value: p.product.price,
|
||||||
},
|
},
|
||||||
raw: p,
|
raw: p,
|
||||||
}
|
}
|
||||||
|
return subscription
|
||||||
})
|
})
|
||||||
.filter(Boolean) as Subscription[]
|
.filter(Boolean) as Subscription[]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {useMutation, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
|
import {useCurrencyFormatter} from '#/lib/currency'
|
||||||
|
import {
|
||||||
|
Subscription,
|
||||||
|
Subscriptions,
|
||||||
|
} from '#/state/purchases/subscriptions/types'
|
||||||
|
import {
|
||||||
|
StripePrice,
|
||||||
|
StripeProduct,
|
||||||
|
} from '#/state/purchases/subscriptions/types/stripe'
|
||||||
|
import {
|
||||||
|
identifierToSubscriptionInfo,
|
||||||
|
organizeSubscriptionsByTier,
|
||||||
|
} from '#/state/purchases/subscriptions/util'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
|
export function useAvailableSubscriptions() {
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
const currencyFormatter = useCurrencyFormatter()
|
||||||
|
|
||||||
|
return useQuery<Subscriptions>({
|
||||||
|
queryKey: ['availableSubscriptions', currentAccount!.did],
|
||||||
|
async queryFn() {
|
||||||
|
const res = await fetch(`http://localhost:8787/getWebOffers`).then(res =>
|
||||||
|
res.json(),
|
||||||
|
)
|
||||||
|
const filtered = res.filter((item: any) =>
|
||||||
|
item.product.name.includes('bsky_tier'),
|
||||||
|
)
|
||||||
|
return organizeSubscriptionsByTier(
|
||||||
|
normalizeProducts(filtered, {currencyFormatter}),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePurchaseSubscription() {
|
||||||
|
return useMutation({
|
||||||
|
async mutationFn(_priceObject: any) {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeProducts(
|
||||||
|
products: {product: StripeProduct; price: StripePrice}[],
|
||||||
|
options: {
|
||||||
|
currencyFormatter: ReturnType<typeof useCurrencyFormatter>
|
||||||
|
},
|
||||||
|
): Subscription[] {
|
||||||
|
return products
|
||||||
|
.map(({product, price}) => {
|
||||||
|
const info = identifierToSubscriptionInfo(product.name)
|
||||||
|
|
||||||
|
if (!info) return
|
||||||
|
|
||||||
|
const priceObj =
|
||||||
|
price.currency_options[options.currencyFormatter.currency]
|
||||||
|
const value = priceObj.unit_amount
|
||||||
|
const formatted = options.currencyFormatter.format(value / 100)
|
||||||
|
|
||||||
|
const subscription: Subscription = {
|
||||||
|
info,
|
||||||
|
price: {
|
||||||
|
value,
|
||||||
|
formatted,
|
||||||
|
},
|
||||||
|
raw: {
|
||||||
|
price_id: price.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscription
|
||||||
|
})
|
||||||
|
.filter(Boolean) as Subscription[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export enum SubscriptionIdentifier {
|
||||||
|
Tier0MonthlyAuto = '0:monthly:auto',
|
||||||
|
Tier0AnnualAuto = '0:annual:auto',
|
||||||
|
Tier1MonthlyAuto = '1:monthly:auto',
|
||||||
|
Tier1AnnualAuto = '1:annual:auto',
|
||||||
|
Tier2MonthlyAuto = '2:monthly:auto',
|
||||||
|
Tier2AnnualAuto = '2:annual:auto',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SubscriptionInfo = {
|
||||||
|
identifier: SubscriptionIdentifier
|
||||||
|
interval: 'monthly' | 'annual'
|
||||||
|
autoRenew: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Subscription = {
|
||||||
|
info: SubscriptionInfo
|
||||||
|
price: {
|
||||||
|
formatted: string
|
||||||
|
value: number
|
||||||
|
}
|
||||||
|
raw: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Subscriptions = {
|
||||||
|
monthly: Subscription[]
|
||||||
|
annual: Subscription[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import {
|
||||||
|
Subscription,
|
||||||
|
SubscriptionIdentifier,
|
||||||
|
SubscriptionInfo,
|
||||||
|
Subscriptions,
|
||||||
|
} from '#/state/purchases/subscriptions/types'
|
||||||
|
|
||||||
|
export function identifierToSubscriptionInfo(
|
||||||
|
identifier: string,
|
||||||
|
): SubscriptionInfo | undefined {
|
||||||
|
switch (identifier) {
|
||||||
|
/*
|
||||||
|
* Android
|
||||||
|
*/
|
||||||
|
case 'bsky_tier_0:monthly-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier0MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_0:annual-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier0AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_1:monthly-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier1MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_1:annual-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier1AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_2:monthly-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier2MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_2:annual-auto': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier2AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stripe
|
||||||
|
*/
|
||||||
|
case 'bsky_tier_0_monthly': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier0MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_0_annual': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier0AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_1_monthly': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier1MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_1_annual': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier1AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_2_monthly': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier2MonthlyAuto,
|
||||||
|
interval: 'monthly',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'bsky_tier_2_annual': {
|
||||||
|
return {
|
||||||
|
identifier: SubscriptionIdentifier.Tier2AnnualAuto,
|
||||||
|
interval: 'annual',
|
||||||
|
autoRenew: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fallback
|
||||||
|
*/
|
||||||
|
default: {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function organizeSubscriptionsByTier(
|
||||||
|
subscriptions: Subscription[],
|
||||||
|
): Subscriptions {
|
||||||
|
const result: Subscriptions = {
|
||||||
|
monthly: [],
|
||||||
|
annual: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const subscription of subscriptions) {
|
||||||
|
const {info} = subscription
|
||||||
|
result[info.interval].push(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.monthly = result.monthly.sort((a, b) => {
|
||||||
|
const _a = parseInt(a.info.identifier.slice(0, 1))
|
||||||
|
const _b = parseInt(b.info.identifier.slice(0, 1))
|
||||||
|
return _a - _b
|
||||||
|
})
|
||||||
|
result.annual = result.annual.sort((a, b) => {
|
||||||
|
const _a = parseInt(a.info.identifier.slice(0, 1))
|
||||||
|
const _b = parseInt(b.info.identifier.slice(0, 1))
|
||||||
|
return _a - _b
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
import {useMutation,useQuery} from '@tanstack/react-query'
|
|
||||||
|
|
||||||
import {useCurrencyFormatter} from '#/lib/currency'
|
|
||||||
import {Subscription} from '#/state/purchases/useSubscriptions/types'
|
|
||||||
import {
|
|
||||||
StripePrice,
|
|
||||||
StripeProduct,
|
|
||||||
} from '#/state/purchases/useSubscriptions/types/stripe'
|
|
||||||
import {identifierToSubscriptionInfo} from '#/state/purchases/useSubscriptions/util'
|
|
||||||
import {useSession} from '#/state/session'
|
|
||||||
|
|
||||||
export function useAvailableSubscriptions() {
|
|
||||||
const {currentAccount} = useSession()
|
|
||||||
const currencyFormatter = useCurrencyFormatter()
|
|
||||||
|
|
||||||
return useQuery<Subscription[]>({
|
|
||||||
queryKey: ['availableSubscriptions', currentAccount!.did],
|
|
||||||
async queryFn() {
|
|
||||||
return normalizeProducts(RESPONSE, {
|
|
||||||
currencyFormatter,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePurchaseSubscription() {
|
|
||||||
return useMutation({
|
|
||||||
async mutationFn(_priceObject: any) {},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeProducts(
|
|
||||||
products: {product: StripeProduct; price: StripePrice}[],
|
|
||||||
options: {
|
|
||||||
currencyFormatter: ReturnType<typeof useCurrencyFormatter>
|
|
||||||
},
|
|
||||||
): Subscription[] {
|
|
||||||
return products
|
|
||||||
.map(({product, price}) => {
|
|
||||||
const info = identifierToSubscriptionInfo(product.name)
|
|
||||||
|
|
||||||
if (!info) return
|
|
||||||
|
|
||||||
const priceObj =
|
|
||||||
price.currency_options[options.currencyFormatter.currency]
|
|
||||||
const value = priceObj.unit_amount
|
|
||||||
const formatted = options.currencyFormatter.format(value / 100)
|
|
||||||
|
|
||||||
return {
|
|
||||||
info,
|
|
||||||
pricing: {
|
|
||||||
value,
|
|
||||||
formatted,
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
price_id: price.id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Boolean) as Subscription[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const RESPONSE = [
|
|
||||||
{
|
|
||||||
product: {
|
|
||||||
id: 'prod_R2eNjNa6mB1Jlu',
|
|
||||||
object: 'product',
|
|
||||||
active: true,
|
|
||||||
attributes: [],
|
|
||||||
created: 1729092225,
|
|
||||||
default_price: 'price_1QAZ4fAwTlpRxHkARl1gtw5C',
|
|
||||||
description: null,
|
|
||||||
features: [],
|
|
||||||
images: [],
|
|
||||||
livemode: false,
|
|
||||||
marketing_features: [],
|
|
||||||
metadata: {},
|
|
||||||
name: 'bsky_tier_0_monthly',
|
|
||||||
package_dimensions: null,
|
|
||||||
shippable: null,
|
|
||||||
statement_descriptor: null,
|
|
||||||
tax_code: 'txcd_10000000',
|
|
||||||
type: 'service',
|
|
||||||
unit_label: null,
|
|
||||||
updated: 1729869343,
|
|
||||||
url: null,
|
|
||||||
},
|
|
||||||
price: {
|
|
||||||
id: 'price_1QAZ4fAwTlpRxHkARl1gtw5C',
|
|
||||||
object: 'price',
|
|
||||||
active: true,
|
|
||||||
billing_scheme: 'per_unit',
|
|
||||||
created: 1729092225,
|
|
||||||
currency: 'usd',
|
|
||||||
currency_options: {
|
|
||||||
gbp: {
|
|
||||||
custom_unit_amount: null,
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
unit_amount: 250,
|
|
||||||
unit_amount_decimal: '250',
|
|
||||||
},
|
|
||||||
usd: {
|
|
||||||
custom_unit_amount: null,
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
unit_amount: 300,
|
|
||||||
unit_amount_decimal: '300',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
custom_unit_amount: null,
|
|
||||||
livemode: false,
|
|
||||||
lookup_key: null,
|
|
||||||
metadata: {},
|
|
||||||
nickname: null,
|
|
||||||
product: 'prod_R2eNjNa6mB1Jlu',
|
|
||||||
recurring: {
|
|
||||||
aggregate_usage: null,
|
|
||||||
interval: 'month',
|
|
||||||
interval_count: 1,
|
|
||||||
meter: null,
|
|
||||||
trial_period_days: null,
|
|
||||||
usage_type: 'licensed',
|
|
||||||
},
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
tiers_mode: null,
|
|
||||||
transform_quantity: null,
|
|
||||||
type: 'recurring',
|
|
||||||
unit_amount: 300,
|
|
||||||
unit_amount_decimal: '300',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
product: {
|
|
||||||
id: 'prod_R37Zg28EeQ9XAz',
|
|
||||||
object: 'product',
|
|
||||||
active: true,
|
|
||||||
attributes: [],
|
|
||||||
created: 1729200807,
|
|
||||||
default_price: 'price_1QB1K0AwTlpRxHkA4Mdfxati',
|
|
||||||
description: null,
|
|
||||||
features: [],
|
|
||||||
images: [],
|
|
||||||
livemode: false,
|
|
||||||
marketing_features: [],
|
|
||||||
metadata: {},
|
|
||||||
name: 'bsky_tier_0_annual',
|
|
||||||
package_dimensions: null,
|
|
||||||
shippable: null,
|
|
||||||
statement_descriptor: null,
|
|
||||||
tax_code: 'txcd_10000000',
|
|
||||||
type: 'service',
|
|
||||||
unit_label: null,
|
|
||||||
updated: 1729869329,
|
|
||||||
url: null,
|
|
||||||
},
|
|
||||||
price: {
|
|
||||||
id: 'price_1QB1K0AwTlpRxHkA4Mdfxati',
|
|
||||||
object: 'price',
|
|
||||||
active: true,
|
|
||||||
billing_scheme: 'per_unit',
|
|
||||||
created: 1729200808,
|
|
||||||
currency: 'usd',
|
|
||||||
currency_options: {
|
|
||||||
gbp: {
|
|
||||||
custom_unit_amount: null,
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
unit_amount: 2000,
|
|
||||||
unit_amount_decimal: '2000',
|
|
||||||
},
|
|
||||||
usd: {
|
|
||||||
custom_unit_amount: null,
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
unit_amount: 2400,
|
|
||||||
unit_amount_decimal: '2400',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
custom_unit_amount: null,
|
|
||||||
livemode: false,
|
|
||||||
lookup_key: null,
|
|
||||||
metadata: {},
|
|
||||||
nickname: null,
|
|
||||||
product: 'prod_R37Zg28EeQ9XAz',
|
|
||||||
recurring: {
|
|
||||||
aggregate_usage: null,
|
|
||||||
interval: 'year',
|
|
||||||
interval_count: 1,
|
|
||||||
meter: null,
|
|
||||||
trial_period_days: null,
|
|
||||||
usage_type: 'licensed',
|
|
||||||
},
|
|
||||||
tax_behavior: 'inclusive',
|
|
||||||
tiers_mode: null,
|
|
||||||
transform_quantity: null,
|
|
||||||
type: 'recurring',
|
|
||||||
unit_amount: 2400,
|
|
||||||
unit_amount_decimal: '2400',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export enum SubscriptionIdentifier {
|
|
||||||
Tier0MonthlyAuto = 'Tier0MonthlyAuto',
|
|
||||||
Tier0AnnualAuto = 'Tier0AnnualAuto',
|
|
||||||
Tier1MonthlyAuto = 'Tier1MonthlyAuto',
|
|
||||||
Tier1AnnualAuto = 'Tier1AnnualAuto',
|
|
||||||
Tier2MonthlyAuto = 'Tier2MonthlyAuto',
|
|
||||||
Tier2AnnualAuto = 'Tier2AnnualAuto',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SubscriptionInfo = {
|
|
||||||
identifier: SubscriptionIdentifier
|
|
||||||
interval: 'monthly' | 'annual'
|
|
||||||
autoRenew: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Subscription = {
|
|
||||||
info: SubscriptionInfo
|
|
||||||
raw: any
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import {
|
|
||||||
SubscriptionIdentifier,
|
|
||||||
SubscriptionInfo,
|
|
||||||
} from '#/state/purchases/useSubscriptions/types'
|
|
||||||
|
|
||||||
export function identifierToSubscriptionInfo(
|
|
||||||
identifier: string,
|
|
||||||
): SubscriptionInfo | undefined {
|
|
||||||
switch (identifier) {
|
|
||||||
/*
|
|
||||||
* Android
|
|
||||||
*/
|
|
||||||
case 'bsky_tier_0:monthly-auto': {
|
|
||||||
return {
|
|
||||||
identifier: SubscriptionIdentifier.Tier0MonthlyAuto,
|
|
||||||
interval: 'monthly',
|
|
||||||
autoRenew: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 'bsky_tier_0:annual-auto': {
|
|
||||||
return {
|
|
||||||
identifier: SubscriptionIdentifier.Tier0AnnualAuto,
|
|
||||||
interval: 'annual',
|
|
||||||
autoRenew: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stripe
|
|
||||||
*/
|
|
||||||
case 'bsky_tier_0_monthly': {
|
|
||||||
return {
|
|
||||||
identifier: SubscriptionIdentifier.Tier0MonthlyAuto,
|
|
||||||
interval: 'monthly',
|
|
||||||
autoRenew: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 'bsky_tier_0_annual': {
|
|
||||||
return {
|
|
||||||
identifier: SubscriptionIdentifier.Tier0MonthlyAuto,
|
|
||||||
interval: 'annual',
|
|
||||||
autoRenew: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fallback
|
|
||||||
*/
|
|
||||||
default: {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user