@goodgamestudios/cxf-webshop 6.27.3 → 7.0.0-qa.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src_old/app.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { DIReader } from './common'
2
+ import { inject } from 'readuz'
3
+
4
+ export const app: DIReader<void> = inject(
5
+ (environment) => environment.postMessageHandlers,
6
+ (environment) => environment.subscribeToCxf,
7
+ (environment) => environment.log,
8
+ (environment) => environment.tryCatch,
9
+ (environment) => environment.preResolveConfig,
10
+ (postMessageHandlers, subscribeCxf, log, tryCatch, preResolveConfig) => {
11
+ log('App has started')
12
+ window.addEventListener(
13
+ 'message',
14
+ tryCatch(({ data }: MessageEvent) => {
15
+ if (data) {
16
+ const handler = postMessageHandlers[data.name]
17
+ if (handler) {
18
+ log('POST MESSAGE', data)
19
+ handler(data.payload)
20
+ }
21
+ }
22
+ })
23
+ )
24
+ // eslint-disable-next-line array-callback-return
25
+ Object.entries(subscribeCxf).map(([_, reducer]) => {
26
+ reducer()
27
+ })
28
+ preResolveConfig()
29
+ }
30
+ )
@@ -0,0 +1,8 @@
1
+ import { IDictionary } from './common'
2
+ import { Reader } from 'readuz'
3
+
4
+ export const combineReaders =
5
+ <E>(readers: IDictionary<Reader<E, any>>) =>
6
+ (environment: E) => {
7
+ return Object.fromEntries(Object.entries(readers).map<any>(([key, reader]) => [key, reader(environment)]))
8
+ }
@@ -0,0 +1,35 @@
1
+ import { IEnvironment } from './env'
2
+ import { Reader } from 'readuz'
3
+
4
+ export interface IDictionary<T> {
5
+ [key: string]: T
6
+ }
7
+
8
+ export type AnyVoidFn = (...arguments_: any[]) => void
9
+
10
+ export type DIReader<TResult> = Reader<IEnvironment, TResult>
11
+
12
+ export type Fn<A, B> = (a: A) => B
13
+ export type PromiseFn<A, B> = Fn<A, Promise<B>>
14
+
15
+ type IPushMessageId = string
16
+
17
+ export type IPushMessageData = {
18
+ id: IPushMessageId
19
+ payload: IDictionary<any>
20
+ }
21
+
22
+ export interface IPushMessage<T> {
23
+ id: string
24
+ payload: T
25
+ }
26
+
27
+ export enum WebshopEvents {
28
+ CXF_DIALOG_CLOSE = 'cxf.dialog.close',
29
+ CXF_NATIVE_SUBSCRIPTION_ENABLE = 'cxf.native.subscription.enable',
30
+ CXF_OPEN_SALES_MSG = 'cxf.webshop.sales.open',
31
+ CXF_SET_CUSTOMIZATION_SUFFIX = 'cxf.set.customization.surfix',
32
+ CXF_JOIN_TEMP_SERVER = 'cxf.join.temp.server',
33
+ LEMONSTAND_CATEGORY_UPDATE = 'lemonstand.category.update',
34
+ LEMONSTAND_NOTIFICATIONS_CREATED = 'lemonstand.notifs.created',
35
+ }
@@ -0,0 +1,42 @@
1
+ import { IDictionary, WebshopEvents } from './common'
2
+ import { CxfEvents } from '@goodgamestudios/cxf-events'
3
+
4
+ export type GameSpecificConfig = {
5
+ LEGEND_LEVEL_IS_USED: boolean
6
+ }
7
+
8
+ const COMMON_CONFIG = {
9
+ CUSTOMIZATION_URL: process.env.CUSTOMIZATION_URL as string,
10
+ CUSTOMIZATION_URL_TEMPLATE: process.env.CUSTOMIZATION_URL_TEMPLATE as string,
11
+ BASE_URL: process.env.BASE_URL as string,
12
+ CXF_DIALOG_OPEN: 'cxf.dialog.open',
13
+ CXF_DIALOG_CLOSE: 'cxf.dialog.close',
14
+ CXF_TRACK_MSG: 'cxf.tracking.message',
15
+ CXF_BTN_CLICK_MSG: CxfEvents.OpenIGS,
16
+ CXF_OPEN_SALES_MSG: WebshopEvents.CXF_OPEN_SALES_MSG,
17
+ WEB_SHOP_CALL_TRACK_ID: 1181,
18
+ CXF_ERROR: 'cxf.error',
19
+ CXF_PUSH: 'cxf.push',
20
+ CXF_AD_STATUS: 'cxf.adBanner.status',
21
+ }
22
+
23
+ export type Config = typeof COMMON_CONFIG & GameSpecificConfig
24
+
25
+ const GAME_SPECIFIC_CONFIG: IDictionary<GameSpecificConfig> = {
26
+ 12: {
27
+ LEGEND_LEVEL_IS_USED: true,
28
+ },
29
+ 15: {
30
+ LEGEND_LEVEL_IS_USED: false,
31
+ },
32
+ 16: {
33
+ LEGEND_LEVEL_IS_USED: true,
34
+ },
35
+ }
36
+
37
+ export const createConfig = (gameId: string): Config => {
38
+ return {
39
+ ...COMMON_CONFIG,
40
+ ...GAME_SPECIFIC_CONFIG[gameId],
41
+ }
42
+ }
package/src_old/cxf.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { DIReader } from './common'
2
+ import { inject } from 'readuz'
3
+ import { CXF as ICXFBase } from '@goodgamestudios/cxf-runtime'
4
+
5
+ export interface IGameApi {
6
+ invokeFn(functionName: string, ...arguments_: any[]): Promise<any>
7
+ }
8
+
9
+ export interface ICXF extends ICXFBase {
10
+ gameApi: IGameApi
11
+ }
12
+
13
+ export type GetCxf = () => ICXF
14
+ export const getCxf: DIReader<GetCxf> = inject(
15
+ (environment) => environment.cxfProvider,
16
+ (cxfProvider) => () => {
17
+ const cxf = cxfProvider.get()
18
+ if (cxf) {
19
+ return cxf
20
+ }
21
+
22
+ throw new Error('CXF is not loaded')
23
+ }
24
+ )
25
+
26
+ export type SetCxf = (cxf: ICXF) => void
27
+ export const setCxf: DIReader<SetCxf> = inject(
28
+ (environment) => environment.cxfProvider,
29
+ (cxfProvider) => (value) => {
30
+ cxfProvider.set(value)
31
+ }
32
+ )
@@ -0,0 +1,25 @@
1
+ import { inject } from 'readuz'
2
+ import { DIReader } from './common'
3
+ import { getCxf } from './helpers'
4
+
5
+ export type RemoveDialog = () => void
6
+ export const removeDialog: DIReader<RemoveDialog> = inject(
7
+ (environment) => environment.config,
8
+ (environment) => environment.cxfProvider,
9
+ ({ CXF_DIALOG_CLOSE }, cxfProvider) =>
10
+ () => {
11
+ const cxf = getCxf(cxfProvider)
12
+ cxf.emit(CXF_DIALOG_CLOSE)
13
+ }
14
+ )
15
+
16
+ export type CreateDialog = (url: string) => void
17
+ export const createDialog: DIReader<CreateDialog> = inject(
18
+ (environment) => environment.config,
19
+ (environment) => environment.cxfProvider,
20
+ ({ CXF_DIALOG_OPEN }, cxfProvider) =>
21
+ (url) => {
22
+ const cxf = getCxf(cxfProvider)
23
+ cxf.emit(CXF_DIALOG_OPEN, url)
24
+ }
25
+ )
package/src_old/env.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { just } from 'readuz'
2
+ import { createCxfReducers, CxfReducers, subscribeToGameEvents, SubscribeToGameEvents } from './handlers/reducers'
3
+ import { DIReader } from './common'
4
+ import { Config, createConfig } from './config'
5
+ import { CreateDialog, createDialog, RemoveDialog, removeDialog } from './dialog'
6
+ import { OnOpen, onOpen } from './handlers/eventHandlers'
7
+ import {
8
+ entityProvider,
9
+ getDomain,
10
+ GetDomain,
11
+ getPing,
12
+ GetPing,
13
+ ggsGetQueryParams as ggsGetQueryParameters,
14
+ GGSGetQueryParams as GGSGetQueryParameters,
15
+ ggsGetReferrerValue,
16
+ GGSGetReferrerValue,
17
+ IProvider,
18
+ loadCxf,
19
+ LoadCxf,
20
+ Log,
21
+ log,
22
+ LogError,
23
+ logError,
24
+ ThrowCxfError,
25
+ throwCxfError,
26
+ TryCatch,
27
+ tryCatch,
28
+ } from './helpers'
29
+ import { TrackAction, trackAction, TrackOpenAction, trackOpenAction } from './track'
30
+ import { CreateCustomizationUrl, createCustomizationUrl, CreateIframeUrl, createIframeUrl } from './url'
31
+ import { createPushHandlers, PushHandlers } from './handlers/pushHandlers'
32
+ import { createPostMessageHandlers, Handlers } from './handlers/postMessageHandlers'
33
+ import { GetStorageData, getStorageData, setStorageData, SetStorageData } from './storage'
34
+ import { defaultStore, getStore, GetStore, IStore, setStore, SetStore } from './store'
35
+ import { getCxf, GetCxf, ICXF } from './cxf'
36
+ import { IShopMessageBus } from './messages/IShopMessageBus'
37
+ import { ShopMessageBus } from './messages/ShopMessageBus'
38
+ import { preResolveConfig, PreFetch } from './preFetch'
39
+ import { OfferNotificationsFetchResult, fetchUnreadOfferNotificationsCount } from './fetch'
40
+
41
+ export interface IEnvironment {
42
+ config: DIReader<Config>
43
+
44
+ cxfProvider: DIReader<IProvider<ICXF>>
45
+ getCxf: DIReader<GetCxf>
46
+
47
+ dialogProvider: DIReader<IProvider<HTMLElement>>
48
+
49
+ store: DIReader<IProvider<IStore>>
50
+ getStore: DIReader<GetStore>
51
+ setStore: DIReader<SetStore>
52
+ log: DIReader<Log>
53
+ logError: DIReader<LogError>
54
+ throwCxfError: DIReader<ThrowCxfError>
55
+
56
+ createDialog: DIReader<CreateDialog>
57
+ removeDialog: DIReader<RemoveDialog>
58
+
59
+ createIframeUrl: DIReader<CreateIframeUrl>
60
+ createCustomizationUrl: DIReader<CreateCustomizationUrl>
61
+
62
+ onOpen: DIReader<OnOpen>
63
+
64
+ pushHandlers: DIReader<PushHandlers>
65
+ postMessageHandlers: DIReader<Handlers>
66
+ subscribeToCxf: DIReader<CxfReducers>
67
+ trackOpenAction: DIReader<TrackOpenAction>
68
+ trackAction: DIReader<TrackAction>
69
+ loadCxf: DIReader<LoadCxf>
70
+ tryCatch: DIReader<TryCatch>
71
+
72
+ getStorageData: DIReader<GetStorageData>
73
+ setStorageData: DIReader<SetStorageData>
74
+ getPing: DIReader<GetPing>
75
+ subscribeToGameEvents: DIReader<SubscribeToGameEvents>
76
+ getDomain: DIReader<GetDomain>
77
+ ggsGetQueryParams: DIReader<GGSGetQueryParameters>
78
+ ggsGetReferrerValue: DIReader<GGSGetReferrerValue>
79
+ shopMessageBus: DIReader<IShopMessageBus>
80
+ preResolveConfig: DIReader<PreFetch>
81
+ fetchUnreadOfferNotificationsCount: DIReader<OfferNotificationsFetchResult>
82
+ }
83
+
84
+ export const createEnv = (environment: Partial<IEnvironment>): IEnvironment => {
85
+ return {
86
+ config: just(createConfig('15')),
87
+
88
+ cxfProvider: just(entityProvider()),
89
+ getCxf,
90
+ subscribeToGameEvents,
91
+
92
+ dialogProvider: just(entityProvider()),
93
+
94
+ store: just(entityProvider(defaultStore({} as ICXF))),
95
+ getStore,
96
+ setStore,
97
+ log: just(log),
98
+ logError: just(logError),
99
+ throwCxfError,
100
+
101
+ createDialog,
102
+ removeDialog,
103
+ pushHandlers: createPushHandlers({}),
104
+ postMessageHandlers: createPostMessageHandlers({}),
105
+ subscribeToCxf: createCxfReducers({}),
106
+ onOpen,
107
+ createIframeUrl,
108
+ createCustomizationUrl,
109
+ trackOpenAction,
110
+ trackAction,
111
+ loadCxf: just(loadCxf),
112
+ tryCatch,
113
+
114
+ getStorageData: just(getStorageData),
115
+ setStorageData: just(setStorageData),
116
+ getPing,
117
+ getDomain,
118
+ ggsGetQueryParams: ggsGetQueryParameters,
119
+ ggsGetReferrerValue,
120
+
121
+ shopMessageBus: just(new ShopMessageBus()),
122
+ preResolveConfig,
123
+ fetchUnreadOfferNotificationsCount,
124
+
125
+ ...environment,
126
+ }
127
+ }
@@ -0,0 +1,46 @@
1
+ import { DIReader } from './common'
2
+ import { inject } from 'readuz'
3
+ import { criteriaSelector } from './store'
4
+
5
+ export type OfferNotificationsFetchResult = () => void
6
+ export const fetchUnreadOfferNotificationsCount: DIReader<OfferNotificationsFetchResult> = inject(
7
+ (environment) => environment.log,
8
+ (environment) => environment.logError,
9
+ (environment) => environment.getStore,
10
+ (environment) => environment.config,
11
+ (log, logError, getStore, { LEGEND_LEVEL_IS_USED }) =>
12
+ async () => {
13
+ const store = getStore()
14
+ if (LEGEND_LEVEL_IS_USED && store.legendLevel === undefined) {
15
+ log('Skip fetchUnreadOfferNotificationsCount due to legendLevel is undefined')
16
+ return
17
+ }
18
+ log('fetchUnreadOfferNotificationsCount')
19
+ if (store.token && store.unreadOfferNotifsCountUrl) {
20
+ let unreadCount = 0
21
+ const headers = {
22
+ Authorization: `Bearer ${store.token}`,
23
+ }
24
+ const url = store.unreadOfferNotifsCountUrl
25
+ .replace('{locale}', store.language || '')
26
+ .replace('{zoneId}', store.zoneId || '')
27
+ .replace('{criteria}', encodeURIComponent(JSON.stringify(criteriaSelector(store))))
28
+ try {
29
+ log('fetch', url)
30
+ const resp = await fetch(url, {
31
+ headers,
32
+ })
33
+ if (resp.ok) {
34
+ const data = await resp.json()
35
+ unreadCount = Number(data?.notifCount)
36
+ }
37
+ } catch (error) {
38
+ logError(`cannot fetch ${url}`, error)
39
+ }
40
+ log('setUnseenOffersCounter', unreadCount)
41
+ store.gameApi.invokeFn('setUnseenOffersCounter', unreadCount).catch((error) => {
42
+ logError('setUnseenOffersCounter error:', error)
43
+ })
44
+ }
45
+ }
46
+ )
@@ -0,0 +1,43 @@
1
+ import { inject } from 'readuz'
2
+ import { DIReader } from '../common'
3
+ import { createSessionId } from '../helpers'
4
+
5
+ export interface OpenIGSPayload {
6
+ page?: string
7
+ route?: string
8
+ sourceId?: string
9
+ config?: Record<string, any>
10
+ }
11
+
12
+ export type OnOpen = (payload?: OpenIGSPayload) => void
13
+ export const onOpen: DIReader<OnOpen> = inject(
14
+ (environment) => environment.createIframeUrl,
15
+ (environment) => environment.createDialog,
16
+ (environment) => environment.log,
17
+ (environment) => environment.trackOpenAction,
18
+ (environment) => environment.getStore,
19
+ (environment) => environment.setStore,
20
+ (createIframeUrl, createDialog, log, trackOpenAction, getStore, setStore) =>
21
+ (payload = {}) => {
22
+ log('OnOpen payload:', payload)
23
+ if (payload.sourceId) {
24
+ setStore({
25
+ sourceId: payload.sourceId,
26
+ })
27
+ }
28
+ const store = getStore()
29
+ const sid = createSessionId()
30
+ trackOpenAction(sid)
31
+ const url = createIframeUrl({
32
+ sid,
33
+ page: store.lastPurchaseTab,
34
+ ...payload,
35
+ })
36
+ createDialog(url)
37
+ setTimeout(() => {
38
+ // remove unread offer notifications counter on the IGS button while opening the IGS
39
+ // small delay makes UX a bit better due to it happens after IGS initialization is started
40
+ store.gameApi.invokeFn('setUnseenOffersCounter', 0)
41
+ }, 1000)
42
+ }
43
+ )
@@ -0,0 +1,43 @@
1
+ import { inject } from 'readuz'
2
+ import { DIReader, WebshopEvents, IDictionary } from '../common'
3
+ import { combineReaders } from '../combineReaders'
4
+ import { createSessionId } from '../helpers'
5
+
6
+ export type OpenSalesPage = () => void
7
+ export const onSalesPageOpen: DIReader<OpenSalesPage> = inject(
8
+ (environment) => environment.log,
9
+ (environment) => environment.createDialog,
10
+ (environment) => environment.createIframeUrl,
11
+ (log, createDialog, createIframeUrl) => () => {
12
+ log('OnOpenSalesOffersPage')
13
+ const sid = createSessionId()
14
+ const url = createIframeUrl({
15
+ page: 'sale-offers',
16
+ sid,
17
+ })
18
+ createDialog(url)
19
+ }
20
+ )
21
+
22
+ export type LemonstandClose = () => void
23
+ export const onLemonstandClose: DIReader<LemonstandClose> = inject(
24
+ (environment) => environment.log,
25
+ (environment) => environment.getStore,
26
+ (environment) => environment.fetchUnreadOfferNotificationsCount,
27
+ (log, getStore, fetchUnreadOfferNotificationsCount) => () => {
28
+ const store = getStore()
29
+ log('onLemonstandClose', store)
30
+ fetchUnreadOfferNotificationsCount()
31
+ }
32
+ )
33
+
34
+ export type Handler = (...arguments_: any[]) => void
35
+ export type Handlers = IDictionary<Handler>
36
+
37
+ export function createPostMessageHandlers(handlers: IDictionary<DIReader<Handler>>) {
38
+ return combineReaders({
39
+ [WebshopEvents.CXF_OPEN_SALES_MSG]: onSalesPageOpen,
40
+ [WebshopEvents.CXF_DIALOG_CLOSE]: onLemonstandClose,
41
+ ...handlers,
42
+ })
43
+ }
@@ -0,0 +1,95 @@
1
+ import { DIReader, WebshopEvents, IDictionary } from '../common'
2
+ import { combineReaders } from '../combineReaders'
3
+ import { inject } from 'readuz'
4
+
5
+ interface OnRewardProperties {
6
+ successUrl: string
7
+ offerId: string
8
+ sid: string
9
+ page: string
10
+ config?: Record<string, any>
11
+ }
12
+
13
+ export type OnReward = (properties: OnRewardProperties) => void
14
+ export const onReward: DIReader<OnReward> = inject(
15
+ (environment) => environment.log,
16
+ (environment) => environment.createDialog,
17
+ (environment) => environment.createIframeUrl,
18
+ (environment) => environment.setStore,
19
+ (environment) => environment.trackOpenAction,
20
+ (log, createDialog, createIframeUrl, setStore, trackOpenAction) => (payload) => {
21
+ log('OnReward: offerId', payload.offerId, 'Page', payload.page)
22
+ const url = createIframeUrl({
23
+ route: encodeURIComponent(payload.successUrl),
24
+ ...payload,
25
+ })
26
+ setStore({
27
+ lastPurchaseTab: payload.page,
28
+ sourceId: 'successfulPayoutReward',
29
+ })
30
+ trackOpenAction(payload.sid)
31
+
32
+ createDialog(url)
33
+ }
34
+ )
35
+
36
+ export interface OnLemonstandCategoryUpdateProperties {
37
+ target: string
38
+ action: string
39
+ data: any
40
+ }
41
+ export type OnLemonstandCategoryUpdate = (properties: OnLemonstandCategoryUpdateProperties) => void
42
+ export const onLemonstandCategoryUpdate: DIReader<OnLemonstandCategoryUpdate> = inject(
43
+ (environment) => environment.shopMessageBus,
44
+ (shopMessageBus) =>
45
+ ({ target, action, data }) => {
46
+ shopMessageBus.post({
47
+ eventName: WebshopEvents.LEMONSTAND_CATEGORY_UPDATE,
48
+ target,
49
+ data: { action, data },
50
+ })
51
+ }
52
+ )
53
+
54
+ export interface OnLemonstandNotificationsCreatedProperties {
55
+ notifCount: number
56
+ }
57
+ type OnLemonstandNotificationsCreated = (properties: OnLemonstandNotificationsCreatedProperties) => void
58
+
59
+ /**
60
+ * this handler works in case of offer notification activation and deactivation
61
+ */
62
+ export const onLemonstandNotificationsCreated: DIReader<OnLemonstandNotificationsCreated> = inject(
63
+ (environment) => environment.log,
64
+ (environment) => environment.logError,
65
+ (environment) => environment.getStore,
66
+ (environment) => environment.fetchUnreadOfferNotificationsCount,
67
+ (log, logError, getStore, fetchUnreadOfferNotificationsCount) =>
68
+ ({ notifCount }) => {
69
+ log('onLemonstandNotificationsCreated -> notifCount:', notifCount)
70
+ const store = getStore()
71
+ if (notifCount > 0) {
72
+ // random delay in range 1-120 sec on LIVE, and 1-15 sec on TEST
73
+ const randomDelayMs = Math.floor(Math.random() * (Number(store.networkId) < 250 ? 120_000 : 15_000))
74
+ setTimeout(() => {
75
+ fetchUnreadOfferNotificationsCount()
76
+ }, randomDelayMs)
77
+ } else {
78
+ store.gameApi.invokeFn('setUnseenOffersCounter', 0).catch((error) => {
79
+ logError('setUnseenOffersCounter error:', error)
80
+ })
81
+ }
82
+ }
83
+ )
84
+
85
+ export type PushHandler = (...arguments_: any[]) => void
86
+ export type PushHandlers = IDictionary<PushHandler>
87
+
88
+ export function createPushHandlers(handlers: IDictionary<DIReader<PushHandler>>) {
89
+ return combineReaders({
90
+ reward: onReward,
91
+ [WebshopEvents.LEMONSTAND_CATEGORY_UPDATE]: onLemonstandCategoryUpdate,
92
+ [WebshopEvents.LEMONSTAND_NOTIFICATIONS_CREATED]: onLemonstandNotificationsCreated,
93
+ ...handlers,
94
+ })
95
+ }