@streamscloud/embeddable 6.3.2 → 6.3.3

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 (27) hide show
  1. package/dist/short-videos/short-video-viewer/cmp.attachments-inline.svelte +63 -5
  2. package/dist/short-videos/short-video-viewer/cmp.attachments-inline.svelte.d.ts +4 -0
  3. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte +9 -2
  4. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte.d.ts +1 -0
  5. package/dist/short-videos/short-video-viewer/cmp.short-video-product-card.svelte +26 -0
  6. package/dist/short-videos/short-video-viewer/cmp.short-video-product-card.svelte.d.ts +17 -0
  7. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte +6 -1
  8. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte.d.ts +2 -0
  9. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte +2 -1
  10. package/dist/short-videos/short-videos-player/index.d.ts +2 -2
  11. package/dist/short-videos/short-videos-player/index.js +6 -0
  12. package/dist/short-videos/short-videos-player/internal-short-video-analytics-handler.d.ts +8 -0
  13. package/dist/short-videos/short-videos-player/internal-short-video-analytics-handler.js +13 -0
  14. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +13 -2
  15. package/dist/short-videos/short-videos-player/types.d.ts +8 -0
  16. package/dist/streams/cmp.stream-product-card.svelte +25 -0
  17. package/dist/streams/cmp.stream-product-card.svelte.d.ts +17 -0
  18. package/dist/streams/layout/cmp.slot-content.svelte +28 -2
  19. package/dist/streams/layout/cmp.slot-content.svelte.d.ts +1 -0
  20. package/dist/streams/stream-page-viewer/cmp.stream-page-viewer.svelte.d.ts +1 -0
  21. package/dist/streams/stream-player/controls.svelte +2 -1
  22. package/dist/streams/stream-player/controls.svelte.d.ts +1 -0
  23. package/dist/streams/stream-player/internal-stream-analytics-handler.d.ts +5 -1
  24. package/dist/streams/stream-player/internal-stream-analytics-handler.js +5 -1
  25. package/dist/streams/stream-player/stream-player.svelte +19 -3
  26. package/dist/streams/stream-player/types.d.ts +4 -0
  27. package/package.json +2 -2
@@ -1,18 +1,76 @@
1
1
  <script lang="ts">import { Icon, IconColor } from '../../ui/icon';
2
2
  import { ImageRounded } from '../../ui/image';
3
3
  import IconTargetArrow from '@fluentui/svg-icons/icons/target_arrow_20_regular.svg?raw';
4
- let { model } = $props();
4
+ import { onMount } from 'svelte';
5
+ let { model, on } = $props();
5
6
  const attachmentsToShow = $derived.by(() => {
6
- const products = model.products.filter((p) => !!p.image).map((p) => ({ isAd: false, image: p.image, link: p.link }));
7
- const ads = (model.ad ? [model.ad] : []).filter((a) => !!a.image).map((a) => { var _a; return ({ isAd: true, image: a.image, link: ((_a = a.ctaButton) === null || _a === void 0 ? void 0 : _a.url) || null }); });
7
+ const products = model.products
8
+ .filter((p) => !!p.image)
9
+ .map((p) => ({
10
+ isAd: false,
11
+ image: p.image,
12
+ link: p.link,
13
+ productId: p.id
14
+ }));
15
+ const ads = (model.ad ? [model.ad] : [])
16
+ .filter((a) => !!a.image)
17
+ .map((a) => {
18
+ var _a;
19
+ return ({
20
+ isAd: true,
21
+ image: a.image,
22
+ link: ((_a = a.ctaButton) === null || _a === void 0 ? void 0 : _a.url) || null,
23
+ productId: null
24
+ });
25
+ });
8
26
  return [...products, ...ads];
9
27
  });
