@smartico/public-api 0.0.434 → 0.0.436

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.
@@ -25,7 +25,7 @@ Fields rendered per row:
25
25
  |---|---|---|
26
26
  | Template icon | `template.thumbnail` (or similar) | 1:1 |
27
27
  | Prize name | Look up `template.prizes[i]` by `saw_prize_id` | Display the prize's `name`. A spin finalised as lost (`miniGameWinAcknowledgeRequest` with `lose: true`) has no prize attached — render it as a loss. |
28
- | Prize amount | `template.prizes[i].prize_value` or `prize_amount` | E.g. "100 points" |
28
+ | Prize amount | `template.prizes[i].prize_value` or `prize_amount`; for gems/diamonds prizes `prize_details_json.gems` / `.diamonds`, for raffle-ticket prizes `prize_details_json.tickets_count` | E.g. "100 points", "50 Diamonds". The history row carries the template as sent by the server, where `prize_value` of a gems/diamonds or raffle-ticket prize is only a default — `getMiniGames()` already resolves it into `prize_value` |
29
29
  | Spin date | `create_date_ts` | Format as user-local relative time ("2h ago") or short date |
30
30
  | Claim status | `is_claimed` | Show check-mark when true; "Pending claim" CTA when false |
31
31
  | Acknowledge date | `acknowledge_date_ts` | Only when `is_claimed === true` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartico/public-api",
3
- "version": "0.0.434",
3
+ "version": "0.0.436",
4
4
  "description": "Smartico public API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -6,13 +6,31 @@ import { SAWBuyInType, SAWBuyInTypeNamed } from './SAWBuyInType';
6
6
  import { SAWExposeUserSpinIdNamed } from './SAWExposeUserSpinId';
7
7
  import { SAWGameLayoutNamed } from './SAWGameLayout';
8
8
  import { SAWGameType, SAWGameTypeNamed } from './SAWGameType';
9
- import { MiniGamePrizeTypeNamed } from './SAWPrizeType';
9
+ import { SAWPrize } from './SAWPrize';
10
+ import { MiniGamePrizeTypeNamed, SAWPrizeType } from './SAWPrizeType';
10
11
  import { SAWTemplate } from './SAWTemplate';
11
12
 
12
13
  export interface SAWGetTemplatesResponse extends ProtocolResponse {
13
14
  templates: SAWTemplate[];
14
15
  }
15
16
 
