@smartico/public-api 0.0.378 → 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
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# UI Guide — `getLevels`
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
- Returns the full level ladder for the label — one `TLevel` per
|
|
5
|
+
active level, server-sorted by `required_points` ASC.
|
|
6
|
+
- Use as a lookup table to resolve `ach_level_current_id` from
|
|
7
|
+
[`getUserProfile`](../../api/classes/WSAPIUser.md#getuserprofile)
|
|
8
|
+
into a richer level object, or as the source for a level map UI.
|
|
9
|
+
- Loading indicator: skip on cache hit (30 s); show a brief shimmer
|
|
10
|
+
on cold fetch (typically 100–300 ms).
|
|
11
|
+
|
|
12
|
+
## List view organization
|
|
13
|
+
|
|
14
|
+
The default Smartico UI renders levels as a **vertical grid** —
|
|
15
|
+
2-column on mobile (`grid-boxes-2 levels`), responsive on desktop
|
|
16
|
+
(`grid-boxes-levels`). No horizontal-scroll layout, no tabs.
|
|
17
|
+
|
|
18
|
+
Items are already sorted by `required_points` ASC; `ordinal_position`
|
|
19
|
+
is a 1-based index matching that sort. Render in the returned array
|
|
20
|
+
order — no client-side sort needed unless your label uses
|
|
21
|
+
sliding-window leveling (then sort secondary on
|
|
22
|
+
`required_level_counter_1`, then `required_level_counter_2`).
|
|
23
|
+
|
|
24
|
+
## Client-side filtering by `visibility_points`
|
|
25
|
+
|
|
26
|
+
The server returns ALL active levels; the default Smartico UI hides
|
|
27
|
+
levels the user hasn't reached the visibility threshold for:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const visible = levels.filter(l =>
|
|
31
|
+
l.visibility_points == null || l.visibility_points <= profile.ach_points_ever
|
|
32
|
+
);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Hidden levels are absent from the render entirely — no "?" tile, no
|
|
36
|
+
silhouette. If your product surface wants a teaser for upcoming
|
|
37
|
+
levels, render the hidden ones with a custom CSS treatment instead
|
|
38
|
+
of filtering them out.
|
|
39
|
+
|
|
40
|
+
## Level tile
|
|
41
|
+
|
|
42
|
+
Fields rendered per tile:
|
|
43
|
+
|
|
44
|
+
| Field | Use |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `image` | Tile icon (square, 256×256 px source). |
|
|
47
|
+
| `name` | Tile heading. |
|
|
48
|
+
| `description` | Optional sub-text under the heading; the default UI shows this in the detail modal, not on the tile. |
|
|
49
|
+
| `required_points` | Threshold display: `"{N} pts to reach"` or progress bar. |
|
|
50
|
+
| `ordinal_position` | Tile order; matches array order. |
|
|
51
|
+
|
|
52
|
+
**Locked vs unlocked treatment** — apply a `disabled` class to tiles
|
|
53
|
+
where the user hasn't met the threshold:
|
|
54
|
+
|
|
55
|
+
- Points-only leveling (most labels): `disabled = ach_points_ever < required_points`
|
|
56
|
+
- Sliding-window leveling: also check
|
|
57
|
+
`level_counter_1 < required_level_counter_1` (and `_2`) from
|
|
58
|
+
[`getUserLevelExtraCounters`](../../api/classes/WSAPIUser.md#getuserlevelextracounters).
|
|
59
|
+
- Manual-only leveling: `disabled` unless the level matches the
|
|
60
|
+
user's current `ach_level_current_id`.
|
|
61
|
+
|
|
62
|
+
The default Smartico UI uses CSS-only treatment for locked tiles —
|
|
63
|
+
no padlock icon, no greyscale by default. Brands can add those via
|
|
64
|
+
custom CSS / Liquid skin overrides.
|
|
65
|
+
|
|
66
|
+
## Detail view (per-level modal)
|
|
67
|
+
|
|
68
|
+
When the user taps a tile, open a modal showing:
|
|
69
|
+
|
|
70
|
+
- Hero image (`image`)
|
|
71
|
+
- Title (`name`), description (`description`)
|
|
72
|
+
- Progress block: for the user's current level, three stacked
|
|
73
|
+
progress bars (points / counter 1 / counter 2) — see "Sliding-window
|
|
74
|
+
leveling" below. For other levels, just the requirement display.
|
|
75
|
+
- Custom fields rendered from `custom_data` (operator-defined).
|
|
76
|
+
|
|
77
|
+
`custom_data` is typed as `string` but at runtime is `any` — the SDK
|
|
78
|
+
auto-parses JSON-looking strings. Always guard with
|
|
79
|
+
`typeof custom_data === 'object'` before property access; treat
|
|
80
|
+
non-object values as raw strings.
|
|
81
|
+
|
|
82
|
+
## Sliding-window leveling (advanced)
|
|
83
|
+
|
|
84
|
+
If your label uses sliding-window leveling (the "Logic 2" model), the
|
|
85
|
+
`required_level_counter_1` and `required_level_counter_2` fields are
|
|
86
|
+
populated. Render alongside the points threshold:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Points: {ach_points_ever} / {required_points}
|
|
90
|
+
Counter 1: {level_counter_1} / {required_level_counter_1} ← from getUserLevelExtraCounters
|
|
91
|
+
Counter 2: {level_counter_2} / {required_level_counter_2}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The operator names the counters via translation keys
|
|
95
|
+
(`levelsCounter1Name`, `levelsCounter2Name`) — typical values are
|
|
96
|
+
"Total Deposits", "Total Wagering", etc. The SDK does not expose the
|
|
97
|
+
operator's chosen labels; resolve them via
|
|
98
|
+
[`getTranslations`](../../api/classes/WSAPIGeneral.md#gettranslations).
|
|
99
|
+
|
|
100
|
+
On points-only labels, both `required_level_counter_*` fields are
|
|
101
|
+
`null` — skip rendering the counter rows.
|
|
102
|
+
|
|
103
|
+
## Progress to next level
|
|
104
|
+
|
|
105
|
+
Two formulas are in use; pick whichever fits your design:
|
|
106
|
+
|
|
107
|
+
- **From-zero (default Smartico UI uses this)**:
|
|
108
|
+
`ach_points_ever / next_level.required_points × 100`. Shows
|
|
109
|
+
"absolute" progress; never decreases as the user gains points.
|
|
110
|
+
- **From-current-level-floor (SDK uses this in
|
|
111
|
+
[`getCurrentLevel`](../../api/classes/WSAPIUser.md#getcurrentlevel))**:
|
|
112
|
+
`(ach_points_ever − current.required_points) / (next.required_points
|
|
113
|
+
− current.required_points) × 100`. Resets to 0 when the user levels
|
|
114
|
+
up; better for "how far through this level" UX.
|
|
115
|
+
|
|
116
|
+
Both bound at 100; at the max level the bar shows full.
|
|
117
|
+
|
|
118
|
+
## Image / asset specs
|
|
119
|
+
|
|
120
|
+
| Field | Aspect | Notes |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `image` | 1:1 (square), 256×256 px documented source | Render in a square tile container; fallback: text-only tile with the level name if `image` is missing. |
|
|
123
|
+
|
|
124
|
+
## Empty / loading / error states
|
|
125
|
+
|
|
126
|
+
- **Loading (cold fetch)**: render a skeleton grid (3–6 placeholder
|
|
127
|
+
tiles) sized to the eventual layout.
|
|
128
|
+
- **Loading (cache hit)**: do not render a loading state — the
|
|
129
|
+
promise resolves within a microtask.
|
|
130
|
+
- **Empty result**: `[]` means no levels are configured for the
|
|
131
|
+
label. Hide the level UI entirely (or render a neutral
|
|
132
|
+
"no levels configured" placeholder).
|
|
133
|
+
- **Error**: keep the prior list visible if any; show a small
|
|
134
|
+
non-blocking error banner; retry on next user-driven action.
|
|
135
|
+
|
|
136
|
+
## Animations / transitions
|
|
137
|
+
|
|
138
|
+
- **Tile entry**: stagger fade-in (~30 ms per tile) on first render.
|
|
139
|
+
- **Level-up celebration**: when `ach_level_current_id` flips on a
|
|
140
|
+
push (detect via [`getUserProfile`](../../api/classes/WSAPIUser.md#getuserprofile)'s
|
|
141
|
+
`props_change`), animate the newly-reached tile (scale-up,
|
|
142
|
+
shine sweep). The default Smartico UI does this on the header
|
|
143
|
+
badge, not on the level-map tiles.
|
|
144
|
+
|
|
145
|
+
## Mobile vs desktop
|
|
146
|
+
|
|
147
|
+
- **Grid columns**: desktop responsive (3–5 columns depending on
|
|
148
|
+
viewport); mobile 2 columns.
|
|
149
|
+
- **Detail view**: desktop opens as a centered modal with backdrop
|
|
150
|
+
dim; mobile opens as a full-screen sheet.
|
|
151
|
+
- **Counter rows in detail**: identical on both — three stacked
|
|
152
|
+
progress bars on Logic 2 labels.
|
|
153
|
+
|
|
154
|
+
## Performance
|
|
155
|
+
|
|
156
|
+
- The 30 s cache deduplicates rapid refetches; a poll loop hitting
|
|
157
|
+
`getLevels()` every 5 s effectively translates to one network
|
|
158
|
+
round-trip per 30 s.
|
|
159
|
+
- `getLevels` is suitable to call once at app boot and cache the
|
|
160
|
+
array in your own state (re-fetch only when the user's level
|
|
161
|
+
changes per `props_change`, since the operator-driven ladder
|
|
162
|
+
rarely changes mid-session).
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# UI Guide — `getUserProfile`
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
- The synchronous source of truth for the current user's public
|
|
5
|
+
properties — balances, level, username, avatar, tags, language,
|
|
6
|
+
inbox count.
|
|
7
|
+
- The SDK keeps a local snapshot updated by a server push channel.
|
|
8
|
+
Every call returns the latest cached values; no network round-trip.
|
|
9
|
+
- Drive long-lived widgets (header user-bar, balance display, inbox
|
|
10
|
+
badge, level badge) by **subscribing to `props_change` events** and
|
|
11
|
+
re-reading via `getUserProfile()` on each fire. Don't poll.
|
|
12
|
+
|
|
13
|
+
## Subscription pattern
|
|
14
|
+
|
|
15
|
+
The default Smartico UI registers a single `props_change` listener
|
|
16
|
+
at boot and re-renders the affected widgets from the current
|
|
17
|
+
`getUserProfile()` snapshot. The callback's argument carries only
|
|
18
|
+
the changed keys, so you can branch on which subset of widgets to
|
|
19
|
+
update:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
window._smartico.on('props_change', (changed) => {
|
|
23
|
+
const profile = window._smartico.api.getUserProfile();
|
|
24
|
+
|
|
25
|
+
if ('ach_points_balance' in changed
|
|
26
|
+
|| 'ach_gems_balance' in changed
|
|
27
|
+
|| 'ach_diamonds_balance' in changed) {
|
|
28
|
+
console.log('[smartico] balance changed — re-render the currency strip:',
|
|
29
|
+
profile.ach_points_balance, profile.ach_gems_balance, profile.ach_diamonds_balance);
|
|
30
|
+
}
|
|
31
|
+
if ('ach_level_current_id' in changed) {
|
|
32
|
+
console.log('[smartico] level changed — call getCurrentLevel() and animate the badge');
|
|
33
|
+
}
|
|
34
|
+
if ('core_inbox_unread_count' in changed) {
|
|
35
|
+
console.log('[smartico] inbox count changed — update the inbox badge to:',
|
|
36
|
+
profile.core_inbox_unread_count);
|
|
37
|
+
}
|
|
38
|
+
if ('core_public_tags' in changed) {
|
|
39
|
+
console.log('[smartico] tags changed — re-evaluate any tag-gated UI:',
|
|
40
|
+
profile.core_public_tags);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For one-time reads (e.g. inside a click handler), call
|
|
46
|
+
`getUserProfile()` directly — no subscription needed.
|
|
47
|
+
|
|
48
|
+
## Balance widget
|
|
49
|
+
|
|
50
|
+
The default Smartico UI renders a horizontal strip of currency
|
|
51
|
+
counters in the header / menu bar. Render rules:
|
|
52
|
+
|
|
53
|
+
| Field | Rendered | Format |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `ach_points_balance` | Always | Locale-aware integer (e.g. `"1,234"`); show even when zero. |
|
|
56
|
+
| `ach_gems_balance` | Only if the operator has enabled gems for this label | Same locale format. |
|
|
57
|
+
| `ach_diamonds_balance` | Only if the operator has enabled diamonds for this label | Same locale format. |
|
|
58
|
+
|
|
59
|
+
Gems and diamonds are conditionally rendered per label
|
|
60
|
+
configuration — not just based on whether the value is non-zero. For
|
|
61
|
+
labels that don't use these currencies, hide the counters entirely
|
|
62
|
+
rather than showing `0`. (The SDK doesn't expose label settings; ask
|
|
63
|
+
the operator or detect by other context.)
|
|
64
|
+
|
|
65
|
+
Pair the counter with an icon for each currency (points icon, gem
|
|
66
|
+
icon, diamond icon). Use brand assets — none ship with the SDK.
|
|
67
|
+
|
|
68
|
+
## Affordability checks
|
|
69
|
+
|
|
70
|
+
`getUserProfile()` is the source for paid-mutation gating across
|
|
71
|
+
the SDK. Same pattern for each domain:
|
|
72
|
+
|
|
73
|
+
| Method | Read balance for | Compare against |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| [`buyStoreItem`](../../api/classes/WSAPIStore.md#buystoreitem) | `item.purchase_type` (`'points'` / `'gems'` / `'diamonds'`) | `item.discounted_price ?? item.price` |
|
|
76
|
+
| [`joinClan`](../../api/classes/WSAPIClans.md#joinclan) | `clan.entry_fee_currency_type_id` (`0`/`1`/`2`/`3`) | `clan.entry_fee_amount` |
|
|
77
|
+
| [`registerInTournament`](../../api/classes/WSAPITournaments.md#registerintournament) | Whichever of `registration_cost_points` / `_gems` / `_diamonds` is set | The same field |
|
|
78
|
+
|
|
79
|
+
Disable the CTA when the user's balance is below the cost; show the
|
|
80
|
+
deficit in the disabled state's text.
|
|
81
|
+
|
|
82
|
+
## Level badge
|
|
83
|
+
|
|
84
|
+
Render the level badge using `ach_level_current_id` as a lookup key
|
|
85
|
+
into the level ladder fetched separately:
|
|
86
|
+
|
|
87
|
+
1. Call [`getLevels`](../../api/classes/WSAPIUser.md#getlevels) once
|
|
88
|
+
at app boot to cache the full ladder.
|
|
89
|
+
2. On `ach_level_current_id` change (via `props_change`), look up the
|
|
90
|
+
level by ID and render its `name` + `image`.
|
|
91
|
+
3. For the richer "progress to next level" UI, call
|
|
92
|
+
[`getCurrentLevel`](../../api/classes/WSAPIUser.md#getcurrentlevel)
|
|
93
|
+
— it adds a computed `progress` percentage.
|
|
94
|
+
|
|
95
|
+
`ach_level_current_id` may briefly be `0` (or undefined) for new
|
|
96
|
+
users with no points yet. Handle that as "no level" — render a
|
|
97
|
+
default badge (e.g. "Newcomer" or hide the badge).
|
|
98
|
+
|
|
99
|
+
## Avatar widget
|
|
100
|
+
|
|
101
|
+
`avatar_url` is a CDN URL resolved by the SDK from the server's
|
|
102
|
+
`avatar_id` field. To render:
|
|
103
|
+
|
|
104
|
+
- Place inside a square container (1:1 aspect ratio).
|
|
105
|
+
- The default Smartico UI proxies the URL through a CDN resizer
|
|
106
|
+
(`resize/128/128/webp/...`) for size-appropriate fetches and
|
|
107
|
+
WebP-where-supported. Brands that don't use that resizer can
|
|
108
|
+
load `avatar_url` directly.
|
|
109
|
+
- **No built-in placeholder**: when `avatar_url` is missing, the
|
|
110
|
+
default Smartico UI renders an empty container (no fallback
|
|
111
|
+
image). Provide your own placeholder asset / initial-letter
|
|
112
|
+
fallback if the empty state matters.
|
|
113
|
+
|
|
114
|
+
## Username widget
|
|
115
|
+
|
|
116
|
+
`public_username` is the user's display name. Fallback chain:
|
|
117
|
+
|
|
118
|
+
- `public_username` if set
|
|
119
|
+
- `'...'` (three dots) or a localized "Anonymous" string if not set
|
|
120
|
+
|
|
121
|
+
The default Smartico UI uses `'...'`. There's no automatic fallback
|
|
122
|
+
to `user_ext_id` — that field is internal and should never be
|
|
123
|
+
displayed.
|
|
124
|
+
|
|
125
|
+
## Inbox badge
|
|
126
|
+
|
|
127
|
+
`core_inbox_unread_count` is the authoritative source for inbox
|
|
128
|
+
unread badge rendering — it's push-updated in real time (under 1
|
|
129
|
+
second), unlike
|
|
130
|
+
[`getInboxUnreadCount()`](../../api/classes/WSAPIInbox.md#getinboxunreadcount)
|
|
131
|
+
which caches for 30 s.
|
|
132
|
+
|
|
133
|
+
Render rules:
|
|
134
|
+
|
|
135
|
+
- `0` (or undefined) → badge hidden entirely
|
|
136
|
+
- `1`–`N` → render the raw integer (e.g. `"5"`, `"42"`)
|
|
137
|
+
- No truncation to `"99+"` in the default Smartico UI; brands that
|
|
138
|
+
want a cap should apply it themselves.
|
|
139
|
+
|
|
140
|
+
## Public tags
|
|
141
|
+
|
|
142
|
+
`core_public_tags` is an array of operator-defined uppercase strings
|
|
143
|
+
(e.g. `['VIP', 'NEWSLETTER_OPT_IN']`). Use them to gate UI
|
|
144
|
+
visibility — show a "VIP rewards" link only when `'VIP'` is in the
|
|
145
|
+
array.
|
|
146
|
+
|
|
147
|
+
To modify tags, use `_smartico.updatePublicTags(operation, tags)` —
|
|
148
|
+
the change round-trips through the server and arrives back as a
|
|
149
|
+
`props_change` push (usually within ~1 second).
|
|
150
|
+
|
|
151
|
+
## Language
|
|
152
|
+
|
|
153
|
+
`core_user_language` is the server-stored language code (e.g.
|
|
154
|
+
`"en"`, `"de"`). The SDK uses this for:
|
|
155
|
+
|
|
156
|
+
- Pre-translated content fields on missions, bonuses, clans, etc.
|
|
157
|
+
- The `lang_code` parameter that
|
|
158
|
+
[`getTranslations`](../../api/classes/WSAPIGeneral.md#gettranslations)
|
|
159
|
+
is typically called with.
|
|
160
|
+
|
|
161
|
+
When the user just changed language client-side, this field may
|
|
162
|
+
briefly lag the local intent until the server push arrives. If your
|
|
163
|
+
UI needs instant accuracy (e.g. switching the in-page language
|
|
164
|
+
without a refresh), use `_smartico.getPublicProps()` which applies
|
|
165
|
+
the client-side fallback.
|
|
166
|
+
|
|
167
|
+
## AI-recommended amounts
|
|
168
|
+
|
|
169
|
+
`core_recommended_deposit_amount` and
|
|
170
|
+
`core_recommended_casino_bet_amount` are AI-computed for the user.
|
|
171
|
+
The default Smartico UI doesn't render them — they're exposed for
|
|
172
|
+
custom integrations (e.g. operator-specific deposit prompts,
|
|
173
|
+
personalized bet suggestions).
|
|
174
|
+
|
|
175
|
+
Guard against `undefined` — these are absent for users with no
|
|
176
|
+
current recommendation.
|
|
177
|
+
|
|
178
|
+
## Empty / loading / error states
|
|
179
|
+
|
|
180
|
+
- **Pre-identify**: `getUserProfile()` throws
|
|
181
|
+
`"Tracker is not initialized, cannot getUserProfile"`. Render
|
|
182
|
+
widgets as skeleton/placeholder until the `identify` event fires
|
|
183
|
+
(or until the first `props_change` callback).
|
|
184
|
+
- **Visitor mode**: not supported; will throw. Render a "Log in to
|
|
185
|
+
see your profile" CTA instead of a balance widget for anonymous
|
|
186
|
+
sessions.
|
|
187
|
+
- **Stale data**: real-time push usually keeps the snapshot under 1
|
|
188
|
+
second behind server state. There's no explicit "stale" state —
|
|
189
|
+
trust the snapshot.
|
|
190
|
+
|
|
191
|
+
## Animations / transitions
|
|
192
|
+
|
|
193
|
+
- **Balance changes**: when `ach_points_balance` / `_gems` /
|
|
194
|
+
`_diamonds` change, animate the count-up/down between the prior
|
|
195
|
+
and new value (200–600 ms). Detect by diffing the prior snapshot
|
|
196
|
+
inside `props_change`.
|
|
197
|
+
- **Level-up**: when `ach_level_current_id` increases, play a
|
|
198
|
+
celebration animation on the badge (sparkle, scale-up, color
|
|
199
|
+
flash). Detect by diffing the prior `ach_level_current_id`.
|
|
200
|
+
- **Inbox badge appearing**: when `core_inbox_unread_count` flips
|
|
201
|
+
from `0` to `>0`, animate the badge fade-in.
|
|
202
|
+
|
|
203
|
+
## Performance
|
|
204
|
+
|
|
205
|
+
- `getUserProfile()` is effectively free (synchronous, in-memory
|
|
206
|
+
copy). Call it as often as you need.
|
|
207
|
+
- Avoid re-rendering every widget on every `props_change` push —
|
|
208
|
+
branch on the changed keys and re-render only the affected
|
|
209
|
+
surfaces.
|
|
210
|
+
- `getUserProfile()` returns a shallow copy on each call; for
|
|
211
|
+
performance-critical paths (e.g. animations), prefer memoizing
|
|
212
|
+
the result inside `props_change` rather than calling on every
|
|
213
|
+
frame.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartico/public-api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.380",
|
|
4
4
|
"description": "Smartico public API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"bump-ach": "cd ../tracker/ach && npm install @smartico/public-api@latest --legacy-peer-deps",
|
|
25
25
|
"bump-bo-server": "cd ../bo_server/server && source ~/.nvm/nvm.sh && nvm use v13.13.0 && npm install @smartico/public-api@latest",
|
|
26
26
|
"bump-bo-client": "cd ../bo_server/client && source ~/.nvm/nvm.sh && nvm use v13.13.0 && npm install @smartico/public-api@latest",
|
|
27
|
-
"doc": "typedoc"
|
|
27
|
+
"doc": "typedoc && node scripts/postdoc-cleanup.js"
|
|
28
28
|
},
|
|
29
29
|
"author": "",
|
|
30
30
|
"license": "ISC",
|
|
@@ -40,6 +40,6 @@
|
|
|
40
40
|
"typedoc-plugin-markdown": "^4.11.0",
|
|
41
41
|
"typedoc-plugin-merge-modules": "^7.0.0",
|
|
42
42
|
"typescript": "~5.1.0",
|
|
43
|
-
"@types/node": "^
|
|
43
|
+
"@types/node": "^22.9.0"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Post-process step after `typedoc` runs.
|
|
4
|
+
*
|
|
5
|
+
* Fixes three cosmetic issues typedoc / typedoc-plugin-markdown produce
|
|
6
|
+
* that have no config flag to disable:
|
|
7
|
+
*
|
|
8
|
+
* 1. **"Extends" / "Extended by" blocks** on every class doc are pure
|
|
9
|
+
* inheritance-chain plumbing that consumers don't need to see. We
|
|
10
|
+
* strip them.
|
|
11
|
+
*
|
|
12
|
+
* 2. **Inherited methods duplicated on every subclass doc.** Each class
|
|
13
|
+
* .md re-lists every method from every ancestor in the inheritance
|
|
14
|
+
* chain (e.g. `WSAPIInbox.md` ends up with all 65+ methods even
|
|
15
|
+
* though only ~8 are its own). We detect inherited methods via the
|
|
16
|
+
* `#### Inherited from` marker typedoc emits, strip those method
|
|
17
|
+
* blocks, and leave each class doc focused on the methods that
|
|
18
|
+
* class actually declares.
|
|
19
|
+
*
|
|
20
|
+
* 3. **`docs/api/_media/` duplication** of UI guides. The TSDoc UI link
|
|
21
|
+
* uses a relative path `[label](../../docs/ui/<domain>/UIGuide_X.md)`
|
|
22
|
+
* which typedoc treats as a local "media" reference — it copies the
|
|
23
|
+
* file into `docs/api/_media/` and rewrites the link to point there.
|
|
24
|
+
* We delete `_media/` and rewrite the links back to the original
|
|
25
|
+
* `docs/ui/<domain>/UIGuide_X.md` so there's a single source of
|
|
26
|
+
* truth (in `docs/ui/`).
|
|
27
|
+
*
|
|
28
|
+
* Run via `npm run doc` (chained after typedoc) — see `package.json`.
|
|
29
|
+
*/
|
|
30
|
+
const fs = require('fs');
|
|
31
|
+
const path = require('path');
|
|
32
|
+
|
|
33
|
+
const DOCS_API = path.join(__dirname, '..', 'docs', 'api');
|
|
34
|
+
const DOCS_API_CLASSES = path.join(DOCS_API, 'classes');
|
|
35
|
+
const DOCS_API_MEDIA = path.join(DOCS_API, '_media');
|
|
36
|
+
|
|
37
|
+
let mdFilesProcessed = 0;
|
|
38
|
+
let mediaLinksRewritten = 0;
|
|
39
|
+
let extendsBlocksRemoved = 0;
|
|
40
|
+
let inheritedMethodsStripped = 0;
|
|
41
|
+
|
|
42
|
+
/** Recursively list all `.md` files under a directory. */
|
|
43
|
+
function walkMd(dir) {
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
46
|
+
const p = path.join(dir, entry.name);
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
out.push(...walkMd(p));
|
|
49
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
50
|
+
out.push(p);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Strip `## Extends\n\n- [Foo](...)` and `## Extended by\n\n- [...]` sections.
|
|
58
|
+
* The block ends at the next `## ` heading (or end of file).
|
|
59
|
+
*/
|
|
60
|
+
function stripExtendsBlocks(text) {
|
|
61
|
+
const lines = text.split('\n');
|
|
62
|
+
const out = [];
|
|
63
|
+
let i = 0;
|
|
64
|
+
let removed = 0;
|
|
65
|
+
while (i < lines.length) {
|
|
66
|
+
const ln = lines[i];
|
|
67
|
+
if (ln === '## Extends' || ln === '## Extended by') {
|
|
68
|
+
// Skip until the next `## ` heading or EOF
|
|
69
|
+
let j = i + 1;
|
|
70
|
+
while (j < lines.length && !lines[j].startsWith('## ')) {
|
|
71
|
+
j++;
|
|
72
|
+
}
|
|
73
|
+
// Also drop one trailing blank line if present right before the
|
|
74
|
+
// `## Extends` line to avoid leaving a double-blank gap.
|
|
75
|
+
while (out.length > 0 && out[out.length - 1] === '') {
|
|
76
|
+
out.pop();
|
|
77
|
+
}
|
|
78
|
+
i = j;
|
|
79
|
+
removed++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
out.push(ln);
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
return { text: out.join('\n'), removed };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Rewrite `(../_media/UIGuide_X.md)` → `(../../docs/ui/<domain>/UIGuide_X.md)`.
|
|
90
|
+
* Domain is inferred from the filename prefix when possible; otherwise we
|
|
91
|
+
* map known UI guides to their domain.
|
|
92
|
+
*/
|
|
93
|
+
const UI_GUIDE_DOMAIN = {
|
|
94
|
+
UIGuide_getMissions: 'missions',
|
|
95
|
+
UIGuide_getBadges: 'missions',
|
|
96
|
+
UIGuide_getAchCategories: 'missions',
|
|
97
|
+
UIGuide_requestMissionOptIn: 'missions',
|
|
98
|
+
UIGuide_requestMissionClaimReward: 'missions',
|
|
99
|
+
UIGuide_getStoreItems: 'store',
|
|
100
|
+
UIGuide_buyStoreItem: 'store',
|
|
101
|
+
UIGuide_getStoreCategories: 'store',
|
|
102
|
+
UIGuide_getStorePurchasedItems: 'store',
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
function rewriteMediaLinks(text) {
|
|
106
|
+
let count = 0;
|
|
107
|
+
// Pattern: `(../_media/<filename>.md)` (when generated inside docs/api/classes/).
|
|
108
|
+
// Rewrite to `(../../ui/<domain>/<filename>.md)` — correct relative from
|
|
109
|
+
// `docs/api/classes/` to `docs/ui/<domain>/`. Going through `docs/` once is
|
|
110
|
+
// enough; an extra `docs/` in the path would resolve to `docs/docs/ui/...`.
|
|
111
|
+
const out = text.replace(/\(\.\.\/_media\/([A-Za-z0-9_]+)\.md\)/g, (m, name) => {
|
|
112
|
+
const domain = UI_GUIDE_DOMAIN[name];
|
|
113
|
+
if (!domain) return m; // unknown media file — leave it
|
|
114
|
+
count++;
|
|
115
|
+
return `(../../ui/${domain}/${name}.md)`;
|
|
116
|
+
});
|
|
117
|
+
return { text: out, count };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Strip inherited method blocks. A method block:
|
|
122
|
+
* - Starts at `### methodName()`
|
|
123
|
+
* - Ends just before the next `### ` (next method) or `## ` (next major
|
|
124
|
+
* section), whichever comes first
|
|
125
|
+
* A method is "inherited" if its block contains `#### Inherited from`.
|
|
126
|
+
*
|
|
127
|
+
* After stripping, the file's `## Methods` section may be empty — that's
|
|
128
|
+
* OK: it means the class has no own methods (which shouldn't happen for
|
|
129
|
+
* the domain classes, but is graceful for edge cases).
|
|
130
|
+
*/
|
|
131
|
+
function stripInheritedMethods(text) {
|
|
132
|
+
const lines = text.split('\n');
|
|
133
|
+
const out = [];
|
|
134
|
+
let i = 0;
|
|
135
|
+
let removed = 0;
|
|
136
|
+
while (i < lines.length) {
|
|
137
|
+
const ln = lines[i];
|
|
138
|
+
// Detect method-block start
|
|
139
|
+
if (ln.startsWith('### ')) {
|
|
140
|
+
// Find block end
|
|
141
|
+
let j = i + 1;
|
|
142
|
+
while (
|
|
143
|
+
j < lines.length &&
|
|
144
|
+
!lines[j].startsWith('### ') &&
|
|
145
|
+
!lines[j].startsWith('## ')
|
|
146
|
+
) {
|
|
147
|
+
j++;
|
|
148
|
+
}
|
|
149
|
+
const block = lines.slice(i, j);
|
|
150
|
+
const isInherited = block.some((l) => l === '#### Inherited from');
|
|
151
|
+
if (isInherited) {
|
|
152
|
+
removed++;
|
|
153
|
+
i = j;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
// Keep the block
|
|
157
|
+
out.push(...block);
|
|
158
|
+
i = j;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
out.push(ln);
|
|
162
|
+
i++;
|
|
163
|
+
}
|
|
164
|
+
return { text: out.join('\n'), removed };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 1. Process every class .md
|
|
168
|
+
if (fs.existsSync(DOCS_API_CLASSES)) {
|
|
169
|
+
for (const file of walkMd(DOCS_API_CLASSES)) {
|
|
170
|
+
const orig = fs.readFileSync(file, 'utf8');
|
|
171
|
+
const a = stripExtendsBlocks(orig);
|
|
172
|
+
const b = stripInheritedMethods(a.text);
|
|
173
|
+
const c = rewriteMediaLinks(b.text);
|
|
174
|
+
if (c.text !== orig) {
|
|
175
|
+
fs.writeFileSync(file, c.text);
|
|
176
|
+
mdFilesProcessed++;
|
|
177
|
+
extendsBlocksRemoved += a.removed;
|
|
178
|
+
inheritedMethodsStripped += b.removed;
|
|
179
|
+
mediaLinksRewritten += c.count;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 2. Delete _media/ (UI guides now linked from docs/ui/; any non-UI media
|
|
185
|
+
// like images would also be wiped — none expected in this project)
|
|
186
|
+
if (fs.existsSync(DOCS_API_MEDIA)) {
|
|
187
|
+
const count = fs.readdirSync(DOCS_API_MEDIA).length;
|
|
188
|
+
fs.rmSync(DOCS_API_MEDIA, { recursive: true, force: true });
|
|
189
|
+
console.log(`Removed docs/api/_media/ (${count} duplicate file(s))`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log(`Processed ${mdFilesProcessed} .md files`);
|
|
193
|
+
console.log(`Removed ${extendsBlocksRemoved} Extends/Extended-by block(s)`);
|
|
194
|
+
console.log(`Stripped ${inheritedMethodsStripped} inherited-method block(s)`);
|
|
195
|
+
console.log(`Rewrote ${mediaLinksRewritten} _media link(s) → docs/ui/`);
|
|
@@ -5,9 +5,12 @@ import { UserAchievement } from "./UserAchievement";
|
|
|
5
5
|
import { UserAchievementTask } from "./UserAchievementTask";
|
|
6
6
|
import { BadgesTimeLimitStates } from "./BadgesTimeLimitStates";
|
|
7
7
|
|
|
8
|
-
type UserStateParamsKeys = 'core_fav_game_top3' | 'core_fav_game_type_top3' | 'core_fav_game_provider_top3' | 'core_recommended_deposit_amount' | 'core_recommended_casino_bet_amount'
|
|
8
|
+
type UserStateParamsKeys = 'core_fav_game_top3' | 'core_fav_game_type_top3' | 'core_fav_game_provider_top3' | 'core_recommended_deposit_amount' | 'core_recommended_casino_bet_amount';
|
|
9
9
|
const USER_STATE_PARAMS_KEYS_GAMES: UserStateParamsKeys[] = ['core_fav_game_top3', 'core_fav_game_type_top3', 'core_fav_game_provider_top3'];
|
|
10
|
-
const USER_STATE_PARAMS_KEYS_BET_AMOUNT: UserStateParamsKeys[] = [
|
|
10
|
+
const USER_STATE_PARAMS_KEYS_BET_AMOUNT: UserStateParamsKeys[] = [
|
|
11
|
+
'core_recommended_deposit_amount',
|
|
12
|
+
'core_recommended_casino_bet_amount',
|
|
13
|
+
];
|
|
11
14
|
|
|
12
15
|
const MINOR_WORDS = new Set([
|
|
13
16
|
'of', 'at', 'in', 'on', 'to', 'up', 'as', 'by', 'for',
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export enum BuyStoreItemErrorCode {
|
|
2
|
+
/** Generic server error / control-group rejection */
|
|
3
|
+
SHOP_FAILED_GENERIC = 1,
|
|
4
|
+
/** Label mismatch detected before purchase transaction */
|
|
5
|
+
SHOP_WRONG_LABEL_PRECHECK = 106,
|
|
2
6
|
/** User don't have enough points on balance */
|
|
3
7
|
SHOP_NO_BALANCE = 11000,
|
|
4
8
|
/** Wrong shop item id */
|
|
@@ -13,6 +17,8 @@ export enum BuyStoreItemErrorCode {
|
|
|
13
17
|
SHOP_FAILED_TO_BUY_MATCHING_BONUS = 11005,
|
|
14
18
|
/** Failed to buy item because of limit of max items is reached */
|
|
15
19
|
SHOP_FAILED_MAX_BOUGHT_ITEMS_REACHED = 11006,
|
|
20
|
+
/** Bonus was issued but a follow-up redemption step failed */
|
|
21
|
+
SHOP_FAILED_BONUS_REDEMPTION = 11007,
|
|
16
22
|
/** Failed to buy item because no more items are available */
|
|
17
23
|
SHOP_FAILED_POOL_EMPTY = 11009,
|
|
18
24
|
/** User doesn't have enough gems on balance */
|
|
@@ -21,4 +27,6 @@ export enum BuyStoreItemErrorCode {
|
|
|
21
27
|
SHOP_NO_BALANCE_DIAMONDS = 11012,
|
|
22
28
|
/** Failed to buy item because of purchase limitation */
|
|
23
29
|
SHOP_FAILED_PURCHASE_LIMITATION = 11014,
|
|
30
|
+
/** Uncaught server exception */
|
|
31
|
+
SHOP_UNEXPECTED_EXCEPTION = 9999,
|
|
24
32
|
}
|
package/src/Store/StoreItem.ts
CHANGED
|
@@ -52,6 +52,7 @@ export const StoreItemTransform = (items: StoreItem[]): TStoreItem[] => {
|
|
|
52
52
|
pool: r.shopPool,
|
|
53
53
|
custom_data: IntUtils.JsonOrText(r.itemPublicMeta.custom_data),
|
|
54
54
|
active_till_date: r.activeTillDate,
|
|
55
|
+
show_timer: r.itemPublicMeta.show_timer,
|
|
55
56
|
discounted_price: r.itemPublicMeta.discount_prize,
|
|
56
57
|
discount_price_ribbon: r.itemPublicMeta.discount_prize_ribbon,
|
|
57
58
|
custom_ribbon_image: r.itemPublicMeta.custom_ribbon_image,
|
|
@@ -55,6 +55,7 @@ export const StoreItemPurchasedTransform = (items: StoreItemPurchased[]): TStore
|
|
|
55
55
|
purchased_this_week: purchasedThisWeek,
|
|
56
56
|
purchased_this_month: purchasedThisMonth,
|
|
57
57
|
custom_data: r.itemPublicMeta.custom_data,
|
|
58
|
+
show_timer: r.itemPublicMeta.show_timer,
|
|
58
59
|
related_games: (r.relatedGames?.filter((g) => g.game_public_meta.enabled) || []).map((g, i) => ({
|
|
59
60
|
ext_game_id: g.ext_game_id,
|
|
60
61
|
game_public_meta: {
|
|
@@ -21,7 +21,7 @@ export const StoreItemTypeNamed = (type: StoreItemType): StoreItemTypeName => {
|
|
|
21
21
|
return (
|
|
22
22
|
{
|
|
23
23
|
[StoreItemType.Bonus]: StoreItemTypeName.Bonus,
|
|
24
|
-
[StoreItemType.Tangible]: StoreItemTypeName.
|
|
24
|
+
[StoreItemType.Tangible]: StoreItemTypeName.Tangible,
|
|
25
25
|
[StoreItemType.MiniGameSpin]: StoreItemTypeName.MiniGameSpin,
|
|
26
26
|
[StoreItemType.ChangeLevel]: StoreItemTypeName.ChangeLevel,
|
|
27
27
|
[StoreItemType.PrizeDrop]: StoreItemTypeName.PrizeDrop,
|
|
@@ -9,4 +9,8 @@ export enum TournamentRegistrationError {
|
|
|
9
9
|
TOURNAMENT_USER_NOT_REGISTERED = 30006,
|
|
10
10
|
TOURNAMENT_CANT_CHANGE_REGISTRATION_STATUS = 30007,
|
|
11
11
|
TOURNAMENT_MAX_REGISTRATIONS_REACHED = 30008,
|
|
12
|
+
TOURNAMENT_REGISTRATION_NOT_ENOUGH_GEMS = 30010,
|
|
13
|
+
TOURNAMENT_REGISTRATION_NOT_ENOUGH_DIAMONDS = 30011,
|
|
14
|
+
|
|
15
|
+
|
|
12
16
|
}
|