28
+ const handleAttachmentClick = (attachment) => {
29
+ if (attachment.productId && (on === null || on === void 0 ? void 0 : on.productClick)) {
30
+ on.productClick(attachment.productId);
31
+ }
32
+ if (attachment.link) {
33
+ window.open(attachment.link, '_blank');
34
+ }
35
+ };
36
+ let attachmentElements = {};
37
+ onMount(() => {
38
+ if (on === null || on === void 0 ? void 0 : on.productImpression) {
39
+ // Track product impressions when they come into view
40
+ const observer = new IntersectionObserver((entries) => {
41
+ entries.forEach((entry) => {
42
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
43
+ const productId = entry.target.getAttribute('data-product-id');
44
+ if (productId) {
45
+ on.productImpression(productId, model.id);
46
+ observer.unobserve(entry.target); // Only track once per session
47
+ }
48
+ }
49
+ });
50
+ }, { threshold: 0.5 });
51
+ // Observe all product elements
52
+ Object.entries(attachmentElements).forEach(([key, element]) => {
53
+ if (element && key.startsWith('product-')) {
54
+ observer.observe(element);
55
+ }
56
+ });
57
+ return () => {
58
+ observer.disconnect();
59
+ };
60
+ }
61
+ });
10
62
  </script>
11
63
 
12
64
  <div class="attachments-inline-container">
13
65
  <div class="attachments-inline">
