@streamlayer/feature-gamification 0.33.5 → 0.34.0

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/background.js CHANGED
@@ -71,6 +71,16 @@ export class GamificationBackground {
71
71
  }
72
72
  });
73
73
  });
74
+ // refresh moderation if question empty, it`s mean that moderation was changed
75
+ this.feedSubscription.addListener('moderation update', (response) => {
76
+ window.requestAnimationFrame(() => {
77
+ if (response.data?.attributes?.question === undefined) {
78
+ if (response.data?.attributes?.moderation) {
79
+ this.moderation.invalidate();
80
+ }
81
+ }
82
+ });
83
+ });
74
84
  this.feedSubscription.connect();
75
85
  }
76
86
  /**
package/lib/deepLink.js CHANGED
@@ -9,7 +9,17 @@ export const deepLink = (transport, $eventId, $userId) => {
9
9
  const mobileDeepLink = error ? 'https://masters.com' : data?.url;
10
10
  if (!loading && mobileDeepLink) {
11
11
  $store.setKey('loading', true);
12
- const desktopLink = `${window.location.host + window.location.pathname}%23sl_eid=${$eventId.get()}&sl_uid=${$userId.get()}`;
12
+ let search = window.location.search;
13
+ let hash = window.location.hash;
14
+ if ((search && hash) || hash) {
15
+ const params = new URLSearchParams(search);
16
+ params.append('slprms', `sl_eid=${$eventId.get()}:sl_uid=${$userId.get()}`);
17
+ search = `?${params.toString()}`;
18
+ }
19
+ else {
20
+ hash = `#slprms::${`sl_eid=${$eventId.get()}:sl_uid=${$userId.get()}`}`;
21
+ }
22
+ const desktopLink = window.location.origin + window.location.pathname + search + hash;
13
23
  const shortLink = await generateShortLink(transport, { web: desktopLink, mobile: mobileDeepLink });
14
24
  $store.set({
15
25
  data: shortLink.data?.link,
package/lib/detail.js CHANGED
@@ -22,8 +22,9 @@ const mergeQuestion = deepmerge({ mergeArray });
22
22
  export const detail = (transport, $openedQuestionId, $feedList) => {
23
23
  const $store = computed([$openedQuestionId, $feedList], (openedQuestion, feedList) => {
24
24
  if (openedQuestion) {
25
- if (feedList.data) {
26
- return feedList.data.find((item) => item.id === openedQuestion);
25
+ const question = feedList.data?.find((item) => item.id === openedQuestion);
26
+ if (question) {
27
+ return question;
27
28
  }
28
29
  else {
29
30
  console.error('Feed list is not loaded yet. Issue with the opened question.');
@@ -36,6 +37,7 @@ export const detail = (transport, $openedQuestionId, $feedList) => {
36
37
  loading: undefined,
37
38
  error: undefined,
38
39
  });
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
41
  $store.subscribe(async (item) => {
40
42
  if (item) {
41
43
  if (item.type === 'question') {
@@ -49,13 +51,13 @@ export const detail = (transport, $openedQuestionId, $feedList) => {
49
51
  });
50
52
  const updateExtendedQuestion = (question) => {
51
53
  const currentQuestion = $extendedStore.get().data;
52
- if (currentQuestion) {
54
+ if (currentQuestion && question?.answers) {
53
55
  /**
54
56
  * We do not merge youVoted property, because it
55
57
  * can be overwritten by the subscription response,
56
58
  * which does not include user-specific data.
57
59
  */
