@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,118 @@
1
+ # UI Guide — `setAvatar`
2
+
3
+ ## Overview
4
+ - Activates the chosen avatar as the user's profile avatar.
5
+ - Confirmation-style mutation — user picks an avatar in
6
+ [`getAvatarsList`](../../api/classes/WSAPIAvatars.md#getavatarslist)
7
+ (or a variant from
8
+ [`getAvatarsCustomized`](../../api/classes/WSAPIAvatars.md#getavatarscustomized)),
9
+ then taps "Apply".
10
+ - Server validates ownership — locked avatars are rejected.
11
+ - The SDK clears both the catalog and the customized-variant caches on
12
+ return; re-call those methods to surface the new `is_in_use` state.
13
+
14
+ ## Loading state
15
+
16
+ User taps "Apply" → the button enters an in-flight state (spinner +
17
+ disabled). The default Smartico UI keeps the picker open during the
18
+ call and closes it after the response lands.
19
+
20
+ ```ts
21
+ const [applying, setApplying] = useState(false);
22
+
23
+ const onApply = async (avatar: TAvatarDefinition) => {
24
+ if (applying) return;
25
+ setApplying(true);
26
+ const r = await window._smartico.api.setAvatar({
27
+ avatar_url: avatar.avatar_url,
28
+ avatar_real_id: avatar.avatar_real_id,
29
+ });
30
+ setApplying(false);
31
+ handleResult(r);
32
+ };
33
+ ```
34
+
35
+ ## Idempotency guard
36
+
37
+ The SDK does NOT prevent double-clicks. Guard the call site as above.
38
+ Re-applying the same avatar is safe server-side (returns `err_code: 0`,
39
+ no double side-effects), but the redundant roundtrip wastes the user's
40
+ time.
41
+
42
+ ## Action button decision matrix
43
+
44
+ UI behavior per `err_code`:
45
+
46
+ | `err_code` | Action |
47
+ |---|---|
48
+ | `0` (success) | Close picker; refresh header avatar; show brief "Avatar updated" confirmation (optional). |
49
+ | `1` (not in catalog) | Refresh catalog (operator may have removed the avatar); show "Avatar no longer available". |
50
+ | `2` (inactive) | Show "This avatar is no longer available"; refresh catalog. |
51
+ | `3` (outside time window) | Show "Available on {active_from_date} – {active_till_date}". |
52
+ | `4` (not owned) | Show unlock requirement / "Earn this avatar first" — possible if the catalog was stale. Refresh and re-render lock states. |
53
+ | Other non-zero | Show generic error toast. Surface `err_message` if present. Allow retry. |
54
+
55
+ The default Smartico UI shows a hardcoded "Failed to apply avatar" toast
56
+ on any non-zero code without branching. Custom UIs should branch on the
57
+ code and prefer `err_message` when present.
58
+
59
+ ## Refresh after success
60
+
61
+ - The SDK auto-clears the
62
+ [`getAvatarsList`](../../api/classes/WSAPIAvatars.md#getavatarslist)
63
+ and
64
+ [`getAvatarsCustomized`](../../api/classes/WSAPIAvatars.md#getavatarscustomized)
65
+ caches.
66
+ - The user's stored avatar updates server-side; the next call to
67
+ [`getUserProfile`](../../api/classes/WSAPIUser.md#getuserprofile)
68
+ reflects the new `avatar_url`.
69
+ - **No push to other open sessions.** A second device / tab the user is
70
+ logged in on will not see the change until it next calls
71
+ `getUserProfile()` or re-identifies. If you maintain a persistent
72
+ header avatar across tabs, plan a periodic refresh.
73
+
74
+ ## Selecting the right `avatar_url`
75
+
76
+ | Source | Pass as `avatar_url` |
77
+ |---|---|
78
+ | Catalog avatar (from `getAvatarsList`) | `avatar.avatar_url` |
79
+ | AI variant (from `getAvatarsCustomized`) | `variant.url` |
80
+
81
+ For both, pass the base `avatar_real_id` — for an AI variant, that is
82
+ the `avatar_real_id` of the base avatar the variant was derived from
83
+ (it's already on the `TAvatarCustomized` record).
84
+
85
+ ## Animations / transitions
86
+
87
+ Success sequence (default Smartico UI):
88
+
89
+ 1. Apply tap → spinner replaces button label.
90
+ 2. On `err_code === 0` → picker closes, header avatar fades to new
91
+ image.
92
+ 3. Optional: brief toast "Avatar updated" auto-dismissing after ~2 s.
93
+
94
+ Failure sequence:
95
+
96
+ 1. Apply tap → spinner replaces button label.
97
+ 2. On non-zero `err_code` → spinner clears; error toast shown; picker
98
+ remains open so the user can pick a different avatar.
99
+
100
+ ## Mobile vs desktop
101
+
102
+ - **Picker**: full-screen sheet on mobile; centered modal on desktop.
103
+ - **Apply button**: bottom bar on mobile; bottom-right of modal on
104
+ desktop.
105
+ - **Toast**: bottom-center on mobile; top-right on desktop.
106
+
107
+ ## Empty / no-selection state
108
+
109
+ The "Apply" button should be disabled until the user selects an avatar.
110
+ While selected avatar is the user's current one, the button label
111
+ becomes "In Use" and stays disabled.
112
+
113
+ ## Performance
114
+
115
+ - Single round-trip.
116
+ - No optimistic update — wait for `err_code === 0` before flipping the
117
+ header avatar. Locked-avatar rejection is real and would otherwise
118
+ produce a visible flicker.
@@ -0,0 +1,144 @@
1
+ # UI Guide — `claimBonus`
2
+
3
+ ## Overview
4
+ - Action-focused mutation. The user is on the bonuses screen, the
5
+ CTA is "Claim" on a pending bonus tile, and they click it.
6
+ - Success (`err_code === 0`) means the operator's integration has
7
+ been called to credit the bonus to the player's account. The
8
+ status flips to `REDEEMED` and the bonuses list auto-refreshes
9
+ via [`getBonuses`](../../api/classes/WSAPIBonuses.md#getbonuses)'s
10
+ `onUpdate`.
11
+ - Latency: typically 300 ms – 2 s — the server calls the operator's
12
+ bonus API synchronously inside the claim handler, so slow
13
+ operator endpoints translate to slow claim responses.
14
+ - Balance updates do NOT arrive in the claim response — the
15
+ operator credits the player externally and the change surfaces
16
+ separately (typically via the SDK's user-properties channel).
17
+
18
+ ## Loading state
19
+
20
+ - **Trigger**: set an in-flight flag (`claiming = true`) immediately
21
+ on click, BEFORE the call.
22
+ - **Visual**: replace the button label with animated dots / spinner.
23
+ Disable the button. Keep the claim modal open during the call.
24
+ - **Reset**: clear the flag on response — success or error.
25
+
26
+ Latency can reach 1–2 s for slow operator integrations. Use a
27
+ clearly-visible loading state (dots ≥ 3 frames, button width
28
+ preserved to prevent layout jump).
29
+
30
+ ## Idempotency UI guard
31
+
32
+ The SDK does NOT prevent double-clicks. Two simultaneous calls
33
+ both reach the server. The first succeeds; the second returns
34
+ `err_code = -1` (bonus already claimed). Guard the call site:
35
+
36
+ ```ts
37
+ const [claiming, setClaiming] = useState(false);
38
+
39
+ const onClaim = async () => {
40
+ if (claiming) return; // in-flight guard
41
+ if (!bonus.is_redeemable) return; // not claimable
42
+ setClaiming(true);
43
+ const r = await window._smartico.api.claimBonus(bonus.bonus_id);
44
+ setClaiming(false);
45
+ handleResponse(r);
46
+ };
47
+ ```
48
+
49
+ Treat `err_code === -1` (already claimed) as **idempotent success**
50
+ in the UI — close the modal, show the success toast, let the
51
+ auto-refresh land. Don't show an error.
52
+
53
+ ## Action button decision matrix
54
+
55
+ | `err_code` | Action |
56
+ |---|---|
57
+ | `0` (success) | Close the claim modal · Show a success toast (e.g. "Bonus claimed!") · The bonuses list auto-refreshes via `onUpdate`; the bonus moves from Pending to Redeemed tab on the next render — DON'T manually re-fetch. Balance credit arrives separately through the operator's integration. |
58
+ | `-1` (not claimable / already claimed) | Same as success — treat as idempotent. Usually means another tab/session already claimed it (or the bonus expired between list fetch and click). |
59
+ | `1` (generic server error) | Show a generic error toast. Allow retry — the bonus typically lands in `REDEEM_FAILED` and remains claimable. |
60
+ | `9999` (uncaught exception) | Same as `1` — generic error toast, retry allowed. |
61
+ | Other non-zero | Show a generic error toast with `err_message` if present. Allow retry. |
62
+
63
+ The bonus's `bonus_status_id` after a failed claim is typically
64
+ `REDEEM_FAILED (4)`. The default Smartico UI treats `REDEEM_FAILED`
65
+ identically to `COUPON_ISSUED` — the user sees a normal Claim
66
+ button on their next visit and can retry without any "previously
67
+ failed" indicator.
68
+
69
+ ## `success` field — ignore it
70
+
71
+ The wire response does NOT consistently carry a `success` boolean.
72
+ The `TClaimBonusResult.success?: boolean` field will be `undefined`
73
+ in practice. **Always branch on `err_code === 0`** for the success
74
+ check, not on the `success` field.
75
+
76
+ ## Acknowledge message — pre-click
77
+
78
+ `label_bonus_template_meta_map.acknowledge` is the operator-supplied
79
+ text shown in the claim modal (wagering terms, expiry notice, etc.).
80
+ It is **template-level and static** — shown regardless of whether
81
+ the user has clicked Claim yet, and regardless of whether the
82
+ claim eventually succeeds. Render it always in the modal body when
83
+ present.
84
+
85
+ ## Optimistic update
86
+
87
+ **Do NOT optimistically flip `bonus_status_id` to `REDEEMED`** before
88
+ the response. The server can fail (operator integration timeout,
89
+ business-rule rejection), and the failure state needs to surface as
90
+ a real error. Keep the bonus in its prior state until the response
91
+ lands.
92
+
93
+ The in-flight `claiming` flag provides the visual feedback during
94
+ the wait.
95
+
96
+ ## Refresh after response
97
+
98
+ The SDK auto-refreshes the bonuses cache on every response (success
99
+ OR error) via the same push that delivers the claim result. The
100
+ `onUpdate` callback registered via `getBonuses({ onUpdate })` fires
101
+ with the refreshed array shortly after — **don't manually call
102
+ `getBonuses()` after a claim response**, the refresh is already
103
+ happening.
104
+
105
+ The user's balance update (after a successful claim) does NOT come
106
+ through the bonuses channel. The operator's integration credits the
107
+ player externally; balance updates surface via
108
+ [`getUserProfile`](../../api/classes/WSAPIUser.md#getuserprofile)'s
109
+ `props_change` push channel — subscribe there separately if your UI
110
+ shows the balance.
111
+
112
+ ## Animations / transitions
113
+
114
+ - **Loading dots**: 3-dot bouncing animation on the button while
115
+ the promise is in flight.
116
+ - **Modal close on success**: animate the modal closure (~150 ms
117
+ ease-out).
118
+ - **Card cross-tab transition**: when the bonus moves from Pending
119
+ to Redeemed (detected via diffing the prior + refreshed lists
120
+ inside `onUpdate`), the default Smartico UI does not animate the
121
+ move — it relies on the list-level fade-in for the new Redeemed
122
+ card.
123
+ - **No celebration animation** (no confetti, no sound) — bonus claim
124
+ uses a plain success toast. Mission and store claims have
125
+ celebrations; bonuses don't.
126
+
127
+ ## Mobile vs desktop
128
+
129
+ - **Loading state**: identical (dots animation on the button).
130
+ - **Error surfacing**: desktop typically uses a toast/snackbar;
131
+ mobile may use a centered modal with a clear "OK" affordance.
132
+ - **Modal style**: desktop centered with backdrop dim; mobile
133
+ full-screen slide-up sheet.
134
+
135
+ ## Performance
136
+
137
+ - Single round-trip per click. The handler invokes the operator's
138
+ bonus API synchronously, so latency depends on the operator's
139
+ endpoint responsiveness.
140
+ - The refresh after the response (server push → SDK cache write →
141
+ `onUpdate` fire) adds ~50–100 ms beyond the claim response —
142
+ fine for UI purposes.
143
+ - Don't poll `getBonuses()` to detect claim completion — the
144
+ response promise is the authoritative signal.
@@ -0,0 +1,176 @@
1
+ # UI Guide — `getBonuses`
2
+
3
+ ## Overview
4
+ - Returns the user's bonuses (pending claims, redeemed history, and —
5
+ rarely — internal statuses). Drive the rendering from
6
+ `bonus_status_id` ({@link BonusStatus}) and `is_redeemable`.
7
+ - The list refreshes automatically only after
8
+ [`claimBonus`](../../api/classes/WSAPIBonuses.md#claimbonus). Server-
9
+ awarded bonuses (CRM, mission rewards, store redemptions) do NOT
10
+ push — poll on the 30 s cache TTL if you need near-live awareness.
11
+ - Loading indicator: skip on cache hit; show a shimmer on cold fetch
12
+ (typically 100–500 ms).
13
+
14
+ ## List view organization
15
+
16
+ The default Smartico UI splits bonuses into **two tabs**:
17
+
18
+ | Tab | Bucket rule | Sort |
19
+ |---|---|---|
20
+ | **Pending** | `bonus_status_id === 2` (`COUPON_ISSUED`) OR `bonus_status_id === 4` (`REDEEM_FAILED`) | `create_date` DESC |
21
+ | **Redeemed** | `bonus_status_id === 3` (`REDEEMED`) | `redeem_date` DESC |
22
+
23
+ Status values `New (1)`, `COUPON_ISSUE_FAILED (5)`, `EXPIRED (6)` are
24
+ typically filtered out by widget-level operator configuration. If they
25
+ appear, the default UI does not surface them — drop them from your
26
+ render.
27
+
28
+ **Pending tab auto-hides**: when the Pending bucket is empty, the
29
+ default Smartico UI removes the tab strip entirely and shows only the
30
+ Redeemed list. Restore the tab strip when a fresh pending bonus
31
+ appears (e.g. after a poll-driven refresh).
32
+
33
+ **Bucketing helper** for custom UIs:
34
+
35
+ ```ts
36
+ function bucket(bonus) {
37
+ if (bonus.bonus_status_id === 2 || bonus.bonus_status_id === 4) return 'pending';
38
+ if (bonus.bonus_status_id === 3) return 'redeemed';
39
+ return null; // drop internal statuses from the UI
40
+ }
41
+ ```
42
+
43
+ ## Bonus card / tile
44
+
45
+ Fields rendered per tile:
46
+
47
+ | Field | Source | Notes |
48
+ |---|---|---|
49
+ | Icon | `label_bonus_template_meta_map.image_url` | 1:1 aspect ratio. No SDK-provided fallback — supply a neutral placeholder if missing. |
50
+ | Amount / title | Prefer `bonus_meta_map.uiAmount` (e.g. `"€50"`, `"100 free spins"`); fall back to `label_bonus_template_meta_map.description` | `description` may include HTML; sanitize before injecting. |
51
+ | Date | `create_date` for pending bonuses; `redeem_date` for redeemed bonuses | ISO 8601 UTC; parse and format in user's local time (`new Date(create_date + 'Z')`). |
52
+ | Redirect affordance | Small icon when `label_bonus_template_meta_map.redirect_url` is set | Separate click target from the card itself (don't open the claim modal on icon click). |
53
+
54
+ **Whole-card click target** behavior depends on the bonus state:
55
+ - Pending + `is_redeemable: true` → opens the claim modal (see "Action
56
+ button decision matrix").
57
+ - All other states → card is non-interactive (apply a CSS class like
58
+ `hover-disable` and suppress the click handler).
59
+
60
+ ## Detail / claim modal
61
+
62
+ When the user clicks a claimable card, open a modal showing:
63
+
64
+ 1. Bonus icon (`label_bonus_template_meta_map.image_url`) at a
65
+ larger size.
66
+ 2. Amount / title (same fields as the card).
67
+ 3. Description (`label_bonus_template_meta_map.description`, HTML).
68
+ 4. **Acknowledge message** —
69
+ `label_bonus_template_meta_map.acknowledge` — operator-supplied
70
+ text always shown when set (wagering terms, expiry notice,
71
+ etc.). May include deep-links — pass through the SDK's deep-link
72
+ handler for safe execution.
73
+ 5. Claim button (see "Action button decision matrix").
74
+
75
+ The acknowledge message is **template-level static text**, not a
76
+ dynamic success message — it appears regardless of whether the
77
+ claim succeeds.
78
+
79
+ ## Action button decision matrix
80
+
81
+ Drive the Claim CTA from `bonus_status_id` + `is_redeemable`:
82
+
83
+ | `bonus_status_id` | `is_redeemable` | UI state |
84
+ |---|---|---|
85
+ | `COUPON_ISSUED` (2) | `true` | Claim button enabled — primary CTA |
86
+ | `REDEEM_FAILED` (4) | `true` | Claim button enabled — "Try again" label is appropriate; the default Smartico UI treats this identically to first-time claim |
87
+ | `COUPON_ISSUED` / `REDEEM_FAILED` | `false` | Card is informational only; no Claim button (auto-redeemed integration) |
88
+ | `REDEEMED` (3) | (irrelevant) | History row; no Claim button; show `redeem_date` |
89
+ | `New` / `COUPON_ISSUE_FAILED` / `EXPIRED` | — | Drop from UI |
90
+
91
+ Clicking the Claim button invokes
92
+ [`claimBonus`](../../api/classes/WSAPIBonuses.md#claimbonus). See its
93
+ own UI guide for the in-flight + per-error-code matrix.
94
+
95
+ ## Image / asset specs
96
+
97
+ | Field | Aspect ratio | Notes |
98
+ |---|---|---|
99
+ | `label_bonus_template_meta_map.image_url` | 1:1 (square) | Operator-supplied; recommended ~256×256 px. Fallback: render a neutral bonus icon if missing. |
100
+
101
+ ## Status-specific visual treatments
102
+
103
+ - **Pending (`COUPON_ISSUED` / `REDEEM_FAILED`)**: full-color card,
104
+ pointer cursor, clickable.
105
+ - **Non-redeemable pending** (`is_redeemable: false`): identical
106
+ visual but `hover-disable` CSS class, no click handler.
107
+ - **Redeemed**: same visual; appears in the Redeemed tab only; show
108
+ the redemption date.
109
+ - **No status-specific colors / badges** in the default Smartico UI
110
+ — branding for "successfully redeemed" lives only in tab placement,
111
+ not in the card chrome.
112
+
113
+ `REDEEM_FAILED` is visually identical to `COUPON_ISSUED` from the
114
+ player's perspective. The "failed" state is a server-internal
115
+ distinction that lets the integration record a prior failed attempt
116
+ without losing the bonus. Don't surface "failed" in the UI copy —
117
+ treat it as "claim available".
118
+
119
+ ## `redirect_url` handling
120
+
121
+ When `label_bonus_template_meta_map.redirect_url` is set, render a
122
+ small redirect icon on the card. Click behavior:
123
+
124
+ - URL starts with `http` / `https` → open in a new browser tab
125
+ (`window.open(url, '_blank')`).
126
+ - Anything else → treat as an internal deep-link; pass to the SDK's
127
+ deep-link handler (`_smartico.dp(url)`).
128
+
129
+ The redirect click target is **separate from** the card's click
130
+ target. Stop event propagation on the icon click so the claim modal
131
+ does not open simultaneously.
132
+
133
+ ## Empty / loading / error states
134
+
135
+ - **Loading (cold fetch)**: render a skeleton grid (3–6 placeholder
136
+ cards) matching the eventual layout.
137
+ - **Loading (cache hit)**: do not render a loading state — the
138
+ promise resolves within a microtask.
139
+ - **Empty list**: `[]` means no bonuses are visible. Show a neutral
140
+ empty-state illustration with copy like "No bonuses available".
141
+ - **Empty Pending tab (but Redeemed has items)**: per the default
142
+ Smartico UI, hide the tab strip entirely and show only the
143
+ Redeemed list. Reverse when a poll-driven refresh restores
144
+ pending bonuses.
145
+ - **Error**: keep the prior list visible if any; show a small
146
+ non-blocking error banner; retry on the next user-driven action.
147
+
148
+ ## Animations / transitions
149
+
150
+ - **Card entry**: stagger fade-in (~30 ms per card) on first render.
151
+ - **Card transition on claim success**: the redeemed bonus's card
152
+ fades out from the Pending tab and the Redeemed tab gains a new
153
+ card on its next render. The default Smartico UI does not animate
154
+ the cross-tab move — bonus rendering relies on the standard list
155
+ refresh.
156
+ - **No celebration animation on claim success** — unlike mission /
157
+ store claim, bonuses use a plain success toast.
158
+
159
+ ## Mobile vs desktop
160
+
161
+ - **Grid columns**: desktop typically 2–3 columns; mobile 1
162
+ (full-width cards).
163
+ - **Tab strip**: identical on both; auto-hidden when Pending is
164
+ empty.
165
+ - **Detail modal**: desktop centered with backdrop dim; mobile
166
+ full-screen slide-up.
167
+
168
+ ## Performance
169
+
170
+ - The 30 s cache deduplicates rapid refetches. A poll loop every
171
+ 5 s effectively translates to one round-trip per 30 s.
172
+ - Diff snapshots between fetches to detect status flips and animate
173
+ only the affected cards.
174
+ - For very large bonus histories, virtualize the Redeemed tab with
175
+ `IntersectionObserver` — the default Smartico UI doesn't
176
+ paginate, so the full list is rendered.
@@ -0,0 +1,153 @@
1
+ # UI Guide — `getClanInfo`
2
+
3
+ ## Overview
4
+ - Powers the **clan detail modal / page** — the surface opened after a
5
+ user clicks a row in the clan list (see
6
+ [`getClans`](../../api/classes/WSAPIClans.md#getclans)).
7
+ - One-shot fetch. No cache, no subscription, no push refresh. Re-call
8
+ to refresh.
9
+ - Returns everything a `TClan` list entry has PLUS the ranked
10
+ `members[]` roster and a fresh `cooldown_until`.
11
+
12
+ ## Detail modal layout
13
+
14
+ Top-to-bottom (single responsive component — same layout on mobile
15
+ and desktop, just resized via the modal frame):
16
+
17
+ 1. **Header** — close affordance, clan icon (`public_meta.image_url`
18
+ fallback to first-letter avatar), clan name, description.
19
+ 2. **Metadata row** — entry fee (or "Free"),
20
+ `member_count / capacity_limit` text, rating position badge.
21
+ 3. **Members list** — see "Members list".
22
+ 4. **Sticky "my member" footer** — when `members.find(m => m.is_me)`
23
+ is non-null, pin a duplicate of the user's member row at the
24
+ bottom of the scroll area. No row-count threshold — fires
25
+ whenever the user is in the clan, regardless of total member
26
+ count.
27
+ 5. **Join CTA** — see "Action button decision matrix" below.
28
+
29
+ There is NO inline capacity progress bar in the detail modal (the
30
+ progress bar appears only on the list-page row, not in detail).
31
+
32
+ ## Members list
33
+
34
+ Sourced from `members[]`, server-ordered by `contribution_score` DESC
35
+ (i.e. `position` ASC). No client-side re-sort required.
36
+
37
+ Per-row columns:
38
+
39
+ | Column | Source | Notes |
40
+ |---|---|---|
41
+ | Position | `member.position` | Plain text — no podium / top-3 styling in the detail modal. (The list page does apply podium styling to clan rows.) |
42
+ | Avatar | `member.avatar_url` (or derived from `avatar_id` + brand avatar domain) | Square. Render as CSS `background-image` or `<img>`. Letter-avatar fallback if both are empty. |
43
+ | Username | `member.public_username` | The default Smartico UI uses `public_username`; some sibling surfaces (tournament clan drill-down) prefer `member.clean_ext_user_id` as primary with `public_username` as fallback. Pick whichever matches your product's identity model. |
44
+ | "You" badge | rendered when `member.is_me === true` | Small inline pill next to the username. |
45
+ | Contribution | `member.contribution_score` | Format with `toLocaleString()` (locale-aware thousand separators). |
46
+
47
+ **"Me" row highlight**: when `member.is_me === true`, apply a row CSS
48
+ class (e.g. `is-me`) — background tint + inline "You" badge.
49
+
50
+ ## Sticky "my member" footer
51
+
52
+ The default Smartico UI pins a duplicate of the user's member row at
53
+ the bottom of the scrollable members list whenever the user is in this
54
+ clan (i.e. `members.find(m => m.is_me)` returns a non-null value).
55
+ Same visual treatment as the inline row, just pinned to the modal's
56
+ footer area above the Join CTA.
57
+
58
+ Skip the sticky footer when the user is not a member of this clan.
59
+
60
+ ## Action button decision matrix
61
+
62
+ Same as the list-level CTA matrix — evaluate in priority order. The
63
+ detail modal has the most accurate state because `cooldown_until` here
64
+ is always fresh (vs the list's 30 s-cached value).
65
+
66
+ | State | Condition | Button label | Enabled? |
67
+ |---|---|---|---|
68
+ | **Your clan** | `detail.clan_id === user_clan_id` | "Your clan" | No-op |
69
+ | **Cooldown active** | `detail.cooldown_until !== null` | `"Cooldown until <local-date>"` | Disabled |
70
+ | **Clan full** | `member_count >= capacity_limit` | "Clan is full" | Disabled |
71
+ | **Insufficient balance** | `entry_fee_amount > 0` AND balance for `entry_fee_currency_type_id` < `entry_fee_amount` | `"Not enough {Points|Gems|Diamonds} (deficit)"` | Disabled |
72
+ | **Joinable — free** | `entry_fee_amount === 0` OR `entry_fee_currency_type_id === 3` | "Join free" | Enabled |
73
+ | **Joinable — paid** | default | `"Join ({amount} {Points|Gems|Diamonds})"` | Enabled |
74
+
75
+ Enabled Join click invokes
76
+ [`joinClan(clan_id)`](../../api/classes/WSAPIClans.md#joinclan); see
77
+ its own UI guide.
78
+
79
+ **Note on cooldown freshness**: the detail's `cooldown_until` will
80
+ reflect a just-expired cooldown 30 s sooner than the list's cached
81
+ value. If your UI cares to surface a "you're now eligible" hint
82
+ right when the cooldown ends, watch the detail's value rather than
83
+ the list's.
84
+
85
+ ## Image / asset specs
86
+
87
+ | Field | Aspect ratio | Used where | Fallback |
88
+ |---|---|---|---|
89
+ | `public_meta.image_url` | 1:1 (square) | Modal header icon | First character of `public_meta.name` rendered as a letter avatar |
90
+ | `members[i].avatar_url` (or derived) | 1:1 | Member row avatars | Letter-avatar with the username's first character |
91
+
92
+ CDN-resolved automatically by the SDK. The default Smartico UI
93
+ re-derives member avatars from `avatar_id` + brand `avatarDomain`
94
+ even though `avatar_url` is pre-populated — either works.
95
+
96
+ ## Empty / loading / error states
97
+
98
+ - **Loading**: render the modal frame and header immediately
99
+ (driven by the caller-side `TClan` from the list); leave the
100
+ members list area as a shimmer skeleton until the detail
101
+ response lands.
102
+ - **`members` empty**: render an empty-state placeholder (e.g.
103
+ "No members yet"). Rare — clans with `member_count === 0` are
104
+ unusual.
105
+ - **Invalid `clanId` / network error**: the default Smartico UI
106
+ silently swallows the error and leaves the members list empty.
107
+ For better UX, attach a `.catch()` and surface "Failed to load
108
+ details — Try again".
109
+
110
+ ## Close affordance
111
+
112
+ Three independent dismiss mechanisms:
113
+
114
+ 1. Close button (top-right).
115
+ 2. Click outside the modal card.
116
+ 3. `Escape` key.
117
+
118
+ The default Smartico UI wires all three via a shared `useModalClose`
119
+ hook.
120
+
121
+ ## Animations / transitions
122
+
123
+ - **Modal entry**: fade-in + scale-up (~150 ms ease-out).
124
+ - **Modal exit**: fade-out + scale-down (~120 ms).
125
+ - **Member rows**: stagger fade-in (~20 ms per row) on first render.
126
+ - **Join success celebration**: when the user successfully joins
127
+ THIS clan (detect by `joinClan` resolving with `errCode === 0`
128
+ for `detail.clan_id`), re-fetch `getClanInfo` and animate the
129
+ sticky-footer row sliding in.
130
+ - **Rank changes between fetches**: if you poll the detail (uncommon
131
+ — typically only the list polls), use a FLIP animation when
132
+ `position` values shift between snapshots.
133
+
134
+ ## Mobile vs desktop
135
+
136
+ - **Single component** — no separate mobile / desktop variants of
137
+ the detail modal. Layout adapts via the modal frame's responsive
138
+ sizing.
139
+ - **Members list density**: identical on both. Rows are compact
140
+ enough to fit ~6–8 visible at once on a mobile sheet.
141
+ - **Sticky footer**: same logic on both — no row-count threshold
142
+ (different from the list-page sticky footer which requires ≥ 7
143
+ rows).
144
+
145
+ ## Performance
146
+
147
+ - Each call is a fresh network round-trip. Avoid auto-polling the
148
+ detail unless your UI explicitly needs live updates — the
149
+ default Smartico UI fetches once per modal mount.
150
+ - If you do poll for live rank/score updates, use a 10–30 s
151
+ interval and diff snapshots to animate only the changed rows.
152
+ - Member avatars use CDN-resized URLs; lazy-loading is usually
153
+ unnecessary for typical clan sizes (capacity_limit is the bound).