@streamlayer/feature-gamification
Advanced tools
Comparing version
@@ -54,26 +54,27 @@ import { createMapStore, eventBus } from '@streamlayer/sdk-web-interfaces'; | ||
const open = (options) => { | ||
const payload = $store.get(); | ||
const id = payload.data?.question.id; | ||
const type = payload.data?.promotion?.type; | ||
if (!id) { | ||
return; | ||
} | ||
eventBus.emit('advertisement', { | ||
action: 'opened', | ||
payload: { | ||
id, | ||
type, | ||
hasBanner: adHasBanner(payload.data), | ||
openedFrom: options?.fromNotification ? 'notification' : 'auto', | ||
}, | ||
}); | ||
if (options?.fromNotification) { | ||
$store.setKey('hasNotification', false); | ||
const payload = $store.get(); | ||
const id = payload.data?.question.id; | ||
const type = payload.data?.promotion?.type; | ||
if (id) { | ||
eventBus.emit('advertisement', { | ||
action: 'opened', | ||
payload: { | ||
id, | ||
type, | ||
hasBanner: adHasBanner(payload.data), | ||
openedFrom: 'notification', | ||
}, | ||
}); | ||
eventBus.emit('advertisement', { | ||
action: 'notification-opened', | ||
payload: { | ||
id, | ||
type, | ||
hasBanner: adHasBanner(payload.data), | ||
}, | ||
}); | ||
} | ||
eventBus.emit('advertisement', { | ||
action: 'notification-opened', | ||
payload: { | ||
id, | ||
type, | ||
hasBanner: adHasBanner(payload.data), | ||
}, | ||
}); | ||
} | ||
@@ -80,0 +81,0 @@ }; |
@@ -40,2 +40,3 @@ import { ApiStore, type StreamLayerContext } from '@streamlayer/sdk-web-interfaces'; | ||
feedList: ApiStore<GetApiResponseType<typeof queries.$feedList>>; | ||
betPack: ApiStore<GetApiResponseType<typeof queries.$betPack>>; | ||
/** moderation id */ | ||
@@ -42,0 +43,0 @@ moderationId: ReadableAtom<string | undefined>; |
@@ -35,2 +35,3 @@ import { ApiStore, SingleStore, createSingleStore } from '@streamlayer/sdk-web-interfaces'; | ||
feedList; | ||
betPack; | ||
/** moderation id */ | ||
@@ -61,2 +62,3 @@ moderationId; | ||
this.feedList = new ApiStore(queries.$feedList(this.slStreamId, this.interactiveAllowed, instance.transport), 'gamification:feedList'); | ||
this.betPack = new ApiStore(queries.$betPack(this.slStreamId, instance.transport), 'gamification:betPack'); | ||
this.activeQuestionId = queries.$activeQuestion(this.slStreamId, instance.transport); | ||
@@ -83,2 +85,29 @@ this.openedQuestion = detail(instance.transport, this.openedQuestionId, this.feedList.getStore()); | ||
this.feedSubscription = queries.feedSubscription(this.slStreamId, instance.transport); | ||
this.cancels.add(this.feedSubscription.addListener('bet-pack-update', async (response) => { | ||
const question = response.data?.attributes?.question; | ||
if (question?.type === QuestionType.PREDICTION) { | ||
const betPackData = this.betPack.getValues().data || {}; | ||
const betPackItem = betPackData?.[question.id]; | ||
if (betPackItem || Object.keys(betPackData).length < 5) { | ||
const data = queries.$questionByUser(question.id, this.transport); | ||
// order of operations is important here | ||
const cancel = data.subscribe(() => { }); | ||
await data.get().promise; | ||
// if question is not in the feed list, get extended question data from the server | ||
let extendedQuestion = data.get().data; | ||
if (!extendedQuestion) { | ||
extendedQuestion = await queries.questionByUser(question.id, this.transport); | ||
} | ||
cancel(); | ||
window.requestAnimationFrame(() => { | ||
data.invalidate(); | ||
}); | ||
// get extended question data and mark as dirty | ||
this.betPack.getStore().mutate({ | ||
...betPackData, | ||
[question.id]: extendedQuestion, | ||
}); | ||
} | ||
} | ||
})); | ||
this.cancels.add(this.feedSubscription.addListener('feed-subscription-active-question', (response) => { | ||
@@ -85,0 +114,0 @@ const activeQuestionId = this.activeQuestionId.get().data?.question?.id; |
@@ -28,2 +28,4 @@ import { AbstractFeature, ApiStore, FeatureSource, type FeatureProps, type StreamLayerContext } from '@streamlayer/sdk-web-interfaces'; | ||
feedList: ApiStore<GetApiResponseType<typeof queries.$feedList>>; | ||
/** list (pack) of predefined questions */ | ||
betPack: ApiStore<GetApiResponseType<typeof queries.$betPack>>; | ||
/** friends list */ | ||
@@ -69,2 +71,3 @@ friends: ApiStore<GetApiResponseType<typeof queries.$friends>>; | ||
disconnect: () => void; | ||
betPackVote: (questionId: string, answerId: string) => Promise<void>; | ||
submitAnswer: (questionId: string, answerId: string) => Promise<void>; | ||
@@ -71,0 +74,0 @@ openQuestion: (questionId?: string, question?: FeedItem & { |
@@ -32,2 +32,4 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
feedList; | ||
/** list (pack) of predefined questions */ | ||
betPack; | ||
/** friends list */ | ||
@@ -75,2 +77,3 @@ friends; | ||
this.feedList = this.background.feedList; | ||
this.betPack = this.background.betPack; | ||
this.friends = new ApiStore(queries.$friends(this.background.userId, instance.transport), 'gamification:friends'); | ||
@@ -330,2 +333,29 @@ this.currentUserId = this.background.userId; | ||
}; | ||
betPackVote = async (questionId, answerId) => { | ||
await this.submitAnswer(questionId, answerId); | ||
const betPackList = { ...this.betPack.getValues().data }; | ||
const question = betPackList?.[questionId]; | ||
if (question) { | ||
question.answers = betPackList[questionId].answers.map((answer) => { | ||
if (answer.id === answerId) { | ||
return { | ||
...answer, | ||
youVoted: true, | ||
}; | ||
} | ||
return answer; | ||
}); | ||
eventBus.emit('poll', { | ||
action: 'voted', | ||
payload: { | ||
questionId, | ||
questionType: question.type, | ||
}, | ||
}); | ||
this.betPack.getStore().mutate({ | ||
...betPackList, | ||
[questionId]: question, | ||
}); | ||
} | ||
}; | ||
submitAnswer = async (questionId, answerId) => { | ||
@@ -332,0 +362,0 @@ const data = $questionByUser(questionId, this.transport); |
@@ -119,2 +119,8 @@ import type { Transport } from '@streamlayer/sdk-web-api'; | ||
}; | ||
readonly betPack: { | ||
readonly name: "BetPack"; | ||
readonly I: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackRequest; | ||
readonly O: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackResponse; | ||
readonly kind: import("@bufbuild/protobuf").MethodKind.Unary; | ||
}; | ||
}; | ||
@@ -236,2 +242,8 @@ }, SubscriptionRequest, SubscriptionResponse, "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>)>; | ||
}; | ||
readonly betPack: { | ||
readonly name: "BetPack"; | ||
readonly I: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackRequest; | ||
readonly O: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackResponse; | ||
readonly kind: import("@bufbuild/protobuf").MethodKind.Unary; | ||
}; | ||
}; | ||
@@ -350,2 +362,8 @@ }, VotingSubscriptionRequest, VotingSubscriptionResponse, "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>)>; | ||
}; | ||
readonly betPack: { | ||
readonly name: "BetPack"; | ||
readonly I: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackRequest; | ||
readonly O: typeof import("@streamlayer/sl-eslib/interactive/feed/interactive.feed_pb").BetPackResponse; | ||
readonly kind: import("@bufbuild/protobuf").MethodKind.Unary; | ||
}; | ||
}; | ||
@@ -422,1 +440,2 @@ }, 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>)>; | ||
export { $moderation } from './moderation'; | ||
export declare const $betPack: ($slStreamId: ReadableAtom<string | undefined>, transport: Transport) => import("@nanostores/query").FetcherStore<Record<string, import("@bufbuild/protobuf").PlainMessage<import("@streamlayer/sl-eslib/interactive/interactive.common_pb").ExtendedQuestion>> | null, any>; |
@@ -173,1 +173,30 @@ import { QuestionStatus, QuestionType } from '@streamlayer/sdk-web-types'; | ||
export { $moderation } from './moderation'; | ||
export const $betPack = ($slStreamId, transport) => { | ||
const { client, queryKey } = transport.createPromiseClient(Feed, { | ||
method: 'betPack', | ||
params: [$slStreamId], | ||
}); | ||
return transport.nanoquery.createFetcherStore(queryKey, { | ||
fetcher: async (_, __, slStreamId) => { | ||
if (!slStreamId) { | ||
return null; | ||
} | ||
const res = await client.betPack({ | ||
eventId: slStreamId, | ||
types: [QuestionType.PREDICTION], | ||
statuses: [QuestionStatus.ACTIVE, QuestionStatus.RESOLVED], | ||
limit: 5, | ||
sort: { | ||
field: 'activated_at', | ||
order: 'asc', | ||
}, | ||
}); | ||
if (!res.data || !res.data.length) { | ||
return null; | ||
} | ||
return res.data?.reduce((acc, item) => item?.attributes?.question?.id ? { ...acc, [item.attributes.question.id]: item.attributes.question } : acc, {}); | ||
}, | ||
dedupeTime: 0, | ||
refetchInterval: 0, | ||
}); | ||
}; |
{ | ||
"name": "@streamlayer/feature-gamification", | ||
"version": "1.13.4", | ||
"version": "1.14.0", | ||
"peerDependencies": { | ||
"@bufbuild/protobuf": "^1.10.0", | ||
"@fastify/deepmerge": "^2.0.0", | ||
"@streamlayer/sl-eslib": "^5.130.0", | ||
"@streamlayer/sl-eslib": "^5.149.1", | ||
"nanostores": "^0.10.3", | ||
"@streamlayer/sdk-web-api": "^1.6.21", | ||
"@streamlayer/sdk-web-interfaces": "^1.4.8", | ||
"@streamlayer/sdk-web-logger": "^1.0.42", | ||
"@streamlayer/sdk-web-core": "^1.9.4", | ||
"@streamlayer/sdk-web-notifications": "^1.3.4", | ||
"@streamlayer/sdk-web-storage": "^1.0.42", | ||
"@streamlayer/sdk-web-types": "^1.9.4" | ||
"@streamlayer/sdk-web-api": "^1.7.0", | ||
"@streamlayer/sdk-web-core": "^1.10.0", | ||
"@streamlayer/sdk-web-interfaces": "^1.4.9", | ||
"@streamlayer/sdk-web-logger": "^1.0.43", | ||
"@streamlayer/sdk-web-notifications": "^1.3.5", | ||
"@streamlayer/sdk-web-storage": "^1.0.43", | ||
"@streamlayer/sdk-web-types": "^1.10.0" | ||
}, | ||
@@ -17,0 +17,0 @@ "devDependencies": { |
144185
3.86%2899
4.06%