@smartico/public-api 0.0.379 → 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 (219) hide show
  1. package/.nvmrc +1 -1
  2. package/CLAUDE.md +103 -0
  3. package/README.md +53 -2
  4. package/dist/Base/ClassId.d.ts +2 -0
  5. package/dist/Jackpots/JackpotDetails.d.ts +14 -15
  6. package/dist/Jackpots/JackpotPot.d.ts +10 -6
  7. package/dist/Raffle/GetRaffleWonPrizesRequest.d.ts +9 -0
  8. package/dist/Raffle/GetRaffleWonPrizesResponse.d.ts +52 -0
  9. package/dist/Raffle/index.d.ts +2 -0
  10. package/dist/SmarticoAPI.d.ts +6 -1
  11. package/dist/SmarticoLib/index.d.ts +5 -1
  12. package/dist/Store/BuyStoreItemErrorCode.d.ts +9 -1
  13. package/dist/Tournaments/TournamentRegistrationError.d.ts +3 -1
  14. package/dist/WSAPI/WSAPI.d.ts +13 -1235
  15. package/dist/WSAPI/WSAPIAvatars.d.ts +296 -0
  16. package/dist/WSAPI/WSAPIBase.d.ts +71 -0
  17. package/dist/WSAPI/WSAPIBonuses.d.ts +240 -0
  18. package/dist/WSAPI/WSAPIClans.d.ts +388 -0
  19. package/dist/WSAPI/WSAPIGamePick.d.ts +593 -0
  20. package/dist/WSAPI/WSAPIGeneral.d.ts +172 -0
  21. package/dist/WSAPI/WSAPIInbox.d.ts +615 -0
  22. package/dist/WSAPI/WSAPIJackpots.d.ts +344 -0
  23. package/dist/WSAPI/WSAPILeaderBoard.d.ts +139 -0
  24. package/dist/WSAPI/WSAPIMiniGames.d.ts +510 -0
  25. package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
  26. package/dist/WSAPI/WSAPIRaffles.d.ts +643 -0
  27. package/dist/WSAPI/WSAPIStore.d.ts +656 -0
  28. package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
  29. package/dist/WSAPI/WSAPITypes.d.ts +376 -205
  30. package/dist/WSAPI/WSAPIUser.d.ts +533 -0
  31. package/dist/index.js +6745 -1661
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.modern.mjs +6324 -1342
  34. package/dist/index.modern.mjs.map +1 -1
  35. package/docs/Callbacks.md +162 -0
  36. package/docs/SmarticoObject.md +445 -0
  37. package/docs/Transforms.md +99 -0
  38. package/docs/api/README.md +82 -2
  39. package/docs/api/classes/WSAPIAvatars.md +344 -0
  40. package/docs/api/classes/WSAPIBonuses.md +271 -0
  41. package/docs/api/classes/WSAPIClans.md +436 -0
  42. package/docs/api/classes/WSAPIGamePick.md +710 -0
  43. package/docs/api/classes/WSAPIGeneral.md +212 -0
  44. package/docs/api/classes/WSAPIInbox.md +801 -0
  45. package/docs/api/classes/WSAPIJackpots.md +439 -0
  46. package/docs/api/classes/WSAPILeaderBoard.md +157 -0
  47. package/docs/api/classes/WSAPIMiniGames.md +612 -0
  48. package/docs/api/classes/WSAPIMissions.md +590 -0
  49. package/docs/api/classes/WSAPIRaffles.md +773 -0
  50. package/docs/api/classes/WSAPIStore.md +719 -0
  51. package/docs/api/classes/WSAPITournaments.md +571 -0
  52. package/docs/api/classes/WSAPIUser.md +637 -0
  53. package/docs/api/documents/Callbacks.md +162 -0
  54. package/docs/api/documents/SmarticoObject.md +445 -0
  55. package/docs/api/documents/Transforms.md +99 -0
  56. package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
  57. package/docs/api/enumerations/BonusStatus-1.md +11 -6
  58. package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -0
  59. package/docs/api/enumerations/JoinClanErrorCode.md +81 -0
  60. package/docs/api/enumerations/TournamentRegistrationError.md +12 -0
  61. package/docs/api/functions/clanTournamentPlayersTransform.md +13 -0
  62. package/docs/api/interfaces/AvatarCustomized.md +25 -0
  63. package/docs/api/interfaces/AvatarDefinition.md +94 -0
  64. package/docs/api/interfaces/AvatarPrompt.md +45 -0
  65. package/docs/api/interfaces/BonusMetaMap-1.md +4 -1
  66. package/docs/api/interfaces/BonusTemplateMetaMap-1.md +9 -4
  67. package/docs/api/interfaces/Clan.md +4 -0
  68. package/docs/api/interfaces/ClanInfo.md +109 -0
  69. package/docs/api/interfaces/ClanMember.md +53 -0
  70. package/docs/api/interfaces/ClanPrizePublicMeta.md +41 -0
  71. package/docs/api/interfaces/ClanPrizeStructureEntry.md +7 -1
  72. package/docs/api/interfaces/ClanPublicMeta.md +4 -0
  73. package/docs/api/interfaces/ClanTournamentPlayerRaw.md +67 -0
  74. package/docs/api/interfaces/GemsDiamondsLog.md +43 -0
  75. package/docs/api/interfaces/GetClanInfoResponse.md +61 -0
  76. package/docs/api/interfaces/GetClanTournamentPlayersResponse.md +81 -0
  77. package/docs/api/interfaces/GetRaffleWonPrizesRequest.md +59 -0
  78. package/docs/api/interfaces/GetRaffleWonPrizesResponse.md +95 -0
  79. package/docs/api/interfaces/InboxMarkMessageAction.md +10 -2
  80. package/docs/api/interfaces/JackpotDetails.md +14 -15
  81. package/docs/api/interfaces/JackpotPot.md +9 -6
  82. package/docs/api/interfaces/LeaderBoardDetailsT.md +14 -8
  83. package/docs/api/interfaces/LeaderBoardUserT.md +8 -5
  84. package/docs/api/interfaces/LeaderBoardsRewardsT.md +7 -0
  85. package/docs/api/interfaces/PointsLog.md +43 -0
  86. package/docs/api/interfaces/RaffleWonPrize.md +59 -0
  87. package/docs/api/interfaces/RaffleWonPrizePublicMeta.md +27 -0
  88. package/docs/api/interfaces/RaffleWonPrizeUser.md +43 -0
  89. package/docs/api/interfaces/SAWTemplateUI.md +10 -0
  90. package/docs/api/interfaces/TAchCategory.md +14 -4
  91. package/docs/api/interfaces/TAvatarCustomized.md +4 -4
  92. package/docs/api/interfaces/TAvatarDefinition.md +13 -14
  93. package/docs/api/interfaces/TAvatarPrompt.md +6 -6
  94. package/docs/api/interfaces/TBonus.md +16 -8
  95. package/docs/api/interfaces/TBuyStoreItemResult.md +4 -11
  96. package/docs/api/interfaces/TClaimBonusResult.md +5 -5
  97. package/docs/api/interfaces/TClan.md +8 -4
  98. package/docs/api/interfaces/TClanInfo.md +47 -0
  99. package/docs/api/interfaces/TClanJoinResult.md +11 -1
  100. package/docs/api/interfaces/TClanTournamentPlayer.md +55 -0
  101. package/docs/api/interfaces/TClanTournamentPlayersResult.md +27 -0
  102. package/docs/api/interfaces/TClans.md +3 -1
  103. package/docs/api/interfaces/TGetTranslations.md +4 -0
  104. package/docs/api/interfaces/TInboxMessage.md +14 -6
  105. package/docs/api/interfaces/TInboxMessageBody.md +18 -12
  106. package/docs/api/interfaces/TLevel.md +17 -20
  107. package/docs/api/interfaces/TLevelCurrent.md +19 -18
  108. package/docs/api/interfaces/TMiniGamePlayBatchResult.md +14 -6
  109. package/docs/api/interfaces/TMiniGamePlayResult.md +9 -4
  110. package/docs/api/interfaces/TMissionClaimRewardResult.md +6 -3
  111. package/docs/api/interfaces/TMissionOptInResult.md +6 -3
  112. package/docs/api/interfaces/TMissionOrBadge.md +5 -4
  113. package/docs/api/interfaces/TRaffleOptinResponse.md +4 -2
  114. package/docs/api/interfaces/TSegmentCheckResult.md +10 -0
  115. package/docs/api/interfaces/TSetAvatarResult.md +3 -3
  116. package/docs/api/interfaces/TStoreItem.md +11 -1
  117. package/docs/api/interfaces/TTournament.md +1 -1
  118. package/docs/api/interfaces/TTournamentDetailed.md +9 -1
  119. package/docs/api/interfaces/TTournamentRegistrationResult.md +4 -2
  120. package/docs/api/interfaces/TUICustomSection.md +23 -19
  121. package/docs/api/interfaces/TUserProfile.md +18 -16
  122. package/docs/api/interfaces/TransformedRaffleClaimPrizeResponse.md +6 -2
  123. package/docs/api/interfaces/UserAchievement.md +1 -1
  124. package/docs/api/interfaces/UserLevelExtraCountersT.md +9 -2
  125. package/docs/api/type-aliases/ActivityLogEntry.md +3 -0
  126. package/docs/native/ADDING_METHODS.md +7 -2
  127. package/docs/native/PROTOCOL.md +337 -0
  128. package/docs/ui/avatars/UIGuide_getAvatarPrompts.md +100 -0
  129. package/docs/ui/avatars/UIGuide_getAvatarsCustomized.md +90 -0
  130. package/docs/ui/avatars/UIGuide_getAvatarsList.md +105 -0
  131. package/docs/ui/avatars/UIGuide_setAvatar.md +118 -0
  132. package/docs/ui/bonuses/UIGuide_claimBonus.md +144 -0
  133. package/docs/ui/bonuses/UIGuide_getBonuses.md +176 -0
  134. package/docs/ui/clans/UIGuide_getClanInfo.md +153 -0
  135. package/docs/ui/clans/UIGuide_getClans.md +172 -0
  136. package/docs/ui/clans/UIGuide_joinClan.md +196 -0
  137. package/docs/ui/gamepick/UIGuide_gamePickGetActiveRound.md +99 -0
  138. package/docs/ui/gamepick/UIGuide_gamePickGetActiveRounds.md +76 -0
  139. package/docs/ui/gamepick/UIGuide_gamePickGetBoard.md +81 -0
  140. package/docs/ui/gamepick/UIGuide_gamePickGetGameInfo.md +78 -0
  141. package/docs/ui/gamepick/UIGuide_gamePickGetHistory.md +55 -0
  142. package/docs/ui/gamepick/UIGuide_gamePickGetRoundInfoForUser.md +71 -0
  143. package/docs/ui/gamepick/UIGuide_gamePickGetUserInfo.md +64 -0
  144. package/docs/ui/gamepick/UIGuide_gamePickSubmitSelection.md +103 -0
  145. package/docs/ui/gamepick/UIGuide_gamePickSubmitSelectionQuiz.md +67 -0
  146. package/docs/ui/general/UIGuide_getCustomSections.md +137 -0
  147. package/docs/ui/general/UIGuide_getRelatedItemsForGame.md +140 -0
  148. package/docs/ui/inbox/UIGuide_deleteInboxMessage.md +135 -0
  149. package/docs/ui/inbox/UIGuide_getInboxMessageBody.md +133 -0
  150. package/docs/ui/inbox/UIGuide_getInboxMessages.md +186 -0
  151. package/docs/ui/inbox/UIGuide_markInboxMessageAsRead.md +122 -0
  152. package/docs/ui/inbox/UIGuide_markUnmarkInboxMessageAsFavorite.md +84 -0
  153. package/docs/ui/jackpots/UIGuide_getJackpotEligibleGames.md +73 -0
  154. package/docs/ui/jackpots/UIGuide_getJackpotWinners.md +83 -0
  155. package/docs/ui/jackpots/UIGuide_jackpotGet.md +138 -0
  156. package/docs/ui/jackpots/UIGuide_jackpotOptIn.md +85 -0
  157. package/docs/ui/jackpots/UIGuide_jackpotOptOut.md +65 -0
  158. package/docs/ui/leaderboard/UIGuide_getLeaderBoard.md +166 -0
  159. package/docs/ui/minigames/UIGuide_getMiniGames.md +153 -0
  160. package/docs/ui/minigames/UIGuide_getMiniGamesHistory.md +90 -0
  161. package/docs/ui/minigames/UIGuide_playMiniGame.md +150 -0
  162. package/docs/ui/minigames/UIGuide_playMiniGameBatch.md +128 -0
  163. package/docs/ui/missions/UIGuide_getAchCategories.md +17 -0
  164. package/docs/ui/missions/UIGuide_getBadges.md +237 -0
  165. package/docs/ui/missions/UIGuide_getMissions.md +268 -0
  166. package/docs/ui/missions/UIGuide_requestMissionClaimReward.md +21 -0
  167. package/docs/ui/missions/UIGuide_requestMissionOptIn.md +16 -0
  168. package/docs/ui/raffles/UIGuide_claimRafflePrize.md +99 -0
  169. package/docs/ui/raffles/UIGuide_getRaffleDrawRun.md +117 -0
  170. package/docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md +92 -0
  171. package/docs/ui/raffles/UIGuide_getRaffleWonPrizes.md +120 -0
  172. package/docs/ui/raffles/UIGuide_getRaffles.md +175 -0
  173. package/docs/ui/raffles/UIGuide_requestRaffleOptin.md +114 -0
  174. package/docs/ui/store/UIGuide_buyStoreItem.md +133 -0
  175. package/docs/ui/store/UIGuide_getStoreCategories.md +19 -0
  176. package/docs/ui/store/UIGuide_getStoreItems.md +264 -0
  177. package/docs/ui/store/UIGuide_getStorePurchasedItems.md +122 -0
  178. package/docs/ui/tournaments/UIGuide_getClanTournamentPlayers.md +140 -0
  179. package/docs/ui/tournaments/UIGuide_getTournamentInstanceInfo.md +265 -0
  180. package/docs/ui/tournaments/UIGuide_getTournamentsList.md +236 -0
  181. package/docs/ui/tournaments/UIGuide_registerInTournament.md +156 -0
  182. package/docs/ui/user/UIGuide_getActivityLog.md +130 -0
  183. package/docs/ui/user/UIGuide_getLevels.md +167 -0
  184. package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
  185. package/package.json +3 -3
  186. package/scripts/postdoc-cleanup.js +195 -0
  187. package/src/Base/ClassId.ts +2 -0
  188. package/src/Jackpots/JackpotDetails.ts +14 -15
  189. package/src/Jackpots/JackpotPot.ts +10 -6
  190. package/src/Missions/MissionsUtils.ts +5 -2
  191. package/src/Raffle/GetRaffleWonPrizesRequest.ts +12 -0
  192. package/src/Raffle/GetRaffleWonPrizesResponse.ts +56 -0
  193. package/src/Raffle/index.ts +3 -1
  194. package/src/SmarticoAPI.ts +14 -1
  195. package/src/SmarticoLib/index.ts +4 -0
  196. package/src/Store/BuyStoreItemErrorCode.ts +8 -0
  197. package/src/Store/StoreItem.ts +1 -0
  198. package/src/Store/StoreItemPurchased.ts +1 -0
  199. package/src/Store/StoreItemType.ts +1 -1
  200. package/src/Tournaments/TournamentRegistrationError.ts +4 -0
  201. package/src/WSAPI/WSAPI.ts +27 -2007
  202. package/src/WSAPI/WSAPIAvatars.ts +345 -0
  203. package/src/WSAPI/WSAPIBase.ts +93 -0
  204. package/src/WSAPI/WSAPIBonuses.ts +268 -0
  205. package/src/WSAPI/WSAPIClans.ts +417 -0
  206. package/src/WSAPI/WSAPIGamePick.ts +667 -0
  207. package/src/WSAPI/WSAPIGeneral.ts +199 -0
  208. package/src/WSAPI/WSAPIInbox.ts +711 -0
  209. package/src/WSAPI/WSAPIJackpots.ts +448 -0
  210. package/src/WSAPI/WSAPILeaderBoard.ts +154 -0
  211. package/src/WSAPI/WSAPIMiniGames.ts +597 -0
  212. package/src/WSAPI/WSAPIMissions.ts +572 -0
  213. package/src/WSAPI/WSAPIRaffles.ts +703 -0
  214. package/src/WSAPI/WSAPIStore.ts +732 -0
  215. package/src/WSAPI/WSAPITournaments.ts +541 -0
  216. package/src/WSAPI/WSAPITypes.ts +376 -207
  217. package/src/WSAPI/WSAPIUser.ts +606 -0
  218. package/tsconfig.json +26 -2
  219. package/docs/api/classes/WSAPI.md +0 -1927
