@smartico/public-api 0.0.380 → 0.0.381

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