@betarena/ad-engine 0.0.6 → 0.0.8

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 (36) hide show
  1. package/.eslintrc.yaml +164 -0
  2. package/dist/icon-close.svg +9 -0
  3. package/dist/index.css +1 -0
  4. package/dist/index.html +2 -1
  5. package/dist/index.js +11 -0
  6. package/dist/roboto-cyrillic-400-normal.woff +0 -0
  7. package/dist/roboto-cyrillic-400-normal.woff2 +0 -0
  8. package/dist/roboto-cyrillic-ext-400-normal.woff +0 -0
  9. package/dist/roboto-cyrillic-ext-400-normal.woff2 +0 -0
  10. package/dist/roboto-greek-400-normal.woff +0 -0
  11. package/dist/roboto-greek-400-normal.woff2 +0 -0
  12. package/dist/roboto-latin-400-normal.woff +0 -0
  13. package/dist/roboto-latin-400-normal.woff2 +0 -0
  14. package/dist/roboto-latin-ext-400-normal.woff +0 -0
  15. package/dist/roboto-latin-ext-400-normal.woff2 +0 -0
  16. package/dist/roboto-vietnamese-400-normal.woff +0 -0
  17. package/dist/roboto-vietnamese-400-normal.woff2 +0 -0
  18. package/package.json +34 -14
  19. package/src/App.svelte +8 -0
  20. package/src/lib/Widget-AdEngine.svelte +492 -0
  21. package/src/lib/Widget-AdGeneral.svelte +284 -0
  22. package/src/lib/Widget-AdvertSlide.svelte +384 -0
  23. package/src/lib/assets/icon-close.svg +9 -0
  24. package/src/lib/assets/icon-external-link.svg +4 -0
  25. package/src/lib/constants/instance.ts +10 -0
  26. package/src/lib/store.ts +284 -0
  27. package/src/lib/types/ad-engine.d.ts +21 -0
  28. package/src/lib/types/geojs.d.ts +83 -0
  29. package/src/lib/types/global.d.ts +4 -0
  30. package/src/lib/types/vite-env.d.ts +2 -0
  31. package/src/lib/utils/device.ts +37 -0
  32. package/src/lib/utils/fetch.ts +107 -0
  33. package/src/lib/utils/geo.ts +34 -0
  34. package/src/main.ts +17 -0
  35. package/vite.config.ts +29 -3
  36. package/dist/assets/index-Cm9IxoHj.js +0 -24
