@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.
- package/.nvmrc +1 -1
- package/CLAUDE.md +103 -0
- package/README.md +53 -2
- package/dist/Base/ClassId.d.ts +2 -0
- package/dist/Jackpots/JackpotDetails.d.ts +14 -15
- package/dist/Jackpots/JackpotPot.d.ts +10 -6
- package/dist/Raffle/GetRaffleWonPrizesRequest.d.ts +9 -0
- package/dist/Raffle/GetRaffleWonPrizesResponse.d.ts +52 -0
- package/dist/Raffle/index.d.ts +2 -0
- package/dist/SmarticoAPI.d.ts +6 -1
- package/dist/SmarticoLib/index.d.ts +5 -1
- package/dist/Store/BuyStoreItemErrorCode.d.ts +9 -1
- package/dist/Tournaments/TournamentRegistrationError.d.ts +3 -1
- package/dist/WSAPI/WSAPI.d.ts +13 -1235
- package/dist/WSAPI/WSAPIAvatars.d.ts +296 -0
- package/dist/WSAPI/WSAPIBase.d.ts +71 -0
- package/dist/WSAPI/WSAPIBonuses.d.ts +240 -0
- package/dist/WSAPI/WSAPIClans.d.ts +388 -0
- package/dist/WSAPI/WSAPIGamePick.d.ts +593 -0
- package/dist/WSAPI/WSAPIGeneral.d.ts +172 -0
- package/dist/WSAPI/WSAPIInbox.d.ts +615 -0
- package/dist/WSAPI/WSAPIJackpots.d.ts +344 -0
- package/dist/WSAPI/WSAPILeaderBoard.d.ts +139 -0
- package/dist/WSAPI/WSAPIMiniGames.d.ts +510 -0
- package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
- package/dist/WSAPI/WSAPIRaffles.d.ts +643 -0
- package/dist/WSAPI/WSAPIStore.d.ts +656 -0
- package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
- package/dist/WSAPI/WSAPITypes.d.ts +376 -205
- package/dist/WSAPI/WSAPIUser.d.ts +533 -0
- package/dist/index.js +6745 -1661
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +6324 -1342
- package/dist/index.modern.mjs.map +1 -1
- package/docs/Callbacks.md +162 -0
- package/docs/SmarticoObject.md +445 -0
- package/docs/Transforms.md +99 -0
- package/docs/api/README.md +82 -2
- package/docs/api/classes/WSAPIAvatars.md +344 -0
- package/docs/api/classes/WSAPIBonuses.md +271 -0
- package/docs/api/classes/WSAPIClans.md +436 -0
- package/docs/api/classes/WSAPIGamePick.md +710 -0
- package/docs/api/classes/WSAPIGeneral.md +212 -0
- package/docs/api/classes/WSAPIInbox.md +801 -0
- package/docs/api/classes/WSAPIJackpots.md +439 -0
- package/docs/api/classes/WSAPILeaderBoard.md +157 -0
- package/docs/api/classes/WSAPIMiniGames.md +612 -0
- package/docs/api/classes/WSAPIMissions.md +590 -0
- package/docs/api/classes/WSAPIRaffles.md +773 -0
- package/docs/api/classes/WSAPIStore.md +719 -0
- package/docs/api/classes/WSAPITournaments.md +571 -0
- package/docs/api/classes/WSAPIUser.md +637 -0
- package/docs/api/documents/Callbacks.md +162 -0
- package/docs/api/documents/SmarticoObject.md +445 -0
- package/docs/api/documents/Transforms.md +99 -0
- package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
- package/docs/api/enumerations/BonusStatus-1.md +11 -6
- package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -0
- package/docs/api/enumerations/JoinClanErrorCode.md +81 -0
- package/docs/api/enumerations/TournamentRegistrationError.md +12 -0
- package/docs/api/functions/clanTournamentPlayersTransform.md +13 -0
- package/docs/api/interfaces/AvatarCustomized.md +25 -0
- package/docs/api/interfaces/AvatarDefinition.md +94 -0
- package/docs/api/interfaces/AvatarPrompt.md +45 -0
- package/docs/api/interfaces/BonusMetaMap-1.md +4 -1
- package/docs/api/interfaces/BonusTemplateMetaMap-1.md +9 -4
- package/docs/api/interfaces/Clan.md +4 -0
- package/docs/api/interfaces/ClanInfo.md +109 -0
- package/docs/api/interfaces/ClanMember.md +53 -0
- package/docs/api/interfaces/ClanPrizePublicMeta.md +41 -0
- package/docs/api/interfaces/ClanPrizeStructureEntry.md +7 -1
- package/docs/api/interfaces/ClanPublicMeta.md +4 -0
- package/docs/api/interfaces/ClanTournamentPlayerRaw.md +67 -0
- package/docs/api/interfaces/GemsDiamondsLog.md +43 -0
- package/docs/api/interfaces/GetClanInfoResponse.md +61 -0
- package/docs/api/interfaces/GetClanTournamentPlayersResponse.md +81 -0
- package/docs/api/interfaces/GetRaffleWonPrizesRequest.md +59 -0
- package/docs/api/interfaces/GetRaffleWonPrizesResponse.md +95 -0
- package/docs/api/interfaces/InboxMarkMessageAction.md +10 -2
- package/docs/api/interfaces/JackpotDetails.md +14 -15
- package/docs/api/interfaces/JackpotPot.md +9 -6
- package/docs/api/interfaces/LeaderBoardDetailsT.md +14 -8
- package/docs/api/interfaces/LeaderBoardUserT.md +8 -5
- package/docs/api/interfaces/LeaderBoardsRewardsT.md +7 -0
- package/docs/api/interfaces/PointsLog.md +43 -0
- package/docs/api/interfaces/RaffleWonPrize.md +59 -0
- package/docs/api/interfaces/RaffleWonPrizePublicMeta.md +27 -0
- package/docs/api/interfaces/RaffleWonPrizeUser.md +43 -0
- package/docs/api/interfaces/SAWTemplateUI.md +10 -0
- package/docs/api/interfaces/TAchCategory.md +14 -4
- package/docs/api/interfaces/TAvatarCustomized.md +4 -4
- package/docs/api/interfaces/TAvatarDefinition.md +13 -14
- package/docs/api/interfaces/TAvatarPrompt.md +6 -6
- package/docs/api/interfaces/TBonus.md +16 -8
- package/docs/api/interfaces/TBuyStoreItemResult.md +4 -11
- package/docs/api/interfaces/TClaimBonusResult.md +5 -5
- package/docs/api/interfaces/TClan.md +8 -4
- package/docs/api/interfaces/TClanInfo.md +47 -0
- package/docs/api/interfaces/TClanJoinResult.md +11 -1
- package/docs/api/interfaces/TClanTournamentPlayer.md +55 -0
- package/docs/api/interfaces/TClanTournamentPlayersResult.md +27 -0
- package/docs/api/interfaces/TClans.md +3 -1
- package/docs/api/interfaces/TGetTranslations.md +4 -0
- package/docs/api/interfaces/TInboxMessage.md +14 -6
- package/docs/api/interfaces/TInboxMessageBody.md +18 -12
- package/docs/api/interfaces/TLevel.md +17 -20
- package/docs/api/interfaces/TLevelCurrent.md +19 -18
- package/docs/api/interfaces/TMiniGamePlayBatchResult.md +14 -6
- package/docs/api/interfaces/TMiniGamePlayResult.md +9 -4
- package/docs/api/interfaces/TMissionClaimRewardResult.md +6 -3
- package/docs/api/interfaces/TMissionOptInResult.md +6 -3
- package/docs/api/interfaces/TMissionOrBadge.md +5 -4
- package/docs/api/interfaces/TRaffleOptinResponse.md +4 -2
- package/docs/api/interfaces/TSegmentCheckResult.md +10 -0
- package/docs/api/interfaces/TSetAvatarResult.md +3 -3
- package/docs/api/interfaces/TStoreItem.md +11 -1
- package/docs/api/interfaces/TTournament.md +1 -1
- package/docs/api/interfaces/TTournamentDetailed.md +9 -1
- package/docs/api/interfaces/TTournamentRegistrationResult.md +4 -2
- package/docs/api/interfaces/TUICustomSection.md +23 -19
- package/docs/api/interfaces/TUserProfile.md +18 -16
- package/docs/api/interfaces/TransformedRaffleClaimPrizeResponse.md +6 -2
- package/docs/api/interfaces/UserAchievement.md +1 -1
- package/docs/api/interfaces/UserLevelExtraCountersT.md +9 -2
- package/docs/api/type-aliases/ActivityLogEntry.md +3 -0
- package/docs/native/ADDING_METHODS.md +7 -2
- package/docs/native/PROTOCOL.md +337 -0
- package/docs/ui/avatars/UIGuide_getAvatarPrompts.md +100 -0
- package/docs/ui/avatars/UIGuide_getAvatarsCustomized.md +90 -0
- package/docs/ui/avatars/UIGuide_getAvatarsList.md +105 -0
- package/docs/ui/avatars/UIGuide_setAvatar.md +118 -0
- package/docs/ui/bonuses/UIGuide_claimBonus.md +144 -0
- package/docs/ui/bonuses/UIGuide_getBonuses.md +176 -0
- package/docs/ui/clans/UIGuide_getClanInfo.md +153 -0
- package/docs/ui/clans/UIGuide_getClans.md +172 -0
- package/docs/ui/clans/UIGuide_joinClan.md +196 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetActiveRound.md +99 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetActiveRounds.md +76 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetBoard.md +81 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetGameInfo.md +78 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetHistory.md +55 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetRoundInfoForUser.md +71 -0
- package/docs/ui/gamepick/UIGuide_gamePickGetUserInfo.md +64 -0
- package/docs/ui/gamepick/UIGuide_gamePickSubmitSelection.md +103 -0
- package/docs/ui/gamepick/UIGuide_gamePickSubmitSelectionQuiz.md +67 -0
- package/docs/ui/general/UIGuide_getCustomSections.md +137 -0
- package/docs/ui/general/UIGuide_getRelatedItemsForGame.md +140 -0
- package/docs/ui/inbox/UIGuide_deleteInboxMessage.md +135 -0
- package/docs/ui/inbox/UIGuide_getInboxMessageBody.md +133 -0
- package/docs/ui/inbox/UIGuide_getInboxMessages.md +186 -0
- package/docs/ui/inbox/UIGuide_markInboxMessageAsRead.md +122 -0
- package/docs/ui/inbox/UIGuide_markUnmarkInboxMessageAsFavorite.md +84 -0
- package/docs/ui/jackpots/UIGuide_getJackpotEligibleGames.md +73 -0
- package/docs/ui/jackpots/UIGuide_getJackpotWinners.md +83 -0
- package/docs/ui/jackpots/UIGuide_jackpotGet.md +138 -0
- package/docs/ui/jackpots/UIGuide_jackpotOptIn.md +85 -0
- package/docs/ui/jackpots/UIGuide_jackpotOptOut.md +65 -0
- package/docs/ui/leaderboard/UIGuide_getLeaderBoard.md +166 -0
- package/docs/ui/minigames/UIGuide_getMiniGames.md +153 -0
- package/docs/ui/minigames/UIGuide_getMiniGamesHistory.md +90 -0
- package/docs/ui/minigames/UIGuide_playMiniGame.md +150 -0
- package/docs/ui/minigames/UIGuide_playMiniGameBatch.md +128 -0
- package/docs/ui/missions/UIGuide_getAchCategories.md +17 -0
- package/docs/ui/missions/UIGuide_getBadges.md +237 -0
- package/docs/ui/missions/UIGuide_getMissions.md +268 -0
- package/docs/ui/missions/UIGuide_requestMissionClaimReward.md +21 -0
- package/docs/ui/missions/UIGuide_requestMissionOptIn.md +16 -0
- package/docs/ui/raffles/UIGuide_claimRafflePrize.md +99 -0
- package/docs/ui/raffles/UIGuide_getRaffleDrawRun.md +117 -0
- package/docs/ui/raffles/UIGuide_getRaffleDrawRunsHistory.md +92 -0
- package/docs/ui/raffles/UIGuide_getRaffleWonPrizes.md +120 -0
- package/docs/ui/raffles/UIGuide_getRaffles.md +175 -0
- package/docs/ui/raffles/UIGuide_requestRaffleOptin.md +114 -0
- package/docs/ui/store/UIGuide_buyStoreItem.md +133 -0
- package/docs/ui/store/UIGuide_getStoreCategories.md +19 -0
- package/docs/ui/store/UIGuide_getStoreItems.md +264 -0
- package/docs/ui/store/UIGuide_getStorePurchasedItems.md +122 -0
- package/docs/ui/tournaments/UIGuide_getClanTournamentPlayers.md +140 -0
- package/docs/ui/tournaments/UIGuide_getTournamentInstanceInfo.md +265 -0
- package/docs/ui/tournaments/UIGuide_getTournamentsList.md +236 -0
- package/docs/ui/tournaments/UIGuide_registerInTournament.md +156 -0
- package/docs/ui/user/UIGuide_getActivityLog.md +130 -0
- package/docs/ui/user/UIGuide_getLevels.md +167 -0
- package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
- package/package.json +3 -3
- package/scripts/postdoc-cleanup.js +195 -0
- package/src/Base/ClassId.ts +2 -0
- package/src/Jackpots/JackpotDetails.ts +14 -15
- package/src/Jackpots/JackpotPot.ts +10 -6
- package/src/Missions/MissionsUtils.ts +5 -2
- package/src/Raffle/GetRaffleWonPrizesRequest.ts +12 -0
- package/src/Raffle/GetRaffleWonPrizesResponse.ts +56 -0
- package/src/Raffle/index.ts +3 -1
- package/src/SmarticoAPI.ts +14 -1
- package/src/SmarticoLib/index.ts +4 -0
- package/src/Store/BuyStoreItemErrorCode.ts +8 -0
- package/src/Store/StoreItem.ts +1 -0
- package/src/Store/StoreItemPurchased.ts +1 -0
- package/src/Store/StoreItemType.ts +1 -1
- package/src/Tournaments/TournamentRegistrationError.ts +4 -0
- package/src/WSAPI/WSAPI.ts +27 -2007
- package/src/WSAPI/WSAPIAvatars.ts +345 -0
- package/src/WSAPI/WSAPIBase.ts +93 -0
- package/src/WSAPI/WSAPIBonuses.ts +268 -0
- package/src/WSAPI/WSAPIClans.ts +417 -0
- package/src/WSAPI/WSAPIGamePick.ts +667 -0
- package/src/WSAPI/WSAPIGeneral.ts +199 -0
- package/src/WSAPI/WSAPIInbox.ts +711 -0
- package/src/WSAPI/WSAPIJackpots.ts +448 -0
- package/src/WSAPI/WSAPILeaderBoard.ts +154 -0
- package/src/WSAPI/WSAPIMiniGames.ts +597 -0
- package/src/WSAPI/WSAPIMissions.ts +572 -0
- package/src/WSAPI/WSAPIRaffles.ts +703 -0
- package/src/WSAPI/WSAPIStore.ts +732 -0
- package/src/WSAPI/WSAPITournaments.ts +541 -0
- package/src/WSAPI/WSAPITypes.ts +376 -207
- package/src/WSAPI/WSAPIUser.ts +606 -0
- package/tsconfig.json +26 -2
- 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).
|