@@ -0,0 +1,17 @@
1
+ # UI Guide — `getAchCategories`
2
+
3
+ ## UI guidance
4
+ - Treat categories as relatively static. It is safe to fetch once on page load and
5
+ reuse for the lifetime of the view; the SDK's 30 s cache handles short-term re-calls.
6
+ - Sort by `order` ascending before rendering. Items with the same `order` should
7
+ fall back to `name` or `id` for stable ordering.
8
+ - For tab UIs, generate one tab per category; "All" / "Other" tabs are
9
+ caller-provided (not returned by the server).
10
+ - For section UIs (mission/badge listing grouped by category), iterate sorted
11
+ categories and render only those whose filtered item list is non-empty unless
12
+ you intentionally want empty sections.
13
+ - Loading indicator: skip on cache hit; show a brief shimmer on cold fetch
14
+ (typically 100–300 ms).
15
+
16
+ **Visitor mode**: supported. Use `_smartico.vapi(lang).getAchCategories()` to fetch
17
+ categories with `name` translated to the given language without an authenticated user.
@@ -0,0 +1,237 @@
1
+ # UI Guide — `getBadges`
2
+
3
+ ## Overview
4
+ - Badges are completion-tracked achievements that **auto-unlock** when their
5
+ criteria are met. No opt-in step, no claim step, no recurring cycles.
6
+ - The same `TMissionOrBadge` shape is reused; treat the mission-only fields
7
+ on a badge object as not-applicable (see method TSDoc for the list).
8
+ - The default Smartico UI renders badges as a **category-grouped grid** —
9
+ not a flat list and not as status tabs. Each category section shows
10
+ `completed / total` in its header.
11
+ - No `onUpdate` subscription. Poll on the 30 s cache TTL or re-fetch on a
12
+ domain event your app already handles (e.g. after a game round, after a
13
+ bonus claim).
14
+ - Loading indicator: skip on cache hit; show a brief shimmer on cold fetch
15
+ (typically 100–500 ms).
16
+
17
+ ## List view organization
18
+
19
+ Group by category (`category_ids`) and resolve display metadata via
20
+ [`getAchCategories`](../../api/classes/WSAPIMissions.md#getachcategories).
21
+ The category list serves both missions and badges — use it directly.
22
+
23
+ Recommended layout — sectioned grid:
24
+
25
+ 1. Fetch badges + categories in parallel.
26
+ 2. Sort categories by `order` ascending.
27
+ 3. For each category, filter `badges.filter(b => b.category_ids.includes(cat.id))`.
28
+ 4. Render one collapsible section per non-empty category, with a header
29
+ showing `<name> (<completed>/<total>)`.
30
+ 5. Items inside a section render as a fixed-cell grid (typically 3–4
31
+ columns on desktop, 2 on mobile — see "Mobile vs desktop").
32
+
33
+ Items with `category_ids: []` (uncategorized): the SDK does NOT return a
34
+ synthetic "Other" category. If your UI surfaces uncategorized badges,
35
+ generate that bucket client-side. Many badge UIs simply hide uncategorized
36
+ badges.
37
+
38
+ A badge can appear in multiple categories — duplicate rendering across
39
+ sections is intentional. Do NOT dedupe; users navigate categories
40
+ independently.
41
+
42
+ **Sort within a category**: typical priority — `is_completed === true`
43
+ first (most recently completed by `complete_date_ts` DESC), then
44
+ in-progress (by `position` ASC), then not-yet-started (by `position` ASC),
45
+ then expired (by `position` ASC). `position` is the operator-configured
46
+ display order; lower = higher priority.
47
+
48
+ ## Badge card / tile
49
+
50
+ Fields to render on the card:
51
+
52
+ - `image` — documented source size 256×256 px. Render at a 1:1 aspect
53
+ ratio. There is no built-in placeholder for missing images — provide a
54
+ neutral fallback (e.g. a generic locked-badge silhouette).
55
+ - `name` — the title. Translated server-side.
56
+ - Stage counter — show **`<completed_tasks> / <total_tasks>`** computed
57
+ from `tasks` (count `t.is_completed === true` over `tasks.length`), NOT
58
+ a percentage `progress` bar. The default Smartico UI deliberately keeps
59
+ task descriptions hidden ("surprise mechanics") and shows only the count
60
+ of stages cleared. The exception: a single-task badge can show just a
61
+ completion check-mark instead of `1/1`.
62
+ - Availability chip — drive from `badgeTimeLimitState`. See "Status-specific
63
+ visual treatments" for the per-state visual treatment.
64
+ - `ribbon` — optional tag rendered as a corner badge (`sale`, `hot`, `new`,
65
+ `vip` or a custom 250×300 px image URL). Render top-right on the card.
66
+
67
+ Fields NOT on the card (detail-view only): `description`, full task list
68
+ with names, `hint_text` (T&C), category memberships.
69
+
70
+ **Click target**: whole card opens the detail view. There is no action
71
+ button on the card itself — badges have no opt-in or claim flow.
72
+
73
+ ## Detail view / popup
74
+
75
+ Top-to-bottom layout:
76
+
77
+ 1. **Hero image** — `image` rendered at a larger size (typically
78
+ 320×320 px or full-width up to a max). Apply the same status overlay
79
+ as the card (see "Status-specific visual treatments").
80
+ 2. **Title & availability chip** — `name` + status chip.
81
+ 3. **Description** — `description` HTML.
82
+ 4. **Task list** — render `tasks[].name` as a vertical list, each with
83
+ a check-mark when `task.is_completed === true`. Do NOT render
84
+ `tasks[].progress` percentages; the badge UX convention is "stages
85
+ cleared", not "percent complete". Optionally show stage `points_reward`
86
+ beside each task name if the brand surfaces task rewards.
87
+ 5. **Reward summary** — `reward` HTML if non-empty.
88
+ 6. **Timing block** — formatted `active_from_ts` / `active_till_ts` or
89
+ completion date `complete_date_ts`. See "Countdown / timing format".
90
+ 7. **T&C** — `hint_text` if present, in a smaller collapsible
91
+ "Terms" panel.
92
+ 8. **Related games** — `related_games` array rendered as a horizontal
93
+ game-tile strip if non-empty. Each tile clicks through to the game
94
+ using `related_games[i].game_public_meta.link`.
95
+
96
+ No primary CTA button at the bottom — badges are passive. If the brand
97
+ wants to drive engagement from the popup, surface a `related_games` strip
98
+ or a deep-link CTA derived from the brand's own configuration; the SDK
99
+ itself does not return one for badges.
100
+
101
+ ## Action button decision matrix
102
+
103
+ Badges have **no action buttons**. They auto-unlock when criteria are met.
104
+ Anything that looks like an action button in a badge view is either:
105
+
106
+ - A close / back affordance (popup chrome), or
107
+ - A "View related game" link derived from `related_games[i].game_public_meta.link`, or
108
+ - A custom brand-defined CTA the operator wires up externally — the SDK
109
+ does not return a `cta_action` payload for badges in practice.
110
+
111
+ Do NOT render opt-in buttons, claim buttons, or anything that mutates
112
+ state. Both surfaces would no-op against badge IDs (no server endpoint
113
+ accepts a badge for opt-in / claim).
114
+
115
+ ## Image / asset specs
116
+
117
+ | Field | Documented source size | Aspect ratio | Fallback |
118
+ |---|---|---|---|
119
+ | `image` | 256×256 px | 1:1 | Neutral locked-badge silhouette |
120
+ | `ribbon` (custom URL) | 250×300 px | 5:6 portrait | Hide ribbon if URL fails to load |
121
+ | `related_games[i].game_public_meta.image` | per game-catalog spec (1:1) | 1:1 | Hide tile if image missing |
122
+
123
+ If `image` is missing or fails to load: render the fallback at the same
124
+ size. Do not show a broken-image icon — this UI surface is consumer-facing
125
+ gamification and a broken image undermines the reward fantasy.
126
+
127
+ ## Status-specific visual treatments
128
+
129
+ Drive from `badgeTimeLimitState` first, then layer completion state on
130
+ top.
131
+
132
+ | `badgeTimeLimitState` | Card visual | Availability chip text |
133
+ |---|---|---|
134
+ | `BeforeStartDate` (0) — window hasn't started | Grayscale + subtle dim overlay. Lock-icon corner badge if `is_locked === true`. | `"Starts on <date>"` from `active_from_ts` |
135
+ | `AfterStartDateNoProgress` (1) — active, no progress yet, no end date | Full-color, no overlay | No chip (or a neutral `"Available"`) |
136
+ | `AfterStartDateNoProgressAndEndDate` (2) — active, no progress, has end date | Full-color | `"Until <date>"` from `active_till_ts` |
137
+ | `AfterStartDateWithProgressAndEndDate` (3) — active with progress, has end date | Full-color | `"<countdown>"` to `active_till_ts` (see "Countdown / timing format") |
138
+ | `AfterEndDateNotStarted` (4) — expired, never started | Grayscale + dim overlay + slash/X overlay | `"Expired"` |
139
+ | `AfterEndDateWithProgress` (5) — expired with some progress | Grayscale + dim overlay | `"Ended"` (or `"Expired"`) |
140
+
141
+ On top of the time-window treatment, layer the completion state:
142
+
143
+ - `is_completed === true` — color-restored card (override grayscale),
144
+ prominent check-mark corner badge, glow / shine accent. The default
145
+ Smartico UI shows the most-recently-completed badges first within a
146
+ category by `complete_date_ts` DESC.
147
+ - `is_completed === false` and at least one `task.is_completed === true` —
148
+ show the stage counter prominently (e.g. larger font, contrasting color)
149
+ to signal in-progress.
150
+ - All other cases — neutral card, stage counter at default emphasis.
151
+
152
+ ## Countdown / timing format
153
+
154
+ Time displayed varies by badge state. Recommended format ("compact"):
155
+
156
+ - **Time-until-start** (`badgeTimeLimitState === BeforeStartDate`):
157
+ - More than 7 days away → `"Starts <date>"` (e.g. `"Starts 12 Jun"`)
158
+ - 1–7 days → `"Starts in <N> days"`
159
+ - < 24 h → `"Starts in <Hh Mm>"`
160
+ - **Time-until-end** (`AfterStartDateWithProgressAndEndDate`,
161
+ `AfterStartDateNoProgressAndEndDate`):
162
+ - > 7 days → `"Until <date>"`
163
+ - 1–7 days → `"<N> days left"`
164
+ - 1–24 h → `"<Hh Mm> left"`
165
+ - < 1 h → `"<Mm Ss> left"`, updated every second
166
+ - **Completed**: `"Completed <relative>"` (e.g. `"Completed 2 days ago"`)
167
+ from `complete_date_ts`. Tooltip shows full timestamp.
168
+ - **Expired / ended**: just the static label `"Expired"` or `"Ended"`.
169
+
170
+ Update cadence:
171
+ - > 1 hour away from boundary → refresh once a minute is enough.
172
+ - < 1 hour → refresh once a second.
173
+ - Avoid rendering ticking timers for badges that don't have an `active_till_ts`
174
+ (most badges) — most badges are open-ended.
175
+
176
+ ## Empty / loading / error states
177
+
178
+ - **Loading (cold fetch)**: render a shimmer grid (skeleton cards) matching
179
+ the eventual grid layout. Show category-section headers if cached, else
180
+ shimmer the entire view.
181
+ - **Loading (cache hit)**: do not render a loading state. The promise
182
+ resolves within a microtask.
183
+ - **Empty result**: `[]` from the server means the brand has no badges
184
+ configured for the user (rare). Render a neutral empty-state illustration
185
+ with copy like `"No badges yet"`. Do NOT show this state during the
186
+ cold-fetch shimmer.
187
+ - **Error**: cache the prior result if any and keep rendering it; show a
188
+ small non-blocking error banner. Retry on the next poll tick. Do not
189
+ break the page on a single fetch failure.
190
+
191
+ ## Animations / transitions
192
+
193
+ - **List entry**: cards fade-in on first render. Within a category section,
194
+ the default Smartico UI staggers the fade by ~30 ms per card.
195
+ - **Category section expand/collapse**: smooth height animation (~200 ms
196
+ ease-out).
197
+ - **Badge completion celebration**: when `is_completed` flips from `false`
198
+ to `true` between fetches (your consumer detects this by diffing the
199
+ prior list), play a celebration animation on the affected card —
200
+ shine sweep + check-mark scale-in. The default Smartico UI also opens
201
+ the detail popup automatically on a freshly-completed badge if the
202
+ user is currently viewing the badge surface; mirror this only if your
203
+ product surface justifies it.
204
+ - **Stage tick**: when `completed_tasks` increases between fetches without
205
+ full completion, briefly highlight the stage counter (color flash for
206
+ ~500 ms) to acknowledge progress.
207
+
208
+ ## Mobile vs desktop
209
+
210
+ - **Grid columns**: desktop typically 3–4 columns, tablet 2–3, mobile 2.
211
+ Cards are square (1:1 image aspect ratio drives the layout).
212
+ - **Card density**: mobile cards may hide the ribbon to reduce visual
213
+ noise; the stage counter remains.
214
+ - **Detail view**: mobile opens as a full-screen modal (slide-up); desktop
215
+ opens as a centered popup with backdrop dim.
216
+ - **Category sections**: mobile may default-collapse all sections except
217
+ the first one with non-zero progress; desktop typically renders all
218
+ sections expanded.
219
+
220
+ ## Performance
221
+
222
+ - Diff the badge list between fetches to detect completion / stage events
223
+ for animations. Avoid full re-renders on every poll tick — keyed
224
+ per-card rendering matters because the celebration animations break
225
+ if the DOM nodes are recreated.
226
+ - The `image` URLs are CDN-hosted; let the browser cache them. Lazy-load
227
+ images below the fold; eager-load images in the first visible category.
228
+ - 30 s polling is fine for a small to medium badge catalog (< 200 badges).
229
+ For very large catalogs, consider polling only when the badges surface
230
+ is in the viewport (use `IntersectionObserver`) — the SDK doesn't
231
+ throttle for you.
232
+
233
+ **Visitor mode: not supported.** Use [`getMissions`](../../api/classes/WSAPIMissions.md#getmissions)
234
+ (visitor mode supported) or [`getAchCategories`](../../api/classes/WSAPIMissions.md#getachcategories)
235
+ (visitor mode supported) if you need achievement data for anonymous users.
236
+ Calling `_smartico.vapi(lang).getBadges()` returns no usable data — visitor
237
+ sessions have no badge-progress path on the server.
@@ -0,0 +1,268 @@
1
+ # UI Guide — `getMissions`
2
+
3
+ ## Overview
4
+ - Register `onUpdate` on first render and treat each invocation as
5
+ "discard prior list, re-render from this array". Do not merge with
6
+ the previous list — fields like `progress` are absolute, not deltas.
7
+ - Loading indicator: the first `getMissions()` is a server round-trip
8
+ (typically 100–500 ms); subsequent calls within the cache window
9
+ resolve effectively synchronously.
10
+ - Don't poll `getMissions()` to detect opt-in / claim completion. The
11
+ `onUpdate` callback is the authoritative signal.
12
+ - The SDK returns a flat array; there is no pre-computed status bucket
13
+ field. Consumers apply the bucketing filter chain below themselves.
14
+
15
+ ## Status bucketing
16
+ Partition the array using this **priority order — first match wins**:
17
+
18
+ 1. **Missed** — time window passed before completion. Test:
19
+ `(!is_completed) && ((is_requires_optin && is_opted_in || !is_requires_optin)`
20
+ ` && time_limit_ms && dt_start && (dt_start + time_limit_ms) < Date.now())`
21
+ `|| (active_till_ts && active_till_ts < Date.now())`.
22
+ Sort: `position` ASC.
23
+ 2. **Completed** — `is_completed === true`, OR for missions of type
24
+ `AchievementStatus.RecurringUponCompletion`,
25
+ `max_completion_count === completion_count` (cap reached) OR
26
+ `completion_count > 0` (at least one cycle completed).
27
+ Sort: `complete_date_ts` DESC (most recent first).
28
+ 3. **Locked** — `is_locked === true`, OR not yet available
29
+ (`active_from_ts > Date.now()`). Sort: `position` ASC.
30
+ 4. **Available (in-progress)** — none of the above.
31
+ Sort: `position` ASC.
32
+
33
+ Each mission belongs to exactly ONE bucket. Many UIs render these as
34
+ status tabs / sections. The `availability_status` field
35
+ ([AchievementAvailabilityStatus](../../api/enumerations/AchievementAvailabilityStatus.md)) is authoritative for **timer /
36
+ window state** (which countdown to show, whether the window has
37
+ elapsed) — but it is NOT a substitute for bucketing: distinguishing
38
+ "locked" from "opt-in required" requires reading `is_locked` and
39
+ `is_opted_in` directly. An "Overview" tab curating featured +
40
+ in-progress + a sample locked is a common pattern.
41
+
42
+ ## Mission card / tile (list view)
43
+
44
+ Fields to render on the card:
45
+ - `image` — documented source size 256×256 px. Render at a 1:1 aspect
46
+ ratio; CSS `background-image` is conventional. There is no built-in
47
+ placeholder for missing images — provide a neutral fallback.
48
+ - `name` — the title. Translated server-side. Safe to render as HTML
49
+ if the consumer sanitizes first.
50
+ - Status chip — derived from the bucket the mission falls into;
51
+ includes a live countdown for time-limited entries (see "time
52
+ formatting" below).
53
+ - Description (fallback chain): `description` → `unlock_mission_description`
54
+ (when `is_locked`) → `tasks[0].name` (when no description and tasks
55
+ exist).
56
+ - Progress bar — render only when `progress > 0` (the 0–100 integer).
57
+ Hide for completed recurring missions (`AchievementStatus.RecurringUponCompletion`
58
+ on the Completed tab) to avoid showing residual percentage from a
59
+ prior cycle.
60
+ - Reward summary (`reward` HTML) — show only when `progress === 0`.
61
+ For in-progress missions, the progress percentage replaces the reward.
62
+ - Ribbon overlay (`ribbon` field) — presets `'sale'`, `'hot'`, `'new'`,
63
+ `'vip'` use built-in styling; a URL means a custom **250×300 px** image.
64
+ Position: top-left corner overlay.
65
+ - "Claim" button — replaces the progress bar when
66
+ `is_completed && requires_prize_claim && !prize_claimed_date_ts`.
67
+ - "Featured" marker — alternative to ribbon for operator-marked
68
+ featured missions.
69
+
70
+ Fields NOT shown on the card (detail popup only):
71
+ - Full `description` HTML beyond a single line
72
+ - `sub_header`
73
+ - `tasks[]` (except as description fallback)
74
+ - `hint_text` (T&C)
75
+ - `related_games`
76
+ - Opt-in / CTA action buttons (the status chip alone communicates
77
+ "opt-in required" on cards; the actual button lives in the popup)
78
+
79
+ Click target: the **whole card** opens the detail popup. The Claim
80
+ button (when present) is the only sub-element with its own handler;
81
+ it must `event.stopPropagation()` so the popup doesn't also open.
82
+
83
+ ## Mission detail popup
84
+
85
+ Top-to-bottom structure (omit sections whose source field is empty):
86
+ 1. Close button.
87
+ 2. Ribbon overlay (same as card).
88
+ 3. Title (`name`).
89
+ 4. Sub-header (`sub_header`).
90
+ 5. Status chip — typically without countdown (use the dedicated
91
+ time-remaining block below).
92
+ 6. Image (`image`) — render larger than the card variant.
93
+ 7. Lock icon overlay on the image when `is_locked === true`.
94
+ 8. Time-remaining block — "Available again in" countdown for
95
+ recurring waiting; "Starts on" for `active_from_ts > now`;
96
+ "Expired on" for missed; countdown for in-window.
97
+ 9. Full `description` (HTML).
98
+ 10. Action button — see the decision matrix below.
99
+ 11. Hint / T&C — `hint_text` surfaced as an info-icon tooltip
100
+ (tap to expand). Not inline.
101
+ 12. Task list — only when `tasks.length > 1` (single-task missions
102
+ use the task name as description fallback on the card; the
103
+ list is redundant). Each task row: completion indicator
104
+ (checkbox/circle) + `task.name`. Append "N / M" using
105
+ `execution_count_actual / execution_count_expected` when the
106
+ operator has enabled count display. Show a points stamp for
107
+ tasks with `points_reward > 0`.
108
+ 13. Progress bar (conditional, same rule as card).
109
+ 14. Reward block (`reward`).
110
+ 15. Related games — only games where `game_public_meta.enabled === true`.
111
+ Render as a horizontal carousel; show navigation arrows when
112
+ 5+ games on desktop, 4+ on mobile. Thumbnails are 1:1 aspect
113
+ ratio; tap a thumbnail to launch the underlying game.
114
+ 16. Unlock description (`unlock_mission_description`) at the
115
+ bottom when `is_locked`.
116
+
117
+ ## Action button decision matrix
118
+
119
+ Apply in priority order; **first match wins**:
120
+
121
+ 1. `is_locked === true` → **no action button**. Show the unlock
122
+ description and a lock-icon overlay on the image.
123
+ 2. `is_completed && requires_prize_claim && !prize_claimed_date_ts`
124
+ AND `prize_claim_expiration_date >= Date.now()` (claimable) →
125
+ **"Claim" button**. Use `claim_button_title` as the label if set,
126
+ otherwise a localized default. On click: call
127
+ `requestMissionClaimReward(id, ach_completed_id)`. Optionally
128
+ animate a celebration overlay after success.
129
+ 3. Same as (2) but claim window expired (`prize_claim_expiration_date < Date.now()`) →
130
+ render the Claim label as **disabled**; show the formatted expiration
131
+ date with a "claim expired on" prefix.
132
+ 4. `is_completed` (no claim required, or already claimed) →
133
+ **no action button**. Show progress / completion state.
134
+ 5. `is_requires_optin && !is_opted_in` (and not locked) →
135
+ **"Opt In" button**. Disable when:
136
+ - `active_from_ts > Date.now()` (not yet started),
137
+ - the mission falls in the Missed bucket,
138
+ - `active_till_ts && active_till_ts < Date.now()` (expired).
139
+ While the opt-in request is in flight, show a loading indicator
140
+ on the button. The SDK does NOT enforce a single in-flight call —
141
+ guard against double-clicks at the UI layer (set a local
142
+ `optInLoading` flag on click).
143
+ 6. `cta_text && cta_action` (and none of the above) → **CTA button**
144
+ labeled with `cta_text`. On click: call
145
+ `_smartico.dp(cta_action)`. `cta_action` is a deep-link string
146
+ (e.g. `'dp:deposit'`, `'dp:gf_store'`) — not a URL.
147
+ Disable when the mission falls in the Missed bucket or is
148
+ otherwise out of window.
149
+ 7. None of the above → no action button.
150
+
151
+ Recurring missions:
152
+ - Waiting for next cycle (`next_recurrence_date_ts > Date.now()`) →
153
+ **no button**; the status chip carries the "Available again in
154
+ DD:HH:MM:SS" countdown.
155
+ - Cap reached (`max_completion_count === completion_count`) → treated
156
+ as Completed; no button.
157
+
158
+ ## `claim_button_action` companion action
159
+
160
+ *(important caveat)*
161
+
162
+ If `claim_button_action` is set, the consumer's claim handler is
163
+ expected to fire BOTH the claim API call AND the deep-link action
164
+ **at the same time** (concurrently). The deep-link runs synchronously
165
+ on click — it does NOT wait for the claim RPC to succeed. Consequences:
166
+ - If the deep-link navigates away (e.g. opens a casino game), the
167
+ user may miss the claim loading animation or any error toast.
168
+ - If the claim RPC fails after the navigation has already started,
169
+ there is no rollback.
170
+ - Treat `claim_button_action` as a *companion navigation*, not a
171
+ post-claim follow-up. Common pattern:
172
+ `dispatch claim → _smartico.dp(claim_button_action)` in the same
173
+ click handler, without `await`-ing the claim.
174
+ - `claim_button_action` accepts both `dp:...` deep-links and full
175
+ `http(s)://...` URLs (URLs open in a new tab).
176
+
177
+ ## Image / asset specs
178
+ - Mission `image`: documented source size **256×256 px**, 1:1 aspect ratio.
179
+ - Custom ribbon URL: documented source size **250×300 px**.
180
+ - Related-game thumbnails: **1:1 aspect ratio** per `game_public_meta.image`.
181
+ - All assets are typically rendered as CSS `background-image` (no
182
+ `<img>` element) so dimensions are controlled by the consumer's CSS.
183
+ - No built-in fallback placeholders — consumers should provide one
184
+ when source fields are empty.
185
+
186
+ ## Status-specific visual treatments
187
+ - **Locked**: lock-icon overlay on the image and a "locked" CSS
188
+ modifier on the image container. NOT grayscale (grayscale is the
189
+ convention for locked badges, not locked missions).
190
+ - **Completed**: no tint or strikethrough on the card itself; the
191
+ status chip carries the completion date.
192
+ - **Missed**: same chip styling as Locked, different label.
193
+ Missions stay visible in the Missed bucket unless an operator
194
+ config hides expired missions after N days.
195
+ - **In progress**: default styling.
196
+ - **Opt-in required**: same as in-progress; the status chip alone
197
+ signals "opt-in required".
198
+ - **Featured**: replace the ribbon (when no `ribbon` is set) with a
199
+ "featured" modifier; some brands use a gold border / glow.
200
+ - **Claimable** (claim button visible): add a "claimable" modifier
201
+ to the card root to apply a highlight border or glow drawing
202
+ attention to the action.
203
+
204
+ ## Time-remaining countdown format
205
+
206
+ Convention used by the default Smartico UI (consumers should match for
207
+ a consistent feel across Smartico widgets):
208
+ - `≤ 0` → `00:00`
209
+ - `< 1 hour` → `MM:SS`
210
+ - `< 1 day` → `HH:MM:SS`
211
+ - `< 1 month` → `DD:HH:MM:SS`
212
+ - `< 1 year` → `MO:DD:HH:MM:SS`
213
+ - `≥ 1 year` → `YY:MO:DD:HH:MM:SS`
214
+
215
+ Update the displayed text every 1 second while the mission is in
216
+ progress.
217
+
218
+ ## Empty states
219
+
220
+ Show a contextual empty-state message per bucket:
221
+ - Completed: "No completed missions yet"
222
+ - Locked: "No locked missions"
223
+ - Others (Available / Missed): "Nothing to show yet"
224
+
225
+ ## Animations / transitions
226
+ - List entry: brief zoom-in or fade-in per card (stagger optional).
227
+ - Popup open: bounce + fade-in; stagger inner elements (title, image,
228
+ description, actions) for a layered reveal.
229
+ - Progress bar fill: animate the width over ~1 second when progress
230
+ advances (especially in the popup; cards often render the bar
231
+ statically).
232
+ - Claim success: hide the Claim button immediately on success and
233
+ (optionally) overlay a confetti or celebration animation.
234
+ - In-flight buttons (opt-in / claim): show a loading indicator
235
+ (animated dots, spinner) and disable the trigger element until the
236
+ response arrives.
237
+
238
+ ## Mobile vs desktop
239
+ - Mobile: single-column vertical scroll.
240
+ - Desktop: multi-column grid. The default Smartico UI alternates a "big"
241
+ and "small" card variant in a masonry pattern (every 4th in even
242
+ rows / every 5th in odd rows is "big"). Consumers may use any grid
243
+ pattern that suits their design.
244
+ - The detail popup is structurally identical on mobile and desktop;
245
+ only sizing differs.
246
+
247
+ ## Performance
248
+
249
+ The list is not paginated; the SDK returns the full visible mission
250
+ set in one response. For very large catalogs (50+ missions visible),
251
+ consider client-side virtualization in the consumer UI. The official
252
+ tracker does NOT virtualize.
253
+
254
+ **Cache TTL**: the SDK caches the response for 30 seconds. The cache
255
+ is invalidated and re-fetched automatically on each of the three
256
+ trigger events above; `onUpdate` fires after the re-fetch completes.
257
+
258
+ **Visitor mode**: supported, with caveats.
259
+ - The returned list reflects the brand's proxy "visitor" user, not
260
+ the actual anonymous viewer. Per-user fields (`is_opted_in`,
261
+ `progress`, `completed_count`) reflect the proxy user's state and
262
+ are not meaningful for display.
263
+ - `onUpdate` is accepted by the API but NEVER fires in visitor mode —
264
+ there is no live channel, so push events are not delivered.
265
+ Visitor-mode consumers should re-poll `getMissions()` periodically
266
+ if fresh data is needed.
267
+ - Additional server-side caching applies on top of the SDK cache,
268
+ so visitor-mode data may be a few minutes stale.
@@ -0,0 +1,21 @@
1
+ # UI Guide — `requestMissionClaimReward`
2
+
3
+ ## UI guidance
4
+ - Show a loading indicator while the promise is pending; this is a
5
+ server round-trip with side effects (DB writes, CRM rules) and may
6
+ take 200–800ms depending on configured CRM automations.
7
+ - Disable the claim button for the duration of the call. The local
8
+ `prize_claimed_date_ts` flag won't flip until the auto-refresh fires
9
+ after the response.
10
+ - Treat `err_code === 0` and `err_code === 40017` identically in the
11
+ UI: hide the claim button. Don't surface 40017 as an error.
12
+ - For `err_code === 40015` (window expired), show a dedicated message
13
+ referencing the original `prize_claim_expiration_date`, not a generic
14
+ error.
15
+ - For `err_code === 40016` (not completed), this should not normally
16
+ happen if the UI gates on `is_completed === true`. If it does, the
17
+ local state is stale — auto-refresh will correct it.
18
+ - Do NOT optimistically mark the prize as claimed before the response.
19
+ Authoritative state comes from the SDK's auto-refresh.
20
+
21
+ **Visitor mode**: not supported.
@@ -0,0 +1,16 @@
1
+ # UI Guide — `requestMissionOptIn`
2
+
3
+ ## UI guidance
4
+ - Show a loading indicator (spinner, dots, button-disable) while the
5
+ promise is pending; opt-in is a server round-trip and may take
6
+ 100–500ms under normal conditions.
7
+ - Disable the trigger element for the duration of the call to prevent
8
+ double-clicks. The local `is_opted_in` flag won't flip until the
9
+ `onUpdate` callback fires post-response.
10
+ - Treat `err_code === 0` and `err_code === 40010` identically in the
11
+ UI: hide the opt-in button. Don't surface 40010 as an error.
12
+ - For `err_code === 40014` (locked), show the mission's
13
+ `unlock_mission_description` instead of a generic error.
14
+ - Do NOT optimistically set `is_opted_in = true` before the response.
15
+ Authoritative refresh comes from the SDK's `onUpdate` invocation,
16
+ not from local state.
@@ -0,0 +1,99 @@
1
+ # UI Guide — `claimRafflePrize`
2
+
3
+ ## Overview
4
+ - Action-focused mutation. The user has a winning row from a raffle
5
+ draw (visible via
6
+ [`getRaffleDrawRun`](../../api/classes/WSAPIRaffles.md#getraffledrawrun)
7
+ with `should_claim === true` or via
8
+ [`getRaffleDrawRunsHistory`](../../api/classes/WSAPIRaffles.md#getraffledrawrunshistory)
9
+ with `has_unclaimed_prize === true`), and they click Claim.
10
+ - Success (`errorCode === 0`) means the claim is recorded and prize
11
+ delivery is queued server-side. The actual delivery (wallet
12
+ credit, free spins, etc.) happens through the operator's
13
+ integration outside the SDK's response cycle.
14
+ - Latency: typically 200 ms – 1 s for a healthy WebSocket.
15
+ - Balance updates do NOT arrive in this response. Subscribe to
16
+ [`getUserProfile`](../../api/classes/WSAPIUser.md#getuserprofile)'s
17
+ `props_change` channel to observe credits.
18
+
19
+ ## Result shape note
20
+
21
+ This method returns `{ errorCode, errorMessage? }` (camelCase
22
+ full-word) — **different** from most other SDK result types that
23
+ use `{ err_code, err_message }` (snake_case). Branch on the
24
+ camelCase keys.
25
+
26
+ ## Loading state
27
+
28
+ - **Trigger**: set an in-flight flag (`claiming = true`)
29
+ immediately on click, BEFORE the call.
30
+ - **Visual**: replace the button label with animated dots /
31
+ spinner. Disable the button. Keep the detail / history view open.
32
+ - **Reset**: clear the flag on response — success or error.
33
+
34
+ ## Idempotency UI guard
35
+
36
+ The SDK does NOT prevent double-clicks. A second call on the same
37
+ `won_id` returns `errorCode === 1` with `errorMessage` indicating
38
+ the prize has already been claimed. Guard the call site:
39
+
40
+ ```ts
41
+ const [claiming, setClaiming] = useState(false);
42
+
43
+ const onClaim = async (won_id: number) => {
44
+ if (claiming) return; // in-flight guard
45
+ setClaiming(true);
46
+ const r = await window._smartico.api.claimRafflePrize({ won_id });
47
+ setClaiming(false);
48
+ handleResponse(r);
49
+ };
50
+ ```
51
+
52
+ Treat `errorCode === 1` with an "already claimed" message as
53
+ **idempotent success** in the UI — the underlying state is what
54
+ the consumer wants.
55
+
56
+ ## Action button decision matrix
57
+
58
+ | Condition | Action |
59
+ |---|---|
60
+ | `errorCode === 0` (success) | Show a success toast ("Prize claimed!"). The raffles list auto-refreshes via [`getRaffles`](../../api/classes/WSAPIRaffles.md#getraffles)'s `onUpdate`; the winner row's `claimed_date` populates on the next refresh. Don't manually re-fetch. |
61
+ | `errorCode === 1` + `errorMessage` mentions "already claimed" | Treat as success — same UI as above. Surface a brief "Already claimed" toast for clarity if you prefer. |
62
+ | `errorCode === 1` + any other `errorMessage` (control group, mismatch) | Show a generic error toast with the operator message. Allow retry only if the message suggests transient failure. |
63
+ | Other non-zero | Show a generic error toast. Allow retry. |
64
+
65
+ ## Refresh after response
66
+
67
+ The SDK auto-refreshes the raffles cache on every claim response
68
+ (success OR failure) via the same push that delivers the result.
69
+ The `onUpdate` callback registered via `getRaffles({ onUpdate })`
70
+ fires with the refreshed list. **Don't manually call `getRaffles()`
71
+ after a claim** — the refresh is already happening.
72
+
73
+ The winner row in the active detail view (`getRaffleDrawRun`) is
74
+ NOT auto-refreshed — call that separately if the detail screen is
75
+ open and you want to see `claimed_date` immediately. The default
76
+ Smartico UI re-fetches the draw detail after a successful claim.
77
+
78
+ ## No celebration animation
79
+
80
+ Unlike mission / SAW celebrations, the default Smartico UI does
81
+ NOT play a confetti or full-screen animation on raffle claim. The
82
+ winner row updates in-place with the claimed timestamp; a
83
+ success toast is the primary visual feedback. Add a celebration
84
+ in your own UI if your product surface calls for it.
85
+
86
+ ## Mobile vs desktop
87
+
88
+ - **Error surfacing**: desktop snackbar / toast; mobile centered
89
+ modal.
90
+ - **Modal style**: desktop centered; mobile full-screen sheet.
91
+ - **Loading state**: identical (dots animation on the button).
92
+
93
+ ## Performance
94
+
95
+ - Single round-trip per click.
96
+ - Prize delivery through the operator's integration is async
97
+ and out-of-band — the SDK consumer doesn't observe it directly.
98
+ - Don't poll for delivery confirmation — trust the success
99
+ response.