@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.
Files changed (99) hide show
  1. package/.nvmrc +1 -1
  2. package/README.md +31 -2
  3. package/dist/Store/BuyStoreItemErrorCode.d.ts +9 -1
  4. package/dist/Tournaments/TournamentRegistrationError.d.ts +3 -1
  5. package/dist/WSAPI/WSAPI.d.ts +13 -1235
  6. package/dist/WSAPI/WSAPIAvatars.d.ts +78 -0
  7. package/dist/WSAPI/WSAPIBase.d.ts +71 -0
  8. package/dist/WSAPI/WSAPIBonuses.d.ts +26 -0
  9. package/dist/WSAPI/WSAPIClans.d.ts +388 -0
  10. package/dist/WSAPI/WSAPIGamePick.d.ts +308 -0
  11. package/dist/WSAPI/WSAPIGeneral.d.ts +30 -0
  12. package/dist/WSAPI/WSAPIInbox.d.ts +126 -0
  13. package/dist/WSAPI/WSAPIJackpots.d.ts +109 -0
  14. package/dist/WSAPI/WSAPILeaderBoard.d.ts +25 -0
  15. package/dist/WSAPI/WSAPIMiniGames.d.ts +94 -0
  16. package/dist/WSAPI/WSAPIMissions.d.ts +517 -0
  17. package/dist/WSAPI/WSAPIRaffles.d.ts +119 -0
  18. package/dist/WSAPI/WSAPIStore.d.ts +656 -0
  19. package/dist/WSAPI/WSAPITournaments.d.ts +501 -0
  20. package/dist/WSAPI/WSAPITypes.d.ts +145 -85
  21. package/dist/WSAPI/WSAPIUser.d.ts +383 -0
  22. package/dist/index.js +3818 -1528
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.modern.mjs +3180 -981
  25. package/dist/index.modern.mjs.map +1 -1
  26. package/docs/api/README.md +56 -2
  27. package/docs/api/classes/WSAPIAvatars.md +116 -0
  28. package/docs/api/classes/WSAPIBonuses.md +50 -0
  29. package/docs/api/classes/WSAPIClans.md +66 -0
  30. package/docs/api/classes/WSAPIGamePick.md +181 -0
  31. package/docs/api/classes/WSAPIGeneral.md +63 -0
  32. package/docs/api/classes/WSAPIInbox.md +277 -0
  33. package/docs/api/classes/WSAPIJackpots.md +185 -0
  34. package/docs/api/classes/WSAPILeaderBoard.md +39 -0
  35. package/docs/api/classes/WSAPIMiniGames.md +175 -0
  36. package/docs/api/classes/WSAPIMissions.md +611 -0
  37. package/docs/api/classes/WSAPIRaffles.md +195 -0
  38. package/docs/api/classes/WSAPIStore.md +744 -0
  39. package/docs/api/classes/WSAPITournaments.md +104 -0
  40. package/docs/api/classes/WSAPIUser.md +200 -0
  41. package/docs/api/enumerations/AchievementClaimPeriodTypeId.md +13 -0
  42. package/docs/api/enumerations/BuyStoreItemErrorCode.md +32 -0
  43. package/docs/api/interfaces/ClanPrizePublicMeta.md +41 -0
  44. package/docs/api/interfaces/ClanPrizeStructureEntry.md +7 -1
  45. package/docs/api/interfaces/ClanPublicMeta.md +4 -0
  46. package/docs/api/interfaces/SAWTemplateUI.md +10 -0
  47. package/docs/api/interfaces/TAchCategory.md +19 -4
  48. package/docs/api/interfaces/TBuyStoreItemResult.md +26 -8
  49. package/docs/api/interfaces/TMissionClaimRewardResult.md +14 -3
  50. package/docs/api/interfaces/TMissionOptInResult.md +10 -3
  51. package/docs/api/interfaces/TMissionOrBadge.md +6 -2
  52. package/docs/api/interfaces/TStoreItem.md +21 -1
  53. package/docs/api/interfaces/TTournamentDetailed.md +8 -0
  54. package/docs/api/interfaces/UserAchievement.md +1 -1
  55. package/docs/ui/clans/UIGuide_getClanInfo.md +153 -0
  56. package/docs/ui/clans/UIGuide_getClans.md +172 -0
  57. package/docs/ui/clans/UIGuide_joinClan.md +196 -0
  58. package/docs/ui/missions/UIGuide_getAchCategories.md +17 -0
  59. package/docs/ui/missions/UIGuide_getBadges.md +237 -0
  60. package/docs/ui/missions/UIGuide_getMissions.md +268 -0
  61. package/docs/ui/missions/UIGuide_requestMissionClaimReward.md +21 -0
  62. package/docs/ui/missions/UIGuide_requestMissionOptIn.md +16 -0
  63. package/docs/ui/store/UIGuide_buyStoreItem.md +133 -0
  64. package/docs/ui/store/UIGuide_getStoreCategories.md +19 -0
  65. package/docs/ui/store/UIGuide_getStoreItems.md +264 -0
  66. package/docs/ui/store/UIGuide_getStorePurchasedItems.md +122 -0
  67. package/docs/ui/tournaments/UIGuide_getClanTournamentPlayers.md +140 -0
  68. package/docs/ui/tournaments/UIGuide_getTournamentInstanceInfo.md +265 -0
  69. package/docs/ui/tournaments/UIGuide_getTournamentsList.md +236 -0
  70. package/docs/ui/tournaments/UIGuide_registerInTournament.md +156 -0
  71. package/docs/ui/user/UIGuide_getLevels.md +162 -0
  72. package/docs/ui/user/UIGuide_getUserProfile.md +213 -0
  73. package/package.json +3 -3
  74. package/scripts/postdoc-cleanup.js +195 -0
  75. package/src/Missions/MissionsUtils.ts +5 -2
  76. package/src/Store/BuyStoreItemErrorCode.ts +8 -0
  77. package/src/Store/StoreItem.ts +1 -0
  78. package/src/Store/StoreItemPurchased.ts +1 -0
  79. package/src/Store/StoreItemType.ts +1 -1
  80. package/src/Tournaments/TournamentRegistrationError.ts +4 -0
  81. package/src/WSAPI/WSAPI.ts +27 -2007
  82. package/src/WSAPI/WSAPIAvatars.ts +127 -0
  83. package/src/WSAPI/WSAPIBase.ts +93 -0
  84. package/src/WSAPI/WSAPIBonuses.ts +54 -0
  85. package/src/WSAPI/WSAPIClans.ts +417 -0
  86. package/src/WSAPI/WSAPIGamePick.ts +382 -0
  87. package/src/WSAPI/WSAPIGeneral.ts +57 -0
  88. package/src/WSAPI/WSAPIInbox.ts +222 -0
  89. package/src/WSAPI/WSAPIJackpots.ts +212 -0
  90. package/src/WSAPI/WSAPILeaderBoard.ts +40 -0
  91. package/src/WSAPI/WSAPIMiniGames.ts +181 -0
  92. package/src/WSAPI/WSAPIMissions.ts +572 -0
  93. package/src/WSAPI/WSAPIRaffles.ts +175 -0
  94. package/src/WSAPI/WSAPIStore.ts +732 -0
  95. package/src/WSAPI/WSAPITournaments.ts +541 -0
  96. package/src/WSAPI/WSAPITypes.ts +145 -87
  97. package/src/WSAPI/WSAPIUser.ts +456 -0
  98. package/tsconfig.json +17 -1
  99. package/docs/api/classes/WSAPI.md +0 -1927
