feat: add app config from server
This commit is contained in:
parent
d27091ae67
commit
a24343a18e
@ -5,6 +5,7 @@ import {
|
|||||||
Element,
|
Element,
|
||||||
Elements,
|
Elements,
|
||||||
AuthTokens,
|
AuthTokens,
|
||||||
|
Apps,
|
||||||
Assets,
|
Assets,
|
||||||
AssetCategories,
|
AssetCategories,
|
||||||
DailyForecasts,
|
DailyForecasts,
|
||||||
@ -17,6 +18,7 @@ import {
|
|||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
auth: createMethod<AuthTokens.Payload, AuthTokens.Response>(AuthTokens.createRequest),
|
auth: createMethod<AuthTokens.Payload, AuthTokens.Response>(AuthTokens.createRequest),
|
||||||
|
getAppConfig: createMethod<Apps.Payload, Apps.Response>(Apps.createRequest),
|
||||||
getElement: createMethod<Element.Payload, Element.Response>(Element.createRequest),
|
getElement: createMethod<Element.Payload, Element.Response>(Element.createRequest),
|
||||||
getElements: createMethod<Elements.Payload, Elements.Response>(Elements.createRequest),
|
getElements: createMethod<Elements.Payload, Elements.Response>(Elements.createRequest),
|
||||||
getUser: createMethod<User.GetPayload, User.Response>(User.createGetRequest),
|
getUser: createMethod<User.GetPayload, User.Response>(User.createGetRequest),
|
||||||
|
|||||||
63
src/api/resources/Apps.ts
Normal file
63
src/api/resources/Apps.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import routes from '../../routes'
|
||||||
|
import { getBaseHeaders } from '../utils'
|
||||||
|
|
||||||
|
export interface Payload {
|
||||||
|
bundleId: 'com.life.aura' | 'com.life.gusebamps' | 'auraweb'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Response {
|
||||||
|
data: {
|
||||||
|
subscription_popup: boolean
|
||||||
|
locale: string
|
||||||
|
alerts: Alert
|
||||||
|
active_iaps: ActiveIAps[]
|
||||||
|
version: string
|
||||||
|
apple_music_api: AppleMusicApi
|
||||||
|
chargebee: ChargebeeConfig
|
||||||
|
first_open_subscription_popup: boolean
|
||||||
|
runs_before_subscription_popup: number
|
||||||
|
appirater_alerts: AppiraterAlertAppiraterAlert[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActiveIAps {
|
||||||
|
bundle_id: string
|
||||||
|
active: boolean
|
||||||
|
subscription_type: 'trial' | 'monthly' | 'yearly'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppiraterAlertAppiraterAlert {
|
||||||
|
id: string
|
||||||
|
type: string
|
||||||
|
body: string
|
||||||
|
label: string
|
||||||
|
cancel: string
|
||||||
|
title: string
|
||||||
|
uses_until_prompt: string
|
||||||
|
days_until_prompt: string
|
||||||
|
time_before_reminding: string
|
||||||
|
significant_events_until_prompt: string
|
||||||
|
show: boolean
|
||||||
|
apple_id: string
|
||||||
|
appirater_link: string
|
||||||
|
appirater_pro_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Alert {
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppleMusicApi {
|
||||||
|
jwt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChargebeeConfig {
|
||||||
|
site: string
|
||||||
|
publishableKey: string
|
||||||
|
gatewayAccountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRequest = ({ bundleId }: Payload): Request => {
|
||||||
|
const url = new URL(routes.server.apps(bundleId))
|
||||||
|
return new Request(url, { method: 'GET', headers: getBaseHeaders() })
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
export * as Assets from './Assets'
|
export * as Assets from './Assets'
|
||||||
export * as AssetCategories from './AssetCategories'
|
export * as AssetCategories from './AssetCategories'
|
||||||
|
export * as Apps from './Apps'
|
||||||
export * as User from './User'
|
export * as User from './User'
|
||||||
export * as DailyForecasts from './UserDailyForecasts'
|
export * as DailyForecasts from './UserDailyForecasts'
|
||||||
export * as Auras from './Auras'
|
export * as Auras from './Auras'
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useId } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { PaymentIntent } from '@chargebee/chargebee-js-types'
|
import { PaymentIntent } from '@chargebee/chargebee-js-types'
|
||||||
import { useApi, useApiCall, extractErrorMessage, SubscriptionReceipts } from '../../../../api'
|
import { useApi, useApiCall, extractErrorMessage, SubscriptionReceipts } from '../../../../api'
|
||||||
@ -17,7 +17,7 @@ interface ApplePayButtonProps {
|
|||||||
|
|
||||||
export function ApplePayButton({ onSuccess, onError }: ApplePayButtonProps): JSX.Element {
|
export function ApplePayButton({ onSuccess, onError }: ApplePayButtonProps): JSX.Element {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
const buttonId = useId()
|
const buttonId = 'apple-pay-btn'
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
const { token } = useAuth()
|
const { token } = useAuth()
|
||||||
const { applePay } = usePayment()
|
const { applePay } = usePayment()
|
||||||
@ -49,7 +49,7 @@ export function ApplePayButton({ onSuccess, onError }: ApplePayButtonProps): JSX
|
|||||||
}, [data, applePay, buttonId, i18n.language, api, token, onSuccess, onError])
|
}, [data, applePay, buttonId, i18n.language, api, token, onSuccess, onError])
|
||||||
|
|
||||||
return isPending ? <Loader /> : (
|
return isPending ? <Loader /> : (
|
||||||
<div id={buttonId} style={{ height: 60 }}>{
|
<div id={buttonId} className='pay-btn'>{
|
||||||
error ? <ErrorText message={extractErrorMessage(error)} isShown={true} size='large'/> : null
|
error ? <ErrorText message={extractErrorMessage(error)} isShown={true} size='large'/> : null
|
||||||
}</div>
|
}</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -77,7 +77,7 @@ export function CardModal({ open, onClose, onSuccess, onError }: CardModalProps)
|
|||||||
setStatus('subscribing')
|
setStatus('subscribing')
|
||||||
cardRef.current?.tokenize({})
|
cardRef.current?.tokenize({})
|
||||||
.then((result: ChargebeeTokenizeResult) => {
|
.then((result: ChargebeeTokenizeResult) => {
|
||||||
return api.createSubscriptionReceipt({ token, itemPriceId, gwToken: result.token })
|
return api.createSubscriptionReceipt({ token, itemPriceId, gwToken: result.vaultToken })
|
||||||
})
|
})
|
||||||
.then(({ subscription_receipt }: SubscriptionReceipts.Response) => {
|
.then(({ subscription_receipt }: SubscriptionReceipts.Response) => {
|
||||||
setStatus('success')
|
setStatus('success')
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useId } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { PaymentIntent } from '@chargebee/chargebee-js-types'
|
import { PaymentIntent } from '@chargebee/chargebee-js-types'
|
||||||
import { SubscriptionReceipts, extractErrorMessage, useApi, useApiCall } from '../../../../api'
|
import { SubscriptionReceipts, extractErrorMessage, useApi, useApiCall } from '../../../../api'
|
||||||
@ -17,7 +17,7 @@ interface GooglePayButtonProps {
|
|||||||
|
|
||||||
export function GooglePayButton({ onSuccess, onError }: GooglePayButtonProps): JSX.Element {
|
export function GooglePayButton({ onSuccess, onError }: GooglePayButtonProps): JSX.Element {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
const buttonId = useId()
|
const buttonId = 'google-pay-btn'
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
const { token } = useAuth()
|
const { token } = useAuth()
|
||||||
const { googlePay } = usePayment()
|
const { googlePay } = usePayment()
|
||||||
@ -49,7 +49,7 @@ export function GooglePayButton({ onSuccess, onError }: GooglePayButtonProps): J
|
|||||||
}, [data, googlePay, buttonId, i18n.language, onSuccess, onError])
|
}, [data, googlePay, buttonId, i18n.language, onSuccess, onError])
|
||||||
|
|
||||||
return isPending ? <Loader /> : (
|
return isPending ? <Loader /> : (
|
||||||
<div id={buttonId} style={{ height: 60 }}>{
|
<div id={buttonId} className='pay-btn'>{
|
||||||
error ? <ErrorText message={extractErrorMessage(error)} isShown={true} size='large'/> : null
|
error ? <ErrorText message={extractErrorMessage(error)} isShown={true} size='large'/> : null
|
||||||
}</div>
|
}</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -98,4 +98,16 @@
|
|||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn {
|
||||||
|
min-height: 60px;
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 250px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-btn .gpay-button {
|
||||||
|
min-height: 60px;
|
||||||
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
@ -1,8 +0,0 @@
|
|||||||
const config = {
|
|
||||||
chargebee: {
|
|
||||||
site: 'kefirapp-test',
|
|
||||||
publishableKey: 'test_VtWSamZEfP175nqGZhkD0uvoouHieElv',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default config
|
|
||||||
13
src/init.tsx
13
src/init.tsx
@ -10,15 +10,18 @@ import { ApiContext, createApi } from './api'
|
|||||||
import { LegalContext, buildLegal } from './legal'
|
import { LegalContext, buildLegal } from './legal'
|
||||||
import { PaymentContext } from './payment'
|
import { PaymentContext } from './payment'
|
||||||
import { getClientLocale, buildResources, fallbackLng } from './locales'
|
import { getClientLocale, buildResources, fallbackLng } from './locales'
|
||||||
import type { AppConfig } from './types'
|
|
||||||
import App from './components/App'
|
import App from './components/App'
|
||||||
|
|
||||||
const init = async (config: AppConfig) => {
|
const init = async () => {
|
||||||
const api = createApi()
|
const api = createApi()
|
||||||
const lng = getClientLocale()
|
const lng = getClientLocale()
|
||||||
const response = await api.getElements({ locale: lng })
|
const [elementsResponse, configResponse] = await Promise.all([
|
||||||
const resources = buildResources(response)
|
api.getElements({ locale: lng }),
|
||||||
const legal = buildLegal(response)
|
api.getAppConfig({ bundleId: 'auraweb' }),
|
||||||
|
])
|
||||||
|
const resources = buildResources(elementsResponse)
|
||||||
|
const legal = buildLegal(elementsResponse)
|
||||||
|
const config = configResponse.data
|
||||||
const i18nextInstance = i18next.createInstance()
|
const i18nextInstance = i18next.createInstance()
|
||||||
const options = { lng, resources, fallbackLng, postProcess: [ `reactPostprocessor` ] }
|
const options = { lng, resources, fallbackLng, postProcess: [ `reactPostprocessor` ] }
|
||||||
await i18nextInstance.use(initReactI18next).use(new ReactPostprocessor()).init(options)
|
await i18nextInstance.use(initReactI18next).use(new ReactPostprocessor()).init(options)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import config from './config'
|
|
||||||
import init from './init'
|
import init from './init'
|
||||||
import 'react-circular-progressbar/dist/styles.css'
|
import 'react-circular-progressbar/dist/styles.css'
|
||||||
import './fonts.css'
|
import './fonts.css'
|
||||||
@ -18,7 +17,7 @@ const getRootElement = (id: string): HTMLElement => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const startApp = async () => {
|
const startApp = async () => {
|
||||||
const vdom = await init(config)
|
const vdom = await init()
|
||||||
const rootElement = getRootElement('root')
|
const rootElement = getRootElement('root')
|
||||||
|
|
||||||
ReactDOM.createRoot(rootElement).render(vdom)
|
ReactDOM.createRoot(rootElement).render(vdom)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ const routes = {
|
|||||||
token: () => [apiHost, prefix, 'auth', 'token.json'].join('/'),
|
token: () => [apiHost, prefix, 'auth', 'token.json'].join('/'),
|
||||||
elements: () => [apiHost, prefix, 'elements.json'].join('/'),
|
elements: () => [apiHost, prefix, 'elements.json'].join('/'),
|
||||||
element: (type: string) => [apiHost, prefix, 'elements', `${type}.json`].join('/'),
|
element: (type: string) => [apiHost, prefix, 'elements', `${type}.json`].join('/'),
|
||||||
|
apps: (bundleId: string) => [apiHost, prefix, 'apps', `${bundleId}.json`].join('/'),
|
||||||
assets: (category: string) => [apiHost, prefix, 'assets', 'categories', `${category}.json`].join('/'),
|
assets: (category: string) => [apiHost, prefix, 'assets', 'categories', `${category}.json`].join('/'),
|
||||||
assetCategories: () => [apiHost, prefix, 'assets', 'categories.json'].join('/'),
|
assetCategories: () => [apiHost, prefix, 'assets', 'categories.json'].join('/'),
|
||||||
dailyForecasts: () => [apiHost, prefix, 'user', 'daily_forecast.json'].join('/'),
|
dailyForecasts: () => [apiHost, prefix, 'user', 'daily_forecast.json'].join('/'),
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Chargebee } from '@chargebee/chargebee-js-types'
|
import { Chargebee } from '@chargebee/chargebee-js-types'
|
||||||
import config from './config'
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -22,5 +21,4 @@ export interface SignupForm {
|
|||||||
birthtime: string
|
birthtime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AppConfig = typeof config
|
|
||||||
export type UserStatus = 'lead' | 'registred' | 'subscribed' | 'unsubscribed'
|
export type UserStatus = 'lead' | 'registred' | 'subscribed' | 'unsubscribed'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user