17
+ /**
18
+ * The amount a prize gives. Gems/diamonds and raffle-ticket prizes carry it in
19
+ * `prize_details_json` (their `prize_value` is only a default), the same way the
20
+ * default Smartico UI reads it; every other type keeps `prize_value`.
21
+ */
22
+ const sawPrizeValue = (p: SAWPrize): number => {
23
+ const d = p.prize_details_json;
24
+ let n = 0;
25
+ if (p.prize_type_id === SAWPrizeType.GEMS_AND_DIAMONDS && d) {
26
+ // _gems_diamonds_type: 0 gems, 1 diamonds, 2 both
27
+ n = (d._gems_diamonds_type === 1 ? 0 : d.gems || 0) + (d._gems_diamonds_type === 0 ? 0 : d.diamonds || 0);
28
+ } else if (p.prize_type_id === SAWPrizeType.RAFFLE_TICKET && d) {
29
+ n = d.tickets_count || 0;
30
+ }
31
+ return n > 0 ? n : p.prize_value;
32
+ };
33
+
16
34
  export const SAWTemplatesTransform = (items: SAWTemplate[]): TMiniGameTemplate[] => {
17
35
  return items.map((r) => {
18
36
  const x: TMiniGameTemplate = {
@@ -66,7 +84,7 @@ export const SAWTemplatesTransform = (items: SAWTemplate[]): TMiniGameTemplate[]
66
84
  id: p.saw_prize_id,
67
85
  name: p.saw_prize_ui_definition.name,
68
86
  prize_type: MiniGamePrizeTypeNamed(p.prize_type_id),
69
- prize_value: p.prize_value,
87
+ prize_value: sawPrizeValue(p),
70
88
  font_size: p.saw_prize_ui_definition.font_size,
71
89
  font_size_mobile: p.saw_prize_ui_definition.font_size_mobile,
72
90
  icon: p.saw_prize_ui_definition.icon,
@@ -1,12 +1,19 @@
1
- import { IntUtils } from "../IntUtils";
2
1
  import { AchievementAvailabilityStatus } from "./AchievementAvailabilityStatus";
3
2
  import { AchievementStatus } from "./AchievementStatus";
4
3
  import { UserAchievement } from "./UserAchievement";
5
4
  import { UserAchievementTask } from "./UserAchievementTask";
6
5
  import { BadgesTimeLimitStates } from "./BadgesTimeLimitStates";
7
6
 
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' | 'core_recommended_sport_bet_amount';
9
- const USER_STATE_PARAMS_KEYS_GAMES: UserStateParamsKeys[] = ['core_fav_game_top3', 'core_fav_game_type_top3', 'core_fav_game_provider_top3'];
7
+ type UserStateParamsKeys =
8
+ | 'core_fav_game_top3' | 'core_fav_game_type_top3' | 'core_fav_game_provider_top3'
9
+ | 'core_fav_sport_type_top3' | 'core_fav_sport_league_top3'
10
+ | 'core_recommended_deposit_amount' | 'core_recommended_casino_bet_amount' | 'core_recommended_sport_bet_amount';
11
+
12
+ // tag -> favorites (top 3 arrays) that fill it; a task has at most one condition per tag (enforced in the BO)
13
+ const FAV_TAGS: [string, UserStateParamsKeys[]][] = [
14
+ ['{{suggested_games}}', ['core_fav_game_top3', 'core_fav_game_type_top3', 'core_fav_game_provider_top3']],
15
+ ['{{suggested_sport}}', ['core_fav_sport_type_top3', 'core_fav_sport_league_top3']],
16
+ ];
10
17
  const USER_STATE_PARAMS_KEYS_BET_AMOUNT: UserStateParamsKeys[] = [
11
18
  'core_recommended_deposit_amount',
12
19
  'core_recommended_casino_bet_amount',
@@ -212,64 +219,47 @@ export class MissionUtils {
212
219
 
213
220
  const userStateParams = (task.user_state_params || {});
214
221
  const userStateOperator = task.task_public_meta?.user_state_operations;
215
- const userStateParamsKeys = Object.keys(userStateParams);
216
-
217
- if (userStateParamsKeys.length === 0 || !userStateOperator) {
222
+ if (Object.keys(userStateParams).length === 0 || !userStateOperator) {
218
223
  return result;
219
224
  }
220
225
 
221
- const operatorsMulti = ['has', '!has'];
222
- const operatorsPos = ['pos1', 'pos2', 'pos3'];
223
-
224
- let suggestedGames: string = '';
225
- let suggestedValue: string = '';
226
-
227
- userStateParamsKeys.forEach((k: UserStateParamsKeys) => {
228
- const operator = userStateOperator[k]?.op;
229
-
230
- if (USER_STATE_PARAMS_KEYS_GAMES.includes(k)) {
231
- if (operatorsMulti.includes(operator)) {
232
- const value = userStateParams[k]?.filter(v => Boolean(v));
233
- if (value && value.length > 0) {
234
- suggestedGames = value.map((v: string) => {
235
- const cleaned = v.replace(/_/g, ' ');
236
- return toGameTitleCase(cleaned);
237
- }).join(', ');
238
- }
239
- }
240
-
241
- if (operatorsPos.includes(operator)) {
242
- const value = userStateParams[k];
243
- const pos = Number(operator.replace('pos', '')) - 1;
226
+ const formatFav = (v: string): string => toGameTitleCase(v.replace(/_/g, ' '));
244
227
 
245
- if (IntUtils.isNotNull(pos) && value && value[pos]) {
246
- suggestedGames = value[pos];
228
+ // 'has' / '!has' -> all favorites, 'posN' -> the N-th one
229
+ const favValue = (k: UserStateParamsKeys): string => {
230
+ const values = userStateParams[k];
231
+ const operator: string = userStateOperator[k]?.op;
247
232
 
248
- if (suggestedGames) {
249
- suggestedGames = toGameTitleCase(suggestedGames.replace(/_/g, ' '));
250
- }
233
+ if (!Array.isArray(values)) {
234
+ return '';
235
+ }
251
236
 
252
- }
253
- }
237
+ if (operator === 'has' || operator === '!has') {
238
+ return values.filter(Boolean).map(formatFav).join(', ');
254
239
  }
255
240
 
256
- if (USER_STATE_PARAMS_KEYS_BET_AMOUNT.includes(k)) {
257
- suggestedValue = userStateParams[k];
241
+ const pos = /^pos[1-3]$/.test(operator) ? values[Number(operator.substring(3)) - 1] : null;
258
242
 
259
- if (suggestedValue) {
260
- const currencyFromTheTask = userStateParams?.core_wallet_currency;
243
+ return pos ? formatFav(pos) : '';
244
+ };
261
245
 
262
- suggestedValue = `${suggestedValue} ${currencySymbol || currencyFromTheTask || ''}`;
263
- }
246
+ // split/join replaces every occurrence of the tag, not only the first one
247
+ const replaceTag = (tag: string, value: string) => {
248
+ if (value && result) {
249
+ result = result.split(tag).join(value);
264
250
  }
251
+ };
252
+
253
+ FAV_TAGS.forEach(([tag, keys]) => {
254
+ replaceTag(tag, keys.map(favValue).find(Boolean));
265
255
  });
266
256
 
267
- if (suggestedGames && result) {
268
- result = result.replace('{{suggested_games}}', suggestedGames);
269
- }
257
+ const amountKey = USER_STATE_PARAMS_KEYS_BET_AMOUNT.find((k) => userStateParams[k]);
258
+
259
+ if (amountKey) {
260
+ const currencyFromTheTask = userStateParams.core_wallet_currency;
270
261
 
271
- if (suggestedValue && result) {
272
- result = result.replace('{{suggested_value}}', suggestedValue);
262
+ replaceTag('{{suggested_value}}', `${userStateParams[amountKey]} ${currencySymbol || currencyFromTheTask || ''}`);
273
263
  }
274
264
 
275
265
  return result;
@@ -76,13 +76,13 @@ export const UserAchievementTransform = (items: UserAchievement[]): TMissionOrBa
76
76
  if (missionName?.includes('{{suggested_') || missionSubHeader?.includes('{{suggested_') || missionDescription?.includes('{{suggested_')) {
77
77
  r.achievementTasks.forEach(t => {
78
78
  if (r.ach_public_meta.name?.includes('{{suggested_')) {
79
- missionName = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: r.ach_public_meta.name });
79
+ missionName = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: missionName });
80
80
  }
81
81
  if (r.ach_public_meta.sub_header?.includes('{{suggested_')) {
82
- missionSubHeader = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: r.ach_public_meta.sub_header });
82
+ missionSubHeader = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: missionSubHeader });
83
83
  }
84
84
  if (r.ach_public_meta.description?.includes('{{suggested_')) {
85
- missionDescription = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: r.ach_public_meta.description });
85
+ missionDescription = MissionUtils.replaceTagsFavMissionTask({ task: t, valueToReplace: missionDescription });
86
86
  }
87
87
  });
88
88
  }
@@ -29,8 +29,8 @@ export interface TMiniGamePrize {
29
29
  name: string;
30
30
  /** The type of the prize — see {@link MiniGamePrizeTypeName} ('no-prize', 'points', 'gems-and-diamonds', 'spin', 'bonus', 'jackpot', 'raffle-ticket', 'mission', 'change-level', 'manual') */
31
31
  prize_type: MiniGamePrizeTypeName;
32
- /** Numeric value of the prize in case it's 'points' or 'spin' type. For other types of prizes this value is not relevant.
33
- * For example for prize '100 points' the prize_value will be 100. For '100 free spins' the prize_value will be 100.
32
+ /** Amount of the prize: points for 'points', attempts for 'spin', gems or diamonds for 'gems-and-diamonds' (their sum when the prize gives both), tickets for 'raffle-ticket'. Not relevant for other types.
33
+ * For example for prize '100 points' the prize_value will be 100, for '100 free spins' 100, for '50 Diamonds' 50.
34
34
  */
35
35
  prize_value?: number;
36
36
  /** Custom font size in px for rendering the prize name on the game surface (e.g. a wheel sector), desktop */