@streamlayer/feature-gamification 1.15.1 → 1.16.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/lib/advertisement/externalAd/index.d.ts +1 -13
- package/lib/advertisement/externalAd/index.js +43 -53
- package/lib/advertisement/index.d.ts +1 -1
- package/lib/advertisement/index.js +0 -22
- package/lib/background.d.ts +1 -1
- package/lib/background.js +15 -6
- package/lib/deepLink.d.ts +1 -1
- package/lib/gamification.d.ts +2 -1
- package/lib/gamification.js +65 -22
- package/lib/leaderboard.d.ts +1 -1
- package/lib/onboarding.d.ts +1 -1
- package/lib/onboarding.js +1 -1
- package/lib/queries/index.d.ts +2 -3
- package/lib/queries/index.js +11 -15
- package/lib/userSummary.d.ts +1 -1
- package/lib/userSummary.js +1 -1
- package/package.json +10 -9
|
@@ -1,15 +1,3 @@
|
|
|
1
1
|
import { AdCampaigns } from '@streamlayer/sdk-web-types';
|
|
2
2
|
export declare const processGamAdvertisement: ({ gamOptions, gamBaseUrl }: AdCampaigns) => string;
|
|
3
|
-
|
|
4
|
-
onPlay?: () => void;
|
|
5
|
-
onStop?: () => void;
|
|
6
|
-
onProgress?: (opts: {
|
|
7
|
-
adBreakDuration: number;
|
|
8
|
-
adPosition: number;
|
|
9
|
-
currentTime: number;
|
|
10
|
-
duration: number;
|
|
11
|
-
totalAds: number;
|
|
12
|
-
}) => void;
|
|
13
|
-
};
|
|
14
|
-
export declare const gam: (adContainer: HTMLDivElement, url: string, { onPlay, onStop, onProgress }: GamHandlers) => () => () => void;
|
|
15
|
-
export {};
|
|
3
|
+
export declare const gam: (adContainer: HTMLDivElement, url: string) => () => Promise<URL | undefined>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validate as uuidValidate, v5 as uuid5, v4 as uuid4 } from 'uuid';
|
|
1
2
|
const encodeUrl = (urlStr) => {
|
|
2
3
|
const isUrl = urlStr.startsWith('http://') || urlStr.startsWith('https://');
|
|
3
4
|
if (!isUrl) {
|
|
@@ -42,65 +43,54 @@ export const processGamAdvertisement = ({ gamOptions, gamBaseUrl }) => {
|
|
|
42
43
|
}
|
|
43
44
|
return url + params.join('&');
|
|
44
45
|
};
|
|
45
|
-
export const gam = (adContainer, url
|
|
46
|
+
export const gam = (adContainer, url) => {
|
|
46
47
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
47
48
|
// @ts-expect-error
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
-
adsManager = adsManagerLoadedEvent.getAdsManager(adContainer);
|
|
56
|
-
if (onPlay) {
|
|
57
|
-
adsManager.addEventListener(ima.AdEvent.Type.STARTED, onPlay);
|
|
58
|
-
}
|
|
59
|
-
if (onStop) {
|
|
60
|
-
adsManager.addEventListener(ima.AdEvent.Type.COMPLETE, onStop);
|
|
61
|
-
}
|
|
62
|
-
if (onProgress) {
|
|
63
|
-
adsManager.addEventListener(ima.AdEvent.Type.AD_PROGRESS, (d) => onProgress(d.getAdData()));
|
|
64
|
-
}
|
|
65
|
-
adsManager.init(adContainer.clientWidth, adContainer.clientHeight, ima.ViewMode.NORMAL);
|
|
66
|
-
adsManager.start();
|
|
67
|
-
}, false);
|
|
68
|
-
adsLoader.addEventListener(ima.AdErrorEvent.Type.AD_ERROR, () => {
|
|
69
|
-
console.log('ad error');
|
|
70
|
-
onStop?.();
|
|
71
|
-
}, false);
|
|
72
|
-
adsRequest.linearAdSlotWidth = adContainer.clientWidth;
|
|
73
|
-
adsRequest.linearAdSlotHeight = adContainer.clientHeight;
|
|
74
|
-
// adsRequest.nonLinearAdSlotWidth = adContainer.clientWidth ??
|
|
75
|
-
// adsRequest.nonLinearAdSlotHeight = adContainer.clientHeight / 3 ??
|
|
76
|
-
adsRequest.adTagUrl = url;
|
|
77
|
-
adsLoader.requestAds(adsRequest);
|
|
78
|
-
const destroy = () => {
|
|
79
|
-
adsManager?.destroy();
|
|
80
|
-
adsLoader?.destroy();
|
|
81
|
-
adDisplayContainer?.destroy();
|
|
82
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
83
|
-
// @ts-expect-error
|
|
84
|
-
adDisplayContainer = undefined;
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
86
|
-
// @ts-expect-error
|
|
87
|
-
adsLoader = undefined;
|
|
88
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
89
|
-
// @ts-expect-error
|
|
90
|
-
adsRequest = undefined;
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
92
|
-
// @ts-expect-error
|
|
93
|
-
adsManager = undefined;
|
|
94
|
-
};
|
|
95
|
-
const play = () => {
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
const pal = goog.pal;
|
|
51
|
+
const consentSettings = new pal.ConsentSettings();
|
|
52
|
+
consentSettings.allowStorage = false;
|
|
53
|
+
const nonceLoader = new pal.NonceLoader(consentSettings);
|
|
54
|
+
const generateUrl = async () => {
|
|
96
55
|
try {
|
|
97
|
-
|
|
56
|
+
const parsedUrl = new URL(url);
|
|
57
|
+
const request = new pal.NonceRequest();
|
|
58
|
+
let deviceId = localStorage.getItem('sl-device-id') || uuid4();
|
|
59
|
+
let sessionId = sessionStorage.getItem('sl-ad-session-id');
|
|
60
|
+
if (!sessionId) {
|
|
61
|
+
sessionId = uuid4();
|
|
62
|
+
sessionStorage.setItem('sl-ad-session-id', sessionId);
|
|
63
|
+
}
|
|
64
|
+
if (!uuidValidate(deviceId)) {
|
|
65
|
+
deviceId = uuid5(`https://${deviceId}`, uuid5.URL);
|
|
66
|
+
}
|
|
67
|
+
request.adWillAutoPlay = parsedUrl.searchParams.get('vpa') === 'auto';
|
|
68
|
+
request.adWillPlayMuted = parsedUrl.searchParams.get('vpmute') === '1';
|
|
69
|
+
request.continuousPlayback = true;
|
|
70
|
+
request.descriptionUrl = parsedUrl.searchParams.get('description_url') || '';
|
|
71
|
+
request.iconsSupported = true;
|
|
72
|
+
request.sessionId = deviceId;
|
|
73
|
+
// Player support for VPAID 2.0, OMID 1.0, and SIMID 1.1
|
|
74
|
+
request.supportedApiFrameworks = '2,7,9';
|
|
75
|
+
request.videoHeight = adContainer.clientHeight;
|
|
76
|
+
request.videoWidth = adContainer.clientWidth;
|
|
77
|
+
const nonceManager = await nonceLoader.loadNonceManager(request);
|
|
78
|
+
parsedUrl.searchParams.set('givn', nonceManager.getNonce());
|
|
79
|
+
if (parsedUrl.searchParams.get('is_lat') === '[placeholder]') {
|
|
80
|
+
parsedUrl.searchParams.set('is_lat', '1');
|
|
81
|
+
}
|
|
82
|
+
if (parsedUrl.searchParams.get('rdid') === '[placeholder]') {
|
|
83
|
+
parsedUrl.searchParams.set('rdid', deviceId);
|
|
84
|
+
}
|
|
85
|
+
if (parsedUrl.searchParams.get('correlator') === '[placeholder]') {
|
|
86
|
+
parsedUrl.searchParams.set('correlator', sessionId);
|
|
87
|
+
}
|
|
88
|
+
return parsedUrl;
|
|
98
89
|
}
|
|
99
90
|
catch (adError) {
|
|
100
|
-
onStop?.();
|
|
101
91
|
console.log('AdsManager could not be started', adError);
|
|
92
|
+
return undefined;
|
|
102
93
|
}
|
|
103
|
-
return destroy;
|
|
104
94
|
};
|
|
105
|
-
return
|
|
95
|
+
return generateUrl;
|
|
106
96
|
};
|
|
@@ -39,6 +39,6 @@ export declare const advertisement: ($slStreamId: GamificationBackground["slStre
|
|
|
39
39
|
fromNotification?: boolean;
|
|
40
40
|
}) => void;
|
|
41
41
|
markAsViewed: () => void;
|
|
42
|
-
$store: import("nanostores").
|
|
42
|
+
$store: import("nanostores").PreinitializedMapStore<Advertisement> & object;
|
|
43
43
|
};
|
|
44
44
|
export {};
|
|
@@ -6,28 +6,6 @@ import { $activePromotionId, getPromotionDetail } from '../queries';
|
|
|
6
6
|
import { AdvertisementStorage } from './storage';
|
|
7
7
|
import { parsePromotion } from './utils';
|
|
8
8
|
import { processGamAdvertisement } from './externalAd';
|
|
9
|
-
// async function generateNonce() {
|
|
10
|
-
// const request = new goog.pal.NonceRequest()
|
|
11
|
-
// request.adWillAutoPlay = true
|
|
12
|
-
// request.adWillPlayMuted = false
|
|
13
|
-
// request.continuousPlayback = false
|
|
14
|
-
// request.descriptionUrl = 'https://example.com'
|
|
15
|
-
// request.iconsSupported = true
|
|
16
|
-
// request.playerType = 'Sample Player Type'
|
|
17
|
-
// request.playerVersion = '1.0'
|
|
18
|
-
// request.ppid = 'Sample PPID'
|
|
19
|
-
// request.sessionId = 'Sample SID'
|
|
20
|
-
// // Player support for VPAID 2.0, OMID 1.0, and SIMID 1.1
|
|
21
|
-
// request.supportedApiFrameworks = '2,7,9'
|
|
22
|
-
// request.url = 'https://developers.google.com/ad-manager/pal/html5'
|
|
23
|
-
// request.videoHeight = 480
|
|
24
|
-
// request.videoWidth = 640
|
|
25
|
-
// const consentSettings = new goog.pal.ConsentSettings()
|
|
26
|
-
// consentSettings.allowStorage = true
|
|
27
|
-
// const nonceLoader = new goog.pal.NonceLoader(consentSettings)
|
|
28
|
-
// const manager = await nonceLoader.loadNonceManager(request)
|
|
29
|
-
// return manager.getNonce()
|
|
30
|
-
// }
|
|
31
9
|
const adHasBanner = (data) => (data?.promotion?.type === PromotionType.INGAME_IAB11_LBAR ||
|
|
32
10
|
data?.promotion?.type === PromotionType.INGAME_IAB21_LBAR) &&
|
|
33
11
|
!!data.promotion.additionalBanner?.imageUrl;
|
package/lib/background.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare class GamificationBackground {
|
|
|
47
47
|
feedSubscription: ReturnType<typeof queries.feedSubscription>;
|
|
48
48
|
/** subscription to opened question (vote percentage) */
|
|
49
49
|
questionSubscription?: ReturnType<typeof queries.questionSubscription>;
|
|
50
|
-
advertisement
|
|
50
|
+
advertisement?: ReturnType<typeof advertisement>;
|
|
51
51
|
storage: GamificationStorage;
|
|
52
52
|
private notifications;
|
|
53
53
|
private log;
|
package/lib/background.js
CHANGED
|
@@ -60,9 +60,10 @@ export class GamificationBackground {
|
|
|
60
60
|
this.openedQuestionId = new SingleStore(createSingleStore(undefined), 'openedQuestionId').getStore();
|
|
61
61
|
this.notifications = instance.notifications;
|
|
62
62
|
this.moderation = new ApiStore(queries.$moderation(this.slStreamId, instance.transport), 'gamification:moderation');
|
|
63
|
-
|
|
63
|
+
const onlyBetPack = !!instance.sdk.options.get().betPack;
|
|
64
|
+
this.feedList = new ApiStore(queries.$feedList(this.slStreamId, this.interactiveAllowed, onlyBetPack, instance.transport), 'gamification:feedList');
|
|
64
65
|
this.betPack = new ApiStore(queries.$betPack(this.slStreamId, this.userId, this.organizationId, this.storage, instance.transport), 'gamification:betPack');
|
|
65
|
-
this.activeQuestionId = queries.$activeQuestion(this.slStreamId, instance.transport);
|
|
66
|
+
this.activeQuestionId = queries.$activeQuestion(this.slStreamId, onlyBetPack, instance.transport);
|
|
66
67
|
this.openedQuestion = detail(instance.transport, this.openedQuestionId, this.feedList.getStore());
|
|
67
68
|
this.cancels.add(this.openedQuestionId.listen((item) => {
|
|
68
69
|
this.log.debug({ item }, 'received question');
|
|
@@ -71,14 +72,19 @@ export class GamificationBackground {
|
|
|
71
72
|
this.questionSubscription.addListener('feed-subscription-opened-question', async (response) => {
|
|
72
73
|
const question = response.data?.attributes?.question;
|
|
73
74
|
this.openedQuestion.updateExtendedQuestion(question);
|
|
74
|
-
if (question?.type === QuestionType.PREDICTION
|
|
75
|
+
if (question?.type === QuestionType.PREDICTION &&
|
|
76
|
+
(question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
|
|
75
77
|
const betPackData = this.betPack.getValues().data || {};
|
|
76
78
|
const betPackItem = betPackData?.[question.id];
|
|
77
79
|
if (betPackItem || Object.keys(betPackData).length < 5) {
|
|
78
80
|
const data = queries.$questionByUser(question.id, this.transport);
|
|
79
81
|
const cancel = data.subscribe(() => { });
|
|
80
82
|
await data.get().promise;
|
|
81
|
-
|
|
83
|
+
// if question is not in the feed list, get extended question data from the server
|
|
84
|
+
let extendedQuestion = data.get().data;
|
|
85
|
+
if (!extendedQuestion) {
|
|
86
|
+
extendedQuestion = await queries.questionByUser(question.id, this.transport);
|
|
87
|
+
}
|
|
82
88
|
cancel();
|
|
83
89
|
window.requestAnimationFrame(() => {
|
|
84
90
|
data.invalidate();
|
|
@@ -104,7 +110,8 @@ export class GamificationBackground {
|
|
|
104
110
|
this.feedSubscription = queries.feedSubscription(this.slStreamId, instance.transport);
|
|
105
111
|
this.cancels.add(this.feedSubscription.addListener('bet-pack-update', async (response) => {
|
|
106
112
|
const question = response.data?.attributes?.question;
|
|
107
|
-
if (question?.type === QuestionType.PREDICTION
|
|
113
|
+
if (question?.type === QuestionType.PREDICTION &&
|
|
114
|
+
(question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
|
|
108
115
|
const betPackData = this.betPack.getValues().data || {};
|
|
109
116
|
const betPackItem = betPackData?.[question.id];
|
|
110
117
|
if (betPackItem || Object.keys(betPackData).length < 5) {
|
|
@@ -201,7 +208,9 @@ export class GamificationBackground {
|
|
|
201
208
|
}
|
|
202
209
|
};
|
|
203
210
|
});
|
|
204
|
-
|
|
211
|
+
if (!onlyBetPack) {
|
|
212
|
+
this.advertisement = advertisement(this.slStreamId, this.feedSubscription, instance);
|
|
213
|
+
}
|
|
205
214
|
}
|
|
206
215
|
/**
|
|
207
216
|
* Get id for notifications and link with current session
|
package/lib/deepLink.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ type DeepLinkData = {
|
|
|
6
6
|
error?: string;
|
|
7
7
|
};
|
|
8
8
|
export declare const deepLink: (transport: Transport, $eventId: ReadableAtom<string | undefined>, $externalEventId: ReadableAtom<string | undefined>, $userId: ReadableAtom<string | undefined>) => {
|
|
9
|
-
$store: import("nanostores").
|
|
9
|
+
$store: import("nanostores").PreinitializedMapStore<DeepLinkData> & object;
|
|
10
10
|
fetch: typeof fetch;
|
|
11
11
|
};
|
|
12
12
|
export {};
|
package/lib/gamification.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare class Gamification extends AbstractFeature<'games', PlainMessage<
|
|
|
53
53
|
advertisement: GamificationBackground['advertisement'];
|
|
54
54
|
onboardingProcessed: WritableAtom<boolean>;
|
|
55
55
|
friendsTabEnabled: WritableAtom<boolean>;
|
|
56
|
+
skipOnboarding: boolean;
|
|
56
57
|
private notifications;
|
|
57
58
|
private transport;
|
|
58
59
|
/** gamification background class, handle subscriptions and notifications for closed overlay */
|
|
@@ -70,7 +71,7 @@ export declare class Gamification extends AbstractFeature<'games', PlainMessage<
|
|
|
70
71
|
betPackVote: (questionId: string, answerId: string) => Promise<void>;
|
|
71
72
|
submitAnswer: (questionId: string, answerId: string) => Promise<void>;
|
|
72
73
|
openQuestion: (questionId?: string, question?: FeedItem & {
|
|
73
|
-
openedFrom?: "list" | "notification";
|
|
74
|
+
openedFrom?: "list" | "notification" | "bet-pack";
|
|
74
75
|
}) => void | (() => void);
|
|
75
76
|
getFeedItem: (id: string) => Promise<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem | undefined>;
|
|
76
77
|
isOpenedQuestion: (questionId: string) => boolean;
|
package/lib/gamification.js
CHANGED
|
@@ -53,6 +53,7 @@ export class Gamification extends AbstractFeature {
|
|
|
53
53
|
advertisement;
|
|
54
54
|
onboardingProcessed;
|
|
55
55
|
friendsTabEnabled;
|
|
56
|
+
skipOnboarding;
|
|
56
57
|
notifications;
|
|
57
58
|
transport;
|
|
58
59
|
/** gamification background class, handle subscriptions and notifications for closed overlay */
|
|
@@ -76,9 +77,6 @@ export class Gamification extends AbstractFeature {
|
|
|
76
77
|
this.currentUserId = this.background.userId;
|
|
77
78
|
this.onboardingProcessed = createSingleStore(!instance.sdk.withAuth);
|
|
78
79
|
this.leaderboardId = new SingleStore(createSingleStore(this.settings.getValue('pinnedLeaderboardId')), 'pinnedLeaderboardId').getStore();
|
|
79
|
-
this.onboardingStatus = onboarding(this, this.background, instance.transport, instance.notifications, {
|
|
80
|
-
skipOnboarding: instance.sdk.options.get().skipOnboarding,
|
|
81
|
-
});
|
|
82
80
|
this.notifications = instance.notifications;
|
|
83
81
|
this.transport = instance.transport;
|
|
84
82
|
this.closeFeature = (destroy = true) => instance.sdk.closeFeature(destroy);
|
|
@@ -98,6 +96,15 @@ export class Gamification extends AbstractFeature {
|
|
|
98
96
|
}));
|
|
99
97
|
}
|
|
100
98
|
this.connect();
|
|
99
|
+
this.skipOnboarding = !!instance.sdk.options.get().skipOnboarding;
|
|
100
|
+
this.onboardingStatus = onboarding(this, this.background, instance.transport, instance.notifications, {
|
|
101
|
+
skipOnboarding: instance.sdk.options.get().skipOnboarding,
|
|
102
|
+
});
|
|
103
|
+
if (!instance.sdk.options.get().skipOnboarding) {
|
|
104
|
+
this.onboardingStatus = onboarding(this, this.background, instance.transport, instance.notifications, {
|
|
105
|
+
skipOnboarding: instance.sdk.options.get().skipOnboarding,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
101
108
|
/**
|
|
102
109
|
* listen for onboarding status, moderation onboarding changes and opt-in settings
|
|
103
110
|
*/
|
|
@@ -137,16 +144,21 @@ export class Gamification extends AbstractFeature {
|
|
|
137
144
|
return this.background.interactiveAllowed.get() === InteractiveAllowed.ALLOWED;
|
|
138
145
|
}
|
|
139
146
|
checkInteractiveFlag = () => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
if (this.skipOnboarding) {
|
|
148
|
+
this.background.interactiveAllowed.set(InteractiveAllowed.ALLOWED);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const onboardingStatus = this.onboardingStatus.$store.get();
|
|
152
|
+
const onboardingEnabled = this.background.moderation.getStore().value?.data?.options?.onboardingEnabled;
|
|
153
|
+
const optInEnabled = this.settings.getValues().inplayGame?.titleCard?.optIn;
|
|
154
|
+
const onboardingCompleted = onboardingStatus === OnboardingStatus.Completed;
|
|
155
|
+
const allowed = !onboardingEnabled || onboardingCompleted || optInEnabled !== true;
|
|
156
|
+
this.background.interactiveAllowed.set(allowed ? InteractiveAllowed.ALLOWED : InteractiveAllowed.DISALLOWED);
|
|
157
|
+
}
|
|
146
158
|
};
|
|
147
159
|
connect = () => {
|
|
148
160
|
this.onboardingProcessed.subscribe((status) => {
|
|
149
|
-
if (status) {
|
|
161
|
+
if (status && this.advertisement) {
|
|
150
162
|
this.advertisement.connect();
|
|
151
163
|
}
|
|
152
164
|
});
|
|
@@ -332,7 +344,18 @@ export class Gamification extends AbstractFeature {
|
|
|
332
344
|
this.background.feedSubscription.removeListener('feed-subscription-questions-list');
|
|
333
345
|
};
|
|
334
346
|
betPackVote = async (questionId, answerId) => {
|
|
335
|
-
|
|
347
|
+
try {
|
|
348
|
+
await actions.submitAnswer(this.transport, { questionId, answerId });
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
if (error.message === ERROR.ALREADY_VOTED) {
|
|
352
|
+
const data = $questionByUser(questionId, this.transport);
|
|
353
|
+
const cancel = data.subscribe(() => { });
|
|
354
|
+
data.invalidate();
|
|
355
|
+
cancel();
|
|
356
|
+
}
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
336
359
|
const betPackList = { ...this.betPack.getValues().data };
|
|
337
360
|
const question = betPackList?.[questionId];
|
|
338
361
|
if (question) {
|
|
@@ -343,6 +366,16 @@ export class Gamification extends AbstractFeature {
|
|
|
343
366
|
questionType: question.type,
|
|
344
367
|
},
|
|
345
368
|
});
|
|
369
|
+
question.answers = question.answers.map((answer) => {
|
|
370
|
+
if (answer.id === answerId) {
|
|
371
|
+
return {
|
|
372
|
+
...answer,
|
|
373
|
+
youVoted: true,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
return answer;
|
|
377
|
+
});
|
|
378
|
+
this.betPack.getStore().mutate(betPackList);
|
|
346
379
|
}
|
|
347
380
|
};
|
|
348
381
|
submitAnswer = async (questionId, answerId) => {
|
|
@@ -423,14 +456,17 @@ export class Gamification extends AbstractFeature {
|
|
|
423
456
|
if (!questionId) {
|
|
424
457
|
return () => { };
|
|
425
458
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
459
|
+
const openedFromBetPack = question?.openedFrom === 'bet-pack';
|
|
460
|
+
if (openedFromBetPack) {
|
|
461
|
+
this.notifications.close(this.background.getCurrentSessionId({
|
|
462
|
+
prefix: 'notification',
|
|
463
|
+
entity: questionId,
|
|
464
|
+
}), {
|
|
465
|
+
animateHiding: false,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
432
468
|
let questionType = question?.attributes?.type;
|
|
433
|
-
if (!questionType) {
|
|
469
|
+
if (!questionType && !openedFromBetPack) {
|
|
434
470
|
const feedList = this.feedList.getStore().value?.data || [];
|
|
435
471
|
questionType = feedList.find((item) => item.id === questionId)?.attributes?.type;
|
|
436
472
|
}
|
|
@@ -445,13 +481,20 @@ export class Gamification extends AbstractFeature {
|
|
|
445
481
|
payload: {
|
|
446
482
|
questionId,
|
|
447
483
|
questionType,
|
|
448
|
-
questionOpenedFrom: question?.openedFrom,
|
|
484
|
+
questionOpenedFrom: question?.openedFrom === 'bet-pack' ? 'list' : question?.openedFrom,
|
|
449
485
|
},
|
|
450
486
|
});
|
|
451
487
|
this.storage.saveQuestionOpened(flags, questionId);
|
|
452
488
|
}
|
|
453
|
-
|
|
454
|
-
|
|
489
|
+
if (!openedFromBetPack) {
|
|
490
|
+
this.openFeature();
|
|
491
|
+
}
|
|
492
|
+
return this.background.openQuestion(questionId, question
|
|
493
|
+
? {
|
|
494
|
+
...question,
|
|
495
|
+
openedFrom: question?.openedFrom === 'bet-pack' ? 'list' : question?.openedFrom,
|
|
496
|
+
}
|
|
497
|
+
: undefined);
|
|
455
498
|
};
|
|
456
499
|
getFeedItem = (id) => {
|
|
457
500
|
return queries.getFeedItem(id, this.transport);
|
|
@@ -578,7 +621,7 @@ export class Gamification extends AbstractFeature {
|
|
|
578
621
|
questionType: question.data.question.type,
|
|
579
622
|
insight: instantView,
|
|
580
623
|
inApp: {
|
|
581
|
-
useMediaFromContent: optionsValue
|
|
624
|
+
useMediaFromContent: optionsValue?.useAsNotification === UseAsNotification.ENABLED,
|
|
582
625
|
notification: question.data.question.notification,
|
|
583
626
|
appearance: question.data.question.appearance,
|
|
584
627
|
sponsorship: question.data.question.sponsorship,
|
package/lib/leaderboard.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type LeaderboardStore = {
|
|
|
15
15
|
error?: string;
|
|
16
16
|
};
|
|
17
17
|
export declare const leaderboard: (transport: Transport, $eventId: ReadableAtom<string | undefined>, $userId: ReadableAtom<string | undefined>, $friends: Gamification["friends"], options?: LeaderboardOptions) => {
|
|
18
|
-
$store: import("nanostores").
|
|
18
|
+
$store: import("nanostores").PreinitializedMapStore<LeaderboardStore> & object;
|
|
19
19
|
fetchMore: (page?: number) => void;
|
|
20
20
|
invalidate: () => void;
|
|
21
21
|
};
|
package/lib/onboarding.d.ts
CHANGED
|
@@ -20,6 +20,6 @@ export declare enum OnboardingStatus {
|
|
|
20
20
|
export declare const onboarding: (service: Gamification, background: GamificationBackground, transport: Transport, notifications: Notifications, options?: {
|
|
21
21
|
skipOnboarding?: boolean;
|
|
22
22
|
}) => {
|
|
23
|
-
$store: import("nanostores").
|
|
23
|
+
$store: import("nanostores").PreinitializedWritableAtom<OnboardingStatus> & object;
|
|
24
24
|
submitInplay: () => Promise<void>;
|
|
25
25
|
};
|
package/lib/onboarding.js
CHANGED
|
@@ -75,7 +75,7 @@ const onboardingProcess = ($store, background, service, notifications, storage,
|
|
|
75
75
|
userId,
|
|
76
76
|
eventId,
|
|
77
77
|
}, OnboardingStatus.Completed);
|
|
78
|
-
void submitInplayApi(transport,
|
|
78
|
+
void submitInplayApi(transport, eventId);
|
|
79
79
|
}
|
|
80
80
|
return;
|
|
81
81
|
}
|
package/lib/queries/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ReadableAtom } from 'nanostores';
|
|
|
4
4
|
import type { SubscriptionRequest, SubscriptionResponse, VotingSubscriptionRequest, VotingSubscriptionResponse, QuestionSubscriptionRequest, QuestionSubscriptionResponse } from '@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb';
|
|
5
5
|
import { InteractiveAllowed } from '../background';
|
|
6
6
|
import { GamificationStorage } from '../storage';
|
|
7
|
-
export declare const $activeQuestion: (slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedQuestion | undefined, any>;
|
|
7
|
+
export declare const $activeQuestion: (slStreamId: ReadableAtom<string | undefined>, onlyBetPack: boolean, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedQuestion | undefined, any>;
|
|
8
8
|
export declare const getFeedItem: (questionId: string, transport: Transport) => Promise<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem | undefined>;
|
|
9
9
|
export declare const feedSubscription: ($slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("packages/sdk-web-api/lib/grpc/subscription").ServerStreamSubscription<import("@bufbuild/protobuf").ServiceType, import("@bufbuild/protobuf").Message<import("@bufbuild/protobuf").AnyMessage>, import("@bufbuild/protobuf").Message<import("@bufbuild/protobuf").AnyMessage>, never, never> | import("packages/sdk-web-api/lib/grpc/subscription").ServerStreamSubscription<{
|
|
10
10
|
readonly typeName: "streamlayer.interactive.feed.Feed";
|
|
@@ -366,7 +366,6 @@ export declare const questionSubscription: (questionId: string, transport: Trans
|
|
|
366
366
|
};
|
|
367
367
|
};
|
|
368
368
|
}, QuestionSubscriptionRequest, QuestionSubscriptionResponse, "subscription" | "votingSubscription" | "questionSubscription" | "feedSubscription", ((request: import("@bufbuild/protobuf").PartialMessage<SubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions) => AsyncIterable<SubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<VotingSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions) => AsyncIterable<VotingSubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<QuestionSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions) => AsyncIterable<QuestionSubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions) => AsyncIterable<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedSubscriptionResponse>)>;
|
|
369
|
-
export declare const getQuestionByUser: (questionId: string, transport: Transport) => Promise<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").ExtendedQuestion | undefined>;
|
|
370
369
|
export declare const getQuestionDetail: (questionId: string, transport: Transport) => Promise<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").Question | undefined>;
|
|
371
370
|
export declare const questionByUser: ($questionId: string, transport: Transport) => Promise<import("@bufbuild/protobuf").PlainMessage<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").ExtendedQuestion>>;
|
|
372
371
|
export declare const $questionByUser: ($questionId: ReadableAtom<string | undefined> | string, transport: Transport) => import("@nanostores/query").FetcherStore<import("@bufbuild/protobuf").PlainMessage<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").ExtendedQuestion>, any>;
|
|
@@ -401,7 +400,7 @@ export declare const getPromotionDetail: (promoId: string, transport: Transport)
|
|
|
401
400
|
notification: import("@streamlayer/sl-eslib/interactive/interactive.common_pb").QuestionNotification | undefined;
|
|
402
401
|
} | undefined>;
|
|
403
402
|
export declare const $pickHistory: (slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<(import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").PickHistory | undefined)[], any>;
|
|
404
|
-
export declare const $feedList: ($slStreamId: ReadableAtom<string | undefined>, $interactiveAllowed: ReadableAtom<InteractiveAllowed>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem[], any>;
|
|
403
|
+
export declare const $feedList: ($slStreamId: ReadableAtom<string | undefined>, $interactiveAllowed: ReadableAtom<InteractiveAllowed>, onlyBetPack: boolean, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem[], any>;
|
|
405
404
|
export declare const $activePromotionId: ($slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<{
|
|
406
405
|
id: string;
|
|
407
406
|
question: {
|
package/lib/queries/index.js
CHANGED
|
@@ -3,11 +3,14 @@ import { eventBus } from '@streamlayer/sdk-web-interfaces';
|
|
|
3
3
|
import { atom } from 'nanostores';
|
|
4
4
|
import { Feed } from '@streamlayer/sl-eslib/interactive/feed/interactive.feed_connect';
|
|
5
5
|
import { InteractiveAllowed } from '../background';
|
|
6
|
-
export const $activeQuestion = (slStreamId, transport) => {
|
|
7
|
-
const { client, queryKey } = transport.createPromiseClient(Feed, {
|
|
6
|
+
export const $activeQuestion = (slStreamId, onlyBetPack, transport) => {
|
|
7
|
+
const { client, queryKey } = transport.createPromiseClient(Feed, {
|
|
8
|
+
method: 'syncQuestion',
|
|
9
|
+
params: [slStreamId, onlyBetPack ? 'true' : ''],
|
|
10
|
+
});
|
|
8
11
|
return transport.nanoquery.createFetcherStore(queryKey, {
|
|
9
|
-
fetcher: async (_, __, id) => {
|
|
10
|
-
if (!id) {
|
|
12
|
+
fetcher: async (_, __, id, onlyBetPack) => {
|
|
13
|
+
if (!id || onlyBetPack) {
|
|
11
14
|
return undefined;
|
|
12
15
|
}
|
|
13
16
|
const res = await client.syncQuestion({
|
|
@@ -50,13 +53,6 @@ export const questionSubscription = (questionId, transport) => {
|
|
|
50
53
|
const subscription = transport.addSubscription(client.questionSubscription, { questionId }, { name: 'questionSubscription' });
|
|
51
54
|
return subscription;
|
|
52
55
|
};
|
|
53
|
-
export const getQuestionByUser = async (questionId, transport) => {
|
|
54
|
-
const { client } = transport.createPromiseClient(Feed, { method: 'questionByUser', params: [questionId] });
|
|
55
|
-
const res = await client.questionByUser({
|
|
56
|
-
questionId: questionId,
|
|
57
|
-
});
|
|
58
|
-
return res.data?.attributes?.question;
|
|
59
|
-
};
|
|
60
56
|
export const getQuestionDetail = async (questionId, transport) => {
|
|
61
57
|
const { client } = transport.createPromiseClient(Feed, { method: 'getQuestion', params: [questionId] });
|
|
62
58
|
const res = await client.getQuestion({
|
|
@@ -112,14 +108,14 @@ export const $pickHistory = (slStreamId, transport) => {
|
|
|
112
108
|
},
|
|
113
109
|
});
|
|
114
110
|
};
|
|
115
|
-
export const $feedList = ($slStreamId, $interactiveAllowed, transport) => {
|
|
111
|
+
export const $feedList = ($slStreamId, $interactiveAllowed, onlyBetPack, transport) => {
|
|
116
112
|
const { client, queryKey } = transport.createPromiseClient(Feed, {
|
|
117
113
|
method: 'list',
|
|
118
|
-
params: [$slStreamId, $interactiveAllowed],
|
|
114
|
+
params: [$slStreamId, $interactiveAllowed, onlyBetPack ? 'true' : ''],
|
|
119
115
|
});
|
|
120
116
|
return transport.nanoquery.createFetcherStore(queryKey, {
|
|
121
|
-
fetcher: async (_, __, slStreamId, interactiveAllowed) => {
|
|
122
|
-
if (!slStreamId) {
|
|
117
|
+
fetcher: async (_, __, slStreamId, interactiveAllowed, onlyBetPack) => {
|
|
118
|
+
if (!slStreamId || onlyBetPack) {
|
|
123
119
|
return [];
|
|
124
120
|
}
|
|
125
121
|
const res = await client.list({
|
package/lib/userSummary.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ import { ReadableAtom } from 'nanostores';
|
|
|
3
3
|
import { LeaderboardSummaryItem } from '@streamlayer/sl-eslib/interactive/leaderboard/interactive.leaderboard_pb';
|
|
4
4
|
import { Gamification } from '.';
|
|
5
5
|
export declare const summary: ($eventId: ReadableAtom<string | undefined>, $userId: ReadableAtom<string | undefined>, $friends: Gamification["friends"] | undefined, transport: Transport) => {
|
|
6
|
-
$store: import("nanostores").
|
|
6
|
+
$store: import("nanostores").PreinitializedMapStore<LeaderboardSummaryItem | undefined> & object;
|
|
7
7
|
invalidate: () => void;
|
|
8
8
|
};
|
package/lib/userSummary.js
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamlayer/feature-gamification",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@bufbuild/protobuf": "^1.10.0",
|
|
6
6
|
"@fastify/deepmerge": "^2.0.0",
|
|
7
7
|
"@streamlayer/sl-eslib": "^5.149.1",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"@streamlayer/sdk-web-
|
|
11
|
-
"@streamlayer/sdk-web-interfaces": "^1.4.
|
|
12
|
-
"@streamlayer/sdk-web-logger": "^1.0.
|
|
13
|
-
"@streamlayer/sdk-web-
|
|
14
|
-
"@streamlayer/sdk-web-
|
|
15
|
-
"@streamlayer/sdk-web-
|
|
8
|
+
"uuid": "^11.1.0",
|
|
9
|
+
"nanostores": "^0.11.4",
|
|
10
|
+
"@streamlayer/sdk-web-api": "^1.8.1",
|
|
11
|
+
"@streamlayer/sdk-web-interfaces": "^1.4.14",
|
|
12
|
+
"@streamlayer/sdk-web-logger": "^1.0.48",
|
|
13
|
+
"@streamlayer/sdk-web-core": "^1.11.3",
|
|
14
|
+
"@streamlayer/sdk-web-notifications": "^1.3.10",
|
|
15
|
+
"@streamlayer/sdk-web-storage": "^1.0.48",
|
|
16
|
+
"@streamlayer/sdk-web-types": "^1.10.5"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"tslib": "^2.7.0"
|