@smartico/public-api 0.0.380 → 0.0.382
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/CLAUDE.md +103 -0
- package/README.md +32 -10
- package/dist/Base/ClassId.d.ts +2 -0
- package/dist/Jackpots/JackpotDetails.d.ts +14 -15
- package/dist/Jackpots/JackpotPot.d.ts +10 -6
- package/dist/MiniGames/SAWGameType.d.ts +3 -1
- package/dist/MiniGames/SAWTemplateUI.d.ts +7 -0
- package/dist/Raffle/GetRaffleWonPrizesRequest.d.ts +9 -0
- package/dist/Raffle/GetRaffleWonPrizesResponse.d.ts +52 -0
- package/dist/Raffle/index.d.ts +2 -0
- package/dist/SmarticoAPI.d.ts +6 -1
- package/dist/SmarticoLib/index.d.ts +5 -1
- package/dist/WSAPI/WSAPIAvatars.d.ts +267 -49
- package/dist/WSAPI/WSAPIBonuses.d.ts +224 -10
- package/dist/WSAPI/WSAPIGamePick.d.ts +538 -253
- package/dist/WSAPI/WSAPIGeneral.d.ts +156 -14
- package/dist/WSAPI/WSAPIInbox.d.ts +547 -58
- package/dist/WSAPI/WSAPIJackpots.d.ts +292 -57
- package/dist/WSAPI/WSAPILeaderBoard.d.ts +127 -13
- package/dist/WSAPI/WSAPIMiniGames.d.ts +465 -49
- package/dist/WSAPI/WSAPIRaffles.d.ts +576 -52
- package/dist/WSAPI/WSAPITournaments.d.ts +3 -3
- package/dist/WSAPI/WSAPITypes.d.ts +243 -132
- package/dist/WSAPI/WSAPIUser.d.ts +193 -43
- package/dist/index.js +3412 -616
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +3395 -609
- package/dist/index.modern.mjs.map +1 -1
- package/docs/Callbacks.md +162 -0
- package/docs/SmarticoObject.md +445 -0
- package/docs/Transforms.md +99 -0
- package/docs/api/README.md +26 -0
- package/docs/api/classes/WSAPIAvatars.md +282 -54
- package/docs/api/classes/WSAPIBonuses.md +233 -12
- package/docs/api/classes/WSAPIClans.md +380 -10
- package/docs/api/classes/WSAPIGamePick.md +555 -26
- package/docs/api/classes/WSAPIGeneral.md +165 -16
- package/docs/api/classes/WSAPIInbox.md +588 -64
- package/docs/api/classes/WSAPIJackpots.md +320 -66
- package/docs/api/classes/WSAPILeaderBoard.md +133 -15
- package/docs/api/classes/WSAPIMiniGames.md +501 -64
- package/docs/api/classes/WSAPIMissions.md +58 -79
- package/docs/api/classes/WSAPIRaffles.md +647 -69
- package/docs/api/classes/WSAPIStore.md +83 -108
- package/docs/api/classes/WSAPITournaments.md +495 -28
- package/docs/api/classes/WSAPIUser.md +520 -83
- package/docs/api/documents/Callbacks.md +162 -0
- package/docs/api/documents/SmarticoObject.md +445 -0
- package/docs/api/documents/Transforms.md +99 -0
- package/docs/api/enumerations/BonusStatus-1.md +11 -6
- package/docs/api/enumerations/JoinClanErrorCode.md +81 -0
- package/docs/api/enumerations/TournamentRegistrationError.md +12 -0
- package/docs/api/functions/clanTournamentPlayersTransform.md +13 -0
- package/docs/api/interfaces/AvatarCustomized.md +25 -0
- package/docs/api/interfaces/AvatarDefinition.md +94 -0
- package/docs/api/interfaces/AvatarPrompt.md +45 -0
- package/docs/api/interfaces/BonusMetaMap-1.md +4 -1
- package/docs/api/interfaces/BonusTemplateMetaMap-1.md +9 -4
- package/docs/api/interfaces/Clan.md +4 -0
- package/docs/api/interfaces/ClanInfo.md +109 -0
- package/docs/api/interfaces/ClanMember.md +53 -0
- package/docs/api/interfaces/ClanTournamentPlayerRaw.md +67 -0
- package/docs/api/interfaces/GemsDiamondsLog.md +43 -0
- package/docs/api/interfaces/GetClanInfoResponse.md +61 -0
- package/docs/api/interfaces/GetClanTournamentPlayersResponse.md +81 -0
- package/docs/api/interfaces/GetRaffleWonPrizesRequest.md +59 -0
- package/docs/api/interfaces/GetRaffleWonPrizesResponse.md +95 -0
- package/docs/api/interfaces/InboxMarkMessageAction.md +10 -2
- package/docs/api/interfaces/JackpotDetails.md +14 -15
- package/docs/api/interfaces/JackpotPot.md +9 -6
- package/docs/api/interfaces/LeaderBoardDetailsT.md +14 -8
- package/docs/api/interfaces/LeaderBoardUserT.md +8 -5
- package/docs/api/interfaces/LeaderBoardsRewardsT.md +7 -0
- package/docs/api/interfaces/PointsLog.md +43 -0
- package/docs/api/interfaces/RaffleWonPrize.md +59 -0
- package/docs/api/interfaces/RaffleWonPrizePublicMeta.md +27 -0
- package/docs/api/interfaces/RaffleWonPrizeUser.md +43 -0
- package/docs/api/interfaces/TAchCategory.md +2 -7
- package/docs/api/interfaces/TAvatarCustomized.md +4 -4
- package/docs/api/interfaces/TAvatarDefinition.md +13 -14
- package/docs/api/interfaces/TAvatarPrompt.md +6 -6
- package/docs/api/interfaces/TBonus.md +16 -8
- package/docs/api/interfaces/TBuyStoreItemResult.md +4 -29
- package/docs/api/interfaces/TClaimBonusResult.md +5 -5
- package/docs/api/interfaces/TClan.md +8 -4
- package/docs/api/interfaces/TClanInfo.md +47 -0
- package/docs/api/interfaces/TClanJoinResult.md +11 -1
- package/docs/api/interfaces/TClanTournamentPlayer.md +55 -0
- package/docs/api/interfaces/TClanTournamentPlayersResult.md +27 -0
- package/docs/api/interfaces/TClans.md +3 -1
- package/docs/api/interfaces/TGetTranslations.md +4 -0
- package/docs/api/interfaces/TInboxMessage.md +14 -6
- package/docs/api/interfaces/TInboxMessageBody.md +18 -12
- package/docs/api/interfaces/TLevel.md +17 -20
- package/docs/api/interfaces/TLevelCurrent.md +19 -18
- package/docs/api/interfaces/TMiniGamePlayBatchResult.md +14 -6
- package/docs/api/interfaces/TMiniGamePlayResult.md +9 -4
- package/docs/api/interfaces/TMissionClaimRewardResult.md +1 -9
- package/docs/api/interfaces/TMissionOptInResult.md +1 -5
- package/docs/api/interfaces/TMissionOrBadge.md +4 -7
- package/docs/api/interfaces/TRaffleOptinResponse.md +4 -2
- package/docs/api/interfaces/TSegmentCheckResult.md +10 -0
- package/docs/api/interfaces/TSetAvatarResult.md +3 -3
- package/docs/api/interfaces/TStoreItem.md +3 -13
- package/docs/api/interfaces/TTournament.md +1 -1
- package/docs/api/interfaces/TTournamentDetailed.md +1 -1
- package/docs/api/interfaces/TTournamentRegistrationResult.md +4 -2
- package/docs/api/interfaces/TUICustomSection.md +23 -19
- package/docs/api/interfaces/TUserProfile.md +18 -16
- package/docs/api/interfaces/TransformedRaffleClaimPrizeResponse.md +6 -2
- package/docs/api/interfaces/UserLevelExtraCountersT.md +9 -2
- package/docs/api/type-aliases/ActivityLogEntry.md +3 -0
- package/docs/native/ADDING_METHODS.md +7 -2
- package/docs/native/PROTOCOL.md +337 -0
- package/docs/ui/avatars/UIGuide_getAvatarPrompts.md +100 -0
- package/docs/ui/avatars/UIGuide_getAvatarsCustomized.md +90 -0
- package/docs/ui/avatars/UIGuide_getAvatarsList.md +105 -0
- package/docs/ui/avatars/UIGuide_setAvatar.md +118 -0
- package/docs/ui/bonuses/UIGuide_claimBonus.md +144 -0
- package/docs/ui/bonuses/UIGuide_getBonuses.md +176 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetActiveRound.md +99 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetActiveRounds.md +76 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetBoard.md +81 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetGameInfo.md +78 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetHistory.md +55 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetRoundInfoForUser.md +71 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetUserInfo.md +64 -0
- package/docs/ui/gamepick/UIGuide_gamePickSubmitSelection.md +103 -0
- package/docs/ui/gamepick/UIGuide_gamePickSubmitSelectionQuiz.md +67 -0
- package/docs/ui/general/UIGuide_getCustomSections.md +137 -0
- package/docs/ui/general/UIGuide_getRelatedItemsForGame.md +140 -0
- package/docs/ui/inbox/UIGuide_deleteInboxMessage.md +135 -0
- package/docs/ui/inbox/UIGuide_getInboxMessageBody.md +133 -0
- package/docs/ui/inbox/UIGuide_getInboxMessages.md +186 -0
- package/docs/ui/inbox/UIGuide_markInboxMessageAsRead.md +122 -0
- package/docs/ui/inbox/UIGuide_markUnmarkInboxMessageAsFavorite.md +84 -0
- package/docs/ui/jackpots/UIGuide_getJackpotEligibleGames.md +73 -0
- package/docs/ui/jackpots/UIGuide_getJackpotWinners.md +83 -0
- package/docs/ui/jackpots/UIGuide_jackpotGet.md +138 -0
- package/docs/ui/jackpots/UIGuide_jackpotOptIn.md +85 -0
- package/docs/ui/jackpots/UIGuide_jackpotOptOut.md +65 -0
- package/docs/ui/leaderboard/UIGuide_getLeaderBoard.md +166 -0
- package/docs/ui/minigames/UIGuide_getMiniGames.md +153 -0
- package/docs/ui/minigames/UIGuide_getMiniGamesHistory.md +90 -0
- package/docs/ui/minigames/UIGuide_playMiniGame.md +150 -0
- package/docs/ui/minigames/UIGuide_playMiniGameBatch.md +128 -0
- package/docs/ui/raffles/UIGuide_claimRafflePrize.md +99 -0
- package/docs/ui/raffles/UIGuide_getRaffleDrawRun.md +117 -0
- package/docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md +92 -0
- package/docs/ui/raffles/UIGuide_getRaffleWonPrizes.md +120 -0
- package/docs/ui/raffles/UIGuide_getRaffles.md +175 -0
- package/docs/ui/raffles/UIGuide_requestRaffleOptin.md +114 -0
- package/docs/ui/user/UIGuide_getActivityLog.md +130 -0
- package/docs/ui/user/UIGuide_getLevels.md +47 -42
- package/package.json +1 -1
- package/src/Base/ClassId.ts +2 -0
- package/src/Jackpots/JackpotDetails.ts +14 -15
- package/src/Jackpots/JackpotPot.ts +10 -6
- package/src/MiniGames/SAWGameType.ts +3 -0
- package/src/MiniGames/SAWTemplateUI.ts +10 -0
- package/src/Raffle/GetRaffleWonPrizesRequest.ts +12 -0
- package/src/Raffle/GetRaffleWonPrizesResponse.ts +56 -0
- package/src/Raffle/index.ts +3 -1
- package/src/SmarticoAPI.ts +14 -1
- package/src/SmarticoLib/index.ts +4 -0
- package/src/WSAPI/WSAPIAvatars.ts +267 -49
- package/src/WSAPI/WSAPIBonuses.ts +224 -10
- package/src/WSAPI/WSAPIGamePick.ts +538 -253
- package/src/WSAPI/WSAPIGeneral.ts +156 -14
- package/src/WSAPI/WSAPIInbox.ts +545 -56
- package/src/WSAPI/WSAPIJackpots.ts +297 -61
- package/src/WSAPI/WSAPILeaderBoard.ts +127 -13
- package/src/WSAPI/WSAPIMiniGames.ts +465 -49
- package/src/WSAPI/WSAPIRaffles.ts +592 -64
- package/src/WSAPI/WSAPITournaments.ts +3 -3
- package/src/WSAPI/WSAPITypes.ts +243 -132
- package/src/WSAPI/WSAPIUser.ts +193 -43
- package/tsconfig.json +9 -1
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
drawRunHistoryTransform,
|
|
11
11
|
raffleClaimPrizeResponseTransform,
|
|
12
|
+
GetRaffleWonPrizesResponse,
|
|
12
13
|
} from '../Raffle';
|
|
13
14
|
import {
|
|
14
15
|
CACHE_DATA_SEC,
|
|
@@ -24,28 +25,113 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* Returns
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* Returns all raffles visible to the current user, each carrying an
|
|
29
|
+
* embedded `draws[]` array with per-draw state (current state, ticket
|
|
30
|
+
* counts, opt-in status, prize structure). Use this to power a
|
|
31
|
+
* raffles lobby screen and to drive per-draw CTAs (opt-in, view
|
|
32
|
+
* winners, claim).
|
|
30
33
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* });
|
|
37
|
-
* ```
|
|
34
|
+
* The embedded `draws[i]` objects are sufficient for rendering all
|
|
35
|
+
* draw cards — winner details with usernames / avatars require a
|
|
36
|
+
* follow-up {@link getRaffleDrawRun} call (the embedded form carries
|
|
37
|
+
* only `winners_total` / `winners_limit` / `winners_offset` metadata,
|
|
38
|
+
* not individual winner rows).
|
|
38
39
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* **Subscription model (`onUpdate`)**
|
|
42
|
+
* The callback receives the FULL refreshed raffle list (never a
|
|
43
|
+
* diff/patch). Each subsequent call to `getRaffles({ onUpdate })`
|
|
44
|
+
* REPLACES the prior callback. Pass `onUpdate: undefined` (or omit
|
|
45
|
+
* it) to keep the prior callback in place; the callback is never
|
|
46
|
+
* auto-cleared.
|
|
47
|
+
*
|
|
48
|
+
* **Update triggers** — the callback fires when:
|
|
49
|
+
*
|
|
50
|
+
* 1. {@link claimRafflePrize} resolves on this connection (any
|
|
51
|
+
* response code) — the refreshed list reflects the new
|
|
52
|
+
* `has_unclaimed_prize` / `claimed_date` state.
|
|
53
|
+
* 2. {@link requestRaffleOptin} resolves on this connection (any
|
|
54
|
+
* response code) — the refreshed list reflects the new
|
|
55
|
+
* `user_opted_in` state on the affected draw.
|
|
56
|
+
*
|
|
57
|
+
* Does NOT fire for: server-side draw executions, ticket increments
|
|
58
|
+
* (other users earning tickets), or operator-side raffle/draw config
|
|
59
|
+
* changes. Those changes surface only on the next cache miss (after
|
|
60
|
+
* the 30 s TTL) — poll manually if your UI needs sub-30s freshness
|
|
61
|
+
* during an in-progress draw.
|
|
62
|
+
*
|
|
63
|
+
* **Reading state from the returned raffle**
|
|
64
|
+
* - `current_tickets_count` vs `max_tickets_count` drives the
|
|
65
|
+
* `ticket_cap_visualization` banner (enum
|
|
66
|
+
* {@link RaffleTicketCapVisualization}: `Empty` = no banner,
|
|
67
|
+
* `Counter` = show "X tickets remaining", `Message` = show
|
|
68
|
+
* sold-out message).
|
|
69
|
+
* - Within each draw, `current_state`
|
|
70
|
+
* ({@link RaffleDrawInstanceState}) buckets the draw into Open
|
|
71
|
+
* (accepting tickets), WinnerSelection (currently drawing), or
|
|
72
|
+
* Executed (winners selected).
|
|
73
|
+
* - `execution_type` ({@link RaffleDrawTypeExecution}) distinguishes
|
|
74
|
+
* one-shot (`ExecDate`), repeating (`Recurring`), or special
|
|
75
|
+
* one-shot (`Grand`) draws. Recurring draws share a stable
|
|
76
|
+
* `draws[i].id` (the schedule definition) across runs — `run_id`
|
|
77
|
+
* is the per-execution instance.
|
|
78
|
+
*
|
|
79
|
+
* **Cache TTL**: the SDK caches the response for 30 seconds. Cache
|
|
80
|
+
* is fully cleared on login / logout. The server also invalidates
|
|
81
|
+
* the SDK cache when a draw executes on the server side.
|
|
82
|
+
*
|
|
83
|
+
* **Idempotency / Side effects**: safe. Read-only.
|
|
84
|
+
*
|
|
85
|
+
* **UI guidance**: see [UI Guide — `getRaffles`](../../docs/ui/raffles/UIGuide_getRaffles.md).
|
|
86
|
+
*
|
|
87
|
+
* **Visitor mode**: supported. The same shape is returned, scoped
|
|
88
|
+
* to the brand's public raffles. Per-user fields (`my_tickets_count`,
|
|
89
|
+
* `my_last_tickets`, `user_opted_in`) are not meaningful for
|
|
90
|
+
* visitors. The `onUpdate` callback is accepted but never fires
|
|
91
|
+
* because the mutation methods that trigger it
|
|
92
|
+
* ({@link claimRafflePrize}, {@link requestRaffleOptin}) are not
|
|
93
|
+
* available / not effective in visitor mode.
|
|
94
|
+
*
|
|
95
|
+
* @param params Optional. Omit to fetch without subscribing.
|
|
96
|
+
* @param params.onUpdate Callback invoked with the full refreshed
|
|
97
|
+
* raffles list after every
|
|
98
|
+
* {@link claimRafflePrize} or
|
|
99
|
+
* {@link requestRaffleOptin} round-trip
|
|
100
|
+
* on this connection.
|
|
101
|
+
* @returns Promise resolving to the raffles list.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* const raffles = await window._smartico.api.getRaffles({
|
|
106
|
+
* onUpdate: (refreshed) => {
|
|
107
|
+
* console.log('[smartico] raffles refreshed (after claim/optin) — re-render from this array:', refreshed);
|
|
108
|
+
* },
|
|
44
109
|
* });
|
|
45
|
-
* ```
|
|
46
110
|
*
|
|
111
|
+
* for (const raffle of raffles) {
|
|
112
|
+
* console.log('[smartico] render raffle', raffle.id, '—', raffle.name, ':', raffle.draws.length, 'draws');
|
|
113
|
+
*
|
|
114
|
+
* // Bucket draws: active/upcoming first (sorted by execution_ts ASC), then executed last.
|
|
115
|
+
* const sorted = [...raffle.draws].sort((a, b) => {
|
|
116
|
+
* const aDone = a.current_state === 3; // Executed
|
|
117
|
+
* const bDone = b.current_state === 3;
|
|
118
|
+
* if (aDone !== bDone) return aDone ? 1 : -1; // executed sink to the bottom
|
|
119
|
+
* return a.execution_ts - b.execution_ts;
|
|
120
|
+
* });
|
|
121
|
+
*
|
|
122
|
+
* for (const d of sorted) {
|
|
123
|
+
* if (d.requires_optin && !d.user_opted_in && d.is_active && d.current_state !== 3) {
|
|
124
|
+
* console.log('[smartico] draw', d.run_id, '— show OPT IN CTA (requires_optin + not yet opted in + still active)');
|
|
125
|
+
* }
|
|
126
|
+
* if (d.current_state === 3) {
|
|
127
|
+
* console.log('[smartico] draw', d.run_id, 'executed — fetch winner details via getRaffleDrawRun');
|
|
128
|
+
* }
|
|
129
|
+
* }
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* // For winner detail on an executed draw, call getRaffleDrawRun separately.
|
|
133
|
+
* ```
|
|
47
134
|
*/
|
|
48
|
-
|
|
49
135
|
public async getRaffles({ onUpdate }: { onUpdate?: (data: TRaffle[]) => void } = {}): Promise<TRaffle[]> {
|
|
50
136
|
if (onUpdate) {
|
|
51
137
|
this.onUpdateCallback.set(onUpdateContextKey.Raffles, onUpdate);
|
|
@@ -55,29 +141,107 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
55
141
|
}
|
|
56
142
|
|
|
57
143
|
/**
|
|
58
|
-
* Returns draw run
|
|
59
|
-
*
|
|
144
|
+
* Returns the full detail of a single raffle draw run — same shape
|
|
145
|
+
* as the embedded `TRaffleDraw` in {@link getRaffles}, but populated
|
|
146
|
+
* with paginated `prizes[].winners[]` rows including usernames and
|
|
147
|
+
* avatars. Use this to render a draw detail / winners screen, or to
|
|
148
|
+
* page through the winner list of an executed draw.
|
|
60
149
|
*
|
|
150
|
+
* Each call is a fresh server round-trip — there is no client cache.
|
|
151
|
+
* Re-call to refresh.
|
|
61
152
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
153
|
+
* @remarks
|
|
154
|
+
* **Preconditions**
|
|
155
|
+
* Pass `raffle_id` (the parent raffle's `id`) and `run_id` (the
|
|
156
|
+
* specific run instance — `TRaffleDraw.run_id` from
|
|
157
|
+
* {@link getRaffles}'s embedded draws). Note that
|
|
158
|
+
* `TRaffleDraw.id` is the *schedule_id* (stable across runs of a
|
|
159
|
+
* recurring draw) — that's NOT what this method takes; it takes the
|
|
160
|
+
* per-instance `run_id`.
|
|
161
|
+
*
|
|
162
|
+
* **Refresh model**
|
|
163
|
+
* - **No subscription.** One-shot promise.
|
|
164
|
+
* - **No client cache.** Every call sends a network request.
|
|
165
|
+
* - **No push event** refreshes the response. Live winner-list
|
|
166
|
+
* updates require a fresh call.
|
|
167
|
+
* - The default Smartico UI polls this method on a variable cadence
|
|
168
|
+
* while a draw is in flight: every 3 s during `WinnerSelection`,
|
|
169
|
+
* every 10 s when the countdown is under 5 minutes, every 30 s
|
|
170
|
+
* otherwise.
|
|
171
|
+
*
|
|
172
|
+
* **Winner pagination**
|
|
173
|
+
* `winners_from` / `winners_to` define a half-open range of winner
|
|
174
|
+
* indices. The default window is `0–20` (20 winners). The server
|
|
175
|
+
* caps the window at 50 rows per call — passing a larger range
|
|
176
|
+
* silently truncates. For "load more" pagination, advance
|
|
177
|
+
* `winners_from` by the prior page size and pass the same
|
|
178
|
+
* `winners_to` offset. `winners_total` on the returned
|
|
179
|
+
* `TRaffleDraw` is the authoritative total count for pagination.
|
|
180
|
+
*
|
|
181
|
+
* The current user's own winning rows (if any) are server-sorted
|
|
182
|
+
* to the top of the result.
|
|
183
|
+
*
|
|
184
|
+
* **Throws**
|
|
185
|
+
* Both `raffle_id` and `run_id` are required — the SDK throws
|
|
186
|
+
* synchronously when either is missing or falsy.
|
|
187
|
+
*
|
|
188
|
+
* **Idempotency / Side effects**: safe. Read-only.
|
|
189
|
+
*
|
|
190
|
+
* **UI guidance**: see [UI Guide — `getRaffleDrawRun`](../../docs/ui/raffles/UIGuide_getRaffleDrawRun.md).
|
|
69
191
|
*
|
|
70
|
-
* **
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
192
|
+
* **Visitor mode**: supported.
|
|
193
|
+
*
|
|
194
|
+
* @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`).
|
|
195
|
+
* @param props.run_id The draw run instance ID (from
|
|
196
|
+
* `TRaffleDraw.run_id`, not `TRaffleDraw.id`).
|
|
197
|
+
* @param props.winners_from First winner index to return (0-based).
|
|
198
|
+
* Defaults to `0`.
|
|
199
|
+
* @param props.winners_to Last winner index (exclusive).
|
|
200
|
+
* Defaults to `20`. Server caps the
|
|
201
|
+
* window at 50 rows per call.
|
|
202
|
+
* @returns Promise resolving to `TRaffleDraw`
|
|
203
|
+
* with `prizes[].winners[]` populated
|
|
204
|
+
* and `winners_total` set.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* const raffles = await window._smartico.api.getRaffles();
|
|
209
|
+
* const raffle = raffles[0];
|
|
210
|
+
* const draw = raffle.draws.find(d => d.current_state === 3); // Executed
|
|
211
|
+
*
|
|
212
|
+
* if (!draw) {
|
|
213
|
+
* console.log('[smartico] no executed draw — skip detail view');
|
|
214
|
+
* return;
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* // First page of winners.
|
|
218
|
+
* const detail = await window._smartico.api.getRaffleDrawRun({
|
|
219
|
+
* raffle_id: raffle.id,
|
|
220
|
+
* run_id: draw.run_id, // NOTE: run_id, NOT draw.id
|
|
221
|
+
* winners_from: 0,
|
|
222
|
+
* winners_to: 20,
|
|
76
223
|
* });
|
|
77
|
-
* ```
|
|
78
224
|
*
|
|
225
|
+
* for (const prize of detail.prizes) {
|
|
226
|
+
* console.log('[smartico] prize', prize.name, '— winners on this page:', prize.winners.length);
|
|
227
|
+
* const myWin = prize.winners.find(w => w.username === currentUsername); // or another match
|
|
228
|
+
* if (myWin) {
|
|
229
|
+
* console.log('[smartico] current user won this prize — surface a Claim CTA if not yet claimed');
|
|
230
|
+
* }
|
|
231
|
+
* }
|
|
232
|
+
*
|
|
233
|
+
* // Load more — pagination via winners_from / winners_to.
|
|
234
|
+
* if ((detail.winners_total ?? 0) > 20) {
|
|
235
|
+
* const next = await window._smartico.api.getRaffleDrawRun({
|
|
236
|
+
* raffle_id: raffle.id,
|
|
237
|
+
* run_id: draw.run_id,
|
|
238
|
+
* winners_from: 20,
|
|
239
|
+
* winners_to: 40,
|
|
240
|
+
* });
|
|
241
|
+
* console.log('[smartico] page 2 loaded — append', next.prizes.flatMap(p => p.winners).length, 'winners');
|
|
242
|
+
* }
|
|
243
|
+
* ```
|
|
79
244
|
*/
|
|
80
|
-
|
|
81
245
|
public async getRaffleDrawRun(props: { raffle_id: number; run_id: number; winners_from?: number; winners_to?: number }): Promise<TRaffleDraw> {
|
|
82
246
|
if (!props.raffle_id || !props.run_id) {
|
|
83
247
|
throw new Error('both raffle_id and run_id are required');
|
|
@@ -87,27 +251,77 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
87
251
|
}
|
|
88
252
|
|
|
89
253
|
/**
|
|
90
|
-
* Returns
|
|
254
|
+
* Returns the history of past-executed draw runs for a raffle —
|
|
255
|
+
* optionally scoped to a single recurring draw schedule. Each row
|
|
256
|
+
* is a previously-executed run with its scheduled and
|
|
257
|
+
* actual-execution timestamps, the user's win status, and an
|
|
258
|
+
* unclaimed-prize flag for surfacing a Claim CTA on history rows.
|
|
259
|
+
*
|
|
260
|
+
* @remarks
|
|
261
|
+
* **Preconditions**
|
|
262
|
+
* `raffle_id` is required. `draw_id` is optional — when omitted,
|
|
263
|
+
* the response includes history for ALL draws of the raffle; when
|
|
264
|
+
* supplied, it scopes to that one draw's recurring history. The
|
|
265
|
+
* `draw_id` to pass is `TRaffleDraw.id` (the schedule_id, stable
|
|
266
|
+
* across runs), not `run_id`.
|
|
267
|
+
*
|
|
268
|
+
* **Server-side filtering**
|
|
269
|
+
* Draws configured by the operator to hide their history are
|
|
270
|
+
* excluded from the response automatically. Cancelled runs are
|
|
271
|
+
* also excluded.
|
|
272
|
+
*
|
|
273
|
+
* **Sort order**
|
|
274
|
+
* Server returns rows by scheduled `execution_ts` descending
|
|
275
|
+
* (newest first). No client-side sort required.
|
|
276
|
+
*
|
|
277
|
+
* **Refresh model**
|
|
278
|
+
* - **No subscription.** One-shot promise.
|
|
279
|
+
* - **No client cache.** Every call hits the server.
|
|
280
|
+
* - **No push event** refreshes the response. Re-call manually to
|
|
281
|
+
* pick up newly-executed runs or `has_unclaimed_prize` flips
|
|
282
|
+
* after a {@link claimRafflePrize} call.
|
|
283
|
+
*
|
|
284
|
+
* **Idempotency / Side effects**: safe. Read-only.
|
|
285
|
+
*
|
|
286
|
+
* **UI guidance**: see [UI Guide — `getRaffleDrawRunsHistory`](../../docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md).
|
|
91
287
|
*
|
|
288
|
+
* **Visitor mode**: supported. The same shape is returned with
|
|
289
|
+
* `is_winner` and `has_unclaimed_prize` always `false` for visitors.
|
|
92
290
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
291
|
+
* @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`).
|
|
292
|
+
* Required.
|
|
293
|
+
* @param props.draw_id Optional — the draw's schedule_id
|
|
294
|
+
* (`TRaffleDraw.id`). When set, scopes the
|
|
295
|
+
* history to that one draw's runs. When
|
|
296
|
+
* omitted, includes all draws of the raffle.
|
|
297
|
+
* @returns Promise resolving to a `TRaffleDrawRun[]`
|
|
298
|
+
* ordered newest-first. Empty if no executed
|
|
299
|
+
* runs exist.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* const raffles = await window._smartico.api.getRaffles();
|
|
304
|
+
* const raffle = raffles[0];
|
|
305
|
+
*
|
|
306
|
+
* // History across all draws of the raffle.
|
|
307
|
+
* const allHistory = await window._smartico.api.getRaffleDrawRunsHistory({
|
|
308
|
+
* raffle_id: raffle.id,
|
|
98
309
|
* });
|
|
99
|
-
* ```
|
|
100
310
|
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
311
|
+
* // Highlight rows where the user has an unclaimed prize.
|
|
312
|
+
* const unclaimed = allHistory.filter(r => r.has_unclaimed_prize);
|
|
313
|
+
* if (unclaimed.length > 0) {
|
|
314
|
+
* console.log('[smartico] surface a "Claim" CTA on these', unclaimed.length, 'history rows:', unclaimed.map(r => r.run_id));
|
|
315
|
+
* }
|
|
316
|
+
*
|
|
317
|
+
* // Scoped history of one recurring draw (use draw.id, the schedule_id).
|
|
318
|
+
* const oneDrawHistory = await window._smartico.api.getRaffleDrawRunsHistory({
|
|
319
|
+
* raffle_id: raffle.id,
|
|
320
|
+
* draw_id: raffle.draws[0].id, // schedule_id (stable across recurring runs)
|
|
106
321
|
* });
|
|
322
|
+
* console.log('[smartico] render history rows for the daily draw — newest first:', oneDrawHistory.length, 'rows');
|
|
107
323
|
* ```
|
|
108
|
-
*
|
|
109
324
|
*/
|
|
110
|
-
|
|
111
325
|
public async getRaffleDrawRunsHistory(props: { raffle_id: number; draw_id?: number }): Promise<TRaffleDrawRun[]> {
|
|
112
326
|
|
|
113
327
|
const res = await this.api.getRaffleDrawRunsHistory(this.userExtId, props);
|
|
@@ -120,25 +334,113 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
120
334
|
}
|
|
121
335
|
|
|
122
336
|
/**
|
|
123
|
-
*
|
|
337
|
+
* Claims a raffle prize the user has won. Call this when the user
|
|
338
|
+
* has a winning row with `should_claim === true` and an unclaimed
|
|
339
|
+
* `won_id` (read from a `TRafflePrizeWinner` on a
|
|
340
|
+
* {@link getRaffleDrawRun} result, or surfaced by `has_unclaimed_prize`
|
|
341
|
+
* on a {@link getRaffleDrawRunsHistory} row that the consumer drills
|
|
342
|
+
* into).
|
|
124
343
|
*
|
|
344
|
+
* On success (`errorCode === 0`), the server records the claim and
|
|
345
|
+
* triggers prize delivery through the operator's integration —
|
|
346
|
+
* delivery is server-side, not part of this response.
|
|
125
347
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
348
|
+
* @remarks
|
|
349
|
+
* **Result shape note**: this method returns
|
|
350
|
+
* `TransformedRaffleClaimPrizeResponse` with `errorCode` /
|
|
351
|
+
* `errorMessage` (camelCase full-word) — different from most other
|
|
352
|
+
* SDK result types which use `err_code` / `err_message` (snake_case
|
|
353
|
+
* short-word). Branch on the camelCase keys when reading this
|
|
354
|
+
* method's result.
|
|
355
|
+
*
|
|
356
|
+
* **Preconditions**
|
|
357
|
+
* Pass a `won_id` that identifies an unclaimed winning row for the
|
|
358
|
+
* current user. The `won_id` comes from
|
|
359
|
+
* `TRafflePrizeWinner.raf_won_id` returned by
|
|
360
|
+
* {@link getRaffleDrawRun}.
|
|
361
|
+
*
|
|
362
|
+
* **Error codes** (in `errorCode`)
|
|
363
|
+
* - `0` — success; the claim is recorded and prize delivery is
|
|
364
|
+
* queued server-side.
|
|
365
|
+
* - `1` — generic claim failure. The `errorMessage` distinguishes
|
|
366
|
+
* the specific cause (the server uses one error code for several
|
|
367
|
+
* distinct conditions): the prize has already been claimed, the
|
|
368
|
+
* `won_id` doesn't match a winning row for this user, or the user
|
|
369
|
+
* is in a control group for this raffle. Treat `1` as a retryable
|
|
370
|
+
* error if the message suggests a transient condition; treat as
|
|
371
|
+
* idempotent success if the message indicates already-claimed
|
|
372
|
+
* (the underlying state is what the consumer wants either way —
|
|
373
|
+
* the prize is claimed).
|
|
374
|
+
* - other non-zero — generic server error. Surface `errorMessage`
|
|
375
|
+
* if any.
|
|
376
|
+
*
|
|
377
|
+
* **Claim window**
|
|
378
|
+
* There is no server-enforced claim deadline. Won prizes remain
|
|
379
|
+
* claimable indefinitely until the operator archives them.
|
|
380
|
+
*
|
|
381
|
+
* **Idempotency**: NOT idempotent. A second call on the same
|
|
382
|
+
* `won_id` returns `errorCode === 1` with `errorMessage` indicating
|
|
383
|
+
* the prize has already been claimed. The SDK does NOT enforce an
|
|
384
|
+
* in-flight lock. Guard the call site against double-clicks (set
|
|
385
|
+
* a local "claiming" flag on click, clear it on response).
|
|
386
|
+
*
|
|
387
|
+
* **Refresh after success (and after failure)**
|
|
388
|
+
* The SDK automatically refreshes the raffles cache on every
|
|
389
|
+
* response — both success and failure paths fire the `onUpdate`
|
|
390
|
+
* callback registered via {@link getRaffles}. After `errorCode === 0`,
|
|
391
|
+
* the affected `TRaffleDrawRun.has_unclaimed_prize` (in history)
|
|
392
|
+
* and the winner row's `claimed_date` reflect the claim on the next
|
|
393
|
+
* refresh.
|
|
133
394
|
*
|
|
134
|
-
* **
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
395
|
+
* **Side effects** (on `errorCode === 0`)
|
|
396
|
+
* - The winner row's `claimed_date` is set server-side.
|
|
397
|
+
* - Prize delivery is queued for the operator's integration to
|
|
398
|
+
* process. Balance / bonus / inbox updates that result from the
|
|
399
|
+
* delivery arrive through their own channels — not in this
|
|
400
|
+
* response.
|
|
401
|
+
*
|
|
402
|
+
* **Throws**
|
|
403
|
+
* `won_id` is required — the SDK throws synchronously when missing
|
|
404
|
+
* or falsy.
|
|
405
|
+
*
|
|
406
|
+
* **UI guidance**: see [UI Guide — `claimRafflePrize`](../../docs/ui/raffles/UIGuide_claimRafflePrize.md).
|
|
407
|
+
*
|
|
408
|
+
* **Visitor mode**: not meaningfully supported. The SDK does not
|
|
409
|
+
* block the call, but visitor sessions have no win history and the
|
|
410
|
+
* server will reject it.
|
|
411
|
+
*
|
|
412
|
+
* @param props.won_id The winning row's `raf_won_id` (from
|
|
413
|
+
* `TRafflePrizeWinner` returned by
|
|
414
|
+
* {@link getRaffleDrawRun}).
|
|
415
|
+
* @returns `{ errorCode, errorMessage? }`; success when
|
|
416
|
+
* `errorCode === 0`. Note camelCase keys (see "Result
|
|
417
|
+
* shape note" above).
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* const detail = await window._smartico.api.getRaffleDrawRun({
|
|
422
|
+
* raffle_id: raffleId,
|
|
423
|
+
* run_id: runId,
|
|
139
424
|
* });
|
|
140
|
-
*
|
|
425
|
+
* const myWin = detail.prizes.flatMap(p => p.winners).find(w => /* user match here *\/ true);
|
|
426
|
+
*
|
|
427
|
+
* if (!myWin || !myWin.raf_won_id || myWin.claimed_date) {
|
|
428
|
+
* console.log('[smartico] nothing to claim — keep CTA hidden');
|
|
429
|
+
* return;
|
|
430
|
+
* }
|
|
141
431
|
*
|
|
432
|
+
* console.log('[smartico] claim starting — set in-flight flag, show loading dots on the Claim button, keep the modal open');
|
|
433
|
+
* const r = await window._smartico.api.claimRafflePrize({ won_id: myWin.raf_won_id });
|
|
434
|
+
* console.log('[smartico] claim response received — clear in-flight flag');
|
|
435
|
+
*
|
|
436
|
+
* if (r.errorCode === 0) {
|
|
437
|
+
* console.log('[smartico] claim succeeded — show a success toast; getRaffles onUpdate above will fire with refreshed state; prize delivery happens server-side');
|
|
438
|
+
* } else if (r.errorCode === 1 && r.errorMessage?.toLowerCase().includes('already claimed')) {
|
|
439
|
+
* console.log('[smartico] prize was already claimed (perhaps from another tab) — treat as success, hide the Claim CTA');
|
|
440
|
+
* } else {
|
|
441
|
+
* console.error('[smartico] claim failed — surface this error message to the user and allow retry:', r.errorMessage);
|
|
442
|
+
* }
|
|
443
|
+
* ```
|
|
142
444
|
*/
|
|
143
445
|
public async claimRafflePrize(props: { won_id: number }): Promise<TransformedRaffleClaimPrizeResponse> {
|
|
144
446
|
if (!props.won_id) {
|
|
@@ -150,9 +452,104 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
150
452
|
}
|
|
151
453
|
|
|
152
454
|
/**
|
|
153
|
-
*
|
|
455
|
+
* Opts the current user into a specific raffle draw run. Required
|
|
456
|
+
* for draws where `TRaffleDraw.requires_optin === true` — without
|
|
457
|
+
* opt-in, the user's tickets do NOT participate in that run, even
|
|
458
|
+
* if they hold tickets for the raffle.
|
|
459
|
+
*
|
|
460
|
+
* Opt-in is per-run: a recurring draw's next run requires a fresh
|
|
461
|
+
* opt-in. The user's `TRaffleDraw.user_opted_in` flag reflects the
|
|
462
|
+
* current state for the current run only.
|
|
463
|
+
*
|
|
464
|
+
* @remarks
|
|
465
|
+
* **Preconditions**
|
|
466
|
+
* Read the candidate draw from {@link getRaffles}'s embedded
|
|
467
|
+
* `draws[]` and gate the call on
|
|
468
|
+
* `requires_optin === true && !user_opted_in && is_active &&
|
|
469
|
+
* current_state !== Executed`. Calling without these guards may
|
|
470
|
+
* return a non-zero `err_code`.
|
|
471
|
+
*
|
|
472
|
+
* **Argument mapping** — the three IDs come from different fields:
|
|
473
|
+
* - `raffle_id` — the parent raffle's `TRaffle.id`
|
|
474
|
+
* - `draw_id` — `TRaffleDraw.id` (schedule_id, stable across runs)
|
|
475
|
+
* - `raffle_run_id` — `TRaffleDraw.run_id` (instance ID for this
|
|
476
|
+
* specific run)
|
|
477
|
+
*
|
|
478
|
+
* **Error codes** (in `err_code`)
|
|
479
|
+
* - `0` — success; the user is opted into this run. Tickets
|
|
480
|
+
* collected after the run's `ticket_start_ts` will participate.
|
|
481
|
+
* - `1` — generic opt-in failure. The `err_message` distinguishes
|
|
482
|
+
* the specific cause: the draw doesn't require opt-in
|
|
483
|
+
* (`requires_optin === false`), `raffle_id` doesn't match the
|
|
484
|
+
* `draw_id`, the user is already opted in (or the draw has
|
|
485
|
+
* completed), or the user is in a control group for this raffle.
|
|
486
|
+
* - other non-zero — generic server error. Surface `err_message`.
|
|
487
|
+
*
|
|
488
|
+
* **Idempotency**: NOT idempotent. A second call on the same
|
|
489
|
+
* `raffle_run_id` returns `err_code === 1` with `err_message`
|
|
490
|
+
* indicating the user is already opted in. Treat as success in
|
|
491
|
+
* the UI — the underlying state is what the consumer wants.
|
|
492
|
+
* Guard the call site against double-clicks.
|
|
154
493
|
*
|
|
155
|
-
* **
|
|
494
|
+
* **Refresh after success (and after failure)**
|
|
495
|
+
* The SDK automatically refreshes the raffles cache on every
|
|
496
|
+
* response and fires the `onUpdate` callback registered via
|
|
497
|
+
* {@link getRaffles}. After `err_code === 0`, the affected draw's
|
|
498
|
+
* `user_opted_in` flips to `true` on the refreshed list.
|
|
499
|
+
*
|
|
500
|
+
* **Side effects** (on `err_code === 0`)
|
|
501
|
+
* - The user is registered for this run. Tickets earned within
|
|
502
|
+
* the run's eligibility window will participate in the draw.
|
|
503
|
+
* - No balance change. No CRM-side rewards. Opt-in is a metadata
|
|
504
|
+
* operation only.
|
|
505
|
+
*
|
|
506
|
+
* **Throws**
|
|
507
|
+
* `raffle_id`, `draw_id`, and `raffle_run_id` are all required —
|
|
508
|
+
* the SDK throws synchronously when any is missing or falsy.
|
|
509
|
+
*
|
|
510
|
+
* **UI guidance**: see [UI Guide — `requestRaffleOptin`](../../docs/ui/raffles/UIGuide_requestRaffleOptin.md).
|
|
511
|
+
*
|
|
512
|
+
* **Visitor mode**: not supported.
|
|
513
|
+
*
|
|
514
|
+
* @param props.raffle_id The parent raffle's `id`.
|
|
515
|
+
* @param props.draw_id The draw's schedule_id (`TRaffleDraw.id`).
|
|
516
|
+
* @param props.raffle_run_id The run instance ID (`TRaffleDraw.run_id`).
|
|
517
|
+
* @returns `{ err_code, err_message? }`; success
|
|
518
|
+
* when `err_code === 0` (treat
|
|
519
|
+
* "already opted in" as idempotent
|
|
520
|
+
* success).
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```ts
|
|
524
|
+
* const raffles = await window._smartico.api.getRaffles({
|
|
525
|
+
* onUpdate: (refreshed) => console.log('[smartico] raffles refreshed — re-render', refreshed),
|
|
526
|
+
* });
|
|
527
|
+
* const raffle = raffles[0];
|
|
528
|
+
* const draw = raffle.draws.find(d =>
|
|
529
|
+
* d.requires_optin && !d.user_opted_in && d.is_active && d.current_state !== 3
|
|
530
|
+
* );
|
|
531
|
+
*
|
|
532
|
+
* if (!draw) {
|
|
533
|
+
* console.log('[smartico] no opt-in-required draw available — keep CTA hidden');
|
|
534
|
+
* return;
|
|
535
|
+
* }
|
|
536
|
+
*
|
|
537
|
+
* console.log('[smartico] opt-in starting — set in-flight flag, show loading dots on the Opt-in button');
|
|
538
|
+
* const r = await window._smartico.api.requestRaffleOptin({
|
|
539
|
+
* raffle_id: raffle.id,
|
|
540
|
+
* draw_id: draw.id, // schedule_id, NOT run_id
|
|
541
|
+
* raffle_run_id: draw.run_id,
|
|
542
|
+
* });
|
|
543
|
+
* console.log('[smartico] opt-in response received — clear in-flight flag');
|
|
544
|
+
*
|
|
545
|
+
* if (r.err_code === 0) {
|
|
546
|
+
* console.log('[smartico] opted in successfully — show "Fully opted in" state on the draw card; onUpdate above will fire with user_opted_in: true');
|
|
547
|
+
* } else if (r.err_code === 1 && r.err_message?.toLowerCase().includes('already opted in')) {
|
|
548
|
+
* console.log('[smartico] already opted in (perhaps from another tab) — treat as success, show "Fully opted in"');
|
|
549
|
+
* } else {
|
|
550
|
+
* console.error('[smartico] opt-in failed — surface this error to the user:', r.err_message);
|
|
551
|
+
* }
|
|
552
|
+
* ```
|
|
156
553
|
*/
|
|
157
554
|
public async requestRaffleOptin(props: { raffle_id: number; draw_id: number; raffle_run_id: number }): Promise<TRaffleOptinResponse> {
|
|
158
555
|
if (!props.raffle_id) {
|
|
@@ -172,4 +569,135 @@ export class WSAPIRaffles extends WSAPIJackpots {
|
|
|
172
569
|
err_message: r.errMsg,
|
|
173
570
|
};
|
|
174
571
|
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Returns every prize the current user has won within a single raffle —
|
|
575
|
+
* across ALL of that raffle's draws, newest-won first — in one paginated
|
|
576
|
+
* call. Use this to power a "my prizes" screen for a raffle (prize name,
|
|
577
|
+
* prize image, the user's name/avatar) without walking
|
|
578
|
+
* {@link getRaffleDrawRunsHistory} and then paging
|
|
579
|
+
* {@link getRaffleDrawRun}'s per-draw winner lists.
|
|
580
|
+
*
|
|
581
|
+
* Each row carries its own `raf_won_id`, which IS the `won_id` to pass to
|
|
582
|
+
* {@link claimRafflePrize}: a row with `requires_claim === true` and no
|
|
583
|
+
* `claimed_date` is directly claimable.
|
|
584
|
+
*
|
|
585
|
+
* @remarks
|
|
586
|
+
* **Authentication required**
|
|
587
|
+
* Works only for an identified (logged-in) user. Visitor / anonymous
|
|
588
|
+
* sessions are rejected — call this only after identify.
|
|
589
|
+
*
|
|
590
|
+
* **Preconditions**
|
|
591
|
+
* `raffle_id` is required — the SDK throws synchronously when it is
|
|
592
|
+
* missing or falsy.
|
|
593
|
+
*
|
|
594
|
+
* **Coverage & sort order**
|
|
595
|
+
* Includes the user's wins from every draw of the raffle — recurring,
|
|
596
|
+
* one-shot, and grand draws, across all historical runs. Rows are ordered
|
|
597
|
+
* newest-win first; there is no "unclaimed first" ordering, so sort
|
|
598
|
+
* client-side if you want claimable prizes at the top.
|
|
599
|
+
*
|
|
600
|
+
* **Pagination**
|
|
601
|
+
* `offset` / `limit` page the `won_prizes[]` rows (the SDK defaults to
|
|
602
|
+
* `0` / `20`). `total` is the authoritative full count of the user's wins
|
|
603
|
+
* for this raffle across all draws — drive "load more" from it
|
|
604
|
+
* (`offset + won_prizes.length < total`). An `offset` past the end returns
|
|
605
|
+
* an empty `won_prizes[]` with the real `total` and `errCode 0` — not an
|
|
606
|
+
* error. The server does NOT clamp `limit`, so always pass an explicit,
|
|
607
|
+
* sane page size.
|
|
608
|
+
*
|
|
609
|
+
* **Rate limit**
|
|
610
|
+
* The server caps this at roughly 30 calls per minute with a ~5-second
|
|
611
|
+
* minimum gap between calls. Fetch on screen open and on explicit "load
|
|
612
|
+
* more" — don't poll it on a timer.
|
|
613
|
+
*
|
|
614
|
+
* **Error codes** (in `errCode`)
|
|
615
|
+
* - `0` — success. Also returned with an empty `won_prizes[]` and
|
|
616
|
+
* `total 0` when the user has no wins, or is not eligible to see this
|
|
617
|
+
* raffle.
|
|
618
|
+
* - `1` — generic server error; surface `errMsg` if present.
|
|
619
|
+
*
|
|
620
|
+
* There are no granular codes — an unknown raffle, an ineligible user,
|
|
621
|
+
* and "no wins" all surface as `errCode 0` with an empty list.
|
|
622
|
+
*
|
|
623
|
+
* **Reading the result**
|
|
624
|
+
* - Null-check `user` before reading it — it is `null` whenever
|
|
625
|
+
* `won_prizes` is empty.
|
|
626
|
+
* - For the avatar, use `user.avatar_id` (already a full URL for a system
|
|
627
|
+
* avatar, otherwise an avatar token to resolve against the widget's
|
|
628
|
+
* avatar domain); `user.avatar_url` is always `null`.
|
|
629
|
+
* - Render `public_username` as-is (it is server-masked for privacy, e.g.
|
|
630
|
+
* `"32:r*****"`) and substitute a "You" label for the current user.
|
|
631
|
+
* - Treat `claimed_date` as the claim flag: `null` until claimed, then
|
|
632
|
+
* epoch ms.
|
|
633
|
+
*
|
|
634
|
+
* **Idempotency / Side effects**: safe and read-only — one-shot promise,
|
|
635
|
+
* no client cache, no subscription. The server caches the response
|
|
636
|
+
* briefly; a successful {@link claimRafflePrize} invalidates that cache,
|
|
637
|
+
* so a follow-up call reflects the new `claimed_date`. This method does
|
|
638
|
+
* NOT refresh the {@link getRaffles} list or fire its `onUpdate` — re-call
|
|
639
|
+
* manually to pick up newly-won prizes or a `claimed_date` flip.
|
|
640
|
+
*
|
|
641
|
+
* **UI guidance**: see [UI Guide — `getRaffleWonPrizes`](../../docs/ui/raffles/UIGuide_getRaffleWonPrizes.md).
|
|
642
|
+
*
|
|
643
|
+
* **Visitor mode**: not supported (see "Authentication required").
|
|
644
|
+
*
|
|
645
|
+
* @param props.raffle_id The parent raffle's `id` (from `TRaffle.id`). Required.
|
|
646
|
+
* @param props.offset Zero-based index of the first row to return. Defaults to `0`.
|
|
647
|
+
* @param props.limit Page size. Defaults to `20`.
|
|
648
|
+
* @returns Promise resolving to {@link GetRaffleWonPrizesResponse}
|
|
649
|
+
* (`user`, this page of `won_prizes`, and `total`;
|
|
650
|
+
* `errCode 0` on success).
|
|
651
|
+
*
|
|
652
|
+
* @example
|
|
653
|
+
* ```ts
|
|
654
|
+
* const raffles = await window._smartico.api.getRaffles();
|
|
655
|
+
* const raffle = raffles[0];
|
|
656
|
+
*
|
|
657
|
+
* // First page of the user's won prizes for this raffle.
|
|
658
|
+
* const page = await window._smartico.api.getRaffleWonPrizes({
|
|
659
|
+
* raffle_id: raffle.id,
|
|
660
|
+
* offset: 0,
|
|
661
|
+
* limit: 20,
|
|
662
|
+
* });
|
|
663
|
+
*
|
|
664
|
+
* if (page.errCode !== 0) {
|
|
665
|
+
* console.error('[smartico] could not load won prizes — show a retry state:', page.errMsg);
|
|
666
|
+
* return;
|
|
667
|
+
* }
|
|
668
|
+
* if (page.won_prizes.length === 0) {
|
|
669
|
+
* console.log('[smartico] no wins in this raffle (or not eligible) — render the empty state');
|
|
670
|
+
* return;
|
|
671
|
+
* }
|
|
672
|
+
*
|
|
673
|
+
* console.log('[smartico]', page.user?.public_username, 'won', page.total, 'prizes total');
|
|
674
|
+
* for (const prize of page.won_prizes) {
|
|
675
|
+
* console.log('[smartico] render prize card —', prize.public_meta.name, prize.public_meta.image_url);
|
|
676
|
+
* if (prize.requires_claim && !prize.claimed_date) {
|
|
677
|
+
* console.log('[smartico] show a Claim CTA — on click call claimRafflePrize({ won_id:', prize.raf_won_id, '})');
|
|
678
|
+
* }
|
|
679
|
+
* }
|
|
680
|
+
*
|
|
681
|
+
* // Load more.
|
|
682
|
+
* if (page.offset + page.won_prizes.length < page.total) {
|
|
683
|
+
* const next = await window._smartico.api.getRaffleWonPrizes({
|
|
684
|
+
* raffle_id: raffle.id,
|
|
685
|
+
* offset: page.offset + page.limit,
|
|
686
|
+
* limit: 20,
|
|
687
|
+
* });
|
|
688
|
+
* console.log('[smartico] appended', next.won_prizes.length, 'more prizes');
|
|
689
|
+
* }
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
public async getRaffleWonPrizes(props: { raffle_id: number; offset?: number; limit?: number }): Promise<GetRaffleWonPrizesResponse> {
|
|
693
|
+
if (!props.raffle_id) {
|
|
694
|
+
throw new Error('raffle_id is required');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return await this.api.getRaffleWonPrizes(this.userExtId, {
|
|
698
|
+
raffle_id: props.raffle_id,
|
|
699
|
+
offset: props.offset ?? 0,
|
|
700
|
+
limit: props.limit ?? 20,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
175
703
|
}
|