@@ -0,0 +1,19 @@
1
+ # UI Guide — `getStoreCategories`
2
+
3
+ ## UI guidance
4
+ - Treat categories as relatively static. Safe to fetch once on store-page entry 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 fall
7
+ back to `name` or `id` for stable ordering.
8
+ - For tab UIs (the common store layout), generate one tab per non-empty category.
9
+ The reference UI also appends the count of items in parentheses on each tab label
10
+ (e.g. `Bonuses (12)`) — compute the count by intersecting `getStoreItems()` with
11
+ each category id.
12
+ - If you want an "All items" tab, generate it client-side; the server does not return one.
13
+ - Loading indicator: skip on cache hit; show a brief shimmer on cold fetch (typically
14
+ 100–300 ms).
15
+ - Empty state: when this method returns `[]`, render the store as a flat grid (no tabs,
16
+ no section headers) over `getStoreItems()`.
17
+
18
+ **Visitor mode**: supported. Use `_smartico.vapi(lang).getStoreCategories()` to fetch
19
+ categories with `name` translated to the given language without an authenticated user.
@@ -0,0 +1,264 @@
1
+ # UI Guide — `getStoreItems`
2
+
3
+ ## Overview
4
+ - Register `onUpdate` on first render and treat each invocation as
5
+ "discard prior list, re-render from this array". Do not merge.
6
+ - Loading indicator: the first `getStoreItems()` is a server round-trip
7
+ (typically 100–500 ms); subsequent calls within the 30 s cache window
8
+ resolve effectively synchronously.
9
+ - The SDK returns a flat array; tabs/sections/filters are applied
10
+ client-side using `category_ids`, `custom_section_id`, and
11
+ `only_in_custom_section`.
12
+ - The catalog card UI is the SAME for all `type` values. Type-specific
13
+ behavior (lootbox reveal, bonus activation toast, SAW redirect) is
14
+ the consumer's responsibility AFTER the purchase succeeds, not on
15
+ the catalog tile itself.
16
+
17
+ ## List view organization
18
+ - **Categories**: render `getStoreCategories()` as tabs/chips. For each
19
+ tab, filter the catalog to items whose `category_ids` includes the
20
+ active category id. An item present in multiple categories appears
21
+ under each.
22
+ - **Custom sections**: the operator can group items into
23
+ custom_section_id buckets that live on a separate route from the main
24
+ store. Items with `only_in_custom_section: true` MUST be hidden from
25
+ the main store and appear only inside their `custom_section_id`.
26
+ Items WITHOUT that flag (but with a `custom_section_id`) appear in
27
+ both places.
28
+ - **Sorting** (within a category): three modes, operator-configurable
29
+ default order:
30
+ 1. "Natural" — a composite sort string from operator config
31
+ (commonly `canbuy desc, priority asc, price asc`). Sorts buyable
32
+ items above non-buyable, then by `priority` (lower first),
33
+ breaking ties by `price`.
34
+ 2. "Price" — by numeric `price`, ASC or DESC.
35
+ 3. "Name" — alphabetic by `name`, ASC or DESC.
36
+ Default is "Natural". Consumers may expose toggles.
37
+ - **No status bucketing** (unlike missions). Sold-out / can't-buy
38
+ items are intermixed with buyable items; the "Natural" sort just
39
+ pushes them lower. Render them with a status overlay (see status
40
+ treatments below) rather than putting them in a separate tab.
41
+ - **Search**: optional client-side substring match on `name`
42
+ (case-insensitive). The SDK does not paginate.
43
+ - **No pagination**: the SDK returns the full visible catalog in one
44
+ response. For very large catalogs (50+ items), consider client-side
45
+ virtualization. The default Smartico UI does NOT virtualize.
46
+
47
+ ## Item card / tile (list view)
48
+
49
+ Fields to render on the card:
50
+ - `image` — documented source size **256×256 px**, 1:1 aspect ratio.
51
+ CSS `background-image` or `<img>` is conventional.
52
+ - `name` — the title. Pre-translated server-side. Safe to render as
53
+ HTML if the consumer sanitizes first.
54
+ - Price block — `price` rendered alongside a currency icon driven by
55
+ `purchase_type` (`'points'` / `'gems'` / `'diamonds'`). When
56
+ `discounted_price` is set, render `discounted_price` as the active
57
+ price and strike-through `price`.
58
+ - Ribbon overlay (`ribbon` field) — presets `'sale'`, `'hot'`, `'new'`,
59
+ `'vip'` use built-in styling; any other string is a custom URL
60
+ (250×300 px). Position: top-left corner overlay.
61
+ - Discount ribbon (`discount_price_ribbon`) — only when set. Presets
62
+ `'10' | '15' | '20' | '25' | '50'` use built-in percent-styled
63
+ ribbons; the literal `'custom'` uses `custom_ribbon_image` (250×300 px)
64
+ as the artwork. Position: top-right corner overlay (or opposite the
65
+ item ribbon).
66
+ - Stock indicator — when `pool !== null`:
67
+ - `pool > 0`: render "In stock — N left" (using
68
+ `pool` as the count).
69
+ - `pool === 0`: render "Out of stock" / "Sold out" overlay
70
+ and grey-out the card if the operator enabled the
71
+ `grey_out_unavailable_items` config flag.
72
+ When `pool === null`, render no stock indicator (unlimited supply).
73
+ - Countdown timer — render only when `active_till_date` is set AND the
74
+ operator enabled the per-item `show_timer` flag. Format below.
75
+ - Buy button — labeled with the "Buy Now" CTA, the price, and the
76
+ currency icon. Disabled / greyed when `can_buy === false`, when the
77
+ user can't afford the item (live balance < `price`), or when
78
+ `pool === 0`.
79
+
80
+ Fields NOT shown on the card (detail popup only):
81
+ - Full `description` HTML (cards typically show just the title)
82
+ - `hint_text` (T&C)
83
+ - `related_games`
84
+ - `related_item_ids`
85
+ - `cant_buy_message` (the verbose explanation; show on the popup or as
86
+ a toast when the Buy button is clicked while disabled)
87
+ - `limit_message` / `purchase_limit_message` (surfaced post-attempt via
88
+ the buy error toast, not pre-emptively on the card)
89
+
90
+ Click target: the **whole card** opens the detail popup. The Buy button
91
+ inside the popup is where the purchase is actually dispatched — there
92
+ is no inline buy from the card in the default Smartico UI.
93
+
94
+ ## Detail popup
95
+
96
+ Top-to-bottom structure (omit sections whose source field is empty):
97
+ 1. Close button.
98
+ 2. Item ribbon overlay (same as card).
99
+ 3. Discount ribbon overlay (same as card).
100
+ 4. Title (`name`).
101
+ 5. Countdown timer (when `active_till_date && show_timer`).
102
+ 6. Stock indicator ("In stock — N left" / "Out of stock"), with
103
+ grey-out applied to the image when the item is unbuyable AND the
104
+ operator enabled `grey_out_unavailable_items`.
105
+ 7. Image (`image`) — render larger than the card variant.
106
+ 8. Full `description` (HTML).
107
+ 9. Insufficient-balance line — when the live balance for
108
+ `purchase_type` is less than `price`, render a localized
109
+ "You're short by N {points|gems|diamonds}" copy with the deficit
110
+ computed client-side (`price − balance`).
111
+ 10. `cant_buy_message` — when `can_buy === false` and there's a
112
+ reason string (e.g. "VIP only").
113
+ 11. Buy button block. Disabled state combines the three conditions
114
+ above. While the purchase RPC is in flight, replace the inner
115
+ price/CTA with a loading dots animation.
116
+ 12. T&C `hint_text` — surfaced as an info-icon tooltip below the
117
+ Buy button (tap to expand). Not inline.
118
+ 13. Related items / related games carousel (collapsed by default,
119
+ expandable). `related_item_ids` resolves against the main
120
+ catalog; `related_games` filtered to those with
121
+ `game_public_meta.enabled === true`. Show navigation arrows when
122
+ 5+ items on desktop, 4+ on mobile.
123
+
124
+ ## Action button decision matrix
125
+
126
+ *(Buy button)*
127
+
128
+ Apply in priority order; first match wins:
129
+
130
+ 1. **Purchase RPC in flight** — show loading dots over the price/CTA,
131
+ keep the button disabled until the response arrives. Guard
132
+ double-clicks at the UI layer.
133
+ 2. `pool === 0` → **"Sold out"** state; button disabled. The card and
134
+ image may be greyed (operator config).
135
+ 3. `can_buy === false` → button disabled. Surface `cant_buy_message`
136
+ (or `limit_message`) on the popup as the explanation.
137
+ 4. Balance < `price` for the relevant `purchase_type` → button
138
+ disabled. Surface a localized insufficient-balance line with the
139
+ deficit.
140
+ 5. All clear → **"Buy Now"** button enabled. On click: call
141
+ [buyStoreItem](../../api/classes/WSAPIStore.md#buystoreitem)(`id`) and show loading dots until the
142
+ response arrives.
143
+
144
+ After a successful purchase ([buyStoreItem](../../api/classes/WSAPIStore.md#buystoreitem) `err_code === 0`):
145
+ - Close the popup, show a success toast.
146
+ - The SDK auto-fires `onUpdate` with the refreshed catalog — re-render
147
+ from that array, do NOT manually decrement the local `pool`.
148
+
149
+ On a failed purchase, branch on `err_code` (see [buyStoreItem](../../api/classes/WSAPIStore.md#buystoreitem)
150
+ for the full error code table — codes `11000` / `11011` / `11012` for
151
+ insufficient balance per currency, `11006` for per-period cap reached,
152
+ `11009` for pool emptied between catalog fetch and buy, `11014` for
153
+ purchase-limit hit, etc.). Surface `purchase_limit_message` for the
154
+ limit-hit case, `limit_message` for the cap-reached case; fall back to
155
+ `err_message` otherwise.
156
+
157
+ ## Price rendering per `purchase_type`
158
+ - **`'points'`**: render `price` with a "points" currency glyph; compare
159
+ against the user's `ach_points_balance`.
160
+ - **`'gems'`**: render with a "gems" glyph; compare against
161
+ `ach_gems_balance`.
162
+ - **`'diamonds'`**: render with a "diamonds" glyph; compare against
163
+ `ach_diamonds_balance`.
164
+ - When `discounted_price` is set: the **discounted** value is the
165
+ active price (used for affordability checks); `price` becomes the
166
+ strikethrough "before" value.
167
+ - All three balances update server-side as the user plays and arrive
168
+ on the user's gamification profile asynchronously — keep them live
169
+ without polling.
170
+
171
+ ## Image / asset specs
172
+ - `image` (item icon): **256×256 px**, 1:1 aspect ratio.
173
+ - `ribbon` (when a URL): **250×300 px** custom artwork.
174
+ - `custom_ribbon_image` (discount ribbon when `discount_price_ribbon === 'custom'`):
175
+ **250×300 px**.
176
+ - Related game thumbnails: **1:1 aspect ratio** per
177
+ `game_public_meta.image`.
178
+ - No built-in fallback placeholders — consumers should provide one when
179
+ source fields are empty.
180
+
181
+ ## Status-specific visual treatments
182
+ - **Sold out** (`pool === 0`): "Out of stock" badge on the card; image
183
+ greyscaled when the operator enabled `grey_out_unavailable_items`.
184
+ Buy button disabled.
185
+ - **Cannot afford** (balance < `price` for `purchase_type`): Buy button
186
+ disabled (greyed); the rest of the card is full-color. Detail popup
187
+ adds the deficit line. The card image is greyscaled only when the
188
+ operator enabled `grey_out_unavailable_items`.
189
+ - **Not eligible** (`can_buy === false`): same as cannot-afford
190
+ visually; the explanation source is `cant_buy_message` (popup) /
191
+ `limit_message` (post-buy-attempt).
192
+ - **Discount active** (`discounted_price` set): show the discount
193
+ ribbon overlay and the strikethrough+new-price treatment.
194
+ - **New item** (operator marked `ribbon === 'new'` OR client-side
195
+ tracking of newly-added ids in localStorage): "New" ribbon preset.
196
+ The SDK does not track "newness" — the operator's `ribbon` field is
197
+ the source of truth.
198
+ - **Flash sale** (`active_till_date && show_timer`): countdown timer
199
+ on the card and popup.
200
+
201
+ ## Countdown / timing format
202
+
203
+ *(for `active_till_date`)*
204
+
205
+ Convention used by the default Smartico UI:
206
+ - `DD:HH:MM:SS` (zero-padded to 2 digits each) when the timer is set.
207
+ - Update the displayed text every **1 second**.
208
+ - When the timer reaches 0, the item disappears from the catalog on
209
+ the next refresh (server filters it out). The consumer should NOT
210
+ need a separate "expired" state for catalog items.
211
+
212
+ ## Empty / loading / error states
213
+ - **Empty catalog**: "No store items" message + illustration.
214
+ - **Empty category** (after filter): same copy or a category-scoped
215
+ variant.
216
+ - **Empty search**: no-results state with the search term.
217
+ - **Loading**: spinner / skeleton until the first response. Subsequent
218
+ `onUpdate` refreshes are fast enough to render in-place without a
219
+ skeleton.
220
+ - **Buy error**: surface `purchase_limit_message` (for
221
+ `err_code === 11014`), `limit_message` (for `err_code === 11006`), or
222
+ the server `err_message` as a modal/toast.
223
+
224
+ ## Animations / transitions
225
+ - List entry: stagger-fade-in per card (the default Smartico UI uses a
226
+ ~100 ms stagger per index).
227
+ - Popup open: bounce + fade-in on title/image; fade-in on description,
228
+ stock line, and balance line.
229
+ - Buy button in flight: loading dots overlay; disable underlying CTA.
230
+ - Purchase success: close popup, show success toast; the auto-refresh
231
+ re-renders the catalog (pool decrements, `can_buy` re-evaluates).
232
+ - Card hover (desktop): optional scale/shadow per consumer's design.
233
+
234
+ ## Mobile vs desktop
235
+ - Mobile: vertical scroll; the default Smartico UI uses a 2-column grid
236
+ for the main store and a list layout for purchase history.
237
+ - Desktop: wider multi-column grid. Related-items carousel shows
238
+ navigation arrows at 5+ items on desktop vs 4+ on mobile.
239
+ - The detail popup is structurally identical on both; only sizing
240
+ differs.
241
+
242
+ ## Performance
243
+ - No pagination. The SDK returns the full visible catalog in one
244
+ response.
245
+ - For very large catalogs (50+ items) consider client-side
246
+ virtualization. The default Smartico UI does NOT virtualize.
247
+ - The 30-second SDK cache makes intra-session re-renders free; do NOT
248
+ poll `getStoreItems()`.
249
+
250
+ **Cache TTL**: the SDK caches the response for 30 seconds. The cache is
251
+ invalidated and re-fetched automatically after every `buyStoreItem(...)`
252
+ call resolves for the current user. It is NOT invalidated by other
253
+ users' purchases, by operator BO edits, or by `active_till_date`
254
+ elapsing while the page is open.
255
+
256
+ **Visitor mode**: supported, with caveats.
257
+ - The catalog reflects the brand's proxy "visitor" user, not the actual
258
+ anonymous viewer. Per-user fields (`can_buy`, `pool` decrements,
259
+ `purchased_*` flags) reflect the proxy user's state and are not
260
+ meaningful for display.
261
+ - `onUpdate` is accepted but NEVER fires in visitor mode — there is no
262
+ live channel, so push events are not delivered.
263
+ - [buyStoreItem](../../api/classes/WSAPIStore.md#buystoreitem) is not supported in visitor mode; the Buy button
264
+ should deep-link to a login/registration flow instead.
@@ -0,0 +1,122 @@
1
+ # UI Guide — `getStorePurchasedItems`
2
+
3
+ ## Overview
4
+ Loading indicator recommended on cold fetch (no cache hit, typical
5
+ 100–500 ms latency). The default Smartico UI renders a full-screen spinner
6
+ while the first page is in flight, then a fade-in on the list. On load-
7
+ more pagination, the recommended pattern is to hide the "Load more"
8
+ button while the next page is fetching rather than showing a separate
9
+ spinner.
10
+
11
+ ## List view
12
+ - Flat newest-first list. The default Smartico UI does NOT group by date
13
+ (no "Today" / "This Week" / "Older" headers) and does NOT offer
14
+ category / type / status filter chips. If your design needs date
15
+ bucketing, use the SDK-provided `purchased_today` /
16
+ `purchased_this_week` / `purchased_this_month` booleans for grouping.
17
+ - Pagination UI: render a "Load more" button below the list when the
18
+ previous page returned exactly `limit` items. Hide it once a page
19
+ returns fewer than `limit` rows. The default Smartico UI uses an explicit
20
+ button; infinite scroll is a valid alternative but not the reference
21
+ pattern.
22
+ - Stagger animation: the default Smartico UI fades each row in with a
23
+ 100 ms incremental `animationDelay` (row 0 at 0 ms, row 1 at 100 ms,
24
+ etc.) for a cascade effect on the first page. Optional.
25
+
26
+ ## Item card (history row)
27
+ Two-column desktop / single-column-with-footer mobile layout. Rendered
28
+ fields, top-to-bottom:
29
+ 1. Item image (`image`) on the left, 1:1 aspect (256×256 source spec,
30
+ typically rendered ~64–96 px on screen via CSS).
31
+ 2. Stock indicator — only when `pool !== null`. `pool > 0` shows
32
+ "In stock — N left"; `pool === 0` shows "Out of stock".
33
+ (This reflects CURRENT stock for "Buy Again" context, not stock at
34
+ purchase time.)
35
+ 3. Item name (`name`) — HTML, sanitize to plain text or render with
36
+ `dangerouslySetInnerHTML` after trusted sanitization.
37
+ 4. Price stamp — `purchase_points_amount` paired with the currency
38
+ icon implied by `purchase_type`. This is the historical amount
39
+ paid, NOT the current item `price`.
40
+ 5. Purchase date — `purchase_ts` formatted via
41
+ `toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'medium' })`
42
+ and prefixed with a "Purchased:" label.
43
+ 6. **"Buy Again" button** — opens the standard buy modal for the
44
+ same item. Disabled when:
45
+ - `can_buy === false` (server says the user cannot purchase it
46
+ right now), OR
47
+ - the user's current balance is below the item's CURRENT
48
+ `price` (not `purchase_points_amount`), OR
49
+ - `pool === 0` (out of stock).
50
+ Layout: inline on desktop (right column), in a bottom footer strip
51
+ on mobile.
52
+
53
+ ## Fields explicitly NOT rendered on the row
54
+ - `description`, `ribbon`, `hint_text`, `custom_data`, `type`,
55
+ `related_games`, `category_ids`, `discounted_price`,
56
+ `discount_price_ribbon`, `custom_ribbon_image`, `active_till_date`,
57
+ `cant_buy_message` — the default Smartico UI omits these on the history
58
+ row.
59
+
60
+ ## Detail view
61
+ No tap-to-expand inline detail view exists for history rows. "Buy
62
+ Again" is the only action; it routes through the standard
63
+ [getStoreItems](../../api/classes/WSAPIStore.md#getstoreitems) buy modal (full description, related games, etc.
64
+ are surfaced there).
65
+
66
+ ## Status-specific treatments
67
+ - No fulfillment status field; rows have no delivered/pending/cancelled
68
+ visual variants.
69
+ - Stock-based modifier: when `pool === 0`, grey out / disable the "Buy
70
+ Again" button and show the "Out of stock" label in the info area.
71
+ This is a CURRENT availability signal, not a status on the past
72
+ purchase itself.
73
+
74
+ ## Image / asset specs
75
+ - `image`: documented source size **256×256 px**, 1:1 aspect ratio.
76
+ - Typically rendered via `<img>` (the default Smartico UI uses an `<img>`,
77
+ not CSS background-image, for history rows).
78
+ - No built-in fallback placeholder — provide one when `image` is empty.
79
+
80
+ ## Date formatting
81
+ - Format `purchase_ts` with `toLocaleString(undefined, ...)` to render
82
+ in the user's OS locale and timezone. Do NOT assume UTC display — the
83
+ stored timestamp is UTC milliseconds but humans read it locally.
84
+ - For relative formatting ("3 hours ago", "Yesterday"), use
85
+ `purchased_today` / `purchased_this_week` / `purchased_this_month`
86
+ as buckets or compute deltas client-side.
87
+
88
+ ## Empty state
89
+ When the first page returns an empty array, render a "No purchases yet"
90
+ empty state (icon + copy). Do NOT distinguish "no purchases at all"
91
+ from "no purchases in selected period" — this method has no period
92
+ filter, so any empty response means the user has zero history entries
93
+ total.
94
+
95
+ ## Error handling
96
+ On a network or server failure the Promise rejects. The SDK does not
97
+ surface an `err_code`/`err_message` shape on this method (the array
98
+ either resolves or the call throws). Wrap in `try { ... } catch` and
99
+ either retry with backoff or surface a generic "Couldn't load purchase
100
+ history" message — the default Smartico UI's behavior is to silently clear
101
+ the loading state, which leaves the previous list visible.
102
+
103
+ ## Mobile vs desktop
104
+ - Desktop: two-column row (image left, info+actions right). "Buy Again"
105
+ and purchase-date inline in the info column.
106
+ - Mobile: single-column with a bottom footer strip carrying the
107
+ purchase-date and the "Buy Again" button.
108
+ - No CSS-breakpoint magic in the default Smartico UI — the layout toggle
109
+ is a runtime `isMobile` boolean.
110
+
111
+ ## Performance
112
+ - 20 rows per page is small enough that virtualization is not needed
113
+ under typical history sizes.
114
+ - Cache (30 s) is fine for in-screen re-renders. Do not call this on
115
+ every render — fetch once on screen mount and on demand for "Load
116
+ more" / `onUpdate` triggers.
117
+ - Polling is unnecessary — the `onUpdate` callback delivers fresh data
118
+ automatically when the user makes another purchase. For background
119
+ activity (purchases made on other surfaces), the cache TTL gives
120
+ eventual consistency within 30 seconds of the next call.
121
+
122
+ **Visitor mode**: not supported.
@@ -0,0 +1,140 @@
1
+ # UI Guide — `getClanTournamentPlayers`
2
+
3
+ ## Overview
4
+ - Powers the clan drill-down modal opened from a clan row on the
5
+ tournament detail's clan leaderboard tab (see
6
+ [`getTournamentInstanceInfo`](../../api/classes/WSAPITournaments.md#gettournamentinstanceinfo)).
7
+ - One-shot fetch. No cache, no polling, no subscription. Re-call to
8
+ refresh.
9
+ - Returns up to ~20 players, server-sorted by score DESC. Client-side
10
+ re-sort is unnecessary.
11
+
12
+ ## Modal / drawer layout
13
+
14
+ Top-to-bottom layout (centered modal on desktop, full-screen
15
+ slide-up sheet on mobile):
16
+
17
+ 1. **Close affordance** — explicit close button (top-right);
18
+ click-outside dismiss; Escape key dismiss.
19
+ 2. **Clan header** — clan image (1:1 aspect ratio, fallback to
20
+ first-letter avatar with the clan's name), clan name, total
21
+ score, contributing-members count, and a rank badge (1/2/3) if
22
+ applicable.
23
+
24
+ The default Smartico UI populates this header from the **caller-side**
25
+ `ClanLeaderboardEntry` object (the row the user clicked) rather
26
+ than from the response's `clan_public_meta` and `clan_id` — they
27
+ contain the same identity but the parent context already has
28
+ richer data (total_score, contributing_members, position) that the
29
+ response doesn't carry. The response's `clan_id` and
30
+ `clan_public_meta.name`/`image_url` are still available for
31
+ consumers that need them.
32
+
33
+ 3. **Table header row** — three columns: `#` (rank) · Player
34
+ (avatar + name) · Score.
35
+ 4. **Player list** — one row per `players[i]`. See "Player row".
36
+ 5. **Empty state** (when `players.length === 0`) — "No leaders" text.
37
+ Shown both during the loading round-trip AND when the result is
38
+ empty.
39
+
40
+ ## Player row
41
+
42
+ Three columns:
43
+
44
+ | Column | Source | Notes |
45
+ |---|---|---|
46
+ | `#` (rank) | `position ?? 0` | Plain text. Server-side rank within this clan. |
47
+ | Player (avatar + name) | `avatar_url` (or derived from `avatar_id` + label `avatarDomain`) + `clean_ext_user_id ?? public_username` | Username prefers `clean_ext_user_id` over `public_username`; if both empty, the avatar fallback letter is also blank. |
48
+ | Score | `scores ?? 0` | Format with space-thousands ("1 234 567") + "pts" suffix. |
49
+
50
+ **"Me" row highlight**: when `is_me === true`, add a distinct
51
+ background (CSS class `is-me` in the default Smartico UI). There is no
52
+ sticky "me" footer in this modal — the user's row scrolls with the
53
+ list. If your UI has many players (rare — server caps at ~20), you may
54
+ want to auto-scroll the "me" row into view on first render.
55
+
56
+ **Avatar resolution**: if `avatar_url` is already populated by the SDK,
57
+ use it directly. Otherwise, derive a CDN URL from `avatar_id` and the
58
+ brand's avatar domain — the SDK's `CoreUtils.avatarUrl()` does this for
59
+ you on the response.
60
+
61
+ **Top-3 styling**: optional — apply podium accent (gold/silver/bronze)
62
+ to rows where `position <= 3`. The default Smartico UI applies the
63
+ podium treatment only on the clan header rank badge, not on individual
64
+ player rows.
65
+
66
+ ## Empty / loading / error states
67
+
68
+ - **Loading**: render the modal frame and clan header immediately
69
+ (driven by caller-side data); render an "empty state" placeholder
70
+ in the player list area while the call is in flight. **Or** render a
71
+ skeleton rows (3–5 grey bars) — typically friendlier than the
72
+ empty-state text appearing then disappearing.
73
+ - **Empty (no players)**: render the "No leaders" text. This can mean:
74
+ - no one in the clan has scored yet,
75
+ - the call failed (network / server error — the default UI silently
76
+ swallows the error),
77
+ - the `(tournamentInstanceId, clanId)` combination is invalid.
78
+
79
+ These three are not distinguishable in the response itself. The
80
+ default UI treats them identically. If your UI cares to distinguish,
81
+ attach a `.catch()` to surface a transient-error toast.
82
+ - **Error**: not surfaced by default. Add explicit error handling if
83
+ needed — wrap the call in try/catch and show a "Failed to load — Try
84
+ again" affordance.
85
+
86
+ ## Close affordance
87
+
88
+ Three independent dismiss mechanisms (all dispatch the same close
89
+ action):
90
+
91
+ 1. Close button (top-right of modal).
92
+ 2. Click outside the modal card.
93
+ 3. `Escape` key.
94
+
95
+ The default Smartico UI wires all three via a shared `useModalClose`
96
+ hook. Mirror this pattern for parity.
97
+
98
+ ## Refresh
99
+
100
+ - **Don't poll inside this modal**. The default Smartico UI doesn't
101
+ poll — the clan-leaderboard tab (parent) does poll via
102
+ `getTournamentInstanceInfo` and refreshes the visible clan rankings
103
+ when the modal closes. Live updates inside the modal are not part
104
+ of the default UX.
105
+ - If your product requires live updates inside this modal, call
106
+ `getClanTournamentPlayers` again on a 3 s interval. Be cautious —
107
+ each call is a fresh network round-trip (no cache).
108
+
109
+ ## Pagination
110
+
111
+ None at the SDK level. The server returns up to ~20 players (configured
112
+ per tournament). There is no "load more" affordance in the default UI.
113
+
114
+ ## Animations / transitions
115
+
116
+ - **Modal entry**: fade-in + scale (~150 ms ease-out).
117
+ - **Modal exit**: fade-out + scale-down (~120 ms).
118
+ - **List entry**: cards/rows fade-in staggered ~20 ms per row on
119
+ first render. No skeleton-to-data crossfade (the list is small
120
+ enough to render instantly once data arrives).
121
+ - **Rank change between calls** (if you implement live polling): FLIP
122
+ animation to reorder rows.
123
+
124
+ ## Mobile vs desktop
125
+
126
+ - **Modal style**: centered overlay on desktop with backdrop dim;
127
+ full-screen slide-up sheet on mobile (with a swipe-down dismiss
128
+ gesture).
129
+ - **Header layout**: image left, identity right on desktop; stacked
130
+ (image above identity) on mobile.
131
+ - **Row density**: identical on both — the row is already compact.
132
+
133
+ ## Performance
134
+
135
+ - Each call is a fresh network round-trip. The page typically has at
136
+ most one of these in flight at a time (driven by user clicks),
137
+ so cost is minimal.
138
+ - If your UI offers a "view all clans" affordance that pre-fetches
139
+ player lists for many clans, throttle the fetches — don't fan out
140
+ 20 simultaneous round-trips.