Init state, Android and web
This commit is contained in:
@@ -5,6 +5,7 @@ import '#/view/icons'
|
|||||||
import React, {useEffect, useState} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
||||||
import {KeyboardProvider} from 'react-native-keyboard-controller'
|
import {KeyboardProvider} from 'react-native-keyboard-controller'
|
||||||
|
import Purchases from 'react-native-purchases'
|
||||||
import {RootSiblingParent} from 'react-native-root-siblings'
|
import {RootSiblingParent} from 'react-native-root-siblings'
|
||||||
import {
|
import {
|
||||||
initialWindowMetrics,
|
initialWindowMetrics,
|
||||||
@@ -24,6 +25,7 @@ import {s} from '#/lib/styles'
|
|||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
import {ThemeProvider} from '#/lib/ThemeContext'
|
||||||
import I18nProvider from '#/locale/i18nProvider'
|
import I18nProvider from '#/locale/i18nProvider'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {isAndroid,isIOS} from '#/platform/detection'
|
||||||
import {Provider as A11yProvider} from '#/state/a11y'
|
import {Provider as A11yProvider} from '#/state/a11y'
|
||||||
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
||||||
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
||||||
@@ -66,6 +68,7 @@ import {NuxDialogs} from '#/components/dialogs/nuxs'
|
|||||||
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
||||||
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
|
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
|
||||||
import {Provider as PortalProvider} from '#/components/Portal'
|
import {Provider as PortalProvider} from '#/components/Portal'
|
||||||
|
import {RC_GOOGLE_PUBLIC_KEY} from '#/env'
|
||||||
import {Splash} from '#/Splash'
|
import {Splash} from '#/Splash'
|
||||||
import {BottomSheetProvider} from '../modules/bottom-sheet'
|
import {BottomSheetProvider} from '../modules/bottom-sheet'
|
||||||
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
||||||
@@ -173,6 +176,11 @@ function App() {
|
|||||||
Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
|
Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
|
||||||
setReady(true),
|
setReady(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (isIOS) {
|
||||||
|
} else if (isAndroid) {
|
||||||
|
Purchases.configure({apiKey: RC_GOOGLE_PUBLIC_KEY})
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
|
|||||||
@@ -7,3 +7,6 @@ export const LOG_LEVEL = (process.env.EXPO_PUBLIC_LOG_LEVEL || 'info') as
|
|||||||
| 'info'
|
| 'info'
|
||||||
| 'warn'
|
| 'warn'
|
||||||
| 'error'
|
| 'error'
|
||||||
|
|
||||||
|
export const RC_GOOGLE_PUBLIC_KEY =
|
||||||
|
process.env.EXPO_PUBLIC_RC_GOOGLE_PUBLIC_KEY || ''
|
||||||
|
|||||||
@@ -0,0 +1,302 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import {deviceLocales} from '#/locale/deviceLocales'
|
||||||
|
import {useGeolocation} from '#/state/geolocation'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Best-guess currency formatting.
|
||||||
|
*
|
||||||
|
* Attempts to use `getLocales` from `expo-localization` if available,
|
||||||
|
* otherwise falls back to the `persisted.appLanguage` setting, and geolocation
|
||||||
|
* API for region.
|
||||||
|
*/
|
||||||
|
export function useCurrencyFormatter(
|
||||||
|
options?: Parameters<typeof Intl.NumberFormat>[1],
|
||||||
|
) {
|
||||||
|
const {geolocation} = useGeolocation()
|
||||||
|
const {appLanguage} = useLanguagePrefs()
|
||||||
|
return React.useMemo(() => {
|
||||||
|
const locale = deviceLocales.at(0)
|
||||||
|
const languageTag = locale?.languageTag || appLanguage || 'en-US'
|
||||||
|
const countryCode = (
|
||||||
|
locale?.regionCode ||
|
||||||
|
geolocation?.countryCode ||
|
||||||
|
'us'
|
||||||
|
).toLowerCase()
|
||||||
|
const currency = countryCodeToCurrency[countryCode]
|
||||||
|
const format = new Intl.NumberFormat(languageTag, {
|
||||||
|
...(options || {}),
|
||||||
|
style: 'currency',
|
||||||
|
currency: currency,
|
||||||
|
}).format
|
||||||
|
|
||||||
|
return {
|
||||||
|
format,
|
||||||
|
currency,
|
||||||
|
countryCode,
|
||||||
|
languageTag,
|
||||||
|
}
|
||||||
|
}, [geolocation, appLanguage, options])
|
||||||
|
}
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
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 {Subscription} from '#/state/purchases/useSubscriptions/types'
|
||||||
|
import {identifierToSubscriptionInfo} from '#/state/purchases/useSubscriptions/util'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
|
export function useAvailableSubscriptions() {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
const did = currentAccount!.did
|
||||||
|
|
||||||
|
return useQuery<Subscription[]>({
|
||||||
|
queryKey: ['availableSubscriptions', did],
|
||||||
|
async queryFn() {
|
||||||
|
Purchases.logIn(did)
|
||||||
|
const offerings = await Purchases.getOfferings()
|
||||||
|
if (
|
||||||
|
offerings.current !== null &&
|
||||||
|
offerings.current.availablePackages.length !== 0
|
||||||
|
) {
|
||||||
|
return normalizePackages(offerings.current.availablePackages)
|
||||||
|
}
|
||||||
|
throw new Error(_(msg`Error loading subscriptions`))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePurchaseSubscription() {
|
||||||
|
return useMutation({
|
||||||
|
async mutationFn(pkg: PurchasesPackage) {
|
||||||
|
return Purchases.purchasePackage(pkg)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePackages(pkgs: PurchasesPackage[]): Subscription[] {
|
||||||
|
return pkgs
|
||||||
|
.map(p => {
|
||||||
|
const info = identifierToSubscriptionInfo(p.product.identifier)
|
||||||
|
if (!info) return
|
||||||
|
return {
|
||||||
|
info,
|
||||||
|
pricing: {
|
||||||
|
formatted: p.product.priceString,
|
||||||
|
value: p.product.price,
|
||||||
|
},
|
||||||
|
raw: p,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean) as Subscription[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
export type StripeProduct = {
|
||||||
|
// main stuff
|
||||||
|
id: string
|
||||||
|
default_price: string // ID of Price obj
|
||||||
|
name: string
|
||||||
|
active: boolean
|
||||||
|
// other stuff
|
||||||
|
object: string
|
||||||
|
attributes: unknown[]
|
||||||
|
created: number
|
||||||
|
description: string | null
|
||||||
|
features: unknown[]
|
||||||
|
images: unknown[]
|
||||||
|
livemode: boolean
|
||||||
|
marketing_features: unknown[]
|
||||||
|
metadata: unknown
|
||||||
|
package_dimensions: unknown | null
|
||||||
|
shippable: unknown | null
|
||||||
|
statement_descriptor: unknown | null
|
||||||
|
tax_code: string
|
||||||
|
type: 'service' | string
|
||||||
|
unit_label: unknown | null
|
||||||
|
updated: number
|
||||||
|
url: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StripePrice = {
|
||||||
|
// main stuff
|
||||||
|
id: string
|
||||||
|
product: string // Product obj associated
|
||||||
|
currency_options: {
|
||||||
|
[key: string]: {
|
||||||
|
custom_unit_amount: number | null
|
||||||
|
tax_behavior: 'inclusive' | string
|
||||||
|
unit_amount: number
|
||||||
|
unit_amount_decimal: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
active: boolean
|
||||||
|
recurring: {
|
||||||
|
interval: 'month' | 'year' | string
|
||||||
|
interval_count: number
|
||||||
|
usage_type: 'licensed' | string
|
||||||
|
}
|
||||||
|
object: 'price' | string
|
||||||
|
type: 'recurring' | string
|
||||||
|
// other stuff
|
||||||
|
metadata: unknown
|
||||||
|
unit_amount: number // default Price in cents
|
||||||
|
currency: string // default currency
|
||||||
|
tax_behavior: 'inclusive' | string // default tax behavior
|
||||||
|
billing_scheme: 'per_unit' | string
|
||||||
|
created: number
|
||||||
|
custom_unit_amount: number | null
|
||||||
|
livemode: boolean
|
||||||
|
lookup_key: string | null
|
||||||
|
nickname: string | null
|
||||||
|
tiers_mode: string | null
|
||||||
|
transform_quantity: string | null
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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