14
- {#each attachmentsToShow as attachment (attachment)}
15
- <div class="attachments-inline__item" onclick={() => attachment.link && window.open(attachment.link, '_blank')} onkeydown={() => {}} role="none">
66
+ {#each attachmentsToShow as attachment, index (attachment)}
67
+ <div
68
+ class="attachments-inline__item"
69
+ onclick={() => handleAttachmentClick(attachment)}
70
+ onkeydown={() => {}}
71
+ role="none"
72
+ bind:this={attachmentElements[attachment.productId ? `product-${attachment.productId}` : `ad-${index}`]}
73
+ data-product-id={attachment.productId || undefined}>
16
74
  <ImageRounded src={attachment.image} alt="" />
17
75
  {#if attachment.isAd}
18
76
  <div class="attachments-inline__item-icon">
@@ -1,6 +1,10 @@
1
1
  import type { ShortVideoViewerModel } from './types';
2
2
  type Props = {
3
3
  model: ShortVideoViewerModel;
4
+ on?: {
5
+ productClick?: (productId: string) => void;
6
+ productImpression?: (productId: string, videoId: string) => void;
7
+ };
4
8
  };
5
9
  declare const Cmp: import("svelte").Component<Props, {}, "">;
6
10
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import { AdCard } from '../../ads/ad-card';
2
- import { ProductCard } from '../../products/product-card';
2
+ import { default as ShortVideoProductCard } from './cmp.short-video-product-card.svelte';
3
3
  import { ShortVideoAttachmentsLocalization } from './short-video-attachments-localization';
4
4
  import {} from './types';
5
5
  let { shortVideo, localization: localizationInit = 'en', on } = $props();
@@ -14,7 +14,14 @@ const localization = $derived(new ShortVideoAttachmentsLocalization(localization
14
14
 
15
15
  {#if shortVideo.products.length}
16
16
  {#each shortVideo.products as product (product.id)}
17
- <ProductCard product={product} localization={localization.productLocalization} on={on} />
17
+ <ShortVideoProductCard
18
+ product={product}
19
+ videoId={shortVideo.id}
20
+ localization={localization.productLocalization}
21
+ on={{
22
+ productClick: on?.productClick,
23
+ impression: on?.productImpression
24
+ }} />
18
25
  {/each}
19
26
  {/if}
20
27
  </div>
@@ -6,6 +6,7 @@ type Props = {
6
6
  localization?: IShortVideoAttachmentsLocalization | Locale;
7
7
  on?: {
8
8
  productClick?: (productId: string) => void;
9
+ productImpression?: (productId: string, videoId: string) => void;
9
10
  };
10
11
  };
11
12
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,26 @@
1
+ <script lang="ts">import { ProductCard } from '../../products/product-card';
2
+ import { onMount } from 'svelte';
3
+ let { product, videoId, localization, includeBeforeNowPrefix, inert = false, on } = $props();
4
+ let productElement;
5
+ const productData = product;
6
+ onMount(() => {
7
+ if (productElement && (on === null || on === void 0 ? void 0 : on.impression)) {
8
+ const observer = new IntersectionObserver((entries) => {
9
+ entries.forEach((entry) => {
10
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
11
+ on.impression(product.id, videoId);
12
+ observer.unobserve(entry.target);
13
+ }
14
+ });
15
+ }, { threshold: 0.5 });
16
+ observer.observe(productElement);
17
+ return () => {
18
+ observer.disconnect();
19
+ };
20
+ }
21
+ });
22
+ </script>
23
+
24
+ <div bind:this={productElement}>
25
+ <ProductCard product={productData} localization={localization} includeBeforeNowPrefix={includeBeforeNowPrefix} inert={inert} on={on} />
26
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { Locale } from '../../core/locale';
2
+ import type { IProductCardLocalization } from '../../products/product-card/product-card-localization';
3
+ import type { ShortVideoProductCardModel } from './types';
4
+ type Props = {
5
+ product: ShortVideoProductCardModel;
6
+ videoId: string;
7
+ localization?: IProductCardLocalization | Locale;
8
+ includeBeforeNowPrefix?: boolean;
9
+ inert?: boolean;
10
+ on?: {
11
+ productClick?: (id: string) => void;
12
+ impression?: (productId: string, videoId: string) => void;
13
+ };
14
+ };
15
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
16
+ type Cmp = ReturnType<typeof Cmp>;
17
+ export default Cmp;
@@ -36,7 +36,12 @@ $effect(() => {
36
36
 
37
37
  <div class="short-video-viewer__actions-panel" class:short-video-viewer__actions-panel--inside-frame={true}>
38
38
  {#if uiManager.showAttachments}
39
- <AttachmentsInline model={model} />
39
+ <AttachmentsInline
40
+ model={model}
41
+ on={{
42
+ productClick: on?.productClick,
43
+ productImpression: on?.productImpression
44
+ }} />
40
45
  {/if}
41
46
  {#if uiManager.showControls}
42
47
  <ShortVideoControls model={model} socialInteractionsHandler={socialInteractionsHandler} on={{ attachmentsClicked: uiManager.toggleEnableAttachments }} />
@@ -10,6 +10,8 @@ type Props = {
10
10
  localization?: IShortVideoViewerLocalization | Locale;
11
11
  on?: {
12
12
  progress?: (progress: number) => void;
13
+ productClick?: (productId: string) => void;
14
+ productImpression?: (productId: string, videoId: string) => void;
13
15
  };
14
16
  };
15
17
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">import { MediaCenter, MediaCenterMode } from '../../media-center/media-center';
2
2
  import { createShadowRoot } from '../../ui/shadow-dom';
3
3
  import { mount, unmount } from 'svelte';
4
- let { dataProvider, socialInteractionsHandler, localization, showStreamsCloudWatermark, disableBackground, on, mediaCenterDataProvider } = $props();
4
+ let { dataProvider, socialInteractionsHandler, localization, showStreamsCloudWatermark, disableBackground, analyticsHandler, on, mediaCenterDataProvider } = $props();
5
5
  const initHost = (node) => {
6
6
  const shadowRoot = createShadowRoot(node);
7
7
  const mounted = mount(MediaCenter, {
@@ -16,6 +16,7 @@ const initHost = (node) => {
16
16
  disableBackground,
17
17
  localization,
18
18
  showStreamsCloudWatermark,
19
+ analyticsHandler,
19
20
  on
20
21
  }
21
22
  }
@@ -3,9 +3,9 @@ import type { ShortVideoViewerModel } from '../short-video-viewer';
3
3
  import type { IPlayerItemsProvider } from '../../ui/player';
4
4
  import { default as ShortVideosPlayer } from './cmp.short-videos-player.svelte';
5
5
  import type { IShortVideosPlayerLocalization } from './short-videos-player-localization';
6
- import { type PlayerSettings } from './types';
6
+ import { type PlayerSettings, type IShortVideoAnalyticsHandler } from './types';
7
7
  export { ShortVideosPlayer };
8
- export type { IShortVideosPlayerLocalization, IMediaCenterDataProvider, IPlayerItemsProvider };
8
+ export type { IShortVideosPlayerLocalization, IMediaCenterDataProvider, IPlayerItemsProvider, IShortVideoAnalyticsHandler };
9
9
  /**
10
10
  * Opens the short videos player modal.
11
11
  *
@@ -3,6 +3,7 @@ import { InternalMediaCenterDataProvider } from '../../media-center/data-provide
3
3
  import { MediaCenter, MediaCenterMode } from '../../media-center/media-center';
4
4
  import { ModalShadowHost } from '../../ui/shadow-dom';
5
5
  import { default as ShortVideosPlayer } from './cmp.short-videos-player.svelte';
6
+ import { InternalShortVideoAnalyticsHandler } from './internal-short-video-analytics-handler';
6
7
  import { InternalShortVideoPlayerProvider } from './internal-short-video-player-provider';
7
8
  import {} from './types';
8
9
  import { mount, unmount } from 'svelte';
@@ -21,6 +22,10 @@ export function openShortVideosPlayer(init) {
21
22
  if (!mediaCenterDataProvider && init.mediaPageId) {
22
23
  mediaCenterDataProvider = new InternalMediaCenterDataProvider(init.mediaPageId, graphqlOrigin);
23
24
  }
25
+ let analyticsHandler = init.analyticsHandler;
26
+ if (!analyticsHandler && !init.shortVideosProvider && initiator) {
27
+ analyticsHandler = new InternalShortVideoAnalyticsHandler(graphqlOrigin);
28
+ }
24
29
  const shadowHost = new ModalShadowHost();
25
30
  const mounted = mount(MediaCenter, {
26
31
  target: shadowHost.shadowRoot,
@@ -34,6 +39,7 @@ export function openShortVideosPlayer(init) {
34
39
  disableBackground,
35
40
  localization,
36
41
  showStreamsCloudWatermark,
42
+ analyticsHandler,
37
43
  on: {
38
44
  playerClosed: async () => {
39
45
  await unmount(mounted);
@@ -0,0 +1,8 @@
1
+ import type { IShortVideoAnalyticsHandler } from './types';
2
+ export declare class InternalShortVideoAnalyticsHandler implements IShortVideoAnalyticsHandler {
3
+ constructor(graphqlOrigin: string | undefined);
4
+ setOrganizationId: (organizationId: string) => void;
5
+ trackShortVideoView: (videoId: string) => void;
6
+ trackShortVideoProductImpression: (productId: string, videoId: string) => void;
7
+ trackShortVideoProductClicked: (productId: string, videoId: string) => void;
8
+ }
@@ -0,0 +1,13 @@
1
+ import { getOrCreateProfileId } from '../../core/analytics.profile-id';
2
+ import { constructGraphQLUrl } from '../../core/graphql';
3
+ import { AppEventsTracker } from '@streamscloud/streams-analytics-collector';
4
+ export class InternalShortVideoAnalyticsHandler {
5
+ constructor(graphqlOrigin) {
6
+ AppEventsTracker.setEndpoint(constructGraphQLUrl(graphqlOrigin));
7
+ AppEventsTracker.setProfileId(getOrCreateProfileId());
8
+ }
9
+ setOrganizationId = (organizationId) => AppEventsTracker.setOrganizationId(organizationId);
10
+ trackShortVideoView = (videoId) => AppEventsTracker.trackShortVideoView(videoId);
11
+ trackShortVideoProductImpression = (productId, videoId) => AppEventsTracker.trackShortVideoProductImpression(productId, videoId);
12
+ trackShortVideoProductClicked = (productId, videoId) => AppEventsTracker.trackShortVideoProductClick(productId, videoId);
13
+ }
@@ -19,7 +19,7 @@ import { InternalShortVideoPlayerProvider } from './internal-short-video-player-
19
19
  import { ShortVideosPlayerLocalization } from './short-videos-player-localization';
20
20
  import { ShortVideosPlayerUiManager } from './ui-manager.svelte';
21
21
  import { untrack } from 'svelte';
22
- let { dataProvider, socialInteractionsHandler, localization: localizationInit = 'en', showStreamsCloudWatermark, disableBackground, on, categoriesSwitcher, playerLogo = null, fadeContent = false } = $props();
22
+ let { dataProvider, socialInteractionsHandler, localization: localizationInit = 'en', showStreamsCloudWatermark, disableBackground, analyticsHandler, on, categoriesSwitcher, playerLogo = null, fadeContent = false } = $props();
23
23
  const localization = $derived(new ShortVideosPlayerLocalization(localizationInit));
24
24
  let everTouched = $state(false);
25
25
  let background = $state(null);
@@ -56,6 +56,7 @@ const onItemActivated = (id) => {
56
56
  return;
57
57
  }
58
58
  background = resolveVideoCover(shortVideo);
59
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoView(id);
59
60
  (_a = on === null || on === void 0 ? void 0 : on.videoActivated) === null || _a === void 0 ? void 0 : _a.call(on, id);
60
61
  };
61
62
  const resolveVideoCover = (shortVideo) => {
@@ -87,6 +88,12 @@ const onPlayerClose = () => {
87
88
  var _a;
88
89
  (_a = on === null || on === void 0 ? void 0 : on.playerClosed) === null || _a === void 0 ? void 0 : _a.call(on);
89
90
  };
91
+ const onShortVideoProductClick = (productId, videoId) => {
92
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProductClicked(productId, videoId);
93
+ };
94
+ const onShortVideoProductImpression = (productId, videoId) => {
95
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProductImpression(productId, videoId);
96
+ };
90
97
  </script>
91
98
 
92
99
  <svelte:document onkeydown={(e) => handleEsc(e, onPlayerClose)} />
@@ -127,7 +134,11 @@ const onPlayerClose = () => {
127
134
  autoplay="on-appearance"
128
135
  showAttachments={uiManager.showShortVideoOverlay}
129
136
  showControls={uiManager.showShortVideoOverlay}
130
- localization={localization.shortVideoViewerLocalization} />
137
+ localization={localization.shortVideoViewerLocalization}
138
+ on={{
139
+ productClick: (productId: string) => onShortVideoProductClick(productId, item.id),
140
+ productImpression: (productId: string, videoId: string) => onShortVideoProductImpression(productId, videoId)
141
+ }} />
131
142
  {/snippet}
132
143
  </PlayerSlider>
133
144
  {#if uiManager.isMobileView && buffer.loaded.length > 1 && !everTouched}
@@ -2,14 +2,22 @@ import type { Locale } from '../../core/locale';
2
2
  import type { ShortVideoViewerModel, IPostSocialInteractionsHandler } from '../short-video-viewer';
3
3
  import type { IPlayerItemsProvider } from '../../ui/player';
4
4
  import type { IShortVideosPlayerLocalization } from './short-videos-player-localization';
5
+ export interface IShortVideoAnalyticsHandler {
6
+ setOrganizationId: (organizationId: string) => void;
7
+ trackShortVideoView: (videoId: string) => void;
8
+ trackShortVideoProductImpression: (productId: string, videoId: string) => void;
9
+ trackShortVideoProductClicked: (productId: string, videoId: string) => void;
10
+ }
5
11
  export type ShortVideoPlayerProps = PlayerSettings & {
6
12
  dataProvider: IPlayerItemsProvider<ShortVideoViewerModel>;
13
+ analyticsHandler?: IShortVideoAnalyticsHandler;
7
14
  };
8
15
  export type PlayerSettings = {
9
16
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
10
17
  disableBackground?: boolean;
11
18
  localization?: IShortVideosPlayerLocalization | Locale;
12
19
  showStreamsCloudWatermark?: boolean;
20
+ analyticsHandler?: IShortVideoAnalyticsHandler;
13
21
  on?: {
14
22
  playerClosed?: () => void;
15
23
  videoActivated?: (id: string) => void;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">import { ProductCard } from '../products/product-card';
2
+ import { onMount } from 'svelte';
3
+ let { product, streamId, localization, includeBeforeNowPrefix, inert = false, on } = $props();
4
+ let productElement;
5
+ onMount(() => {
6
+ if (productElement && (on === null || on === void 0 ? void 0 : on.impression)) {
7
+ const observer = new IntersectionObserver((entries) => {
8
+ entries.forEach((entry) => {
9
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
10
+ on.impression(product.id, streamId);
11
+ observer.unobserve(entry.target);
12
+ }
13
+ });
14
+ }, { threshold: 0.5 });
15
+ observer.observe(productElement);
16
+ return () => {
17
+ observer.disconnect();
18
+ };
19
+ }
20
+ });
21
+ </script>
22
+
23
+ <div bind:this={productElement}>
24
+ <ProductCard product={product} localization={localization} includeBeforeNowPrefix={includeBeforeNowPrefix} inert={inert} on={on} />
25
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { Locale } from '../core/locale';
2
+ import type { IProductCardLocalization } from '../products/product-card/product-card-localization';
3
+ import type { ProductCardModel } from '../products/product-card/types';
4
+ type Props = {
5
+ product: ProductCardModel;
6
+ streamId: string;
7
+ localization?: IProductCardLocalization | Locale;
8
+ includeBeforeNowPrefix?: boolean;
9
+ inert?: boolean;
10
+ on?: {
11
+ productClick?: (id: string) => void;
12
+ impression?: (productId: string, streamId: string) => void;
13
+ };
14
+ };
15
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
16
+ type Cmp = ReturnType<typeof Cmp>;
17
+ export default Cmp;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">import { Utils } from '../../core/utils';
2
2
  import { StreamElementView } from './element-views';
3
3
  import { StreamComponentDataType } from './enums';
4
+ import { onMount } from 'svelte';
4
5
  let { model, localization, on } = $props();
5
6
  const component = $derived.by(() => {
6
7
  return model.components.find((c) => (model.data ? c.dataType === model.data.type : c.dataType === StreamComponentDataType.NoData));
@@ -39,6 +40,23 @@ const handleProductClick = (e) => {
39
40
  window.open(productModel.link, '_blank', 'noopener noreferrer');
40
41
  }
41
42
  };
43
+ let productElement = $state();
44
+ onMount(() => {
45
+ if (productElement && (productModel === null || productModel === void 0 ? void 0 : productModel.id) && (on === null || on === void 0 ? void 0 : on.productImpression)) {
46
+ const observer = new IntersectionObserver((entries) => {
47
+ entries.forEach((entry) => {
48
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
49
+ on.productImpression(productModel.id);
50
+ observer.unobserve(entry.target);
51
+ }
52
+ });
53
+ }, { threshold: 0.5 });
54
+ observer.observe(productElement);
55
+ return () => {
56
+ observer.disconnect();
57
+ };
58
+ }
59
+ });
42
60
  </script>
43
61
 
44
62
  {#snippet slotContent()}
@@ -49,11 +67,19 @@ const handleProductClick = (e) => {
49
67
  {/if}
50
68
  {/snippet}
51
69
  {#if productModel?.link}
52
- <a class="stream-slot-content-product-link" href={productModel.link} onclick={handleProductClick} target="_blank" rel="noopener noreferrer">
70
+ <a
71
+ class="stream-slot-content-product-link"
72
+ href={productModel.link}
73
+ onclick={handleProductClick}
74
+ target="_blank"
75
+ rel="noopener noreferrer"
76
+ bind:this={productElement}>
53
77
  {@render slotContent()}
54
78
  </a>
55
79
  {:else}
56
- {@render slotContent()}
80
+ <div bind:this={productElement}>
81
+ {@render slotContent()}
82
+ </div>
57
83
  {/if}
58
84
 
59
85
  <style>@keyframes fadeIn {
@@ -6,6 +6,7 @@ type Props = {
6
6
  localization: IStreamElementLocalization | Locale;
7
7
  on?: {
8
8
  productClick: (productId: string) => void;
9
+ productImpression?: (productId: string) => void;
9
10
  progress?: (videoId: string, progress: number) => void;
10
11
  };
11
12
  };
@@ -6,6 +6,7 @@ type Props = {
6
6
  localization: IStreamPageViewerLocalization | Locale;
7
7
  on?: {
8
8
  productClick: (productId: string) => void;
9
+ productImpression?: (productId: string) => void;
9
10
  progress?: (videoId: string, progress: number) => void;
10
11
  };
11
12
  };
@@ -82,7 +82,8 @@ const changeShowShortVideoAttachments = () => {
82
82
  shortVideo={shortVideo}
83
83
  localization={localization.shortVideoAttachmentsLocalization}
84
84
  on={{
85
- productClick: on.productClick
85
+ productClick: on.productClick,
86
+ productImpression: on.productImpression
86
87
  }} />
87
88
  </div>
88
89
  {/if}
@@ -10,6 +10,7 @@ type Props = {
10
10
  on: {
11
11
  closePlayer: () => void;
12
12
  productClick?: (productId: string) => void;
13
+ productImpression?: (productId: string) => void;
13
14
  };
14
15
  };
15
16
  declare const Controls: import("svelte").Component<Props, {}, "">;
@@ -4,9 +4,13 @@ export declare class InternalStreamAnalyticsHandler implements IStreamAnalyticsH
4
4
  setOrganizationId: (organizationId: string) => void;
5
5
  trackStreamView: (streamId: string) => void;
6
6
  trackStreamPageView: (pageId: string, streamId: string) => void;
7
- trackStreamProductClicked: (productId: string, streamId: string) => void;
8
7
  trackStreamEngagementTime: (streamId: string, engagementTime: number) => void;
9
8
  trackStreamScrollDepth: (streamId: string, scrollDepth: number) => void;
9
+ trackStreamProductImpression: (productId: string, streamId: string) => void;
10
+ trackStreamProductClicked: (productId: string, streamId: string) => void;
10
11
  reportPageVideoViews: (videoId: string, streamId: string) => void;
12
+ trackShortVideoView: (videoId: string) => void;
13
+ trackShortVideoProductImpression: (productId: string, videoId: string) => void;
14
+ trackShortVideoProductClicked: (productId: string, videoId: string) => void;
11
15
  trackShortVideoProgress: (pageId: string, videoId: string, progress: number, streamId: string) => void;
12
16
  }
@@ -9,9 +9,13 @@ export class InternalStreamAnalyticsHandler {
9
9
  setOrganizationId = (organizationId) => AppEventsTracker.setOrganizationId(organizationId);
10
10
  trackStreamView = (streamId) => AppEventsTracker.trackStreamView(streamId);
11
11
  trackStreamPageView = (pageId, streamId) => AppEventsTracker.trackStreamPageView(pageId, streamId);
12
- trackStreamProductClicked = (productId, streamId) => AppEventsTracker.trackStreamProductClicked(productId, streamId);
13
12
  trackStreamEngagementTime = (streamId, engagementTime) => AppEventsTracker.trackStreamEngagementTime(streamId, engagementTime);
14
13
  trackStreamScrollDepth = (streamId, scrollDepth) => AppEventsTracker.trackStreamScrollDepth(streamId, scrollDepth);
14
+ trackStreamProductImpression = (productId, streamId) => AppEventsTracker.trackStreamProductImpression(productId, streamId);
15
+ trackStreamProductClicked = (productId, streamId) => AppEventsTracker.trackStreamProductClicked(productId, streamId);
15
16
  reportPageVideoViews = (videoId, streamId) => AppEventsTracker.reportPageVideoViews(videoId, streamId);
17
+ trackShortVideoView = (videoId) => AppEventsTracker.trackShortVideoView(videoId);
18
+ trackShortVideoProductImpression = (productId, videoId) => AppEventsTracker.trackShortVideoProductImpression(productId, videoId);
19
+ trackShortVideoProductClicked = (productId, videoId) => AppEventsTracker.trackShortVideoProductClick(productId, videoId);
16
20
  trackShortVideoProgress = (pageId, videoId, progress, streamId) => AppEventsTracker.trackShortVideoProgress(pageId, videoId, progress, streamId);
17
21
  }
@@ -134,6 +134,9 @@ const onPageActivated = (id) => {
134
134
  background = (page === null || page === void 0 ? void 0 : page.cover) || null;
135
135
  if (page) {
136
136
  analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamPageView(id, streamId);
137
+ if (page.type === 'short-video' && page.shortVideo) {
138
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoView(page.shortVideo.id);
139
+ }
137
140
  const currentIndex = buffer === null || buffer === void 0 ? void 0 : buffer.loaded.findIndex((p) => p.id === id);
138
141
  if (currentIndex !== undefined && currentIndex > maxPageIndexViewed) {
139
142
  maxPageIndexViewed = currentIndex;
@@ -143,6 +146,15 @@ const onPageActivated = (id) => {
143
146
  const onProductCardClick = (productId) => {
144
147
  analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamProductClicked(productId, streamId);
145
148
  };
149
+ const onShortVideoProductClick = (productId, videoId) => {
150
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProductClicked(productId, videoId);
151
+ };
152
+ const onStreamProductImpression = (productId) => {
153
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackStreamProductImpression(productId, streamId);
154
+ };
155
+ const onShortVideoProductImpression = (productId, videoId) => {
156
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProductImpression(productId, videoId);
157
+ };
146
158
  const onPlayerClose = () => {
147
159
  var _a;
148
160
  stopActivityTracking();
@@ -191,13 +203,16 @@ const onProgress = (pageId, videoId, progress) => {
191
203
  localization={localization.streamPageViewerLocalization}
192
204
  on={{
193
205
  progress: (videoId: String, progress: Number) => onProgress(item.id, videoId, progress),
194
- productClick: (productId: String) => onProductCardClick(productId)
206
+ productClick: (productId: String) => onProductCardClick(productId),
207
+ productImpression: (productId: String) => onStreamProductImpression(productId)
195
208
  }} />
196
209
  {:else if item.type === 'short-video'}
197
210
  <ShortVideoViewer
198
211
  model={mapToShortVideoViewerModel(item.shortVideo)}
199
212
  on={{
200
- progress: (progress) => onProgress(item.id, item.shortVideo.id, progress)
213
+ progress: (progress) => onProgress(item.id, item.shortVideo.id, progress),
214
+ productClick: (productId: string) => onShortVideoProductClick(productId, item.shortVideo.id),
215
+ productImpression: (productId: string, videoId: string) => onShortVideoProductImpression(productId, videoId)
201
216
  }}
202
217
  autoplay="on-appearance"
203
218
  socialInteractionsHandler={postSocialInteractionsHandler}
@@ -231,7 +246,8 @@ const onProgress = (pageId, videoId, progress) => {
231
246
  postSocialInteractionsHandler={postSocialInteractionsHandler}
232
247
  on={{
233
248
  closePlayer: () => onPlayerClose(),
234
- productClick: (productId: String) => onProductCardClick(productId)
249
+ productClick: (productId: String) => onProductCardClick(productId),
250
+ productImpression: (productId: String) => onStreamProductImpression(productId)
235
251
  }} />
236
252
  {/if}
237
253
  </div>
@@ -44,9 +44,13 @@ export interface IStreamAnalyticsHandler {
44
44
  setOrganizationId: (organizationId: string) => void;
45
45
  trackStreamView: (streamId: string) => void;
46
46
  trackStreamPageView: (pageId: string, streamId: string) => void;
47
+ trackStreamProductImpression: (productId: string, streamId: string) => void;
47
48
  trackStreamProductClicked: (productId: string, streamId: string) => void;
48
49
  trackStreamEngagementTime: (streamId: string, engagementTime: number) => void;
49
50
  trackStreamScrollDepth: (streamId: string, scrollDepth: number) => void;
50
51
  reportPageVideoViews: (videoId: string, streamId: string) => void;
52
+ trackShortVideoView: (videoId: string) => void;
53
+ trackShortVideoProductImpression: (productId: string, videoId: string) => void;
54
+ trackShortVideoProductClicked: (productId: string, videoId: string) => void;
51
55
  trackShortVideoProgress: (pageId: string, videoId: string, progress: number, streamId: string) => void;
52
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/embeddable",
3
- "version": "6.3.2",
3
+ "version": "6.3.3",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -108,7 +108,7 @@
108
108
  },
109
109
  "peerDependencies": {
110
110
  "@fluentui/svg-icons": "^1.1.292",
111
- "@streamscloud/streams-analytics-collector": "^2.0.1",
111
+ "@streamscloud/streams-analytics-collector": "^2.0.9",
112
112
  "@urql/core": "^5.1.1",
113
113
  "dompurify": "^3.2.6",
114
114
  "mobile-detect": "^1.4.5",