@@ -0,0 +1,492 @@
1
+ <!--
2
+ ╭──────────────────────────────────────────────────────────────────────────────────╮
3
+ │ 📌 High Order Component Overview │
4
+ ┣──────────────────────────────────────────────────────────────────────────────────┫
5
+ │ ➤ Internal Svelte Code Format :|: V.8.0 │
6
+ │ ➤ Status :|: 🔒 LOCKED │
7
+ │ ➤ Author(s) :|: @migbash │
8
+ ┣──────────────────────────────────────────────────────────────────────────────────┫
9
+ │ 📝 Description │
10
+ ┣──────────────────────────────────────────────────────────────────────────────────┫
11
+ │ Betarena Ad-Engine Component │
12
+ ╰──────────────────────────────────────────────────────────────────────────────────╯
13
+ -->
14
+
15
+ <!--
16
+ ╭──────────────────────────────────────────────────────────────────────────────────╮
17
+ │ 🟦 Svelte Component JS/TS │
18
+ ┣──────────────────────────────────────────────────────────────────────────────────┫
19
+ │ ➤ HINT: │ Access snippets for '<script> [..] </script>' those found in │
20
+ │ │ '.vscode/snippets.code-snippets' via intellisense using 'doc' │
21
+ ╰──────────────────────────────────────────────────────────────────────────────────╯
22
+ -->
23
+
24
+ <script lang="ts">
25
+
26
+ // #region ➤ 📦 Package Imports
27
+
28
+ // ╭────────────────────────────────────────────────────────────────────────╮
29
+ // │ NOTE: │
30
+ // │ Please add inside 'this' region the 'imports' that are required │
31
+ // │ by 'this' .svelte file is ran. │
32
+ // │ IMPORTANT │
33
+ // │ Please, structure the imports as follows: │
34
+ // │ 1. svelte/sveltekit imports │
35
+ // │ 2. project-internal files and logic │
36
+ // │ 3. component import(s) │
37
+ // │ 4. assets import(s) │
38
+ // │ 5. type(s) imports(s) │
39
+ // ╰────────────────────────────────────────────────────────────────────────╯
40
+
41
+ import { onMount } from 'svelte';
42
+
43
+ import { betarenaEndpoint } from './constants/instance.js';
44
+ import { betarenaAdEngineStore } from './store.js';
45
+ import { postMod } from './utils/fetch.js';
46
+ import { detectDeviceType } from './utils/device.js';
47
+ import { getUserLocation } from './utils/geo.js';
48
+
49
+ import WidgetAdvertSlide from './Widget-AdvertSlide.svelte';
50
+ import WidgetAdGeneral from './Widget-AdGeneral.svelte';
51
+
52
+ import type { IAdsRequestBody, IAdsResponseBody } from '@betarena/scores-lib/types/ad-engine/index.js';
53
+ import type { GeoJsResponse } from './types/geojs.js';
54
+
55
+ // #endregion ➤ 📦 Package Imports
56
+
57
+ // #region ➤ 📌 VARIABLES
58
+
59
+ // ╭────────────────────────────────────────────────────────────────────────╮
60
+ // │ NOTE: │
61
+ // │ Please add inside 'this' region the 'variables' that are to be │
62
+ // │ and are expected to be used by 'this' .svelte file / component. │
63
+ // │ IMPORTANT │
64
+ // │ Please, structure the imports as follows: │
65
+ // │ 1. export const / let [..] │
66
+ // │ 2. const [..] │
67
+ // │ 3. let [..] │
68
+ // │ 4. $: [..] │
69
+ // ╰────────────────────────────────────────────────────────────────────────╯
70
+
71
+ export let
72
+ /**
73
+ * @description
74
+ * 📝 Width device change onset number
75
+ */
76
+ deviceWidthList: [number, number] = [768, 1024],
77
+ /**
78
+ * @description
79
+ * 📝 **author id**
80
+ */
81
+ authorId: number | null = null,
82
+ /**
83
+ * @description
84
+ * 📝 `List` of **tag ids**
85
+ */
86
+ authorArticleTagIds: number[] = []
87
+ ;
88
+
89
+ /**
90
+ * @description
91
+ * 📝 Component Local Interface
92
+ */
93
+ type IDeviceType =
94
+ | 'desktop'
95
+ | 'tablet'
96
+ | 'mobile'
97
+ ;
98
+
99
+ let
100
+ /**
101
+ * @description
102
+ * 📝 Device type detected
103
+ */
104
+ deviceType: IDeviceType = 'desktop',
105
+ /**
106
+ * @description
107
+ * 📝 Geo-Location response
108
+ */
109
+ geoLocation: GeoJsResponse | null = null,
110
+ /**
111
+ * @description
112
+ * 📝 `Map` where, `key=ZoneId` and `value=HTMLElement`
113
+ */
114
+ betarenaAdsInjectMap: Map < number, Element > = new Map()
115
+ ;
116
+
117
+ // #endregion ➤ 📌 VARIABLES
118
+
119
+ // #region ➤ 🛠️ METHODS
120
+
121
+ // ╭────────────────────────────────────────────────────────────────────────╮
122
+ // │ NOTE: │
123
+ // │ Please add inside 'this' region the 'methods' that are to be │
124
+ // │ and are expected to be used by 'this' .svelte file / component. │
125
+ // │ IMPORTANT │
126
+ // │ Please, structure the imports as follows: │
127
+ // │ 1. function (..) │
128
+ // │ 2. async function (..) │
129
+ // ╰────────────────────────────────────────────────────────────────────────╯
130
+
131
+ /**
132
+ * @author
133
+ * @migbash
134
+ * @summary
135
+ * 🟥 MAIN
136
+ * @description
137
+ * 📝 `Map` generation for `HTMLElements`.
138
+ * @returns { void }
139
+ */
140
+ function generateElementMap
141
+ (
142
+ ): void
143
+ {
144
+ const
145
+ /**
146
+ * @description
147
+ * 📝 `List` of `HTMLElements` identified on `page` for a target `zone`.
148
+ */
149
+ htmlElementList = document.querySelectorAll('[data-betarena-zone-id]')
150
+ ;
151
+
152
+ // ╭─────
153
+ // │ NOTE: |:| loop over elements detected as betarena elegible ads
154
+ // ╰─────
155
+ for (const elem of htmlElementList)
156
+ {
157
+ const
158
+ /**
159
+ * @description
160
+ * 📝 Value of Betarena Zone Id
161
+ */
162
+ value = elem.attributes.getNamedItem('data-betarena-zone-id')?.value
163
+ ;
164
+
165
+ if (!value) continue;
166
+
167
+ betarenaAdsInjectMap.set(parseInt(value), elem);
168
+ }
169
+
170
+ return
171
+ }
172
+
173
+ /**
174
+ * @author
175
+ * @migbash
176
+ * @summary
177
+ * 🟦 HELPER
178
+ * @description
179
+ * 📝 Generates adverts (+ complementary data) for appropiate zones
180
+ * @param { IAdsRequestBody } opts
181
+ * 💠 **[required]** `list` of zone ids
182
+ * @returns { Promise < void > }
183
+ */
184
+ async function injectBetarenaAds
185
+ (
186
+ opts: IAdsRequestBody
187
+ ): Promise < void >
188
+ {
189
+ if (!document) return;
190
+
191
+ const
192
+ /**
193
+ * @description
194
+ * 📝 Response from `fetch`
195
+ */
196
+ response
197
+ = await postMod
198
+ <
199
+ IAdsRequestBody,
200
+ IAdsResponseBody
201
+ >
202
+ (
203
+ `${betarenaEndpoint}/ads`,
204
+ opts
205
+ )
206
+ ;
207
+
208
+ // [🐞]
209
+ console.log(response);
210
+
211
+ const
212
+ /**
213
+ * @description
214
+ * 📝 `Map`
215
+ */
216
+ dataMap = new Map((response as IAdsResponseBody).ads ?? []),
217
+ /**
218
+ * @description
219
+ * 📝 `Map`
220
+ */
221
+ mapZoneIdToCampaignId = new Map ((response as IAdsResponseBody).mapZoneIdToCampaignId),
222
+ /**
223
+ * @description
224
+ * 📝 `Map`
225
+ */
226
+ mapCreativeIdToCampaignId = new Map ((response as IAdsResponseBody).mapCampaignIdToCreativeId),
227
+ /**
228
+ * @description
229
+ * 📝 `Map`
230
+ */
231
+ mapZoneToAuthorIds = new Map ((response as IAdsResponseBody).mapZoneIdToAuthorIds),
232
+ /**
233
+ * @description
234
+ * 📝 `Map`
235
+ */
236
+ mapZoneToTagIds = new Map ((response as IAdsResponseBody).mapZoneIdToTagIds)
237
+ ;
238
+
239
+ // ╭─────
240
+ // │ NOTE:
241
+ // │ ➤ [1] loop over retrieved/fetched elements, and
242
+ // │ ➤ [2] inject target `ads` in specific locations
243
+ // ╰─────
244
+ for (const [zoneId, element] of betarenaAdsInjectMap)
245
+ {
246
+ if (!geoLocation) continue;
247
+
248
+ const
249
+ /**
250
+ * @description
251
+ * 📝 **campaign ids** of respective **zone id**
252
+ */
253
+ zoneIdCampaignIds
254
+ = (mapZoneIdToCampaignId.get(zoneId) ?? []),
255
+ /**
256
+ * @description
257
+ * 📝 `List` of creative data point(s)
258
+ */
259
+ creativeAdData
260
+ = zoneIdCampaignIds.map
261
+ (
262
+ x =>
263
+ {
264
+ if (dataMap.has(x))
265
+ return dataMap.get(x);
266
+ }
267
+ )
268
+ ;
269
+
270
+ for (const adData of creativeAdData ?? [])
271
+ {
272
+ new WidgetAdGeneral
273
+ (
274
+ {
275
+ target: element,
276
+ props:
277
+ {
278
+ adData
279
+ }
280
+ }
281
+ );
282
+ }
283
+ }
284
+
285
+ // ╭─────
286
+ // │ NOTE:
287
+ // │ ➤ inject of 'global' placements ads (based on global page data)
288
+ // ╰─────
289
+ if (authorId || authorArticleTagIds.length > 0)
290
+ {
291
+ for (const [zoneId, authorIds] of mapZoneToAuthorIds)
292
+ {
293
+ if (authorId && !authorIds.includes(authorId))
294
+ continue;
295
+ ;
296
+
297
+ const
298
+ /**
299
+ * @description
300
+ * 📝 **campaign ids** of respective **zone id**
301
+ */
302
+ zoneIdCampaignIds
303
+ = (mapZoneIdToCampaignId.get(zoneId) ?? []),
304
+ /**
305
+ * @description
306
+ * 📝 `List` of creative data point(s)
307
+ */
308
+ creativeAdData
309
+ = zoneIdCampaignIds.map
310
+ (
311
+ x =>
312
+ {
313
+ if (dataMap.has(x))
314
+ return dataMap.get(x);
315
+ }
316
+ )
317
+ ;
318
+
319
+ for (const adData of creativeAdData)
320
+ {
321
+ new WidgetAdvertSlide
322
+ (
323
+ {
324
+ target: document.body,
325
+ props:
326
+ {
327
+ adData
328
+ }
329
+ }
330
+ );
331
+ }
332
+ }
333
+
334
+ for (const [zoneId, tagIds] of mapZoneToTagIds)
335
+ {
336
+ if (authorId && !tagIds.includes(authorId))
337
+ continue;
338
+ ;
339
+
340
+ const
341
+ /**
342
+ * @description
343
+ * 📝 **campaign ids** of respective **zone id**
344
+ */
345
+ zoneIdCampaignIds
346
+ = (mapZoneIdToCampaignId.get(zoneId) ?? []),
347
+ /**
348
+ * @description
349
+ * 📝 `List` of creative data point(s)
350
+ */
351
+ creativeAdData
352
+ = zoneIdCampaignIds.map
353
+ (
354
+ x =>
355
+ {
356
+ if (dataMap.has(x))
357
+ return dataMap.get(x);
358
+ }
359
+ )
360
+ ;
361
+
362
+ for (const adData of creativeAdData)
363
+ {
364
+ new WidgetAdvertSlide
365
+ (
366
+ {
367
+ target: document.body,
368
+ props:
369
+ {
370
+ adData
371
+ }
372
+ }
373
+ );
374
+ }
375
+ }
376
+ }
377
+
378
+ return;
379
+ }
380
+
381
+ /**
382
+ * @author
383
+ * @migbash
384
+ * @summary
385
+ * 🟥 MAIN
386
+ * @description
387
+ * 📝 Logic bundle for advert initialization
388
+ * @returns { Promise < void > }
389
+ */
390
+ async function initialize
391
+ (
392
+ ): Promise < void >
393
+ {
394
+ detectDeviceType();
395
+ geoLocation = await getUserLocation();
396
+ generateElementMap();
397
+
398
+ // [🐞]
399
+ // console.log('elements', betarenaAdsInjectMap);
400
+ // console.log('elements', zoneIds);
401
+
402
+ injectBetarenaAds
403
+ (
404
+ {
405
+ deviceType,
406
+ isoCountryCode: geoLocation?.country_code ?? 'EB',
407
+ authorId,
408
+ tagIds: authorArticleTagIds,
409
+ zoneIds: [...betarenaAdsInjectMap.keys()]
410
+ }
411
+ );
412
+
413
+ return;
414
+ }
415
+
416
+ // #endregion ➤ 🛠️ METHODS
417
+
418
+ // #region ➤ 🔄 LIFECYCLE [SVELTE]
419
+
420
+ // ╭────────────────────────────────────────────────────────────────────────╮
421
+ // │ NOTE: │
422
+ // │ Please add inside 'this' region the 'logic' that should run │
423
+ // │ immediately and as part of the 'lifecycle' of svelteJs, │
424
+ // │ as soon as 'this' .svelte file is ran. │
425
+ // ╰────────────────────────────────────────────────────────────────────────╯
426
+
427
+ onMount
428
+ (
429
+ async () =>
430
+ {
431
+ betarenaAdEngineStore.useLocalStorage();
432
+ await initialize();
433
+ return;
434
+ }
435
+ );
436
+
437
+ // #endregion ➤ 🔄 LIFECYCLE [SVELTE]
438
+
439
+ </script>
440
+
441
+ <svelte:window
442
+ on:resize=
443
+ {
444
+ () =>
445
+ {
446
+ detectDeviceType();
447
+ return;
448
+ }
449
+ }
450
+ />
451
+
452
+ <!--
453
+ ╭──────────────────────────────────────────────────────────────────────────────────╮
454
+ │ 💠 Svelte Component HTML │
455
+ ┣──────────────────────────────────────────────────────────────────────────────────┫
456
+ │ ➤ HINT: │ Use 'Ctrl + Space' to autocomplete global class=styles, dynamically │
457
+ │ │ imported from './static/app.css' │
458
+ │ ➤ HINT: │ access custom Betarena Scores VScode Snippets by typing emmet-like │
459
+ │ │ abbrev. │
460
+ ╰──────────────────────────────────────────────────────────────────────────────────╯
461
+ -->
462
+
463
+ <!--
464
+ ╭─────
465
+ │ ➤ Testing [🐞]
466
+ ╰─────
467
+ -->
468
+ <div>
469
+
470
+ <p>
471
+ Device Type: {deviceType}
472
+ </p>
473
+
474
+ <p>
475
+ {geoLocation?.country_code}
476
+ </p>
477
+
478
+ </div>
479
+
480
+ <div
481
+ data-betarena-zone-id=1
482
+ >
483
+ </div>
484
+
485
+ <!--
486
+ <hr>
487
+
488
+ <div
489
+ data-betarena-zone-id=2
490
+ >
491
+ </div>
492
+ -->