@smartico/public-api 0.0.379 → 0.0.380
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/README.md +31 -2
- 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 +78 -0
- package/dist/WSAPI/WSAPIBase.d.ts +71 -0
- package/dist/WSAPI/WSAPIBonuses.d.ts +26 -0
- package/dist/WSAPI/WSAPIClans.d.ts +388 -0
- package/dist/WSAPI/WSAPIGamePick.d.ts +308 -0
- package/dist/WSAPI/WSAPIGeneral.d.ts +30 -0
- package/dist/WSAPI/WSAPIInbox.d.ts +126 -0
- package/dist/WSAPI/WSAPIJackpots.d.ts +109 -0
- package/dist/WSAPI/WSAPILeaderBoard.d.ts +25 -0
- package/dist/WSAPI/WSAPIMiniGames.d.ts +94 -0
- package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
- package/dist/WSAPI/WSAPIRaffles.d.ts +119 -0
- package/dist/WSAPI/WSAPIStore.d.ts +656 -0
- package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
- package/dist/WSAPI/WSAPITypes.d.ts +145 -85
- package/dist/WSAPI/WSAPIUser.d.ts +383 -0
- package/dist/index.js +3818 -1528
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +3180 -981
- package/dist/index.modern.mjs.map +1 -1
- package/docs/api/README.md +56 -2
- package/docs/api/classes/WSAPIAvatars.md +116 -0
- package/docs/api/classes/WSAPIBonuses.md +50 -0
- package/docs/api/classes/WSAPIClans.md +66 -0
- package/docs/api/classes/WSAPIGamePick.md +181 -0
- package/docs/api/classes/WSAPIGeneral.md +63 -0
- package/docs/api/classes/WSAPIInbox.md +277 -0
- package/docs/api/classes/WSAPIJackpots.md +185 -0
- package/docs/api/classes/WSAPILeaderBoard.md +39 -0
- package/docs/api/classes/WSAPIMiniGames.md +175 -0
- package/docs/api/classes/WSAPIMissions.md +611 -0
- package/docs/api/classes/WSAPIRaffles.md +195 -0
- package/docs/api/classes/WSAPIStore.md +744 -0
- package/docs/api/classes/WSAPITournaments.md +104 -0
- package/docs/api/classes/WSAPIUser.md +200 -0
- package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
- package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -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/SAWTemplateUI.md +10 -0
- package/docs/api/interfaces/TAchCategory.md +19 -4
- package/docs/api/interfaces/TBuyStoreItemResult.md +26 -8
- package/docs/api/interfaces/TMissionClaimRewardResult.md +14 -3
- package/docs/api/interfaces/TMissionOptInResult.md +10 -3
- package/docs/api/interfaces/TMissionOrBadge.md +6 -2
- package/docs/api/interfaces/TStoreItem.md +21 -1
- package/docs/api/interfaces/TTournamentDetailed.md +8 -0
- package/docs/api/interfaces/UserAchievement.md +1 -1
- 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/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/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_getLevels.md +162 -0
- package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
- package/package.json +3 -3
- package/scripts/postdoc-cleanup.js +195 -0
- package/src/Missions/MissionsUtils.ts +5 -2
- 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 +127 -0
- package/src/WSAPI/WSAPIBase.ts +93 -0
- package/src/WSAPI/WSAPIBonuses.ts +54 -0
- package/src/WSAPI/WSAPIClans.ts +417 -0
- package/src/WSAPI/WSAPIGamePick.ts +382 -0
- package/src/WSAPI/WSAPIGeneral.ts +57 -0
- package/src/WSAPI/WSAPIInbox.ts +222 -0
- package/src/WSAPI/WSAPIJackpots.ts +212 -0
- package/src/WSAPI/WSAPILeaderBoard.ts +40 -0
- package/src/WSAPI/WSAPIMiniGames.ts +181 -0
- package/src/WSAPI/WSAPIMissions.ts +572 -0
- package/src/WSAPI/WSAPIRaffles.ts +175 -0
- package/src/WSAPI/WSAPIStore.ts +732 -0
- package/src/WSAPI/WSAPITournaments.ts +541 -0
- package/src/WSAPI/WSAPITypes.ts +145 -87
- package/src/WSAPI/WSAPIUser.ts +456 -0
- package/tsconfig.json +17 -1
- package/docs/api/classes/WSAPI.md +0 -1927
|
@@ -214,4 +214,4 @@
|
|
|
214
214
|
|
|
215
215
|
### prize\_claim\_period\_type\_id?
|
|
216
216
|
|
|
217
|
-
> `optional` **prize\_claim\_period\_type\_id?**: `AchievementClaimPeriodTypeId`
|
|
217
|
+
> `optional` **prize\_claim\_period\_type\_id?**: [`AchievementClaimPeriodTypeId`](../enumerations/AchievementClaimPeriodTypeId.md)
|
|
@@ -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).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# UI Guide — `getClans`
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
- Powers the **clan-browser screen** (and the clan-pick modal during
|
|
5
|
+
tournament registration via
|
|
6
|
+
[`registerInTournament`](../../api/classes/WSAPITournaments.md#registerintournament)).
|
|
7
|
+
- Returned `clans[]` is already server-sorted by `rating_position` ASC
|
|
8
|
+
(1 = best). The default Smartico UI re-sorts on the same key as a
|
|
9
|
+
defensive measure but no client-side ordering work is required.
|
|
10
|
+
- Loading indicator: the first call is a server round-trip
|
|
11
|
+
(typically 100–500 ms); subsequent calls within the 30 s cache
|
|
12
|
+
window resolve effectively synchronously.
|
|
13
|
+
- `onUpdate` is poll-driven (no server push). For near-live state, the
|
|
14
|
+
consumer must poll on an interval — the default Smartico UI polls
|
|
15
|
+
every 30 s while the clan screen is open.
|
|
16
|
+
|
|
17
|
+
## List view organization
|
|
18
|
+
|
|
19
|
+
A single flat ranked list — no tabs. Render `clans[]` in the order
|
|
20
|
+
returned (already sorted by `rating_position`).
|
|
21
|
+
|
|
22
|
+
**Client-side search filter**: filter `clan.public_meta.name` against
|
|
23
|
+
the user's typed query (case-insensitive). No server round-trip.
|
|
24
|
+
|
|
25
|
+
**Sticky "my clan" footer**: when the user is in a clan and the
|
|
26
|
+
visible list is long enough (the default Smartico UI uses ≥ 7 visible
|
|
27
|
+
items), pin a duplicate of the user's clan row at the bottom of the
|
|
28
|
+
scroll area so it remains visible while the user scrolls. Skip this
|
|
29
|
+
when the user is clanless or the list is short.
|
|
30
|
+
|
|
31
|
+
No dedicated "My Clan" panel at the top of the list — the user's clan
|
|
32
|
+
appears at its natural `rating_position`, just highlighted in place.
|
|
33
|
+
|
|
34
|
+
## Item card / row
|
|
35
|
+
|
|
36
|
+
Fields rendered (column structure for desktop; mobile may collapse):
|
|
37
|
+
|
|
38
|
+
| Column | Source | Notes |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| Rank | `rating_position` | Display as `#N`. Apply `.top-1` / `.top-2` / `.top-3` styling for positions 1–3. |
|
|
41
|
+
| Icon / image | `public_meta.image_url` | Square. Fallback: first character of `public_meta.name` rendered as a letter avatar. |
|
|
42
|
+
| Name | `public_meta.name` | Translated server-side. Add "Your clan" badge next to the name if `clan.clan_id === user_clan_id`. |
|
|
43
|
+
| Rating score | `rating_score` | Numeric; the higher, the better. |
|
|
44
|
+
| Members | `member_count` / `capacity_limit` | Desktop: render a progress bar at `member_count / capacity_limit * 100%` with a label `N / M`. Mobile: text-only `N / M`. |
|
|
45
|
+
| Entry fee | `entry_fee_amount` + `entry_fee_currency_type_id` | "Free" when `entry_fee_amount === 0` or `entry_fee_currency_type_id === 3`. Otherwise `"{amount} {Points|Gems|Diamonds}"`. |
|
|
46
|
+
|
|
47
|
+
**Whole-row click target**: opens the detail modal (via
|
|
48
|
+
[`getClanInfo`](../../api/classes/WSAPIClans.md#getclaninfo) to load
|
|
49
|
+
members on demand). The row itself has no inline Join CTA — joining
|
|
50
|
+
happens from inside the detail modal (see "Action button decision
|
|
51
|
+
matrix" below).
|
|
52
|
+
|
|
53
|
+
**Detail-only fields** (not on row): `description`, full `members[]`
|
|
54
|
+
list (from `getClanInfo`), full progress bar styling on desktop.
|
|
55
|
+
|
|
56
|
+
## Action button decision matrix
|
|
57
|
+
|
|
58
|
+
The Join CTA lives in the detail modal (or the clan-pick modal during
|
|
59
|
+
tournament registration). Evaluate in priority order — first match
|
|
60
|
+
wins.
|
|
61
|
+
|
|
62
|
+
| State | Condition | Button label | Enabled? | Notes |
|
|
63
|
+
|---|---|---|---|---|
|
|
64
|
+
| **Your clan** | `clan.clan_id === user_clan_id` | "Your clan" | No-op | Highlight; no join action. |
|
|
65
|
+
| **Cooldown active** | `cooldown_until !== null` | `"Cooldown until <local-date>"` | Disabled | Affects ALL clans — the cooldown is user-level, not per-clan. Format `cooldown_until` from UTC to local time (`DD-MM-YYYY HH:mm` style). |
|
|
66
|
+
| **Clan full** | `member_count >= capacity_limit` | "Clan is full" | Disabled | |
|
|
67
|
+
| **Insufficient balance** | `entry_fee_amount > 0` AND user's balance for `entry_fee_currency_type_id` < `entry_fee_amount` | `"Not enough {Points|Gems|Diamonds} (deficit)"` | Disabled | Cross-check against {@link getUserProfile} balance for the currency. |
|
|
68
|
+
| **Joinable — free** | `entry_fee_amount === 0` OR `entry_fee_currency_type_id === 3` | "Join free" | Enabled | |
|
|
69
|
+
| **Joinable — paid** | default | `"Join ({amount} {Points|Gems|Diamonds})"` | Enabled | |
|
|
70
|
+
|
|
71
|
+
The enabled Join click invokes
|
|
72
|
+
[`joinClan(clan_id)`](../../api/classes/WSAPIClans.md#joinclan). See
|
|
73
|
+
its own UI guide for the in-flight + error-code matrix.
|
|
74
|
+
|
|
75
|
+
**Picker mode (`registerInTournament` clan-pick modal)**: when the
|
|
76
|
+
user is in cooldown, the default Smartico UI disables every row in the
|
|
77
|
+
picker (not just the buttons) — `onClick` is suppressed entirely.
|
|
78
|
+
|
|
79
|
+
## Cooldown rendering
|
|
80
|
+
|
|
81
|
+
- The cooldown is **user-level**, not per-clan. While
|
|
82
|
+
`cooldown_until !== null`, the user cannot join any clan.
|
|
83
|
+
- Format: `cooldown_until` is an ISO 8601 UTC string
|
|
84
|
+
(`"YYYY-MM-DDTHH:MM:SS"`, no timezone suffix). Parse as UTC, display
|
|
85
|
+
in user-local time. The default Smartico UI shows
|
|
86
|
+
`DD-MM-YYYY HH:mm` (e.g. `"01-06-2026 16:30"`).
|
|
87
|
+
- No "X days remaining" countdown — show the absolute expiry datetime.
|
|
88
|
+
If your product surface justifies a countdown, render one yourself.
|
|
89
|
+
|
|
90
|
+
## Image / asset specs
|
|
91
|
+
|
|
92
|
+
| Field | Aspect ratio | Notes |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `public_meta.image_url` | 1:1 (square) | Recommended source size not strictly enforced; the default Smartico UI sizes via CSS. Provide a square image for best results. |
|
|
95
|
+
|
|
96
|
+
**Fallback**: when `image_url` is missing or fails to load, render
|
|
97
|
+
the first character of `public_meta.name` as a letter avatar in the
|
|
98
|
+
icon container.
|
|
99
|
+
|
|
100
|
+
## Status-specific visual treatments
|
|
101
|
+
|
|
102
|
+
- **Your clan**: row gets a `.highlight` background tint + "Your clan"
|
|
103
|
+
badge next to the name.
|
|
104
|
+
- **Top-3 rank**: rows for `rating_position` 1–3 get podium accents
|
|
105
|
+
(gold/silver/bronze).
|
|
106
|
+
- **Full clan**: no row-level treatment — only the detail-modal button
|
|
107
|
+
shows the disabled state.
|
|
108
|
+
- **Cooldown active**: only the detail-modal button is disabled (or
|
|
109
|
+
in the picker, the whole row is dimmed).
|
|
110
|
+
- **Insufficient balance**: only the detail-modal button is disabled.
|
|
111
|
+
|
|
112
|
+
## Empty / loading / error states
|
|
113
|
+
|
|
114
|
+
- **Loading (first fetch)**: render a spinner / shimmer skeleton of
|
|
115
|
+
rows.
|
|
116
|
+
- **Empty list (no clans configured)**: render a neutral empty-state
|
|
117
|
+
illustration with copy like "No clans available".
|
|
118
|
+
- **Empty search results**: same empty-state illustration with
|
|
119
|
+
query-aware copy (e.g. "No clans matching '<query>'").
|
|
120
|
+
- **Error**: the default Smartico UI keeps the spinner visible
|
|
121
|
+
indefinitely on fetch failure (no error boundary). For a better UX,
|
|
122
|
+
catch the rejected promise and render a "Failed to load — Try again"
|
|
123
|
+
affordance.
|
|
124
|
+
|
|
125
|
+
## Refresh
|
|
126
|
+
|
|
127
|
+
`onUpdate` is poll-driven only. Two ways to keep the list fresh:
|
|
128
|
+
|
|
129
|
+
1. **Poll**: re-call `getClans()` on a 30-second interval while the
|
|
130
|
+
clan screen is visible. The cache deduplicates rapid refetches.
|
|
131
|
+
2. **Re-call after mutations**: after a successful
|
|
132
|
+
[`joinClan`](../../api/classes/WSAPIClans.md#joinclan), re-call
|
|
133
|
+
`getClans()` immediately to pick up the new `user_clan_id` and any
|
|
134
|
+
refreshed `member_count` / `cooldown_until` fields.
|
|
135
|
+
|
|
136
|
+
There is no server push that refreshes the clans list automatically
|
|
137
|
+
— another user joining your clan, an operator kicking you, or a clan
|
|
138
|
+
being archived will all only surface on the next consumer-driven
|
|
139
|
+
fetch.
|
|
140
|
+
|
|
141
|
+
## Animations / transitions
|
|
142
|
+
|
|
143
|
+
- **List entry**: rows fade-in with a ~30 ms stagger on first render.
|
|
144
|
+
- **Rank reorder between polls**: if you implement live updates,
|
|
145
|
+
detect `rating_position` changes by diffing the previous and
|
|
146
|
+
current arrays, and animate rows to their new position (FLIP
|
|
147
|
+
animation). Don't full-re-render the list.
|
|
148
|
+
- **Join success celebration**: when `user_clan_id` flips between
|
|
149
|
+
polls (detect by comparing pre- and post-refresh values), play a
|
|
150
|
+
brief "Welcome to {clan name}" toast and animate the now-highlighted
|
|
151
|
+
row.
|
|
152
|
+
|
|
153
|
+
## Mobile vs desktop
|
|
154
|
+
|
|
155
|
+
- **Member fill**: desktop renders a progress bar; mobile renders
|
|
156
|
+
text-only (`N / M`).
|
|
157
|
+
- **Columns**: desktop shows `#`, Clan, Rating, Members, Entry;
|
|
158
|
+
mobile drops Members (entry fee inlines below the name).
|
|
159
|
+
- **Sticky my-clan footer**: same threshold on both (≥ 7 visible
|
|
160
|
+
rows).
|
|
161
|
+
- **Search**: same client-side filter; desktop typically has a
|
|
162
|
+
search input at the top; mobile may use a dedicated search sheet.
|
|
163
|
+
|
|
164
|
+
## Performance
|
|
165
|
+
|
|
166
|
+
- 30 s polling on the clans surface is fine for typical clan
|
|
167
|
+
catalogs (< 200 clans). For very large catalogs, consider polling
|
|
168
|
+
only while the surface is in the viewport.
|
|
169
|
+
- Use keyed per-row rendering — celebration / rank-reorder animations
|
|
170
|
+
break if the DOM nodes are recreated on every poll tick.
|
|
171
|
+
- Image lazy-loading is safe; clans below the fold rarely need
|
|
172
|
+
immediate paint.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# UI Guide — `joinClan`
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
- Action-focused mutation. The user is on the clans browser or the
|
|
5
|
+
detail modal, the CTA is "Join (...)", and they click it.
|
|
6
|
+
- A successful response (`errCode === 0`) means: membership persisted,
|
|
7
|
+
entry fee (if any) already debited, cooldown restarted, CRM events
|
|
8
|
+
fired. The SDK has done all of this server-side by the time the
|
|
9
|
+
promise resolves.
|
|
10
|
+
- The SDK does NOT auto-refresh `getClans` after success. The
|
|
11
|
+
consumer must re-call manually.
|
|
12
|
+
- Latency: typically 200–800 ms for a healthy WebSocket connection
|
|
13
|
+
(the server performs balance checks + atomic DB writes
|
|
14
|
+
synchronously).
|
|
15
|
+
|
|
16
|
+
## Loading state
|
|
17
|
+
|
|
18
|
+
- **Trigger**: set an in-flight flag (`joining = true`) immediately
|
|
19
|
+
on click, BEFORE the call. This is the consumer's responsibility
|
|
20
|
+
— the SDK has no in-flight guard.
|
|
21
|
+
- **Visual**: replace the button label with animated dots / spinner.
|
|
22
|
+
Disable the button. Keep the modal open.
|
|
23
|
+
- **Reset**: clear the in-flight flag on response — success or error.
|
|
24
|
+
|
|
25
|
+
## Idempotency UI guard
|
|
26
|
+
|
|
27
|
+
**Two distinct hazards** the consumer must guard against:
|
|
28
|
+
|
|
29
|
+
1. **Double-click during in-flight**: the SDK does NOT prevent two
|
|
30
|
+
simultaneous `joinClan` calls. If the user clicks twice before the
|
|
31
|
+
first response arrives, both requests reach the server. If the
|
|
32
|
+
first succeeds, the second behaves as a clan-switch to the same
|
|
33
|
+
clan — which, on labels with `CLAN_COOLDOWN_DAYS = 0`, will
|
|
34
|
+
**deduct the entry fee a second time**. Guard with an in-flight
|
|
35
|
+
flag (see "Loading state").
|
|
36
|
+
|
|
37
|
+
2. **Same-clan re-click**: the SDK does NOT short-circuit when the
|
|
38
|
+
user clicks Join on the clan they're already in. The server
|
|
39
|
+
treats it as a clan-switch to the same clan, and on labels with
|
|
40
|
+
cooldown=0 will re-deduct the fee. The Join button MUST be
|
|
41
|
+
disabled (or show "Your clan") whenever
|
|
42
|
+
`target.clan_id === user_clan_id`. Don't rely on the server to
|
|
43
|
+
silently no-op.
|
|
44
|
+
|
|
45
|
+
Recommended pattern:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const [joining, setJoining] = useState(false);
|
|
49
|
+
|
|
50
|
+
const onJoin = async () => {
|
|
51
|
+
if (joining) return; // in-flight guard
|
|
52
|
+
if (target.clan_id === userClanId) return; // same-clan guard
|
|
53
|
+
if (cooldownUntil) return; // cooldown guard
|
|
54
|
+
if (target.member_count >= target.capacity_limit) return;
|
|
55
|
+
// (also: balance guard — handled by the pre-render CTA state matrix)
|
|
56
|
+
|
|
57
|
+
setJoining(true);
|
|
58
|
+
const r = await window._smartico.api.joinClan(target.clan_id);
|
|
59
|
+
setJoining(false);
|
|
60
|
+
handleResponse(r);
|
|
61
|
+
if (r.errCode === 0) await window._smartico.api.getClans();
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Action button decision matrix
|
|
66
|
+
|
|
67
|
+
`errCode` branch behavior. Refer to the `joinClan` TSDoc for the full
|
|
68
|
+
table of codes; UI handling per code:
|
|
69
|
+
|
|
70
|
+
| `errCode` | Action |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `0` (success) | Show success toast (e.g. `"Joined {clan.name}"`). Close modal (or transition it to the "Your clan" state). Call `getClans()` to refresh `user_clan_id`, `member_count`, and `cooldown_until`. The default Smartico UI also dispatches an optimistic local state update so the Join button instantly flips to "Your clan" before the refresh lands. |
|
|
73
|
+
| `1000` (invalid parameters) | Programming error from SDK consumer side — should not occur. Show a generic error toast. |
|
|
74
|
+
| `1001` (not found / archived) | Refresh `getClans()`; the clan should disappear from the list. Show a brief "clan no longer available" toast. |
|
|
75
|
+
| `1002` (full) | Show "Clan is full". Refresh `getClans()`; the now-full clan's button will pre-disable to "Clan is full". |
|
|
76
|
+
| `1003` (insufficient funds) | Show insufficient-balance UI naming the currency (`['points','gems','diamonds'][entry_fee_currency_type_id]`) and the deficit (`entry_fee_amount`). Optional: deep-link to a currency-earning surface. |
|
|
77
|
+
| `1004` (segment mismatch) | Show a gating message — operator-supplied copy if the clan exposes one; otherwise a generic "Not eligible for this clan". Don't retry. |
|
|
78
|
+
| `1005` | `joinClan` does NOT return `1005`. If you see it in this method's response, treat as a generic error. |
|
|
79
|
+
| `1006` (cooldown active) | Show "Cooldown until {cooldown_until local-formatted}". Disable the Join CTA across ALL clans until cooldown expires. |
|
|
80
|
+
| `1007` (archived) | Defined in the public enum but the server emits `1001` instead. Handle as a synonym for `1001` defensively. |
|
|
81
|
+
| `1011` | `joinClan` does NOT return `1011`. If you see it in this method's response, treat as a generic error. |
|
|
82
|
+
| Other | Generic error toast with `errMsg` if any. |
|
|
83
|
+
|
|
84
|
+
## Per-error-code message strategy
|
|
85
|
+
|
|
86
|
+
| `errCode` | `errMsg` usable? | Operator-supplied copy | Best source |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `0` (success) | — | — | Localized `"Joined {clan.name}"` |
|
|
89
|
+
| `1003` (insufficient funds) | Fallback | — | Localized `"Insufficient {currency}"` + deficit derived from `entry_fee_amount` and the user's balance |
|
|
90
|
+
| `1004` (segment mismatch) | Fallback | If the clan has an operator-supplied entry-conditions message, prefer it | Otherwise localized "Not eligible for this clan" |
|
|
91
|
+
| `1006` (cooldown) | Fallback | — | Localized "Cooldown until {date}" — format `cooldown_until` from UTC to local |
|
|
92
|
+
| `1002` (full) | Fallback | — | Localized "Clan is full" |
|
|
93
|
+
| All others | Use `errMsg` as a fallback when no specific localized copy is available | — | Localized error per code |
|
|
94
|
+
|
|
95
|
+
## Optimistic update
|
|
96
|
+
|
|
97
|
+
The default Smartico UI optimistically flips the user's clan
|
|
98
|
+
membership state on `errCode === 0` (before `getClans()` refreshes).
|
|
99
|
+
This is **safe** for this method because:
|
|
100
|
+
|
|
101
|
+
- The server has already committed the membership row when the
|
|
102
|
+
response returns.
|
|
103
|
+
- The fee is already debited.
|
|
104
|
+
- If the optimistic update sets `user_clan_id` to the new clan, the
|
|
105
|
+
refresh from `getClans()` will confirm the same value.
|
|
106
|
+
|
|
107
|
+
You can mirror this pattern: on `errCode === 0`, immediately update
|
|
108
|
+
the UI to show the user in the new clan, then re-fetch in the
|
|
109
|
+
background. If the refresh disagrees (very unlikely), reconcile.
|
|
110
|
+
|
|
111
|
+
Do NOT optimistically update on any non-zero `errCode` — those are
|
|
112
|
+
real failures.
|
|
113
|
+
|
|
114
|
+
## Success celebration
|
|
115
|
+
|
|
116
|
+
The default Smartico UI does not play a dedicated celebration
|
|
117
|
+
animation (no confetti, no full-screen overlay). The button flips
|
|
118
|
+
to "Your clan" immediately via optimistic update, and the modal
|
|
119
|
+
re-renders with refreshed member data once `getClans()` returns.
|
|
120
|
+
|
|
121
|
+
If your product surface justifies a celebration, drive it from the
|
|
122
|
+
`onUpdate` detection: when `result.user_clan_id` flips between
|
|
123
|
+
pre-join and post-join fetches, play your celebration.
|
|
124
|
+
|
|
125
|
+
## Refresh after response
|
|
126
|
+
|
|
127
|
+
The SDK does NOT auto-refresh the `getClans` cache. After a
|
|
128
|
+
successful join, manually call `getClans()` to pick up:
|
|
129
|
+
|
|
130
|
+
- The new `user_clan_id`
|
|
131
|
+
- The new `cooldown_until` (cooldown restarts at join time)
|
|
132
|
+
- The updated `member_count` on the joined clan
|
|
133
|
+
- The decremented `member_count` on any previously-joined clan
|
|
134
|
+
(clan-switch case)
|
|
135
|
+
|
|
136
|
+
The user's balance update from the entry-fee debit arrives via the
|
|
137
|
+
SDK's user-properties update channel — subscribe separately to
|
|
138
|
+
{@link getUserProfile} if your UI shows the balance.
|
|
139
|
+
|
|
140
|
+
## Clan-switch semantics
|
|
141
|
+
|
|
142
|
+
When the user is in clan A and successfully joins clan B, the
|
|
143
|
+
server performs an **atomic transition**: deactivate A membership,
|
|
144
|
+
insert B membership, debit fee — all in one transaction. The user
|
|
145
|
+
is never observably clanless during the switch.
|
|
146
|
+
|
|
147
|
+
From the UI's perspective, this is identical to a fresh join. No
|
|
148
|
+
special handling required — the response is the same `errCode === 0`,
|
|
149
|
+
and `getClans()` refresh will show the user in clan B with a fresh
|
|
150
|
+
cooldown.
|
|
151
|
+
|
|
152
|
+
## Special case — tournament clan-pick flow
|
|
153
|
+
|
|
154
|
+
When `registerInTournament(tournamentId)` returns `1005` (user has
|
|
155
|
+
no clan and the tournament is clan-based), the default UI typically:
|
|
156
|
+
|
|
157
|
+
1. Opens a clan-picker driven by `getClans`.
|
|
158
|
+
2. User picks a clan → call `joinClan(clanId)`.
|
|
159
|
+
3. On `errCode === 0`, automatically retry
|
|
160
|
+
`registerInTournament(tournamentId)`.
|
|
161
|
+
4. Handle `1011` on the retry: user joined the clan but joined
|
|
162
|
+
after this tournament started (and has prior tournament scores)
|
|
163
|
+
— show an explanatory message; the user is in the clan but
|
|
164
|
+
blocked from this specific tournament run.
|
|
165
|
+
|
|
166
|
+
The SDK does NOT chain these calls automatically. Each step is the
|
|
167
|
+
consumer's responsibility. See the
|
|
168
|
+
[UI Guide for `registerInTournament`](../tournaments/UIGuide_registerInTournament.md)
|
|
169
|
+
for the recommended sequence.
|
|
170
|
+
|
|
171
|
+
## Animations / transitions
|
|
172
|
+
|
|
173
|
+
- **Loading dots**: 3-dot bouncing animation on the button while the
|
|
174
|
+
promise is in flight.
|
|
175
|
+
- **Button state flip**: when the response arrives, animate the
|
|
176
|
+
button label transition (~150 ms ease-out).
|
|
177
|
+
- **Member list refresh**: after `getClans()` re-fetch, the affected
|
|
178
|
+
clan rows (`member_count` change, your clan now highlighted) get a
|
|
179
|
+
brief highlight pulse on update.
|
|
180
|
+
|
|
181
|
+
## Mobile vs desktop
|
|
182
|
+
|
|
183
|
+
- **Loading state**: identical (dots on the button).
|
|
184
|
+
- **Error surfacing**: desktop typically uses a toast/snackbar;
|
|
185
|
+
mobile may use a centered modal with a clear "OK" affordance.
|
|
186
|
+
- **Cooldown / insufficient-balance disabled states**: rendered the
|
|
187
|
+
same way on both — the disabled button shows the constraint text.
|
|
188
|
+
|
|
189
|
+
## Performance
|
|
190
|
+
|
|
191
|
+
- Single round-trip per click. No batching needed.
|
|
192
|
+
- The `getClans()` refresh after success adds ~50–500 ms (cache miss
|
|
193
|
+
→ fresh fetch). Treat as fire-and-forget; the optimistic UI flip
|
|
194
|
+
has already happened.
|
|
195
|
+
- Don't poll `getClans()` to detect join completion — the response
|
|
196
|
+
promise is the authoritative signal.
|
|
@@ -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.
|