@goodgamestudios/cxf-webshop 6.27.3 → 7.0.0-qa.1
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/REFACTORING_README.md +265 -0
- package/TEST_MIGRATION.md +441 -0
- package/TYPES_REFACTORING.md +308 -0
- package/dist/webshop-cxf.js +1 -1
- package/dist/webshop-cxf.js.map +4 -4
- package/package.json +1 -1
- package/src_old/@types/global.d.ts +2 -0
- package/src_old/ArgumentNullError.ts +6 -0
- package/src_old/app.ts +30 -0
- package/src_old/combineReaders.ts +8 -0
- package/src_old/common.ts +35 -0
- package/src_old/config.ts +42 -0
- package/src_old/cxf.ts +32 -0
- package/src_old/dialog.ts +25 -0
- package/src_old/env.ts +127 -0
- package/src_old/fetch.ts +46 -0
- package/src_old/handlers/eventHandlers.ts +43 -0
- package/src_old/handlers/postMessageHandlers.ts +43 -0
- package/src_old/handlers/pushHandlers.ts +95 -0
- package/src_old/handlers/reducers.ts +207 -0
- package/src_old/helpers.ts +143 -0
- package/src_old/index.ts +35 -0
- package/src_old/messages/IShopMessageBus.ts +3 -0
- package/src_old/messages/ShopMessageBus.ts +10 -0
- package/src_old/messages/TestShopMessageBus.ts +8 -0
- package/src_old/ping.ts +15 -0
- package/src_old/preFetch.ts +43 -0
- package/src_old/storage.ts +32 -0
- package/src_old/store.ts +82 -0
- package/src_old/track.ts +59 -0
- package/src_old/url.ts +95 -0
- package/src_old/utils.ts +64 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { inject, Reader } from 'readuz'
|
|
2
|
+
import { CxfEvents, IGameEvent, ILoginData } from '@goodgamestudios/cxf-events'
|
|
3
|
+
import { DIReader, WebshopEvents, IDictionary, IPushMessageData } from '../common'
|
|
4
|
+
import { combineReaders } from '../combineReaders'
|
|
5
|
+
|
|
6
|
+
export type SubscribeToCxf = Reader<void, void>
|
|
7
|
+
const commonCxfReducer: DIReader<SubscribeToCxf> = inject(
|
|
8
|
+
(environment) => environment.log,
|
|
9
|
+
(environment) => environment.getCxf,
|
|
10
|
+
(environment) => environment.onOpen,
|
|
11
|
+
(environment) => environment.tryCatch,
|
|
12
|
+
(environment) => environment.pushHandlers,
|
|
13
|
+
(log, getCxf, onOpen, tryCatch, pushHandlers) => () => {
|
|
14
|
+
const cxf = getCxf()
|
|
15
|
+
cxf.on(CxfEvents.OpenIGS, tryCatch(onOpen))
|
|
16
|
+
cxf.on(
|
|
17
|
+
CxfEvents.Push,
|
|
18
|
+
tryCatch(({ id, payload }: IPushMessageData) => {
|
|
19
|
+
log('cxf.push', id, payload)
|
|
20
|
+
const handler = pushHandlers[id]
|
|
21
|
+
handler && handler(payload)
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
export type CxfReducers = IDictionary<SubscribeToCxf>
|
|
28
|
+
|
|
29
|
+
export function createCxfReducers(handlers: IDictionary<DIReader<SubscribeToCxf>>) {
|
|
30
|
+
return combineReaders({
|
|
31
|
+
common: commonCxfReducer,
|
|
32
|
+
gameEvents: subscribeToGameEvents,
|
|
33
|
+
...handlers,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type SubscribeToGameEvents = () => void
|
|
38
|
+
export const subscribeToGameEvents: DIReader<SubscribeToGameEvents> = inject(
|
|
39
|
+
(environment) => environment.log,
|
|
40
|
+
(environment) => environment.logError,
|
|
41
|
+
(environment) => environment.getCxf,
|
|
42
|
+
(environment) => environment.getStore,
|
|
43
|
+
(environment) => environment.setStore,
|
|
44
|
+
(environment) => environment.fetchUnreadOfferNotificationsCount,
|
|
45
|
+
(log, logError, getCxf, getStore, setStore, fetchUnreadOfferNotificationsCount) => () => {
|
|
46
|
+
const cxf = getCxf()
|
|
47
|
+
cxf.on(CxfEvents.Login, (e: ILoginData) => {
|
|
48
|
+
const { gameEvents } = getStore()
|
|
49
|
+
const { gameEvents: eventsInLogin } = e
|
|
50
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
51
|
+
const eventNotExistPredicateGenerator = (existingEvents: IGameEvent[]) => (event: IGameEvent) =>
|
|
52
|
+
!existingEvents.map((event_) => event_.type).includes(event.type)
|
|
53
|
+
setStore({
|
|
54
|
+
...e,
|
|
55
|
+
gameEvents: [...gameEvents.filter(eventNotExistPredicateGenerator(eventsInLogin)), ...eventsInLogin],
|
|
56
|
+
})
|
|
57
|
+
log(CxfEvents.Login, 'reducer', getStore())
|
|
58
|
+
fetchUnreadOfferNotificationsCount()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
cxf.on(CxfEvents.GameEventUpdate, (e: IGameEvent[]) => {
|
|
62
|
+
log(CxfEvents.GameEventUpdate, e)
|
|
63
|
+
const store = getStore()
|
|
64
|
+
const updatedEventTypes = new Set(e.map((event) => event.type))
|
|
65
|
+
setStore({
|
|
66
|
+
gameEvents: [...store.gameEvents.filter((event) => !updatedEventTypes.has(event.type)), ...e],
|
|
67
|
+
})
|
|
68
|
+
log(CxfEvents.GameEventUpdate, 'reducer', getStore())
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
cxf.on(CxfEvents.GameEventAdd, (e: IGameEvent) => {
|
|
72
|
+
log(CxfEvents.GameEventAdd, e)
|
|
73
|
+
const store = getStore()
|
|
74
|
+
setStore({
|
|
75
|
+
gameEvents: [...store.gameEvents, e],
|
|
76
|
+
})
|
|
77
|
+
log(CxfEvents.GameEventAdd, 'reducer', getStore())
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
cxf.on(CxfEvents.GameEventRemove, (e: number) => {
|
|
81
|
+
log(CxfEvents.GameEventRemove, e)
|
|
82
|
+
const store = getStore()
|
|
83
|
+
setStore({
|
|
84
|
+
gameEvents: store.gameEvents.filter(({ type }) => type !== e),
|
|
85
|
+
})
|
|
86
|
+
log(CxfEvents.GameEventRemove, 'reducer', getStore())
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
cxf.on(CxfEvents.LevelChanged, (level: number) => {
|
|
90
|
+
log(CxfEvents.LevelChanged, level)
|
|
91
|
+
setStore({
|
|
92
|
+
level,
|
|
93
|
+
})
|
|
94
|
+
log(CxfEvents.LevelChanged, 'reducer', getStore())
|
|
95
|
+
fetchUnreadOfferNotificationsCount()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
cxf.on(CxfEvents.LegendLevelChanged, (legendLevel: number) => {
|
|
99
|
+
log(CxfEvents.LegendLevelChanged, `legendLevel: ${legendLevel}`)
|
|
100
|
+
setStore({
|
|
101
|
+
legendLevel,
|
|
102
|
+
})
|
|
103
|
+
const store = getStore()
|
|
104
|
+
log(CxfEvents.LegendLevelChanged, 'reducer', store)
|
|
105
|
+
fetchUnreadOfferNotificationsCount()
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
In E4K this event is used to control the subscriptions tab
|
|
112
|
+
This is deprecated, as specific config values/tab visibility can be controlled using Lemonstands `config` query param
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
export const nativeSubscriptionEnableReducer: DIReader<SubscribeToCxf> = inject(
|
|
116
|
+
(environment) => environment.getCxf,
|
|
117
|
+
(environment) => environment.setStore,
|
|
118
|
+
(environment) => environment.preResolveConfig,
|
|
119
|
+
(getCxf, setStore, preResolveConfig) => () => {
|
|
120
|
+
const cxf = getCxf()
|
|
121
|
+
cxf.on(WebshopEvents.CXF_NATIVE_SUBSCRIPTION_ENABLE, (enabled: 0 | 1) => {
|
|
122
|
+
setStore({
|
|
123
|
+
subscriptionDisabled: enabled === 0,
|
|
124
|
+
customizationSuffix: enabled === 0 ? 'no-subscription' : '',
|
|
125
|
+
})
|
|
126
|
+
preResolveConfig()
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
The config file suffix (e.g. "em.json" + "mobile" -> "em-mobile.json") can be set through an event
|
|
133
|
+
Used by MS and BFW integration pages
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
export const setCustomizationSuffixReducer: DIReader<SubscribeToCxf> = inject(
|
|
137
|
+
(environment) => environment.getCxf,
|
|
138
|
+
(environment) => environment.getStore,
|
|
139
|
+
(environment) => environment.setStore,
|
|
140
|
+
(environment) => environment.preResolveConfig,
|
|
141
|
+
(getCxf, getStore, setStore, preResolveConfig) => () => {
|
|
142
|
+
const cxf = getCxf()
|
|
143
|
+
cxf.on(WebshopEvents.CXF_SET_CUSTOMIZATION_SUFFIX, (suffix: string) => {
|
|
144
|
+
const store = getStore()
|
|
145
|
+
if (suffix === store.customizationSuffix) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
setStore({
|
|
149
|
+
customizationSuffix: suffix || '',
|
|
150
|
+
})
|
|
151
|
+
preResolveConfig()
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
Information about whether ads are enabled or not is retrieved externally from `cxf-ad-banners`
|
|
158
|
+
and stored to be passed to IGS
|
|
159
|
+
*/
|
|
160
|
+
|
|
161
|
+
export const receiveAdStatusReducer: DIReader<SubscribeToCxf> = inject(
|
|
162
|
+
(environment) => environment.getCxf,
|
|
163
|
+
(environment) => environment.setStore,
|
|
164
|
+
(environment) => environment.config,
|
|
165
|
+
(getCxf, setStore, { CXF_AD_STATUS }) =>
|
|
166
|
+
() => {
|
|
167
|
+
const cxf = getCxf()
|
|
168
|
+
cxf.on(CXF_AD_STATUS, ({ areBannersAvailable, bannersDetails }: Record<string, any>) => {
|
|
169
|
+
setStore({
|
|
170
|
+
adStatus: {
|
|
171
|
+
areBannersAvailable,
|
|
172
|
+
bannersDetails,
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
Use a dedicated config variant on temp servers
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
export const tempServerContextReducer: DIReader<SubscribeToCxf> = inject(
|
|
184
|
+
(environment) => environment.getCxf,
|
|
185
|
+
(environment) => environment.getStore,
|
|
186
|
+
(environment) => environment.setStore,
|
|
187
|
+
(environment) => environment.preResolveConfig,
|
|
188
|
+
(getCxf, getStore, setStore, preResolveConfig) => () => {
|
|
189
|
+
const cxf = getCxf()
|
|
190
|
+
cxf.on(WebshopEvents.CXF_JOIN_TEMP_SERVER, (isTemp: 0 | 1) => {
|
|
191
|
+
const store = getStore()
|
|
192
|
+
setStore({
|
|
193
|
+
isTempServer: Boolean(isTemp),
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
// ensure suffix is not already set by the environment, e.g. BFW or MS integration
|
|
197
|
+
// TODO: fully migrate client detection into `cxf-webshop`
|
|
198
|
+
if (store.customizationSuffix === '' || store.customizationSuffix === 'temp') {
|
|
199
|
+
setStore({
|
|
200
|
+
customizationSuffix: isTemp ? 'temp' : '',
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
preResolveConfig()
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/* eslint-disable unicorn/consistent-function-scoping */
|
|
2
|
+
import debug from 'debug'
|
|
3
|
+
import { inject } from 'readuz'
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
5
|
+
import { DIReader, IDictionary } from './common'
|
|
6
|
+
import { parentDomain, timeout } from './utils'
|
|
7
|
+
import { ArgumentNullError } from './ArgumentNullError'
|
|
8
|
+
import { encodePing } from './ping'
|
|
9
|
+
import { IStore } from './store'
|
|
10
|
+
import { ICXF } from './cxf'
|
|
11
|
+
|
|
12
|
+
export function formatQueryString(object: IDictionary<string | number | undefined | null>) {
|
|
13
|
+
return Object.entries(object)
|
|
14
|
+
.filter(([key, value]) => value !== null && value !== undefined)
|
|
15
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`)
|
|
16
|
+
.join('&')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const getTokenAndLanguage = (store: IStore) => {
|
|
20
|
+
const { playerId, token, zoneId, language } = store
|
|
21
|
+
if (!playerId) {
|
|
22
|
+
throw new ArgumentNullError('playerId', playerId)
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
token,
|
|
26
|
+
zoneId,
|
|
27
|
+
locale: language,
|
|
28
|
+
ping: encodePing({ ...store, playerId }),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface IProvider<T> {
|
|
33
|
+
get: () => T | undefined
|
|
34
|
+
set: (value: T) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const getCxf = (cxfProvider: IProvider<ICXF>) => {
|
|
38
|
+
const cxf = cxfProvider.get()
|
|
39
|
+
if (!cxf) {
|
|
40
|
+
throw new ArgumentNullError('cxf', cxf)
|
|
41
|
+
}
|
|
42
|
+
return cxf
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type GetPing = () => string
|
|
46
|
+
export const getPing: DIReader<GetPing> = inject(
|
|
47
|
+
(environment) => environment.getStore,
|
|
48
|
+
(getStore) => () => {
|
|
49
|
+
const store = getStore()
|
|
50
|
+
const { playerId } = store
|
|
51
|
+
if (!playerId) {
|
|
52
|
+
throw new ArgumentNullError('playerId', playerId)
|
|
53
|
+
}
|
|
54
|
+
return encodePing({ ...store, playerId })
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export const entityProvider = <T>(initial?: T): IProvider<T> => {
|
|
59
|
+
let element = initial
|
|
60
|
+
return {
|
|
61
|
+
get: () => element,
|
|
62
|
+
set: (value) => {
|
|
63
|
+
element = value
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type TryCatch = {
|
|
69
|
+
<R>(function_: () => R): () => R
|
|
70
|
+
<P1, R>(function_: (p1: P1) => R): (p1: P1) => R
|
|
71
|
+
<P1, P2, R>(function_: (p1: P1, p2: P2) => R): (p1: P1, p2: P2) => R
|
|
72
|
+
<P1, P2, P3, R>(function_: (p1: P1, p2: P2, p3: P3) => R): (p1: P1, p2: P2, p3: P3) => R
|
|
73
|
+
}
|
|
74
|
+
export const tryCatch: DIReader<TryCatch> = inject(
|
|
75
|
+
(environment) => environment.logError,
|
|
76
|
+
(environment) => environment.throwCxfError,
|
|
77
|
+
(logError_, throwAnError) =>
|
|
78
|
+
(function_: any) =>
|
|
79
|
+
(...arguments_: any[]) => {
|
|
80
|
+
try {
|
|
81
|
+
function_(...arguments_)
|
|
82
|
+
} catch (error) {
|
|
83
|
+
logError_(error)
|
|
84
|
+
throwAnError(error as Error)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
export type ThrowCxfError = (e: Error) => void
|
|
90
|
+
export const throwCxfError: DIReader<ThrowCxfError> = inject(
|
|
91
|
+
(environment) => environment.config,
|
|
92
|
+
(environment) => environment.cxfProvider,
|
|
93
|
+
({ CXF_ERROR }, cxfProvider) =>
|
|
94
|
+
(e) => {
|
|
95
|
+
const cxf = getCxf(cxfProvider)
|
|
96
|
+
cxf.emit(CXF_ERROR, e)
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
export const isArgumentNullError = (e: Error): e is ArgumentNullError => e.name === 'ArgumentNullError'
|
|
101
|
+
|
|
102
|
+
export type LoadCxf = (...arguments_: any[]) => Promise<ICXF>
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
104
|
+
export const loadCxf = timeout(() => require('@goodgamestudios/cxf-ready') as Promise<ICXF>, 10_000)
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* To show CXF-WEBSHOP debug messages just run in a browser console
|
|
108
|
+
* localStorage.debug = 'CXF-WEBSHOP:*'
|
|
109
|
+
*/
|
|
110
|
+
const logger = debug('CXF-WEBSHOP')
|
|
111
|
+
export type Log = (...arguments_: any[]) => void
|
|
112
|
+
export const log: Log = (argument0: any, ...rest: any[]) => logger(argument0, ...rest)
|
|
113
|
+
|
|
114
|
+
export type LogError = (...arguments_: any[]) => void
|
|
115
|
+
export const logError: LogError = (...arguments_: any[]) =>
|
|
116
|
+
// tslint:disable-next-line:no-console
|
|
117
|
+
console.error('%c CXF-WEBSHOP:', 'background: #ff0000; color: #fff', ...arguments_)
|
|
118
|
+
|
|
119
|
+
export const createSessionId = () => uuidv4()
|
|
120
|
+
|
|
121
|
+
export type GetDomain = (referrer: string) => string | undefined
|
|
122
|
+
export const getDomain: DIReader<GetDomain> = inject(
|
|
123
|
+
(environment) => environment.log,
|
|
124
|
+
() => (referrer) => {
|
|
125
|
+
return parentDomain(referrer)
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
export type GGSGetQueryParams = () => string
|
|
130
|
+
export const ggsGetQueryParams: DIReader<GGSGetQueryParams> = inject(
|
|
131
|
+
(environment) => environment.log,
|
|
132
|
+
(nothing) => () => {
|
|
133
|
+
return ggsGetQueryParameters()
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
export type GGSGetReferrerValue = () => string
|
|
138
|
+
export const ggsGetReferrerValue: DIReader<GGSGetReferrerValue> = inject(
|
|
139
|
+
(environment) => environment.log,
|
|
140
|
+
(nothing) => () => {
|
|
141
|
+
return ggsGetReferrer()
|
|
142
|
+
}
|
|
143
|
+
)
|
package/src_old/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createEnv as createEnvironment } from './env'
|
|
2
|
+
import { app } from './app'
|
|
3
|
+
import { just } from 'readuz'
|
|
4
|
+
import { entityProvider, log } from './helpers'
|
|
5
|
+
import { defaultStore } from './store'
|
|
6
|
+
import { createConfig } from './config'
|
|
7
|
+
import {
|
|
8
|
+
createCxfReducers,
|
|
9
|
+
nativeSubscriptionEnableReducer,
|
|
10
|
+
setCustomizationSuffixReducer,
|
|
11
|
+
receiveAdStatusReducer,
|
|
12
|
+
tempServerContextReducer,
|
|
13
|
+
} from './handlers/reducers'
|
|
14
|
+
import { ICXF } from './cxf'
|
|
15
|
+
|
|
16
|
+
if (localStorage.getItem('cxf_canvas') === 'enabled') {
|
|
17
|
+
log('Skip cxf-webshop loading...')
|
|
18
|
+
} else {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, unicorn/prefer-top-level-await
|
|
20
|
+
require('@goodgamestudios/cxf-ready').then((cxf: ICXF) => {
|
|
21
|
+
app(
|
|
22
|
+
createEnvironment({
|
|
23
|
+
config: just(createConfig(cxf.gameId)),
|
|
24
|
+
cxfProvider: just(entityProvider(cxf)),
|
|
25
|
+
store: just(entityProvider(defaultStore(cxf))),
|
|
26
|
+
subscribeToCxf: createCxfReducers({
|
|
27
|
+
receiveAdStatus: receiveAdStatusReducer,
|
|
28
|
+
tempServerContext: tempServerContextReducer,
|
|
29
|
+
nativeSubscription: nativeSubscriptionEnableReducer,
|
|
30
|
+
setCustomizationSuffix: setCustomizationSuffixReducer,
|
|
31
|
+
}),
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IShopMessageBus } from './IShopMessageBus'
|
|
2
|
+
|
|
3
|
+
export class ShopMessageBus implements IShopMessageBus {
|
|
4
|
+
public post(message: any) {
|
|
5
|
+
const element = document.querySelector('#dialog') as HTMLIFrameElement
|
|
6
|
+
if (element && element.tagName.toLocaleLowerCase() === 'iframe') {
|
|
7
|
+
element.contentWindow?.postMessage(message, '*')
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IShopMessageBus } from './IShopMessageBus'
|
|
2
|
+
|
|
3
|
+
export class TestShopMessageBus implements IShopMessageBus {
|
|
4
|
+
public post(message: any) {
|
|
5
|
+
/* eslint-disable-next-line prettier/prettier */
|
|
6
|
+
(window as any).dialogPostMessage = JSON.stringify(message)
|
|
7
|
+
}
|
|
8
|
+
}
|
package/src_old/ping.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PingProperties {
|
|
2
|
+
gameId: string
|
|
3
|
+
networkId: string
|
|
4
|
+
instanceId: string
|
|
5
|
+
playerId: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function decodePing(value: string): PingProperties {
|
|
9
|
+
const [gameId, networkId, instanceId, playerId] = value.split('-')
|
|
10
|
+
return { gameId, networkId, instanceId, playerId }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function encodePing({ gameId, networkId, instanceId, playerId }: PingProperties): string {
|
|
14
|
+
return [gameId, networkId, instanceId, playerId].join('-')
|
|
15
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { DIReader } from './common'
|
|
2
|
+
import { inject } from 'readuz'
|
|
3
|
+
|
|
4
|
+
type LemonstandConfig = {
|
|
5
|
+
css: string
|
|
6
|
+
js: string
|
|
7
|
+
unreadOfferNotifsCountUrl: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type PreFetch = (...parameter: any[]) => void
|
|
11
|
+
|
|
12
|
+
export const preResolveConfig: DIReader<PreFetch> = inject(
|
|
13
|
+
(environment) => environment.log,
|
|
14
|
+
(environment) => environment.setStore,
|
|
15
|
+
(environment) => environment.createCustomizationUrl,
|
|
16
|
+
(log, setStore, getCustomizationUrl) => () => {
|
|
17
|
+
if (typeof fetch !== 'function') {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
const originalCustomUrl = getCustomizationUrl()
|
|
21
|
+
let resolvedUrl = ''
|
|
22
|
+
fetch(originalCustomUrl)
|
|
23
|
+
.then((resp) => {
|
|
24
|
+
const currentCustomUrl = getCustomizationUrl()
|
|
25
|
+
if (currentCustomUrl === originalCustomUrl) {
|
|
26
|
+
// this is the latest, we keep it
|
|
27
|
+
resolvedUrl = resp.url
|
|
28
|
+
log('parsed customization url is ' + resolvedUrl)
|
|
29
|
+
setStore({
|
|
30
|
+
resolvedCustomizationUrl: resolvedUrl,
|
|
31
|
+
})
|
|
32
|
+
return resp.json()
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
.then((config: LemonstandConfig | undefined) => {
|
|
36
|
+
if (config) {
|
|
37
|
+
setStore({
|
|
38
|
+
unreadOfferNotifsCountUrl: config.unreadOfferNotifsCountUrl || '',
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IDictionary } from './common'
|
|
2
|
+
|
|
3
|
+
export interface IStorageData {
|
|
4
|
+
growthFund: {
|
|
5
|
+
lastPopup: IDictionary<number>
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type GetStorageData = () => IStorageData
|
|
10
|
+
export const getStorageData: GetStorageData = () => {
|
|
11
|
+
const restoreData = () => JSON.parse(localStorage.getItem('webshop') as string) as IStorageData
|
|
12
|
+
|
|
13
|
+
if (localStorage.getItem('webshop')) {
|
|
14
|
+
return restoreData()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
localStorage.setItem(
|
|
18
|
+
'webshop',
|
|
19
|
+
JSON.stringify({
|
|
20
|
+
growthFund: {
|
|
21
|
+
lastPopup: {},
|
|
22
|
+
},
|
|
23
|
+
} as IStorageData)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return restoreData()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type SetStorageData = (data: IStorageData) => void
|
|
30
|
+
export const setStorageData: SetStorageData = (data: IStorageData) => {
|
|
31
|
+
localStorage.setItem('webshop', JSON.stringify(data))
|
|
32
|
+
}
|
package/src_old/store.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DIReader, IDictionary } from './common'
|
|
2
|
+
import { inject } from 'readuz'
|
|
3
|
+
import { CountryCode, IGameEvent } from '@goodgamestudios/cxf-events'
|
|
4
|
+
import { ICXF, IGameApi } from './cxf'
|
|
5
|
+
|
|
6
|
+
export interface IStore {
|
|
7
|
+
playerId?: string
|
|
8
|
+
instanceId: string
|
|
9
|
+
networkId: string
|
|
10
|
+
gameId: string
|
|
11
|
+
gameApi: IGameApi
|
|
12
|
+
language?: string
|
|
13
|
+
token?: string
|
|
14
|
+
zoneId?: string
|
|
15
|
+
xp: number
|
|
16
|
+
level: number
|
|
17
|
+
gameEvents: IGameEvent[]
|
|
18
|
+
countryCode: CountryCode
|
|
19
|
+
lastPurchaseTab: string
|
|
20
|
+
legendLevel?: number
|
|
21
|
+
subscriptionDisabled: boolean
|
|
22
|
+
isTempServer: boolean
|
|
23
|
+
customizationSuffix: string
|
|
24
|
+
resolvedCustomizationUrl?: string
|
|
25
|
+
sourceId: string
|
|
26
|
+
unreadOfferNotifsCountUrl: string
|
|
27
|
+
adStatus?: Record<string, any>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function defaultStore(cxf: ICXF): IStore {
|
|
31
|
+
return {
|
|
32
|
+
playerId: cxf.playerId,
|
|
33
|
+
instanceId: cxf.instanceId,
|
|
34
|
+
networkId: cxf.networkId,
|
|
35
|
+
gameId: cxf.gameId,
|
|
36
|
+
gameApi: cxf.gameApi,
|
|
37
|
+
language: cxf.language,
|
|
38
|
+
token: cxf.token,
|
|
39
|
+
zoneId: cxf.zoneId,
|
|
40
|
+
gameEvents: [],
|
|
41
|
+
xp: 0,
|
|
42
|
+
level: 0,
|
|
43
|
+
legendLevel: undefined,
|
|
44
|
+
countryCode: '',
|
|
45
|
+
lastPurchaseTab: '',
|
|
46
|
+
subscriptionDisabled: false,
|
|
47
|
+
isTempServer: false,
|
|
48
|
+
customizationSuffix: '',
|
|
49
|
+
resolvedCustomizationUrl: '',
|
|
50
|
+
sourceId: 'unknown',
|
|
51
|
+
unreadOfferNotifsCountUrl: '',
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type GetStore = () => IStore
|
|
56
|
+
export const getStore: DIReader<GetStore> = inject(
|
|
57
|
+
(environment) => environment.log,
|
|
58
|
+
(environment) => environment.store,
|
|
59
|
+
(log, store) => () => {
|
|
60
|
+
return store.get() as IStore
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
export type SetStore = (data: Partial<IStore>) => void
|
|
65
|
+
export const setStore: DIReader<SetStore> = inject(
|
|
66
|
+
(environment) => environment.log,
|
|
67
|
+
(environment) => environment.store,
|
|
68
|
+
(log, store) => (data) => {
|
|
69
|
+
const state = store.get() as IStore
|
|
70
|
+
store.set({
|
|
71
|
+
...state,
|
|
72
|
+
...data,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
export function criteriaSelector({ legendLevel, level }: IStore): IDictionary<any> {
|
|
78
|
+
return {
|
|
79
|
+
legendLevel,
|
|
80
|
+
level,
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src_old/track.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { inject } from 'readuz'
|
|
2
|
+
import { DIReader, IDictionary } from './common'
|
|
3
|
+
import { msToSec } from './utils'
|
|
4
|
+
import { getCxf, getTokenAndLanguage } from './helpers'
|
|
5
|
+
|
|
6
|
+
export type IRanchWebShopCallProperties = {
|
|
7
|
+
eventId: number
|
|
8
|
+
gameId: number
|
|
9
|
+
playerId: number
|
|
10
|
+
instanceId: number
|
|
11
|
+
zoneId: number
|
|
12
|
+
networkId: number
|
|
13
|
+
sessionId: string
|
|
14
|
+
date: number
|
|
15
|
+
unixtimeMS: number
|
|
16
|
+
sourceId: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type TrackOpenAction = (sid: string) => void
|
|
20
|
+
export const trackOpenAction: DIReader<TrackOpenAction> = inject(
|
|
21
|
+
(environment) => environment.config,
|
|
22
|
+
(environment) => environment.trackAction,
|
|
23
|
+
(environment) => environment.getStore,
|
|
24
|
+
({ WEB_SHOP_CALL_TRACK_ID }, trackUserAction, getStore) =>
|
|
25
|
+
(sid) => {
|
|
26
|
+
const now = Date.now()
|
|
27
|
+
const parameters = getTokenAndLanguage(getStore())
|
|
28
|
+
const { zoneId } = parameters
|
|
29
|
+
const sessionId = sid
|
|
30
|
+
const { playerId, gameId, networkId, instanceId, sourceId } = getStore()
|
|
31
|
+
trackUserAction({
|
|
32
|
+
eventId: WEB_SHOP_CALL_TRACK_ID,
|
|
33
|
+
date: msToSec(now),
|
|
34
|
+
unixtimeMS: now,
|
|
35
|
+
sessionId,
|
|
36
|
+
zoneId: zoneId ? Number.parseInt(zoneId, 10) : undefined,
|
|
37
|
+
playerId: Number.parseInt(playerId as string, 10),
|
|
38
|
+
gameId: Number.parseInt(gameId, 10),
|
|
39
|
+
networkId: Number.parseInt(networkId, 10),
|
|
40
|
+
instanceId: Number.parseInt(instanceId, 10),
|
|
41
|
+
sourceId,
|
|
42
|
+
} as IRanchWebShopCallProperties)
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
export interface ITrackPayload extends IDictionary<string | number> {
|
|
47
|
+
eventId: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type TrackAction = (payload: ITrackPayload) => void
|
|
51
|
+
export const trackAction: DIReader<TrackAction> = inject(
|
|
52
|
+
(environment) => environment.config,
|
|
53
|
+
(environment) => environment.cxfProvider,
|
|
54
|
+
({ CXF_TRACK_MSG }, cxfProvider) =>
|
|
55
|
+
(payload) => {
|
|
56
|
+
const cxf = getCxf(cxfProvider)
|
|
57
|
+
cxf.emit(CXF_TRACK_MSG, payload)
|
|
58
|
+
}
|
|
59
|
+
)
|