feat: add app config from server

This commit is contained in:
Aidar Shaikhutdin @makeweb.space 2023-06-20 14:02:35 +03:00
parent d27091ae67
commit a24343a18e
12 changed files with 95 additions and 24 deletions

View File

@ -5,6 +5,7 @@ import {
Element,
Elements,
AuthTokens,
Apps,
Assets,
AssetCategories,
DailyForecasts,
@ -17,6 +18,7 @@ import {
const api = {
auth: createMethod<AuthTokens.Payload, AuthTokens.Response>(AuthTokens.createRequest),
getAppConfig: createMethod<Apps.Payload, Apps.Response>(Apps.createRequest),
getElement: createMethod<Element.Payload, Element.Response>(Element.createRequest),
getElements: createMethod<Elements.Payload, Elements.Response>(Elements.createRequest),
getUser: createMethod<User.GetPayload, User.Response>(User.createGetRequest),

63
src/api/resources/Apps.ts Normal file
View 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() })
}

View File

@ -1,5 +1,6 @@
export * as Assets from './Assets'
export * as AssetCategories from './AssetCategories'
export * as Apps from './Apps'
export * as User from './User'
export * as DailyForecasts from './UserDailyForecasts'
export * as Auras from './Auras'

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useId } from 'react'
import { useCallback, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { PaymentIntent } from '@chargebee/chargebee-js-types'
import { useApi, useApiCall, extractErrorMessage, SubscriptionReceipts } from '../../../../api'
@ -17,7 +17,7 @@ interface ApplePayButtonProps {
export function ApplePayButton({ onSuccess, onError }: ApplePayButtonProps): JSX.Element {
const api = useApi()
const buttonId = useId()
const buttonId = 'apple-pay-btn'
const { i18n } = useTranslation()
const { token } = useAuth()
const { applePay } = usePayment()
@ -49,7 +49,7 @@ export function ApplePayButton({ onSuccess, onError }: ApplePayButtonProps): JSX
}, [data, applePay, buttonId, i18n.language, api, token, onSuccess, onError])
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
}</div>
)

View File

@ -77,7 +77,7 @@ export function CardModal({ open, onClose, onSuccess, onError }: CardModalProps)
setStatus('subscribing')
cardRef.current?.tokenize({})
.then((result: ChargebeeTokenizeResult) => {
return api.createSubscriptionReceipt({ token, itemPriceId, gwToken: result.token })
return api.createSubscriptionReceipt({ token, itemPriceId, gwToken: result.vaultToken })
})
.then(({ subscription_receipt }: SubscriptionReceipts.Response) => {
setStatus('success')

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useId } from 'react'
import { useCallback, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { PaymentIntent } from '@chargebee/chargebee-js-types'
import { SubscriptionReceipts, extractErrorMessage, useApi, useApiCall } from '../../../../api'
@ -17,7 +17,7 @@ interface GooglePayButtonProps {
export function GooglePayButton({ onSuccess, onError }: GooglePayButtonProps): JSX.Element {
const api = useApi()
const buttonId = useId()
const buttonId = 'google-pay-btn'
const { i18n } = useTranslation()
const { token } = useAuth()
const { googlePay } = usePayment()
@ -49,7 +49,7 @@ export function GooglePayButton({ onSuccess, onError }: GooglePayButtonProps): J
}, [data, googlePay, buttonId, i18n.language, onSuccess, onError])
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
}</div>
)

View File

@ -98,4 +98,16 @@
padding-left: 12px;
line-height: 1.5;
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;
}

View File

@ -1,8 +0,0 @@
const config = {
chargebee: {
site: 'kefirapp-test',
publishableKey: 'test_VtWSamZEfP175nqGZhkD0uvoouHieElv',
},
}
export default config

View File

@ -10,15 +10,18 @@ import { ApiContext, createApi } from './api'
import { LegalContext, buildLegal } from './legal'
import { PaymentContext } from './payment'
import { getClientLocale, buildResources, fallbackLng } from './locales'
import type { AppConfig } from './types'
import App from './components/App'
const init = async (config: AppConfig) => {
const init = async () => {
const api = createApi()
const lng = getClientLocale()
const response = await api.getElements({ locale: lng })
const resources = buildResources(response)
const legal = buildLegal(response)
const [elementsResponse, configResponse] = await Promise.all([
api.getElements({ locale: lng }),
api.getAppConfig({ bundleId: 'auraweb' }),
])
const resources = buildResources(elementsResponse)
const legal = buildLegal(elementsResponse)
const config = configResponse.data
const i18nextInstance = i18next.createInstance()
const options = { lng, resources, fallbackLng, postProcess: [ `reactPostprocessor` ] }
await i18nextInstance.use(initReactI18next).use(new ReactPostprocessor()).init(options)

View File

@ -1,5 +1,4 @@
import ReactDOM from 'react-dom/client'
import config from './config'
import init from './init'
import 'react-circular-progressbar/dist/styles.css'
import './fonts.css'
@ -18,7 +17,7 @@ const getRootElement = (id: string): HTMLElement => {
}
const startApp = async () => {
const vdom = await init(config)
const vdom = await init()
const rootElement = getRootElement('root')
ReactDOM.createRoot(rootElement).render(vdom)

View File

@ -22,6 +22,7 @@ const routes = {
token: () => [apiHost, prefix, 'auth', 'token.json'].join('/'),
elements: () => [apiHost, prefix, 'elements.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('/'),
assetCategories: () => [apiHost, prefix, 'assets', 'categories.json'].join('/'),
dailyForecasts: () => [apiHost, prefix, 'user', 'daily_forecast.json'].join('/'),

View File

@ -1,5 +1,4 @@
import { Chargebee } from '@chargebee/chargebee-js-types'
import config from './config'
declare global {
interface Window {
@ -22,5 +21,4 @@ export interface SignupForm {
birthtime: string
}
export type AppConfig = typeof config
export type UserStatus = 'lead' | 'registred' | 'subscribed' | 'unsubscribed'