58
- for (const answer of question?.answers || []) {
60
+ for (const answer of question.answers) {
59
61
  if (answer.youVoted !== true) {
60
62
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
61
63
  // @ts-ignore
@@ -81,27 +81,26 @@ export class Gamification extends AbstractFeature {
81
81
  question.data.question?.bypassNotifications?.inAppSilence !== SilenceSetting.ON &&
82
82
  question.data.question.status === QuestionStatus.ACTIVE) {
83
83
  if (GamificationQuestionTypes.has(question.data.question.type)) {
84
+ const onboardingEnabled = this.background.moderation.getStore().value?.data?.options?.onboardingEnabled;
84
85
  const optInEnabled = this.settings.getValues().inplayGame?.titleCard?.optIn;
85
86
  const onboardingCompleted = onboardingStatus === OnboardingStatus.Completed;
86
- if (optInEnabled !== undefined) {
87
- if (!optInEnabled || onboardingCompleted) {
88
- this.notifications.add({
89
- type: NotificationType.QUESTION,
90
- action: () => question.data?.question && this.openQuestion(question.data.question.id),
91
- close: () => question.data?.question && this.closeQuestion(question.data.question.id),
92
- autoHideDuration: 1000 * 60,
93
- id: this.background.getCurrentSessionId({
94
- prefix: 'notification',
95
- entity: question.data.question.id,
96
- }),
97
- data: {
98
- questionType: question.data.question.type,
99
- question: {
100
- title: question.data.question.notification.title,
101
- },
87
+ if (!onboardingEnabled || onboardingCompleted || optInEnabled !== true) {
88
+ this.notifications.add({
89
+ type: NotificationType.QUESTION,
90
+ action: () => question.data?.question && this.openQuestion(question.data.question.id),
91
+ close: () => question.data?.question && this.closeQuestion(question.data.question.id),
92
+ autoHideDuration: 1000 * 60,
93
+ id: this.background.getCurrentSessionId({
94
+ prefix: 'notification',
95
+ entity: question.data.question.id,
96
+ }),
97
+ data: {
98
+ questionType: question.data.question.type,
99
+ question: {
100
+ title: question.data.question.notification.title,
102
101
  },
103
- });
104
- }
102
+ },
103
+ });
105
104
  }
106
105
  }
107
106
  else if (question.data.question.type === QuestionType.FACTOID) {
@@ -226,6 +225,10 @@ export class Gamification extends AbstractFeature {
226
225
  };
227
226
  openQuestion = (questionId) => {
228
227
  this.openFeature();
228
+ this.notifications.close(this.background.getCurrentSessionId({
229
+ prefix: 'notification',
230
+ entity: questionId,
231
+ }));
229
232
  return this.background.openQuestion(questionId);
230
233
  };
231
234
  closeQuestion = (questionId) => {
package/lib/onboarding.js CHANGED
@@ -22,6 +22,7 @@ export var OnboardingStatus;
22
22
  const showOnboardingInApp = (service, background, notifications, storage) => {
23
23
  const { inplayGame } = service.featureSettings.get();
24
24
  const notificationId = background.getCurrentSessionId({ prefix: 'onboarding' });
25
+ // type safe check
25
26
  if (inplayGame) {
26
27
  notifications.add({
27
28
  type: NotificationType.ONBOARDING,
@@ -30,12 +31,10 @@ const showOnboardingInApp = (service, background, notifications, storage) => {
30
31
  close: () => {
31
32
  notifications.markAsViewed(notificationId);
32
33
  },
33
- delay: 1000,
34
+ persistent: true,
34
35
  autoHideDuration: 1000000,
35
36
  data: {
36
37
  questionType: QuestionType.UNSET,
37
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
38
- // @ts-ignore
39
38
  onboarding: {
40
39
  ...inplayGame,
41
40
  instantOpen: !storage.getOnboardingInstantOpen({
@@ -52,7 +51,7 @@ const showOnboardingInApp = (service, background, notifications, storage) => {
52
51
  * check onboarding status, sync with browser cache
53
52
  * retrieve onboarding settings from api
54
53
  */
55
- const onboardingProcess = ($store, background, service, storage, listeners) => {
54
+ const onboardingProcess = ($store, background, service, notifications, storage, listeners) => {
56
55
  try {
57
56
  const userId = background.userId.get();
58
57
  if (!userId) {
@@ -75,8 +74,8 @@ const onboardingProcess = ($store, background, service, storage, listeners) => {
75
74
  if (moderation === undefined || inplayGame === undefined) {
76
75
  return;
77
76
  }
78
- const onboardingEnabled = !!moderation?.options?.onboardingEnabled && inplayGame?.enable;
79
- const optIn = !!inplayGame?.titleCard?.optIn;
77
+ const onboardingEnabled = moderation?.options?.onboardingEnabled;
78
+ const optIn = inplayGame?.titleCard?.optIn;
80
79
  if (onboardingEnabled) {
81
80
  if (optIn) {
82
81
  $store.set(OnboardingStatus.Required);
@@ -92,6 +91,8 @@ const onboardingProcess = ($store, background, service, storage, listeners) => {
92
91
  else {
93
92
  $store.set(OnboardingStatus.Disabled);
94
93
  }
94
+ // close previous onboarding notification, f.e moderation was disabled onboarding
95
+ notifications.close(background.getCurrentSessionId({ prefix: 'onboarding' }), false);
95
96
  }
96
97
  }
97
98
  catch (error) {
@@ -118,21 +119,21 @@ export const onboarding = (service, background, transport, notifications) => {
118
119
  });
119
120
  });
120
121
  const listeners = [];
121
- onboardingProcess($store, background, service, storage, listeners);
122
+ onboardingProcess($store, background, service, notifications, storage, listeners);
122
123
  if ($store.get() !== OnboardingStatus.Completed) {
123
124
  listeners.push(background.userId.listen((userId) => {
124
125
  if (userId) {
125
- void onboardingProcess($store, background, service, storage, listeners);
126
+ onboardingProcess($store, background, service, notifications, storage, listeners);
126
127
  }
127
128
  }));
128
129
  listeners.push(background.moderation.listen((value) => {
129
130
  if (value.data) {
130
- void onboardingProcess($store, background, service, storage, listeners);
131
+ onboardingProcess($store, background, service, notifications, storage, listeners);
131
132
  }
132
133
  }));
133
134
  listeners.push(service.featureSettings.listen((value) => {
134
135
  if (value) {
135
- void onboardingProcess($store, background, service, storage, listeners);
136
+ onboardingProcess($store, background, service, notifications, storage, listeners);
136
137
  }
137
138
  }));
138
139
  }
@@ -6,5 +6,5 @@ export declare const $deepLink: (transport: Transport, params: [EventId]) => imp
6
6
  export declare const generateShortLink: (transport: Transport, { web, mobile }: {
7
7
  web: string;
8
8
  mobile: string;
9
- }) => Promise<import("@streamlayer/sl-eslib/shortLinks/client_pb").GenerateResponse>;
9
+ }) => Promise<import("@streamlayer/sl-eslib/shortLinks/linksClient_pb").GenerateResponse>;
10
10
  export {};
@@ -1,5 +1,5 @@
1
1
  import { Client } from '@streamlayer/sl-eslib/sdkSettings/client/client_connect';
2
- import { Client as ShortLinkClient } from '@streamlayer/sl-eslib/shortLinks/client_connect';
2
+ import { LinksClient } from '@streamlayer/sl-eslib/shortLinks/linksClient_connect';
3
3
  export const $deepLink = (transport, params) => {
4
4
  const { client, queryKey } = transport.createPromiseClient(Client, {
5
5
  method: 'generateDeepLink',
@@ -16,6 +16,6 @@ export const $deepLink = (transport, params) => {
16
16
  });
17
17
  };
18
18
  export const generateShortLink = (transport, { web, mobile }) => {
19
- const { client } = transport.createPromiseClient(ShortLinkClient, { method: 'generate' });
19
+ const { client } = transport.createPromiseClient(LinksClient, { method: 'generate' });
20
20
  return client.generate({ web, mobile });
21
21
  };
@@ -327,6 +327,7 @@ export declare const questionSubscription: (questionId: string, transport: Trans
327
327
  };
328
328
  }, QuestionSubscriptionRequest, QuestionSubscriptionResponse, "subscription" | "votingSubscription" | "questionSubscription" | "feedSubscription", ((request: import("@bufbuild/protobuf").PartialMessage<SubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions | undefined) => AsyncIterable<SubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<VotingSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions | undefined) => AsyncIterable<VotingSubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<QuestionSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions | undefined) => AsyncIterable<QuestionSubscriptionResponse>) | ((request: import("@bufbuild/protobuf").PartialMessage<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedSubscriptionRequest>, options?: import("@connectrpc/connect").CallOptions | undefined) => AsyncIterable<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedSubscriptionResponse>)>;
329
329
  export declare const getQuestionByUser: (questionId: string, transport: Transport) => Promise<import("@streamlayer/sdk-web-types").ExtendedQuestion | undefined>;
330
+ export declare const getQuestionDetail: (questionId: string, transport: Transport) => Promise<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").Question | undefined>;
330
331
  export declare const $questionByUser: ($questionId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sdk-web-types").ExtendedQuestion | undefined, any>;
331
332
  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>;
332
333
  export declare const $feedList: (slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").FeedItem[], any>;
@@ -43,6 +43,13 @@ export const getQuestionByUser = async (questionId, transport) => {
43
43
  });
44
44
  return res.data?.attributes?.question;
45
45
  };
46
+ export const getQuestionDetail = async (questionId, transport) => {
47
+ const { client } = transport.createPromiseClient(Feed, { method: 'getQuestion', params: [questionId] });
48
+ const res = await client.getQuestion({
49
+ id: questionId,
50
+ });
51
+ return res.data?.attributes;
52
+ };
46
53
  export const $questionByUser = ($questionId, transport) => {
47
54
  const { client, queryKey } = transport.createPromiseClient(Feed, { method: 'questionByUser', params: [$questionId] });
48
55
  return transport.nanoquery.createFetcherStore(queryKey, {
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@streamlayer/feature-gamification",
3
- "version": "0.33.5",
3
+ "version": "0.34.0",
4
4
  "peerDependencies": {
5
- "@bufbuild/protobuf": "^1.4.2",
6
- "@streamlayer/sl-eslib": "^5.61.1",
5
+ "@bufbuild/protobuf": "^1.6.0",
7
6
  "@fastify/deepmerge": "*",
7
+ "@streamlayer/sl-eslib": "^5.63.3",
8
8
  "nanostores": "^0.9.5",
9
- "@streamlayer/sdk-web-api": "^0.1.0",
10
- "@streamlayer/sdk-web-core": "^0.0.1",
9
+ "@streamlayer/sdk-web-api": "^0.18.0",
10
+ "@streamlayer/sdk-web-core": "^0.17.8",
11
11
  "@streamlayer/sdk-web-interfaces": "^0.18.21",
12
- "@streamlayer/sdk-web-logger": "^0.0.1",
13
- "@streamlayer/sdk-web-notifications": "^0.0.6",
14
- "@streamlayer/sdk-web-storage": "^0.0.4",
15
- "@streamlayer/sdk-web-types": "^0.1.0"
12
+ "@streamlayer/sdk-web-logger": "^0.5.10",
13
+ "@streamlayer/sdk-web-notifications": "^0.13.4",
14
+ "@streamlayer/sdk-web-storage": "^0.3.10",
15
+ "@streamlayer/sdk-web-types": "^0.20.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "tslib": "^2.6.2"