@streamlayer/feature-gamification 1.16.10 → 1.16.12

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
@@ -4,7 +4,6 @@ import { QuestionStatus, QuestionType } from '@streamlayer/sdk-web-types';
4
4
  import '@streamlayer/sdk-web-core/store';
5
5
  import * as queries from './queries';
6
6
  import { detail } from './detail';
7
- import { advertisement } from './advertisement';
8
7
  import { GamificationStorage } from './storage';
9
8
  export var InteractiveAllowed;
10
9
  (function (InteractiveAllowed) {
@@ -68,32 +67,50 @@ export class GamificationBackground {
68
67
  this.cancels.add(this.openedQuestionId.listen((item) => {
69
68
  this.log.debug({ item }, 'received question');
70
69
  if (item?.questionId) {
70
+ this.log.info('cleanup on close question');
71
+ if (this.questionSubscription !== undefined) {
72
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
+ instance.transport.removeSubscription(this.questionSubscription);
74
+ this.questionSubscription = undefined;
75
+ }
71
76
  this.questionSubscription = queries.questionSubscription(item.questionId, instance.transport);
72
- this.questionSubscription.addListener('feed-subscription-opened-question', async (response) => {
77
+ this.questionSubscription.addListener('feed-subscription-opened-question', (response) => {
73
78
  const question = response.data?.attributes?.question;
74
79
  this.openedQuestion.updateExtendedQuestion(question);
75
- if (question?.type === QuestionType.PREDICTION &&
80
+ if (this.betPack &&
81
+ question?.type === QuestionType.PREDICTION &&
76
82
  (question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
77
83
  const betPackData = this.betPack.getValues().data?.data || {};
78
84
  const betPackItem = betPackData?.[question.id];
79
- if (betPackItem || Object.keys(betPackData).length < 5) {
80
- const data = queries.$questionByUser(question.id, this.transport);
81
- const cancel = data.subscribe(() => { });
82
- await data.get().promise;
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
- }
88
- cancel();
89
- window.requestAnimationFrame(() => {
90
- data.invalidate();
85
+ if (betPackItem) {
86
+ const answers = [];
87
+ const sortedPrev = betPackItem.answers.sort((a, b) => {
88
+ return a.id > b.id ? 1 : -1;
91
89
  });
90
+ const sortedNew = question.answers.sort((a, b) => {
91
+ return a.id > b.id ? 1 : -1;
92
+ });
93
+ for (let i = 0; i < sortedPrev.length; i++) {
94
+ answers.push({
95
+ ...sortedPrev[i],
96
+ ...sortedNew[i],
97
+ correct: sortedPrev[i].correct,
98
+ youVoted: sortedPrev[i].youVoted,
99
+ pointsEarned: sortedPrev[i].pointsEarned,
100
+ });
101
+ }
92
102
  this.betPack.getStore().mutate({
93
103
  timestamp: Date.now(),
94
104
  data: {
95
105
  ...betPackData,
96
- [question.id]: extendedQuestion,
106
+ [question.id]: {
107
+ ...betPackItem,
108
+ status: question.status,
109
+ marketClosed: question.marketClosed,
110
+ activatedAt: question.activatedAt,
111
+ answerSetAt: question.answerSetAt,
112
+ answers,
113
+ },
97
114
  },
98
115
  });
99
116
  }
@@ -113,25 +130,28 @@ export class GamificationBackground {
113
130
  this.feedSubscription = queries.feedSubscription(this.slStreamId, instance.transport);
114
131
  this.cancels.add(this.feedSubscription.addListener('bet-pack-update', async (response) => {
115
132
  const question = response.data?.attributes?.question;
116
- if (question?.type === QuestionType.PREDICTION &&
133
+ if (this.betPack &&
134
+ question?.type === QuestionType.PREDICTION &&
117
135
  (question.status === QuestionStatus.ACTIVE || question.status === QuestionStatus.RESOLVED)) {
118
136
  const betPackData = this.betPack.getValues().data?.data || {};
119
137
  const betPackItem = betPackData?.[question.id];
120
- if (betPackItem || Object.keys(betPackData).length < 5) {
121
- const data = queries.$questionByUser(question.id, this.transport);
122
- // order of operations is important here
123
- const cancel = data.subscribe(() => { });
124
- await data.get().promise;
125
- // if question is not in the feed list, get extended question data from the server
126
- let extendedQuestion = data.get().data;
127
- if (!extendedQuestion) {
128
- extendedQuestion = await queries.questionByUser(question.id, this.transport);
129
- }
130
- cancel();
131
- window.requestAnimationFrame(() => {
132
- data.invalidate();
138
+ if (betPackItem) {
139
+ this.betPack.getStore().mutate({
140
+ timestamp: Date.now(),
141
+ data: {
142
+ ...betPackData,
143
+ [question.id]: {
144
+ ...betPackItem,
145
+ status: question.status,
146
+ marketClosed: question.marketClosed,
147
+ activatedAt: question.activatedAt,
148
+ answerSetAt: question.answerSetAt,
149
+ },
150
+ },
133
151
  });
134
- // get extended question data and mark as dirty
152
+ }
153
+ else if (!betPackItem && Object.keys(betPackData).length < 5) {
154
+ const extendedQuestion = await queries.questionByUser(question.id, this.transport);
135
155
  this.betPack.getStore().mutate({
136
156
  timestamp: Date.now(),
137
157
  data: {
@@ -215,7 +235,7 @@ export class GamificationBackground {
215
235
  };
216
236
  });
217
237
  if (!onlyBetPack) {
218
- this.advertisement = advertisement(this.slStreamId, this.feedSubscription, instance);
238
+ // this.advertisement = advertisement(this.slStreamId, this.feedSubscription, instance)
219
239
  }
220
240
  }
221
241
  /**
package/lib/detail.js CHANGED
@@ -22,16 +22,24 @@ export const detail = (transport, $openedQuestionId, $feedList) => {
22
22
  const currentQuestion = $extendedStore.get().data;
23
23
  const mergeQuestionAnswers = (currentAnswers, newAnswers) => {
24
24
  if (!currentAnswers || !newAnswers) {
25
- return currentAnswers || newAnswers || [];
25
+ return (currentAnswers || newAnswers || []).sort((a, b) => {
26
+ return a.id > b.id ? 1 : -1;
27
+ });
26
28
  }
29
+ const sortedPrev = currentAnswers.sort((a, b) => {
30
+ return a.id > b.id ? 1 : -1;
31
+ });
32
+ const sortedNew = newAnswers.sort((a, b) => {
33
+ return a.id > b.id ? 1 : -1;
34
+ });
27
35
  const answers = [];
28
- for (let i = 0; i < currentAnswers.length; i++) {
36
+ for (let i = 0; i < sortedPrev.length; i++) {
29
37
  answers.push({
30
- ...currentAnswers[i],
31
- ...newAnswers[i],
32
- correct: currentAnswers[i].correct,
33
- youVoted: currentAnswers[i].youVoted,
34
- pointsEarned: currentAnswers[i].pointsEarned,
38
+ ...sortedPrev[i],
39
+ ...sortedNew[i],
40
+ correct: sortedPrev[i].correct,
41
+ youVoted: sortedPrev[i].youVoted,
42
+ pointsEarned: sortedPrev[i].pointsEarned,
35
43
  });
36
44
  }
37
45
  return answers;
@@ -190,6 +190,7 @@ export class Gamification extends AbstractFeature {
190
190
  let extendedQuestion = data.get().data;
191
191
  if (!extendedQuestion) {
192
192
  extendedQuestion = await questionByUser(id, this.transport);
193
+ data.mutate(extendedQuestion);
193
194
  }
194
195
  cancel();
195
196
  window.requestAnimationFrame(() => {
@@ -301,7 +302,12 @@ export class Gamification extends AbstractFeature {
301
302
  status: prev.attributes.attributes.value.status,
302
303
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
303
304
  // @ts-ignore
304
- openForVoting: prev.attributes.attributes.value.openForVoting,
305
+ openForVoting:
306
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
307
+ // @ts-ignore
308
+ prev.attributes.attributes.value.openForVoting === false
309
+ ? false
310
+ : feedItem.attributes.attributes.value.openForVoting,
305
311
  },
306
312
  },
307
313
  },
@@ -348,6 +354,9 @@ export class Gamification extends AbstractFeature {
348
354
  this.background.feedSubscription.removeListener('feed-subscription-questions-list');
349
355
  };
350
356
  betPackVote = async (questionId, answerId) => {
357
+ if (!this.betPack) {
358
+ return;
359
+ }
351
360
  try {
352
361
  await actions.submitAnswer(this.transport, { questionId, answerId });
353
362
  }
@@ -461,6 +470,10 @@ export class Gamification extends AbstractFeature {
461
470
  return () => { };
462
471
  }
463
472
  const openedFromBetPack = question?.openedFrom === 'bet-pack';
473
+ if (!openedFromBetPack) {
474
+ const query = queries.$questionByUser(questionId, this.transport);
475
+ query.invalidate();
476
+ }
464
477
  this.notifications.close(this.background.getCurrentSessionId({
465
478
  prefix: 'notification',
466
479
  entity: questionId,
@@ -21,7 +21,7 @@ export const $deepLink = (transport, params) => {
21
21
  }
22
22
  },
23
23
  dedupeTime: 1000 * 60 * 60 * 24, // 24 hours
24
- refetchInterval: 0,
24
+ refetchInterval: Infinity,
25
25
  });
26
26
  };
27
27
  export const generateShortLink = (transport, { web, mobile }) => {
@@ -24,7 +24,7 @@ export const $activeQuestion = (slStreamId, onlyBetPack, transport) => {
24
24
  return res.data?.attributes;
25
25
  },
26
26
  dedupeTime: 1000 * 60 * 10, // 10 minutes
27
- refetchInterval: 0,
27
+ refetchInterval: Infinity,
28
28
  });
29
29
  };
30
30
  export const getFeedItem = async (questionId, transport) => {
@@ -67,17 +67,29 @@ export const questionByUser = async ($questionId, transport) => {
67
67
  });
68
68
  return res.data?.attributes?.question;
69
69
  };
70
+ const storeCache = new Map();
70
71
  export const $questionByUser = ($questionId, transport) => {
71
- const { client, queryKey } = transport.createPromiseClient(Feed, { method: 'questionByUser', params: [$questionId] });
72
- return transport.nanoquery.createFetcherStore(queryKey, {
73
- fetcher: async (_, __, questionId) => {
74
- const res = await client.questionByUser({
75
- questionId: questionId,
76
- });
77
- return res.data?.attributes?.question;
78
- },
79
- dedupeTime: 1000 * 60 * 5,
72
+ const { client, queryKey, queryKeyStr } = transport.createPromiseClient(Feed, {
73
+ method: 'questionByUser',
74
+ params: [$questionId],
80
75
  });
76
+ if (storeCache.has(queryKeyStr)) {
77
+ return storeCache.get(queryKeyStr);
78
+ }
79
+ else {
80
+ const store = transport.nanoquery.createFetcherStore(queryKey, {
81
+ fetcher: async (_, __, questionId) => {
82
+ const res = await client.questionByUser({
83
+ questionId: questionId,
84
+ });
85
+ return res.data?.attributes?.question;
86
+ },
87
+ dedupeTime: Infinity,
88
+ refetchInterval: Infinity,
89
+ });
90
+ storeCache.set(queryKeyStr, store);
91
+ return store;
92
+ }
81
93
  };
82
94
  export const getPromotionDetail = async (promoId, transport) => {
83
95
  if (!promoId) {
@@ -146,8 +158,8 @@ export const $feedList = ($slStreamId, $interactiveAllowed, $slUserId, $slOrgani
146
158
  }
147
159
  return res.data;
148
160
  },
149
- dedupeTime: 0,
150
- refetchInterval: 0,
161
+ dedupeTime: Infinity,
162
+ refetchInterval: Infinity,
151
163
  });
152
164
  };
153
165
  export const $activePromotionId = ($slStreamId, transport) => {
@@ -177,8 +189,8 @@ export const $activePromotionId = ($slStreamId, transport) => {
177
189
  }
178
190
  return undefined;
179
191
  },
180
- dedupeTime: 0,
181
- refetchInterval: 0,
192
+ dedupeTime: Infinity,
193
+ refetchInterval: Infinity,
182
194
  });
183
195
  };
184
196
  export { $userSummary, $leaderboardList } from './leaderboard';
@@ -235,11 +247,14 @@ export const $betPack = ($slStreamId, $slUserId, $slOrganizationId, storage, tra
235
247
  });
236
248
  storage.saveQuestionReceived(flags, question.id);
237
249
  }
250
+ question.answers = question.answers.sort((a, b) => {
251
+ return a.id > b.id ? 1 : -1;
252
+ });
238
253
  return { ...acc, [question.id]: question };
239
254
  }, {}),
240
255
  };
241
256
  },
242
- dedupeTime: 0,
243
- refetchInterval: 0,
257
+ dedupeTime: Infinity,
258
+ refetchInterval: Infinity,
244
259
  });
245
260
  };
@@ -8,7 +8,7 @@ export const $moderation = (slStreamId, transport) => {
8
8
  });
9
9
  return res.data?.attributes;
10
10
  },
11
- refetchInterval: 0,
11
+ refetchInterval: Infinity,
12
12
  dedupeTime: 1000 * 60 * 60,
13
13
  });
14
14
  };
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@streamlayer/feature-gamification",
3
- "version": "1.16.10",
3
+ "version": "1.16.12",
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
8
  "uuid": "^11.1.0",
9
9
  "nanostores": "^0.11.4",
10
- "@streamlayer/sdk-web-api": "^1.8.10",
11
- "@streamlayer/sdk-web-core": "^1.11.12",
12
- "@streamlayer/sdk-web-interfaces": "^1.5.1",
13
- "@streamlayer/sdk-web-logger": "^1.0.57",
14
- "@streamlayer/sdk-web-notifications": "^1.3.19",
15
- "@streamlayer/sdk-web-storage": "^1.0.57",
16
- "@streamlayer/sdk-web-types": "^1.10.14"
10
+ "@streamlayer/sdk-web-api": "^1.8.12",
11
+ "@streamlayer/sdk-web-core": "^1.11.14",
12
+ "@streamlayer/sdk-web-interfaces": "^1.5.3",
13
+ "@streamlayer/sdk-web-logger": "^1.0.59",
14
+ "@streamlayer/sdk-web-notifications": "^1.3.21",
15
+ "@streamlayer/sdk-web-storage": "^1.0.59",
16
+ "@streamlayer/sdk-web-types": "^1.10.16"
17
17
  },
18
18
  "devDependencies": {
19
19
  "tslib": "^2.7.0"