@streamlayer/feature-gamification 0.2.6 → 0.13.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/README.md +1 -1
- package/lib/background.d.ts +61 -0
- package/lib/background.js +121 -0
- package/lib/gamification.d.ts +65 -0
- package/lib/gamification.js +263 -0
- package/lib/highlights.d.ts +19 -0
- package/lib/highlights.js +81 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +3 -0
- package/{src → lib}/queries/actions.js +0 -1
- package/{src → lib}/queries/index.d.ts +7 -4
- package/{src → lib}/queries/index.js +22 -8
- package/{src → lib}/queries/leaderboard.js +0 -1
- package/{src → lib}/queries/moderation.js +0 -1
- package/lib/storage.d.ts +13 -0
- package/lib/storage.js +16 -0
- package/package.json +26 -16
- package/src/index.d.ts +0 -37
- package/src/index.js +0 -147
- package/src/index.js.map +0 -1
- package/src/queries/actions.js.map +0 -1
- package/src/queries/index.js.map +0 -1
- package/src/queries/leaderboard.js.map +0 -1
- package/src/queries/moderation.js.map +0 -1
- /package/{src → lib}/queries/actions.d.ts +0 -0
- /package/{src → lib}/queries/leaderboard.d.ts +0 -0
- /package/{src → lib}/queries/moderation.d.ts +0 -0
package/README.md
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ApiStore, type StreamLayerContext } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import type { GetApiResponseType } from '@streamlayer/sdk-web-api';
|
|
3
|
+
import '@streamlayer/sdk-web-core/store';
|
|
4
|
+
import { ReadableAtom, WritableAtom } from 'nanostores';
|
|
5
|
+
import * as queries from './queries';
|
|
6
|
+
/**
|
|
7
|
+
* get GamificationBackground singleton
|
|
8
|
+
*/
|
|
9
|
+
export declare const gamificationBackground: (instance: StreamLayerContext) => GamificationBackground;
|
|
10
|
+
/**
|
|
11
|
+
* Background Singleton class for Gamification and Highlights overlays
|
|
12
|
+
*/
|
|
13
|
+
export declare class GamificationBackground {
|
|
14
|
+
/** sl event id */
|
|
15
|
+
slStreamId: ReadableAtom<string | undefined>;
|
|
16
|
+
/** organization id */
|
|
17
|
+
organizationId: ReadableAtom<string | undefined>;
|
|
18
|
+
/** current user id */
|
|
19
|
+
userId: ReadableAtom<string | undefined>;
|
|
20
|
+
/** opened question, using to download statistics */
|
|
21
|
+
openedQuestionId: WritableAtom<string | undefined>;
|
|
22
|
+
/** opened question statistics */
|
|
23
|
+
openedQuestion: ApiStore<GetApiResponseType<typeof queries.$questionByUser>>;
|
|
24
|
+
/** last active question in feed */
|
|
25
|
+
activeQuestionId: ApiStore<GetApiResponseType<typeof queries.$activeQuestion>>;
|
|
26
|
+
/** moderation id */
|
|
27
|
+
moderationId: ReadableAtom<string | undefined>;
|
|
28
|
+
/** moderation */
|
|
29
|
+
moderation: ApiStore<GetApiResponseType<typeof queries.$moderation>>;
|
|
30
|
+
/** feed subscription to receive new active question, update last active question */
|
|
31
|
+
feedSubscription: ReturnType<typeof queries.feedSubscription>;
|
|
32
|
+
/** subscription to opened question (vote percentage) */
|
|
33
|
+
questionSubscription?: ReturnType<typeof queries.questionSubscription>;
|
|
34
|
+
private notifications;
|
|
35
|
+
private log;
|
|
36
|
+
constructor(instance: StreamLayerContext);
|
|
37
|
+
/**
|
|
38
|
+
* Get id for notifications and link with current session
|
|
39
|
+
* @param opts.prefix - id prefix (onboarding, question, tweet, ...etc)
|
|
40
|
+
* @param opts.userId - current user id, if not presented get from sdk automatically
|
|
41
|
+
* @param opts.eventId - current event id, if not presented get from sdk automatically
|
|
42
|
+
* @param opts.organizationId - current organization id, if not presented get from sdk automatically
|
|
43
|
+
* @param opts.entity - entity id (question id, tweet id, ...etc)
|
|
44
|
+
*/
|
|
45
|
+
getCurrentSessionId: (opts: {
|
|
46
|
+
prefix?: string;
|
|
47
|
+
userId?: string;
|
|
48
|
+
eventId?: string;
|
|
49
|
+
organizationId?: string;
|
|
50
|
+
entity?: string;
|
|
51
|
+
}) => string;
|
|
52
|
+
disconnect: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Open question and mark notification for this question as viewed
|
|
55
|
+
*/
|
|
56
|
+
openQuestion: (questionId: string) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Close question and mark notification for this question as viewed
|
|
59
|
+
*/
|
|
60
|
+
closeQuestion: (questionId?: string) => void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ApiStore, SingleStore, createSingleStore } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { createLogger } from '@streamlayer/sdk-web-logger';
|
|
3
|
+
import '@streamlayer/sdk-web-core/store';
|
|
4
|
+
import * as queries from './queries';
|
|
5
|
+
/**
|
|
6
|
+
* get GamificationBackground singleton
|
|
7
|
+
*/
|
|
8
|
+
export const gamificationBackground = (instance) => {
|
|
9
|
+
if (!instance.gamification) {
|
|
10
|
+
instance.gamification = new GamificationBackground(instance);
|
|
11
|
+
}
|
|
12
|
+
return instance.gamification;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Background Singleton class for Gamification and Highlights overlays
|
|
16
|
+
*/
|
|
17
|
+
export class GamificationBackground {
|
|
18
|
+
/** sl event id */
|
|
19
|
+
slStreamId;
|
|
20
|
+
/** organization id */
|
|
21
|
+
organizationId;
|
|
22
|
+
/** current user id */
|
|
23
|
+
userId;
|
|
24
|
+
/** opened question, using to download statistics */
|
|
25
|
+
openedQuestionId;
|
|
26
|
+
/** opened question statistics */
|
|
27
|
+
openedQuestion;
|
|
28
|
+
/** last active question in feed */
|
|
29
|
+
activeQuestionId;
|
|
30
|
+
/** moderation id */
|
|
31
|
+
moderationId;
|
|
32
|
+
/** moderation */
|
|
33
|
+
moderation;
|
|
34
|
+
/** feed subscription to receive new active question, update last active question */
|
|
35
|
+
feedSubscription;
|
|
36
|
+
/** subscription to opened question (vote percentage) */
|
|
37
|
+
questionSubscription;
|
|
38
|
+
notifications;
|
|
39
|
+
log;
|
|
40
|
+
constructor(instance) {
|
|
41
|
+
if (instance.gamification) {
|
|
42
|
+
throw new Error('GamificationBackground Singleton error');
|
|
43
|
+
}
|
|
44
|
+
this.log = createLogger('gamification-background');
|
|
45
|
+
this.slStreamId = instance.stores.slStreamId.getAtomStore();
|
|
46
|
+
this.organizationId = instance.stores.organizationSettings.getAtomStore();
|
|
47
|
+
this.userId = instance.stores.user.getAtomStore();
|
|
48
|
+
this.moderationId = new SingleStore(createSingleStore(), 'moderationId').getStore();
|
|
49
|
+
this.openedQuestionId = new SingleStore(createSingleStore(), 'openedQuestionId').getStore();
|
|
50
|
+
this.notifications = instance.notifications;
|
|
51
|
+
this.moderation = new ApiStore(queries.$moderation(this.slStreamId, instance.transport), 'gamification:moderation');
|
|
52
|
+
this.activeQuestionId = new ApiStore(queries.$activeQuestion(this.slStreamId, instance.transport), 'gamification:activeQuestionId');
|
|
53
|
+
this.openedQuestion = new ApiStore(queries.$questionByUser(this.openedQuestionId, instance.transport), 'gamification:openedQuestion');
|
|
54
|
+
this.openedQuestionId.listen((questionId) => {
|
|
55
|
+
this.log.debug({ questionId }, 'received question');
|
|
56
|
+
if (questionId) {
|
|
57
|
+
this.questionSubscription = queries.questionSubscription(questionId, instance.transport);
|
|
58
|
+
this.questionSubscription.addListener('feed-subscription-opened-question', (response) => {
|
|
59
|
+
window.requestAnimationFrame(() => {
|
|
60
|
+
this.openedQuestion?.getStore().mutate(response.data?.attributes?.question);
|
|
61
|
+
this.openedQuestion?.getStore().invalidate();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
this.questionSubscription.connect();
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.log.info('cleanup on close question');
|
|
68
|
+
this.openedQuestion?.getStore().mutate(undefined);
|
|
69
|
+
if (this.questionSubscription !== undefined) {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
instance.transport.removeSubscription(this.questionSubscription);
|
|
72
|
+
this.questionSubscription = undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
this.feedSubscription = queries.feedSubscription(this.slStreamId, instance.transport);
|
|
77
|
+
this.feedSubscription.addListener('feed-subscription-active-question', (response) => {
|
|
78
|
+
window.requestAnimationFrame(() => {
|
|
79
|
+
const $activeQuestionId = this.activeQuestionId.getStore();
|
|
80
|
+
if ($activeQuestionId) {
|
|
81
|
+
$activeQuestionId.mutate(response.data?.attributes);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get id for notifications and link with current session
|
|
88
|
+
* @param opts.prefix - id prefix (onboarding, question, tweet, ...etc)
|
|
89
|
+
* @param opts.userId - current user id, if not presented get from sdk automatically
|
|
90
|
+
* @param opts.eventId - current event id, if not presented get from sdk automatically
|
|
91
|
+
* @param opts.organizationId - current organization id, if not presented get from sdk automatically
|
|
92
|
+
* @param opts.entity - entity id (question id, tweet id, ...etc)
|
|
93
|
+
*/
|
|
94
|
+
getCurrentSessionId = (opts) => {
|
|
95
|
+
const eventId = opts.eventId || this.slStreamId.get() || '';
|
|
96
|
+
const userId = opts.userId || this.userId.get() || '';
|
|
97
|
+
const organizationId = opts.organizationId || this.organizationId.get() || '';
|
|
98
|
+
const entity = opts.entity || '';
|
|
99
|
+
const prefix = opts.prefix || '';
|
|
100
|
+
return [organizationId, eventId, userId, prefix, entity].join(':');
|
|
101
|
+
};
|
|
102
|
+
disconnect = () => {
|
|
103
|
+
this.feedSubscription?.disconnect();
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Open question and mark notification for this question as viewed
|
|
107
|
+
*/
|
|
108
|
+
openQuestion = (questionId) => {
|
|
109
|
+
this.openedQuestionId.set(questionId);
|
|
110
|
+
this.notifications.markAsViewed(this.getCurrentSessionId({ prefix: 'notification', entity: questionId }));
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Close question and mark notification for this question as viewed
|
|
114
|
+
*/
|
|
115
|
+
closeQuestion = (questionId) => {
|
|
116
|
+
this.openedQuestionId.set(undefined);
|
|
117
|
+
if (questionId) {
|
|
118
|
+
this.notifications.markAsViewed(this.getCurrentSessionId({ prefix: 'notification', entity: questionId }));
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AbstractFeature, ApiStore, FeatureSource, type FeatureProps, type StreamLayerContext, createComputedStore } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { type GamesOverlaySettings, ExtendedQuestion } from '@streamlayer/sdk-web-types';
|
|
3
|
+
import type { GetApiResponseType } from '@streamlayer/sdk-web-api';
|
|
4
|
+
import '@streamlayer/sdk-web-core/store';
|
|
5
|
+
import type { PlainMessage } from '@bufbuild/protobuf';
|
|
6
|
+
import { WritableAtom } from 'nanostores';
|
|
7
|
+
import * as queries from './queries';
|
|
8
|
+
/**
|
|
9
|
+
* Required: in-app should be displayed and questions not available
|
|
10
|
+
* Optional: in-app should be displayed but questions are available
|
|
11
|
+
* Completed: user completed onboarding, cached in browser. Linked by eventId, organizationId and userId
|
|
12
|
+
* Disabled: no in-app but questions are available
|
|
13
|
+
* Unavailable: no in-app and questions not available [behavior is discussed]
|
|
14
|
+
*/
|
|
15
|
+
export declare enum OnboardingStatus {
|
|
16
|
+
Unset = "unset",
|
|
17
|
+
Required = "required",
|
|
18
|
+
Optional = "optional",
|
|
19
|
+
Completed = "completed",
|
|
20
|
+
Disabled = "disabled",
|
|
21
|
+
Unavailable = "unavailable"
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Gamification (Games) Overlay
|
|
25
|
+
* Includes:
|
|
26
|
+
* - questions list (pick history)
|
|
27
|
+
* - active question (question from active queue, available from pick history and in-app)
|
|
28
|
+
* - leaderboard (currently only global pinned leaderboard)
|
|
29
|
+
* - user summary (current user summary)
|
|
30
|
+
* - onboarding (welcome book)
|
|
31
|
+
*/
|
|
32
|
+
export declare class Gamification extends AbstractFeature<'games', PlainMessage<GamesOverlaySettings>> {
|
|
33
|
+
/** user statistics (leaderboard panel) */
|
|
34
|
+
userSummary?: ApiStore<GetApiResponseType<typeof queries.$userSummary>>;
|
|
35
|
+
/** questions list (pick history) */
|
|
36
|
+
questions?: ApiStore<GetApiResponseType<typeof queries.$pickHistory>>;
|
|
37
|
+
/** pinned leaderboard id */
|
|
38
|
+
leaderboardId: WritableAtom<string | undefined>;
|
|
39
|
+
/** onboarding status */
|
|
40
|
+
onboardingStatus: WritableAtom<OnboardingStatus | undefined>;
|
|
41
|
+
/** opened question */
|
|
42
|
+
openedQuestion: ReturnType<typeof createComputedStore<ExtendedQuestion | undefined>>;
|
|
43
|
+
private notifications;
|
|
44
|
+
private transport;
|
|
45
|
+
private closeFeature;
|
|
46
|
+
private openFeature;
|
|
47
|
+
/** gamification background class, handle subscriptions and notifications for closed overlay */
|
|
48
|
+
private background;
|
|
49
|
+
/** Browser cache */
|
|
50
|
+
private storage;
|
|
51
|
+
constructor(config: FeatureProps, source: FeatureSource, instance: StreamLayerContext);
|
|
52
|
+
/**
|
|
53
|
+
* check onboarding status, sync with browser cache
|
|
54
|
+
* retrieve onboarding settings from api
|
|
55
|
+
*/
|
|
56
|
+
onboardingProcess: () => Promise<void>;
|
|
57
|
+
showOnboardingInApp: () => void;
|
|
58
|
+
connect: (transport: StreamLayerContext['transport']) => void;
|
|
59
|
+
disconnect: () => void;
|
|
60
|
+
submitInplay: () => Promise<void>;
|
|
61
|
+
submitAnswer: (questionId: string, answerId: string) => Promise<void>;
|
|
62
|
+
skipQuestion: (questionId: string) => Promise<void>;
|
|
63
|
+
openQuestion: (questionId: string) => void;
|
|
64
|
+
closeQuestion: (questionId?: string) => void;
|
|
65
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { AbstractFeature, ApiStore, FeatureStatus, SingleStore, createSingleStore, createComputedStore, } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { QuestionStatus, QuestionType, FeatureType, } from '@streamlayer/sdk-web-types';
|
|
3
|
+
import { NotificationType } from '@streamlayer/sdk-web-notifications';
|
|
4
|
+
import '@streamlayer/sdk-web-core/store';
|
|
5
|
+
import * as queries from './queries';
|
|
6
|
+
import * as actions from './queries/actions';
|
|
7
|
+
import { GamificationStorage } from './storage';
|
|
8
|
+
import { gamificationBackground } from './';
|
|
9
|
+
const GamificationQuestionTypes = new Set([QuestionType.POLL, QuestionType.PREDICTION, QuestionType.TRIVIA]);
|
|
10
|
+
/**
|
|
11
|
+
* Required: in-app should be displayed and questions not available
|
|
12
|
+
* Optional: in-app should be displayed but questions are available
|
|
13
|
+
* Completed: user completed onboarding, cached in browser. Linked by eventId, organizationId and userId
|
|
14
|
+
* Disabled: no in-app but questions are available
|
|
15
|
+
* Unavailable: no in-app and questions not available [behavior is discussed]
|
|
16
|
+
*/
|
|
17
|
+
export var OnboardingStatus;
|
|
18
|
+
(function (OnboardingStatus) {
|
|
19
|
+
OnboardingStatus["Unset"] = "unset";
|
|
20
|
+
OnboardingStatus["Required"] = "required";
|
|
21
|
+
OnboardingStatus["Optional"] = "optional";
|
|
22
|
+
OnboardingStatus["Completed"] = "completed";
|
|
23
|
+
OnboardingStatus["Disabled"] = "disabled";
|
|
24
|
+
OnboardingStatus["Unavailable"] = "unavailable";
|
|
25
|
+
})(OnboardingStatus || (OnboardingStatus = {}));
|
|
26
|
+
/**
|
|
27
|
+
* Gamification (Games) Overlay
|
|
28
|
+
* Includes:
|
|
29
|
+
* - questions list (pick history)
|
|
30
|
+
* - active question (question from active queue, available from pick history and in-app)
|
|
31
|
+
* - leaderboard (currently only global pinned leaderboard)
|
|
32
|
+
* - user summary (current user summary)
|
|
33
|
+
* - onboarding (welcome book)
|
|
34
|
+
*/
|
|
35
|
+
export class Gamification extends AbstractFeature {
|
|
36
|
+
/** user statistics (leaderboard panel) */
|
|
37
|
+
userSummary;
|
|
38
|
+
/** questions list (pick history) */
|
|
39
|
+
questions;
|
|
40
|
+
/** pinned leaderboard id */
|
|
41
|
+
leaderboardId;
|
|
42
|
+
/** onboarding status */
|
|
43
|
+
onboardingStatus;
|
|
44
|
+
/** opened question */
|
|
45
|
+
openedQuestion;
|
|
46
|
+
notifications;
|
|
47
|
+
transport;
|
|
48
|
+
closeFeature;
|
|
49
|
+
openFeature;
|
|
50
|
+
/** gamification background class, handle subscriptions and notifications for closed overlay */
|
|
51
|
+
background;
|
|
52
|
+
/** Browser cache */
|
|
53
|
+
storage;
|
|
54
|
+
constructor(config, source, instance) {
|
|
55
|
+
super(config, source);
|
|
56
|
+
this.background = gamificationBackground(instance);
|
|
57
|
+
this.storage = new GamificationStorage();
|
|
58
|
+
this.leaderboardId = new SingleStore(createSingleStore(this.settings.getValue('pinnedLeaderboardId')), 'pinnedLeaderboardId').getStore();
|
|
59
|
+
this.onboardingStatus = new SingleStore(createSingleStore(OnboardingStatus.Unset), 'onboardingStatus').getStore();
|
|
60
|
+
this.notifications = instance.notifications;
|
|
61
|
+
this.transport = instance.transport;
|
|
62
|
+
this.closeFeature = instance.sdk.closeFeature;
|
|
63
|
+
this.openFeature = () => instance.sdk.openFeature(FeatureType.GAMES);
|
|
64
|
+
this.openedQuestion = createComputedStore(this.background.openedQuestion.getStore(), (openedQuestion) => {
|
|
65
|
+
if (openedQuestion.data?.type && GamificationQuestionTypes.has(openedQuestion.data.type)) {
|
|
66
|
+
return openedQuestion.data;
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
});
|
|
70
|
+
this.onboardingStatus.subscribe((onboardingStatus) => {
|
|
71
|
+
if (onboardingStatus === OnboardingStatus.Optional || OnboardingStatus.Required) {
|
|
72
|
+
this.showOnboardingInApp();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
this.status.subscribe((status) => {
|
|
76
|
+
if (status === FeatureStatus.Ready) {
|
|
77
|
+
this.notifications.close(this.background.getCurrentSessionId({ prefix: 'onboarding' }));
|
|
78
|
+
this.connect(instance.transport);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.disconnect();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
this.onboardingStatus.subscribe((onboardingStatus) => {
|
|
85
|
+
if (onboardingStatus) {
|
|
86
|
+
this.background.activeQuestionId.invalidate();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
this.background.activeQuestionId.listen((question) => {
|
|
90
|
+
if (question && question.data && this.onboardingStatus.get()) {
|
|
91
|
+
if (GamificationQuestionTypes.has(question.data.question.type) &&
|
|
92
|
+
question.data.question.status === QuestionStatus.ACTIVE) {
|
|
93
|
+
this.notifications.add({
|
|
94
|
+
type: NotificationType.QUESTION,
|
|
95
|
+
action: () => this.openQuestion(question.data.question.id),
|
|
96
|
+
close: () => this.closeQuestion(question.data.question.id),
|
|
97
|
+
autoHideDuration: 5000,
|
|
98
|
+
id: this.background.getCurrentSessionId({ prefix: 'notification', entity: question.data.question.id }),
|
|
99
|
+
data: {
|
|
100
|
+
title: question.data.notification.title,
|
|
101
|
+
color: question.data.notification.indicatorColor,
|
|
102
|
+
icon: question.data.notification.image,
|
|
103
|
+
imageMode: question.data.notification.imageMode,
|
|
104
|
+
imagePosition: question.data.notification.imagePosition,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
void this.onboardingProcess();
|
|
111
|
+
this.background.userId.subscribe((userId) => {
|
|
112
|
+
if (userId) {
|
|
113
|
+
void this.onboardingProcess();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
this.background.moderation.subscribe((value) => {
|
|
117
|
+
if (value.data) {
|
|
118
|
+
void this.onboardingProcess();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* check onboarding status, sync with browser cache
|
|
124
|
+
* retrieve onboarding settings from api
|
|
125
|
+
*/
|
|
126
|
+
onboardingProcess = async () => {
|
|
127
|
+
const userId = this.background.userId.get();
|
|
128
|
+
if (!userId) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const onboardingStatus = this.storage.getOnboardingStatus({
|
|
132
|
+
userId,
|
|
133
|
+
organizationId: this.background.organizationId.get() || '',
|
|
134
|
+
eventId: this.background.slStreamId.get() || '',
|
|
135
|
+
});
|
|
136
|
+
if (onboardingStatus === OnboardingStatus.Completed) {
|
|
137
|
+
this.onboardingStatus.set(OnboardingStatus.Completed);
|
|
138
|
+
}
|
|
139
|
+
const moderation = await this.background.moderation.getValue();
|
|
140
|
+
if (this.onboardingStatus.get() === OnboardingStatus.Completed) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const onboardingEnabled = !!(moderation?.options?.onboardingEnabled && this.featureSettings.get().inplayGame?.onboarding?.completed);
|
|
144
|
+
const optIn = !!this.featureSettings.get().inplayGame?.titleCard?.optIn;
|
|
145
|
+
if (onboardingEnabled) {
|
|
146
|
+
if (optIn) {
|
|
147
|
+
this.onboardingStatus.set(OnboardingStatus.Required);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.onboardingStatus.set(OnboardingStatus.Optional);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (optIn) {
|
|
155
|
+
this.onboardingStatus.set(OnboardingStatus.Unavailable);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.onboardingStatus.set(OnboardingStatus.Disabled);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
showOnboardingInApp = () => {
|
|
163
|
+
const { inplayGame } = this.featureSettings.get();
|
|
164
|
+
if (!inplayGame) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const { titleCard, overview } = inplayGame;
|
|
168
|
+
this.notifications.add({
|
|
169
|
+
type: NotificationType.ONBOARDING,
|
|
170
|
+
id: this.background.getCurrentSessionId({ prefix: 'onboarding' }),
|
|
171
|
+
action: this.openFeature,
|
|
172
|
+
close: this.closeFeature,
|
|
173
|
+
autoHideDuration: 100000,
|
|
174
|
+
data: {
|
|
175
|
+
header: titleCard?.header,
|
|
176
|
+
title: titleCard?.title,
|
|
177
|
+
subtitle: titleCard?.subtitle,
|
|
178
|
+
graphicBg: titleCard?.appearance?.graphic,
|
|
179
|
+
icon: titleCard?.media?.icon,
|
|
180
|
+
sponsorLogo: titleCard?.media?.sponsorLogo,
|
|
181
|
+
primaryColor: overview?.appearance?.primaryColor,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
connect = (transport) => {
|
|
186
|
+
if (!this.userSummary) {
|
|
187
|
+
this.userSummary = new ApiStore(queries.$userSummary(this.background.slStreamId, this.background.userId, transport), 'gamification:userSummary');
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
this.userSummary.invalidate();
|
|
191
|
+
}
|
|
192
|
+
if (!this.questions) {
|
|
193
|
+
this.questions = new ApiStore(queries.$pickHistory(this.background.slStreamId, transport), 'gamification:questions');
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
this.questions.invalidate();
|
|
197
|
+
}
|
|
198
|
+
this.background.feedSubscription.addListener('feed-subscription-prediction-close', (response) => {
|
|
199
|
+
window.requestAnimationFrame(async () => {
|
|
200
|
+
const question = response.data?.attributes?.question;
|
|
201
|
+
if (!question) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const { status, type, id } = question;
|
|
205
|
+
if (status === QuestionStatus.RESOLVED && type === QuestionType.PREDICTION) {
|
|
206
|
+
const notificationId = this.background.getCurrentSessionId({
|
|
207
|
+
prefix: `notification-id:${id}`,
|
|
208
|
+
});
|
|
209
|
+
const question = await queries.getQuestionByUser(id, transport);
|
|
210
|
+
const correctAnswer = question?.answers.find(({ correct }) => correct);
|
|
211
|
+
this.notifications.add({
|
|
212
|
+
type: NotificationType.ONBOARDING,
|
|
213
|
+
action: () => this.openQuestion(id),
|
|
214
|
+
close: () => this.closeQuestion(id),
|
|
215
|
+
autoHideDuration: 5000,
|
|
216
|
+
id: notificationId,
|
|
217
|
+
data: {
|
|
218
|
+
title: correctAnswer?.youVoted
|
|
219
|
+
? `Congratulations! You answered correctly! You won ${correctAnswer.points} pts!`
|
|
220
|
+
: `Better luck next time! Correct: ${correctAnswer?.text}!`,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
this.background.feedSubscription.addListener('feed-subscription-questions-list', () => {
|
|
227
|
+
window.requestAnimationFrame(() => {
|
|
228
|
+
this.questions?.invalidate();
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
disconnect = () => {
|
|
233
|
+
this.background.feedSubscription.removeListener('feed-subscription-questions-list');
|
|
234
|
+
};
|
|
235
|
+
// onboarding
|
|
236
|
+
submitInplay = async () => {
|
|
237
|
+
const eventId = this.background.slStreamId.get();
|
|
238
|
+
if (eventId) {
|
|
239
|
+
await actions.submitInplay(this.transport, eventId);
|
|
240
|
+
this.onboardingStatus.set(OnboardingStatus.Completed);
|
|
241
|
+
this.storage.saveOnboardingStatus({
|
|
242
|
+
organizationId: this.background.organizationId.get() || '',
|
|
243
|
+
userId: this.background.userId.get() || '',
|
|
244
|
+
eventId,
|
|
245
|
+
}, OnboardingStatus.Completed);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
submitAnswer = async (questionId, answerId) => {
|
|
249
|
+
await actions.submitAnswer(this.transport, { questionId, answerId });
|
|
250
|
+
this.questions?.invalidate();
|
|
251
|
+
};
|
|
252
|
+
skipQuestion = async (questionId) => {
|
|
253
|
+
await actions.skipQuestion(this.transport, questionId);
|
|
254
|
+
this.questions?.invalidate();
|
|
255
|
+
};
|
|
256
|
+
openQuestion = (questionId) => {
|
|
257
|
+
this.openFeature();
|
|
258
|
+
return this.background.openQuestion(questionId);
|
|
259
|
+
};
|
|
260
|
+
closeQuestion = (questionId) => {
|
|
261
|
+
return this.background.closeQuestion(questionId);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AbstractFeature, ApiStore, FeatureSource, type FeatureProps, type StreamLayerContext, createComputedStore } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { ExtendedQuestion } from '@streamlayer/sdk-web-types';
|
|
3
|
+
import type { GetApiResponseType } from '@streamlayer/sdk-web-api';
|
|
4
|
+
import '@streamlayer/sdk-web-core/store';
|
|
5
|
+
import * as queries from './queries';
|
|
6
|
+
export declare class Highlights extends AbstractFeature<undefined> {
|
|
7
|
+
insights?: ApiStore<GetApiResponseType<typeof queries.$insightHistory>>;
|
|
8
|
+
closeFeature: () => void;
|
|
9
|
+
openFeature: () => void;
|
|
10
|
+
openedInsight: ReturnType<typeof createComputedStore<ExtendedQuestion | undefined>>;
|
|
11
|
+
private notifications;
|
|
12
|
+
private transport;
|
|
13
|
+
private background;
|
|
14
|
+
constructor(config: FeatureProps, source: FeatureSource, instance: StreamLayerContext);
|
|
15
|
+
connect: () => void;
|
|
16
|
+
disconnect: () => void;
|
|
17
|
+
openHighlight: (questionId: string) => void;
|
|
18
|
+
closeHighlight: (questionId?: string) => void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { AbstractFeature, ApiStore, FeatureStatus, createComputedStore, } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
+
import { QuestionStatus, QuestionType, FeatureType } from '@streamlayer/sdk-web-types';
|
|
3
|
+
import { NotificationType } from '@streamlayer/sdk-web-notifications';
|
|
4
|
+
import '@streamlayer/sdk-web-core/store';
|
|
5
|
+
import * as queries from './queries';
|
|
6
|
+
import { gamificationBackground } from './';
|
|
7
|
+
export class Highlights extends AbstractFeature {
|
|
8
|
+
insights;
|
|
9
|
+
closeFeature;
|
|
10
|
+
openFeature;
|
|
11
|
+
openedInsight;
|
|
12
|
+
notifications;
|
|
13
|
+
transport;
|
|
14
|
+
background;
|
|
15
|
+
constructor(config, source, instance) {
|
|
16
|
+
super(config, source);
|
|
17
|
+
this.background = gamificationBackground(instance);
|
|
18
|
+
this.notifications = instance.notifications;
|
|
19
|
+
this.transport = instance.transport;
|
|
20
|
+
this.closeFeature = instance.sdk.closeFeature;
|
|
21
|
+
this.openFeature = () => instance.sdk.openFeature(FeatureType.HIGHLIGHTS);
|
|
22
|
+
this.status.subscribe((status) => {
|
|
23
|
+
if (status === FeatureStatus.Ready) {
|
|
24
|
+
this.connect();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this.disconnect();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
this.background.activeQuestionId.listen((question) => {
|
|
31
|
+
if (question &&
|
|
32
|
+
question.data &&
|
|
33
|
+
question.data.question.type === QuestionType.FACTOID &&
|
|
34
|
+
question.data.question.status === QuestionStatus.ACTIVE) {
|
|
35
|
+
this.notifications.add({
|
|
36
|
+
type: NotificationType.QUESTION,
|
|
37
|
+
action: () => this.openHighlight(question.data.question.id),
|
|
38
|
+
close: () => this.closeHighlight(question.data.question.id),
|
|
39
|
+
autoHideDuration: 5000,
|
|
40
|
+
id: this.background.getCurrentSessionId({ prefix: 'notification', entity: question.data.question.id }),
|
|
41
|
+
data: {
|
|
42
|
+
title: question.data.notification.title,
|
|
43
|
+
color: question.data.notification.indicatorColor,
|
|
44
|
+
icon: question.data.notification.image,
|
|
45
|
+
imageMode: question.data.notification.imageMode,
|
|
46
|
+
imagePosition: question.data.notification.imagePosition,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
this.openedInsight = createComputedStore(this.background.openedQuestion.getStore(), (openedQuestion) => {
|
|
52
|
+
if (openedQuestion.data?.type === QuestionType.FACTOID) {
|
|
53
|
+
return openedQuestion.data;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
connect = () => {
|
|
59
|
+
if (!this.insights) {
|
|
60
|
+
this.insights = new ApiStore(queries.$insightHistory(this.background.slStreamId, this.transport), 'gamification:insights');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.insights.invalidate();
|
|
64
|
+
}
|
|
65
|
+
this.background.feedSubscription.addListener('feed-subscription-insights-list', () => {
|
|
66
|
+
window.requestAnimationFrame(() => {
|
|
67
|
+
this.insights?.invalidate();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
disconnect = () => {
|
|
72
|
+
this.background.feedSubscription.removeListener('feed-subscription-insights-list');
|
|
73
|
+
};
|
|
74
|
+
openHighlight = (questionId) => {
|
|
75
|
+
this.openFeature();
|
|
76
|
+
return this.background.openQuestion(questionId);
|
|
77
|
+
};
|
|
78
|
+
closeHighlight = (questionId) => {
|
|
79
|
+
return this.background.closeQuestion(questionId);
|
|
80
|
+
};
|
|
81
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { GamificationBackground, gamificationBackground } from './background';
|
|
2
|
+
export { Gamification } from './gamification';
|
|
3
|
+
export { Highlights } from './highlights';
|
|
4
|
+
declare module '@streamlayer/sdk-web-interfaces' {
|
|
5
|
+
interface StreamLayerContext {
|
|
6
|
+
gamification: import('./background').GamificationBackground;
|
|
7
|
+
}
|
|
8
|
+
}
|
package/lib/index.js
ADDED
|
@@ -2,7 +2,7 @@ import type { Transport } from '@streamlayer/sdk-web-api';
|
|
|
2
2
|
import { ReadableAtom } from 'nanostores';
|
|
3
3
|
import type { SubscriptionRequest, SubscriptionResponse, VotingSubscriptionRequest, VotingSubscriptionResponse, QuestionSubscriptionRequest, QuestionSubscriptionResponse } from '@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb';
|
|
4
4
|
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>;
|
|
5
|
-
export declare const feedSubscription: ($slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("
|
|
5
|
+
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<{
|
|
6
6
|
readonly typeName: "streamlayer.interactive.feed.Feed";
|
|
7
7
|
readonly methods: {
|
|
8
8
|
readonly get: {
|
|
@@ -100,7 +100,7 @@ export declare const feedSubscription: ($slStreamId: ReadableAtom<string | undef
|
|
|
100
100
|
export declare const votingSubscription: (params: {
|
|
101
101
|
questionId: string;
|
|
102
102
|
feedId: string;
|
|
103
|
-
}, transport: Transport) => import("
|
|
103
|
+
}, 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<{
|
|
104
104
|
readonly typeName: "streamlayer.interactive.feed.Feed";
|
|
105
105
|
readonly methods: {
|
|
106
106
|
readonly get: {
|
|
@@ -195,7 +195,7 @@ export declare const votingSubscription: (params: {
|
|
|
195
195
|
};
|
|
196
196
|
};
|
|
197
197
|
}, VotingSubscriptionRequest, VotingSubscriptionResponse, "subscription" | "votingSubscription" | "questionSubscription", ((request: import("@bufbuild/protobuf").PartialMessage<SubscriptionRequest>, messageCallback: (response: SubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void) | ((request: import("@bufbuild/protobuf").PartialMessage<VotingSubscriptionRequest>, messageCallback: (response: VotingSubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void) | ((request: import("@bufbuild/protobuf").PartialMessage<QuestionSubscriptionRequest>, messageCallback: (response: QuestionSubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void)>;
|
|
198
|
-
export declare const questionSubscription: (questionId: string, transport: Transport) => import("
|
|
198
|
+
export declare const questionSubscription: (questionId: string, 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<{
|
|
199
199
|
readonly typeName: "streamlayer.interactive.feed.Feed";
|
|
200
200
|
readonly methods: {
|
|
201
201
|
readonly get: {
|
|
@@ -290,6 +290,9 @@ export declare const questionSubscription: (questionId: string, transport: Trans
|
|
|
290
290
|
};
|
|
291
291
|
};
|
|
292
292
|
}, QuestionSubscriptionRequest, QuestionSubscriptionResponse, "subscription" | "votingSubscription" | "questionSubscription", ((request: import("@bufbuild/protobuf").PartialMessage<SubscriptionRequest>, messageCallback: (response: SubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void) | ((request: import("@bufbuild/protobuf").PartialMessage<VotingSubscriptionRequest>, messageCallback: (response: VotingSubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void) | ((request: import("@bufbuild/protobuf").PartialMessage<QuestionSubscriptionRequest>, messageCallback: (response: QuestionSubscriptionResponse) => void, closeCallback: (error: import("@connectrpc/connect").ConnectError | undefined) => void, options?: import("@connectrpc/connect").CallOptions | undefined) => () => void)>;
|
|
293
|
-
export declare const
|
|
293
|
+
export declare const getQuestionByUser: (questionId: string, transport: Transport) => Promise<import("packages/sdk-web-types/lib").ExtendedQuestion | undefined>;
|
|
294
|
+
export declare const $questionByUser: ($questionId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("packages/sdk-web-types/lib").ExtendedQuestion | undefined, any>;
|
|
294
295
|
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)[] | undefined, any>;
|
|
296
|
+
export declare const $insightHistory: (slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<(import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").InsightHistory | undefined)[] | undefined, any>;
|
|
295
297
|
export { $userSummary } from './leaderboard';
|
|
298
|
+
export { $moderation } from './moderation';
|
|
@@ -31,17 +31,17 @@ export const votingSubscription = (params, transport) => {
|
|
|
31
31
|
return subscription;
|
|
32
32
|
};
|
|
33
33
|
export const questionSubscription = (questionId, transport) => {
|
|
34
|
-
// const { queryKeyStr } = transport.createPromiseClient(Feed, {
|
|
35
|
-
// method: 'questionByUser',
|
|
36
|
-
// params: [$params.get().questionId],
|
|
37
|
-
// })
|
|
38
34
|
const { client } = transport.createCallbackClient(Feed);
|
|
39
35
|
const subscription = transport.addSubscription(client.questionSubscription, { questionId }, { name: 'questionSubscription' });
|
|
40
|
-
// subscription.addListener('user-question-subscription', (response) => {
|
|
41
|
-
// transport.nanoquery.utils.mutateCache((key) => key === queryKeyStr, response)
|
|
42
|
-
// })
|
|
43
36
|
return subscription;
|
|
44
37
|
};
|
|
38
|
+
export const getQuestionByUser = async (questionId, transport) => {
|
|
39
|
+
const { client } = transport.createPromiseClient(Feed, { method: 'questionByUser', params: [questionId] });
|
|
40
|
+
const res = await client.questionByUser({
|
|
41
|
+
questionId: questionId,
|
|
42
|
+
});
|
|
43
|
+
return res.data?.attributes?.question;
|
|
44
|
+
};
|
|
45
45
|
export const $questionByUser = ($questionId, transport) => {
|
|
46
46
|
const { client, queryKey } = transport.createPromiseClient(Feed, { method: 'questionByUser', params: [$questionId] });
|
|
47
47
|
return transport.nanoquery.createFetcherStore(queryKey, {
|
|
@@ -67,5 +67,19 @@ export const $pickHistory = (slStreamId, transport) => {
|
|
|
67
67
|
},
|
|
68
68
|
});
|
|
69
69
|
};
|
|
70
|
+
export const $insightHistory = (slStreamId, transport) => {
|
|
71
|
+
const { client, queryKey } = transport.createPromiseClient(Feed, { method: 'insightHistory', params: [slStreamId] });
|
|
72
|
+
return transport.nanoquery.createFetcherStore(queryKey, {
|
|
73
|
+
fetcher: async (_, __, eventId) => {
|
|
74
|
+
if (!eventId) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const res = await client.insightHistory({
|
|
78
|
+
eventId: eventId,
|
|
79
|
+
});
|
|
80
|
+
return res.data?.map(({ attributes }) => attributes);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
};
|
|
70
84
|
export { $userSummary } from './leaderboard';
|
|
71
|
-
|
|
85
|
+
export { $moderation } from './moderation';
|
package/lib/storage.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Storage } from '@streamlayer/sdk-web-storage';
|
|
2
|
+
import { OnboardingStatus } from './gamification';
|
|
3
|
+
type UserProps = {
|
|
4
|
+
userId: string;
|
|
5
|
+
eventId: string;
|
|
6
|
+
organizationId: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class GamificationStorage extends Storage {
|
|
9
|
+
constructor();
|
|
10
|
+
saveOnboardingStatus: ({ userId, eventId, organizationId }: UserProps, status: OnboardingStatus) => void;
|
|
11
|
+
getOnboardingStatus: ({ userId, eventId, organizationId }: UserProps) => string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
package/lib/storage.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Storage } from '@streamlayer/sdk-web-storage';
|
|
2
|
+
var KEY_PREFIX;
|
|
3
|
+
(function (KEY_PREFIX) {
|
|
4
|
+
KEY_PREFIX["ONBOARDING"] = "onboarding";
|
|
5
|
+
})(KEY_PREFIX || (KEY_PREFIX = {}));
|
|
6
|
+
export class GamificationStorage extends Storage {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('gamification');
|
|
9
|
+
}
|
|
10
|
+
saveOnboardingStatus = ({ userId, eventId, organizationId }, status) => {
|
|
11
|
+
this.write(KEY_PREFIX.ONBOARDING, organizationId, userId, eventId, status);
|
|
12
|
+
};
|
|
13
|
+
getOnboardingStatus = ({ userId, eventId, organizationId }) => {
|
|
14
|
+
return this.read(KEY_PREFIX.ONBOARDING, organizationId, userId, eventId);
|
|
15
|
+
};
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamlayer/feature-gamification",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"@
|
|
6
|
-
"@
|
|
7
|
-
"
|
|
8
|
-
"@
|
|
9
|
-
"@streamlayer/
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"@streamlayer/sdk-web-
|
|
3
|
+
"version": "0.13.1",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@bufbuild/protobuf": "*",
|
|
6
|
+
"@streamlayer/sl-eslib": "*",
|
|
7
|
+
"nanostores": "*",
|
|
8
|
+
"@streamlayer/sdk-web-interfaces": "^0.16.1",
|
|
9
|
+
"@streamlayer/sdk-web-core": "^0.9.0",
|
|
10
|
+
"@streamlayer/sdk-web-api": "^0.17.0",
|
|
11
|
+
"@streamlayer/sdk-web-types": "^0.1.0",
|
|
12
|
+
"@streamlayer/sdk-web-storage": "^0.1.1",
|
|
13
|
+
"@streamlayer/sdk-web-notifications": "^0.7.0",
|
|
14
|
+
"@streamlayer/sdk-web-logger": "^0.3.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"tslib": "^2.6.2"
|
|
13
18
|
},
|
|
14
19
|
"type": "module",
|
|
15
|
-
"main": "./
|
|
16
|
-
"typings": "./
|
|
20
|
+
"main": "./lib/index.js",
|
|
21
|
+
"typings": "./lib/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": "./lib/index.js",
|
|
24
|
+
"./gamification": "./lib/gamification.js",
|
|
25
|
+
"./highlights": "./lib/highlights.js"
|
|
26
|
+
},
|
|
17
27
|
"files": [
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
28
|
+
"lib/",
|
|
29
|
+
"package.json"
|
|
30
|
+
]
|
|
31
|
+
}
|
package/src/index.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { AbstractFeature, ApiStore, FeatureSource, type FeatureProps } from '@streamlayer/sdk-web-interfaces';
|
|
2
|
-
import type { GetApiResponseType } from '@streamlayer/sdk-web-api';
|
|
3
|
-
type StreamLayerContext = any;
|
|
4
|
-
import type { PlainMessage } from '@bufbuild/protobuf';
|
|
5
|
-
import type { GamesOverlaySettings } from '@streamlayer/sl-eslib/sdkSettings/sdkSettings.common_pb';
|
|
6
|
-
import { ReadableAtom, WritableAtom } from 'nanostores';
|
|
7
|
-
import * as queries from './queries';
|
|
8
|
-
export declare class Gamification extends AbstractFeature<'games', PlainMessage<GamesOverlaySettings>> {
|
|
9
|
-
userSummary?: ApiStore<GetApiResponseType<typeof queries.$userSummary>>;
|
|
10
|
-
questions?: ApiStore<GetApiResponseType<typeof queries.$pickHistory>>;
|
|
11
|
-
leaderboardId: WritableAtom<string | undefined>;
|
|
12
|
-
slStreamId: ReadableAtom<string | undefined>;
|
|
13
|
-
userId: ReadableAtom<string | undefined>;
|
|
14
|
-
organizationId: ReadableAtom<string | undefined>;
|
|
15
|
-
openedQuestionId: WritableAtom<string | undefined>;
|
|
16
|
-
openedQuestion?: ApiStore<GetApiResponseType<typeof queries.$questionByUser>>;
|
|
17
|
-
activeQuestionId?: ApiStore<GetApiResponseType<typeof queries.$activeQuestion>>;
|
|
18
|
-
moderationId: ReadableAtom<string | undefined>;
|
|
19
|
-
feedId: ReadableAtom<string | undefined>;
|
|
20
|
-
onbordingComplete: WritableAtom<boolean | undefined>;
|
|
21
|
-
private notifications;
|
|
22
|
-
private transport;
|
|
23
|
-
constructor(config: FeatureProps, source: FeatureSource, instance: StreamLayerContext);
|
|
24
|
-
getCurrentSessionIdPrefix: (opts: {
|
|
25
|
-
prefix?: string;
|
|
26
|
-
userId?: string;
|
|
27
|
-
eventId?: string;
|
|
28
|
-
organizationId?: string;
|
|
29
|
-
}) => string;
|
|
30
|
-
connect: (transport: StreamLayerContext['transport']) => void;
|
|
31
|
-
submitInplay: () => Promise<void>;
|
|
32
|
-
submitAnswer: (questionId: string, answerId: string) => Promise<void>;
|
|
33
|
-
skipQuestion: (questionId: string) => Promise<void>;
|
|
34
|
-
openQuestion: (questionId: string) => void;
|
|
35
|
-
closeQuestion: () => void;
|
|
36
|
-
}
|
|
37
|
-
export {};
|
package/src/index.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { AbstractFeature, ApiStore, SingleStore, createSingleStore,
|
|
2
|
-
// type StreamLayerContext,
|
|
3
|
-
} from '@streamlayer/sdk-web-interfaces';
|
|
4
|
-
import { QuestionStatus } from '@streamlayer/sdk-web-types';
|
|
5
|
-
import * as queries from './queries';
|
|
6
|
-
import * as actions from './queries/actions';
|
|
7
|
-
export class Gamification extends AbstractFeature {
|
|
8
|
-
// user statistics (leaderboard panel)
|
|
9
|
-
userSummary;
|
|
10
|
-
// questions list (pick history)
|
|
11
|
-
questions;
|
|
12
|
-
// pinned leaderboard id
|
|
13
|
-
leaderboardId;
|
|
14
|
-
// sl event id
|
|
15
|
-
slStreamId;
|
|
16
|
-
// current user id
|
|
17
|
-
userId;
|
|
18
|
-
organizationId;
|
|
19
|
-
// opened question, using to download statistics
|
|
20
|
-
openedQuestionId;
|
|
21
|
-
// opened question statistics
|
|
22
|
-
openedQuestion;
|
|
23
|
-
// last active question in feed
|
|
24
|
-
activeQuestionId;
|
|
25
|
-
// moderation id
|
|
26
|
-
moderationId;
|
|
27
|
-
// feed id (deprecated?)
|
|
28
|
-
feedId;
|
|
29
|
-
// pinned leaderboard id
|
|
30
|
-
onbordingComplete;
|
|
31
|
-
notifications;
|
|
32
|
-
transport;
|
|
33
|
-
constructor(config, source, instance) {
|
|
34
|
-
super(config, source);
|
|
35
|
-
this.leaderboardId = new SingleStore(createSingleStore(this.settings.getValue('pinnedLeaderboardId')), 'pinnedLeaderboardId').getStore();
|
|
36
|
-
this.slStreamId = instance.stores.slStreamId.getAtomStore();
|
|
37
|
-
this.userId = instance.stores.user.getAtomStore();
|
|
38
|
-
this.organizationId = instance.stores.organizationSettings.getAtomStore();
|
|
39
|
-
this.moderationId = new SingleStore(createSingleStore(), 'moderationId').getStore();
|
|
40
|
-
this.feedId = new SingleStore(createSingleStore(), 'feedId').getStore();
|
|
41
|
-
this.onbordingComplete = new SingleStore(createSingleStore(false), 'onbordingComplete').getStore();
|
|
42
|
-
this.openedQuestionId = new SingleStore(createSingleStore(), 'openedQuestionId').getStore();
|
|
43
|
-
this.notifications = instance.notifications;
|
|
44
|
-
this.transport = instance.transport;
|
|
45
|
-
if (!this.userId.get()) {
|
|
46
|
-
this.userId.subscribe((userId) => {
|
|
47
|
-
if (userId) {
|
|
48
|
-
this.connect(instance.transport);
|
|
49
|
-
const cached = localStorage.getItem(`sl-onbording:${userId}:${this.slStreamId.get()}`);
|
|
50
|
-
this.onbordingComplete.set(!!cached);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
this.connect(instance.transport);
|
|
56
|
-
const userId = this.userId.get();
|
|
57
|
-
const cached = localStorage.getItem(`sl-onbording:${userId}:${this.slStreamId.get()}`);
|
|
58
|
-
this.onbordingComplete.set(!!cached);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
getCurrentSessionIdPrefix = (opts) => {
|
|
62
|
-
const eventId = opts.eventId || this.slStreamId.get();
|
|
63
|
-
const userId = opts.userId || this.userId.get();
|
|
64
|
-
const organizationId = opts.organizationId || this.organizationId.get();
|
|
65
|
-
return `${organizationId}:${userId}:${eventId}:${opts.prefix || ''}`;
|
|
66
|
-
};
|
|
67
|
-
connect = (transport) => {
|
|
68
|
-
this.userSummary = new ApiStore(queries.$userSummary(this.slStreamId, this.userId, transport), 'gamification:userSummary');
|
|
69
|
-
this.questions = new ApiStore(queries.$pickHistory(this.slStreamId, transport), 'gamification:questions');
|
|
70
|
-
this.activeQuestionId = new ApiStore(queries.$activeQuestion(this.slStreamId, transport), 'gamification:activeQuestionId');
|
|
71
|
-
this.openedQuestion = new ApiStore(queries.$questionByUser(this.openedQuestionId, transport), 'gamification:activeQuestionId');
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
-
let questionSubscription = undefined;
|
|
74
|
-
this.openedQuestionId.listen((questionId) => {
|
|
75
|
-
if (questionId) {
|
|
76
|
-
questionSubscription = queries.questionSubscription(questionId, transport);
|
|
77
|
-
questionSubscription.addListener('feed-subscription-opened-question', (response) => {
|
|
78
|
-
window.requestAnimationFrame(() => {
|
|
79
|
-
this.openedQuestion?.getStore().mutate(response.data?.attributes?.question);
|
|
80
|
-
this.openedQuestion?.getStore().invalidate();
|
|
81
|
-
this.userSummary?.getStore().invalidate();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
questionSubscription.connect();
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
console.log('cleanup on close question');
|
|
88
|
-
this.openedQuestion?.getStore().mutate(undefined);
|
|
89
|
-
if (questionSubscription !== undefined) {
|
|
90
|
-
transport.removeSubscription(questionSubscription);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
this.activeQuestionId?.listen((question) => {
|
|
95
|
-
if (question?.data?.notification?.title) {
|
|
96
|
-
if (question.data.question.status === QuestionStatus.ACTIVE) {
|
|
97
|
-
this.notifications.add({
|
|
98
|
-
id: this.getCurrentSessionIdPrefix({ prefix: `notification-id:${question.data.question.id}` }),
|
|
99
|
-
data: question.data,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
const feedSubscription = queries.feedSubscription(this.slStreamId, transport);
|
|
105
|
-
feedSubscription.addListener('feed-subscription-active-question', (response) => {
|
|
106
|
-
window.requestAnimationFrame(() => {
|
|
107
|
-
const $activeQuestionId = this.activeQuestionId?.getStore();
|
|
108
|
-
if ($activeQuestionId) {
|
|
109
|
-
$activeQuestionId.mutate(response.data?.attributes);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
feedSubscription.addListener('feed-subscription-questions-list', () => {
|
|
114
|
-
window.requestAnimationFrame(() => {
|
|
115
|
-
this.questions?.invalidate();
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
// onboarding
|
|
120
|
-
submitInplay = async () => {
|
|
121
|
-
const eventId = this.slStreamId.get();
|
|
122
|
-
if (eventId) {
|
|
123
|
-
await actions.submitInplay(this.transport, eventId);
|
|
124
|
-
this.onbordingComplete.set(true);
|
|
125
|
-
localStorage.setItem(`sl-onbording:${this.userId.get()}:${eventId}`, 'true');
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
submitAnswer = async (questionId, answerId) => {
|
|
129
|
-
await actions.submitAnswer(this.transport, { questionId, answerId });
|
|
130
|
-
this.questions?.invalidate();
|
|
131
|
-
};
|
|
132
|
-
skipQuestion = async (questionId) => {
|
|
133
|
-
await actions.skipQuestion(this.transport, questionId);
|
|
134
|
-
this.questions?.invalidate();
|
|
135
|
-
};
|
|
136
|
-
openQuestion = (questionId) => {
|
|
137
|
-
this.openedQuestionId.set(questionId);
|
|
138
|
-
this.notifications.markAsViewed(this.getCurrentSessionIdPrefix({ prefix: `notification-id:${questionId}` }));
|
|
139
|
-
};
|
|
140
|
-
closeQuestion = () => {
|
|
141
|
-
this.notifications.markAsViewed(this.getCurrentSessionIdPrefix({ prefix: `notification-id:${this.openedQuestionId.get()}` }));
|
|
142
|
-
window.requestAnimationFrame(() => {
|
|
143
|
-
this.openedQuestionId.set(undefined);
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/feature-gamification/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EAGR,WAAW,EACX,iBAAiB;AACjB,2BAA2B;EAC5B,MAAM,iCAAiC,CAAA;AAMxC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAU3D,OAAO,KAAK,OAAO,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAA;AAE5C,MAAM,OAAO,YAAa,SAAQ,eAA4D;IAC5F,sCAAsC;IAC/B,WAAW,CAA4D;IAC9E,gCAAgC;IACzB,SAAS,CAA4D;IAC5E,wBAAwB;IACjB,aAAa,CAAkC;IACtD,cAAc;IACP,UAAU,CAAkC;IACnD,kBAAkB;IACX,MAAM,CAAkC;IACxC,cAAc,CAAkC;IACvD,gDAAgD;IACzC,gBAAgB,CAAkC;IACzD,6BAA6B;IACtB,cAAc,CAA+D;IACpF,+BAA+B;IACxB,gBAAgB,CAA+D;IACtF,gBAAgB;IACT,YAAY,CAAkC;IACrD,wBAAwB;IACjB,MAAM,CAAkC;IAC/C,wBAAwB;IACjB,iBAAiB,CAAmC;IAEnD,aAAa,CAAqC;IAClD,SAAS,CAAiC;IAElD,YAAY,MAAoB,EAAE,MAAqB,EAAE,QAA4B;QACnF,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAErB,IAAI,CAAC,aAAa,GAAG,IAAI,WAAW,CAClC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAW,CAAC,EAC1E,qBAAqB,CACtB,CAAC,QAAQ,EAAE,CAAA;QACZ,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,CAAA;QAC3D,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,CAAA;QACjD,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,YAAY,EAAE,CAAA;QACzE,IAAI,CAAC,YAAY,GAAG,IAAI,WAAW,CAAC,iBAAiB,EAAsB,EAAE,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAA;QACvG,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,iBAAiB,EAAsB,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3F,IAAI,CAAC,iBAAiB,GAAG,IAAI,WAAW,CAAC,iBAAiB,CAAU,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC3G,IAAI,CAAC,gBAAgB,GAAG,IAAI,WAAW,CAAC,iBAAiB,EAAsB,EAAE,kBAAkB,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC/G,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAA;QAC3C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAA;QAEnC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE;YACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC/B,IAAI,MAAM,EAAE;oBACV,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;oBAEhC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,gBAAgB,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;oBAEtF,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;iBACrC;YACH,CAAC,CAAC,CAAA;SACH;aAAM;YACL,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAA;YAEhC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,gBAAgB,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;YAEtF,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;SACrC;IACH,CAAC;IAED,yBAAyB,GAAG,CAAC,IAK5B,EAAE,EAAE;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAA;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAA;QAC/C,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAA;QAEvE,OAAO,GAAG,cAAc,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAA;IACtE,CAAC,CAAA;IAED,OAAO,GAAG,CAAC,SAA0C,EAAE,EAAE;QACvD,IAAI,CAAC,WAAW,GAAG,IAAI,QAAQ,CAC7B,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAC7D,0BAA0B,CAC3B,CAAA;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,QAAQ,CAC3B,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,EAChD,wBAAwB,CACzB,CAAA;QAED,IAAI,CAAC,gBAAgB,GAAG,IAAI,QAAQ,CAClC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,EACnD,+BAA+B,CAChC,CAAA;QAED,IAAI,CAAC,cAAc,GAAG,IAAI,QAAQ,CAChC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,EACzD,+BAA+B,CAChC,CAAA;QAED,8DAA8D;QAC9D,IAAI,oBAAoB,GAAQ,SAAS,CAAA;QAEzC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;YAC1C,IAAI,UAAU,EAAE;gBACd,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;gBAC1E,oBAAoB,CAAC,WAAW,CAC9B,mCAAmC,EACnC,CAAC,QAAsC,EAAE,EAAE;oBACzC,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;wBAChC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;wBAC3E,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,CAAA;wBAC5C,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,CAAA;oBAC3C,CAAC,CAAC,CAAA;gBACJ,CAAC,CACF,CAAA;gBACD,oBAAoB,CAAC,OAAO,EAAE,CAAA;aAC/B;iBAAM;gBACL,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;gBACxC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;gBACjD,IAAI,oBAAoB,KAAK,SAAS,EAAE;oBACtC,SAAS,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,CAAA;iBACnD;aACF;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzC,IAAI,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE;gBACvC,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,EAAE;oBAC3D,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;wBACrB,EAAE,EAAE,IAAI,CAAC,yBAAyB,CAAC,EAAE,MAAM,EAAE,mBAAmB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;wBAC9F,IAAI,EAAE,QAAQ,CAAC,IAAI;qBACpB,CAAC,CAAA;iBACH;aACF;QACH,CAAC,CAAC,CAAA;QAEF,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAE7E,gBAAgB,CAAC,WAAW,CAAC,mCAAmC,EAAE,CAAC,QAA8B,EAAE,EAAE;YACnG,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;gBAChC,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,QAAQ,EAAE,CAAA;gBAE3D,IAAI,iBAAiB,EAAE;oBACrB,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;iBACpD;YACH,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,gBAAgB,CAAC,WAAW,CAAC,kCAAkC,EAAE,GAAG,EAAE;YACpE,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;gBAChC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAA;YAC9B,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,aAAa;IACb,YAAY,GAAG,KAAK,IAAI,EAAE;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAA;QAErC,IAAI,OAAO,EAAE;YACX,MAAM,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;YACnD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAChC,YAAY,CAAC,OAAO,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;SAC7E;IACH,CAAC,CAAA;IAED,YAAY,GAAG,KAAK,EAAE,UAAkB,EAAE,QAAgB,EAAE,EAAE;QAC5D,MAAM,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;QACpE,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAA;IAC9B,CAAC,CAAA;IAED,YAAY,GAAG,KAAK,EAAE,UAAkB,EAAE,EAAE;QAC1C,MAAM,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAA;IAC9B,CAAC,CAAA;IAED,YAAY,GAAG,CAAC,UAAkB,EAAE,EAAE;QACpC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACrC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,yBAAyB,CAAC,EAAE,MAAM,EAAE,mBAAmB,UAAU,EAAE,EAAE,CAAC,CAAC,CAAA;IAC9G,CAAC,CAAA;IAED,aAAa,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,aAAa,CAAC,YAAY,CAC7B,IAAI,CAAC,yBAAyB,CAAC,EAAE,MAAM,EAAE,mBAAmB,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAC7F,CAAA;QAED,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../../../packages/feature-gamification/src/queries/actions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,iEAAiE,CAAA;AAEtF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAoB,EAAE,IAA8C,EAAE,EAAE;IACnG,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAElF,OAAO,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;AACtC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAoB,EAAE,OAAe,EAAE,EAAE;IACpE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAElF,OAAO,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;AAC7D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAoB,EAAE,UAAkB,EAAE,EAAE;IACvE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;IAElF,OAAO,MAAM,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;AAC1D,CAAC,CAAA"}
|
package/src/queries/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/feature-gamification/src/queries/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"leaderboard.js","sourceRoot":"","sources":["../../../../../packages/feature-gamification/src/queries/leaderboard.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,+EAA+E,CAAA;AAE3G,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,QAA0C,EAC1C,OAAyC,EACzC,SAAoB,EACpB,EAAE;IACF,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,WAAW,EAAE;QACtE,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC5B,CAAC,CAAA;IAEF,OAAO,SAAS,CAAC,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE;QACtD,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;gBAC/B,OAAO,EAAE,OAA4B;gBACrC,MAAM,EAAE,MAAgB;aACzB,CAAC,CAAA;YAEF,OAAO,GAAG,CAAC,IAAI,EAAE,UAAU,CAAA;QAC7B,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"moderation.js","sourceRoot":"","sources":["../../../../../packages/feature-gamification/src/queries/moderation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,iEAAiE,CAAA;AAEtF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,UAA4C,EAAE,SAAoB,EAAE,EAAE;IAChG,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IAEzG,OAAO,SAAS,CAAC,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE;QACtD,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;YAC3B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC;gBAC3B,OAAO,EAAE,EAAY;aACtB,CAAC,CAAA;YAEF,OAAO,GAAG,CAAC,IAAI,EAAE,UAAU,CAAA;QAC7B,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|