@capillarytech/creatives-library 9.0.32 → 9.0.34-alpha.2
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/AppRoot.js +124 -0
- package/app-config.js +61 -0
- package/app.js +10 -175
- package/bootstrap.js +185 -0
- package/entry.js +67 -1
- package/mfe-exposed-components.js +2 -4
- package/package.json +2 -2
- package/services/api.js +9 -1
- package/styles/containers/layout/_layoutPage.scss +8 -6
- package/utils/getDataLayer.js +15 -0
- package/utils/gtmTrackers/gtmEvents/creativeDetails.js +2 -1
- package/utils/mfeDetect.js +1 -0
- package/utils/mfeFirstPaintReady.js +29 -0
- package/utils/mfeHistory.js +62 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +132 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +108 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +139 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +131 -0
- package/v2Components/CommonTestAndPreview/index.js +240 -26
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +364 -0
- package/v2Components/NavigationBar/index.js +9 -7
- package/v2Components/NavigationBar/mfeModuleHeader.config.js +16 -0
- package/v2Components/NavigationBar/tests/index.test.js +39 -19
- package/v2Containers/Cap/constants.js +1 -0
- package/v2Containers/Cap/index.js +57 -27
- package/v2Containers/Templates/_templates.scss +115 -1
- package/v2Containers/Templates/index.js +91 -10
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +5 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +8 -3
- package/v2Containers/TemplatesV2/index.js +22 -9
- package/v2Containers/Viber/constants.js +21 -0
- package/v2Containers/Viber/index.js +719 -49
- package/v2Containers/Viber/index.scss +175 -0
- package/v2Containers/Viber/messages.js +121 -0
- package/v2Containers/Viber/tests/index.test.js +80 -0
|
@@ -79,7 +79,6 @@
|
|
|
79
79
|
flex: 1;
|
|
80
80
|
height: calc(100vh - 50px);
|
|
81
81
|
overflow: auto;
|
|
82
|
-
padding: 8px 16px 0;
|
|
83
82
|
color: #333333;
|
|
84
83
|
}
|
|
85
84
|
|
|
@@ -154,16 +153,19 @@
|
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
.cap-loader-box {
|
|
157
|
-
position:
|
|
156
|
+
position: absolute;
|
|
158
157
|
top: 0;
|
|
158
|
+
left: 0;
|
|
159
159
|
width: 100%;
|
|
160
|
-
height:
|
|
161
|
-
background:
|
|
162
|
-
|
|
160
|
+
min-height: calc(100vh - 48px);
|
|
161
|
+
background: #ffffff;
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
justify-content: center;
|
|
163
165
|
|
|
164
166
|
.loader-image {
|
|
165
167
|
width: 80px;
|
|
166
|
-
|
|
168
|
+
height: auto;
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
171
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isMFEMode } from './mfeDetect';
|
|
2
|
+
import appConfig from '../app-config';
|
|
3
|
+
|
|
4
|
+
const getDataLayerName = () => {
|
|
5
|
+
if (isMFEMode()) {
|
|
6
|
+
return `dataLayer_${appConfig.appName.replace(/-/g, '_')}`;
|
|
7
|
+
}
|
|
8
|
+
return 'dataLayer';
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getDataLayer = () => {
|
|
12
|
+
const name = getDataLayerName();
|
|
13
|
+
window[name] = window[name] || [];
|
|
14
|
+
return window[name];
|
|
15
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CREATIVES } from "../../../v2Containers/App/constants";
|
|
2
|
+
import { getDataLayer } from '../../getDataLayer';
|
|
2
3
|
|
|
3
4
|
const creativeDetails = ({
|
|
4
5
|
name,
|
|
@@ -23,7 +24,7 @@ const creativeDetails = ({
|
|
|
23
24
|
videoAdded,
|
|
24
25
|
stickersAdded
|
|
25
26
|
};
|
|
26
|
-
|
|
27
|
+
getDataLayer().push({
|
|
27
28
|
creativeDetails: parsedObj,
|
|
28
29
|
event: 'creativeDetails',
|
|
29
30
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const isMFEMode = () => Boolean(window.MFE_HOST);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MFEEventBus } from '@capillarytech/cap-ui-utils';
|
|
2
|
+
import appConfig from '../app-config';
|
|
3
|
+
import { isMFEMode } from './mfeDetect';
|
|
4
|
+
|
|
5
|
+
// Routes whose containers emit the data-settled 'lcp' themselves —
|
|
6
|
+
// the first-paint emit must NOT fire for these.
|
|
7
|
+
// TemplatesV2 renders at relative '/v2' and '/v2/loyalty' (routes.js); in MFE mode
|
|
8
|
+
// the shared history is rebased on publicPath, so the real browser pathname carries
|
|
9
|
+
// the '/creatives/ui' prefix. Match the prefixed paths — this util reads
|
|
10
|
+
// window.location.pathname, not the rebased router location. (v1 standalone is
|
|
11
|
+
// non-MFE and irrelevant here.)
|
|
12
|
+
const DATA_LANDING_MATCHERS = ['/creatives/ui/v2', '/creatives/ui/v2/loyalty'];
|
|
13
|
+
|
|
14
|
+
export const isDataLandingPath = (pathname) => {
|
|
15
|
+
const p = (pathname || '').replace(/\/+$/, '') || '/';
|
|
16
|
+
return DATA_LANDING_MATCHERS.some((m) => (m instanceof RegExp ? m.test(p) : m === p));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const emitFirstPaintReadyIfNotDataLanding = () => {
|
|
20
|
+
if (!isMFEMode() || isDataLandingPath(window.location.pathname)) return;
|
|
21
|
+
requestAnimationFrame(() => {
|
|
22
|
+
MFEEventBus.emit('mfe:segment', {
|
|
23
|
+
action: 'stop',
|
|
24
|
+
appId: appConfig.appName,
|
|
25
|
+
type: 'lcp',
|
|
26
|
+
timestamp: performance.now(),
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-base the host's shared root history for this MFE remote.
|
|
3
|
+
*
|
|
4
|
+
* The MFE host owns ONE root history instance and hands it to every remote, so host + all
|
|
5
|
+
* remotes stay perfectly in sync: a push on the shared instance notifies every mounted
|
|
6
|
+
* router directly (no popstate hack, no drift on fast remote switching).
|
|
7
|
+
*
|
|
8
|
+
* This remote's routes / <Link>s / history.push calls are written RELATIVE to its serving
|
|
9
|
+
* prefix. This adapter presents a basename'd VIEW of the shared history — stripping the
|
|
10
|
+
* prefix when the router reads the location, and prepending it when the router navigates —
|
|
11
|
+
* while delegating all actual navigation to the shared instance. Net effect: relative
|
|
12
|
+
* routing keeps working unchanged, and navigation still flows through the single shared
|
|
13
|
+
* history. Standalone (no host history) is unaffected; the remote keeps creating its own.
|
|
14
|
+
*/
|
|
15
|
+
const addBase = (base, to) => {
|
|
16
|
+
if (typeof to === 'string') {
|
|
17
|
+
if (!to.startsWith('/')) return to; // already relative to current location
|
|
18
|
+
return to === '/' ? base : `${base}${to}`;
|
|
19
|
+
}
|
|
20
|
+
if (to && typeof to === 'object') {
|
|
21
|
+
return { ...to, pathname: addBase(base, to.pathname || '/') };
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const stripBase = (base, pathname) => {
|
|
27
|
+
if (!pathname) return pathname;
|
|
28
|
+
if (pathname === base) return '/';
|
|
29
|
+
if (pathname.startsWith(`${base}/`)) return pathname.slice(base.length);
|
|
30
|
+
return pathname;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default function rebaseHistory(history, rawBase) {
|
|
34
|
+
const base = String(rawBase || '').replace(/\/+$/, ''); // normalise: no trailing slash
|
|
35
|
+
if (!base) return history;
|
|
36
|
+
const view = loc => ({ ...loc, pathname: stripBase(base, loc.pathname) });
|
|
37
|
+
return {
|
|
38
|
+
get length() {
|
|
39
|
+
return history.length;
|
|
40
|
+
},
|
|
41
|
+
get action() {
|
|
42
|
+
return history.action;
|
|
43
|
+
},
|
|
44
|
+
get location() {
|
|
45
|
+
return view(history.location);
|
|
46
|
+
},
|
|
47
|
+
push: (to, state) => history.push(addBase(base, to), state),
|
|
48
|
+
replace: (to, state) => history.replace(addBase(base, to), state),
|
|
49
|
+
go: n => history.go(n),
|
|
50
|
+
goBack: () => history.goBack(),
|
|
51
|
+
goForward: () => history.goForward(),
|
|
52
|
+
block: (...args) => history.block(...args),
|
|
53
|
+
listen: listener =>
|
|
54
|
+
history.listen((loc, action) => listener(view(loc), action)),
|
|
55
|
+
createHref: to =>
|
|
56
|
+
history.createHref(
|
|
57
|
+
typeof to === 'string'
|
|
58
|
+
? addBase(base, to)
|
|
59
|
+
: { ...to, pathname: addBase(base, (to && to.pathname) || '/') },
|
|
60
|
+
),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
4
|
+
import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
|
|
5
|
+
import CapImage from '@capillarytech/cap-ui-library/CapImage';
|
|
6
|
+
|
|
7
|
+
const getTrimmedText = (value = '') => (value ?? '').trim();
|
|
8
|
+
const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
|
|
9
|
+
|
|
10
|
+
const getCarouselButtonsWithTitles = (card) => (
|
|
11
|
+
(card?.buttons ?? []).filter((button) => hasTrimmedText(button?.title)).slice(0, 2)
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const getCarouselButtonSlotCount = (cards = []) => {
|
|
15
|
+
const buttonCounts = cards.map((card) => getCarouselButtonsWithTitles(card).length);
|
|
16
|
+
return Math.min(2, Math.max(0, ...buttonCounts, 0));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ViberCarouselPreviewCards = ({ cards = [] }) => {
|
|
20
|
+
const previewCards = Array.isArray(cards) && cards.length ? cards : [{}];
|
|
21
|
+
const carouselButtonSlotCount = useMemo(
|
|
22
|
+
() => getCarouselButtonSlotCount(previewCards),
|
|
23
|
+
[previewCards],
|
|
24
|
+
);
|
|
25
|
+
const carouselTitleRefs = useRef([]);
|
|
26
|
+
const [carouselTitleLineCount, setCarouselTitleLineCount] = useState(1);
|
|
27
|
+
|
|
28
|
+
carouselTitleRefs.current = previewCards.map(() => null);
|
|
29
|
+
|
|
30
|
+
useLayoutEffect(() => {
|
|
31
|
+
let maxLines = 1;
|
|
32
|
+
carouselTitleRefs.current.forEach((node) => {
|
|
33
|
+
if (!node) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const { lineHeight } = window.getComputedStyle(node);
|
|
37
|
+
const parsedLineHeight = parseFloat(lineHeight) || 18;
|
|
38
|
+
const lines = Math.min(2, Math.max(1, Math.round(node.scrollHeight / parsedLineHeight)));
|
|
39
|
+
if (lines > maxLines) {
|
|
40
|
+
maxLines = lines;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
setCarouselTitleLineCount((prev) => (prev === maxLines ? prev : maxLines));
|
|
44
|
+
}, [previewCards]);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<CapRow type="flex" noWrap className="viber-carousel-preview-scroll">
|
|
48
|
+
{previewCards.map((card, index) => {
|
|
49
|
+
const cardButtons = getCarouselButtonsWithTitles(card);
|
|
50
|
+
const titleLineClass = `viber-carousel-preview-text-wrap--${carouselTitleLineCount}-line`;
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<CapRow type="flex-column" className="viber-carousel-preview-card" key={`viber-carousel-preview-card-${index}`}>
|
|
54
|
+
{hasTrimmedText(card?.mediaUrl) ? (
|
|
55
|
+
<CapImage
|
|
56
|
+
src={card?.mediaUrl}
|
|
57
|
+
className="viber-carousel-preview-image"
|
|
58
|
+
alt="Viber carousel card"
|
|
59
|
+
/>
|
|
60
|
+
) : (
|
|
61
|
+
<CapRow className="viber-carousel-preview-image-placeholder" />
|
|
62
|
+
)}
|
|
63
|
+
<CapRow className="viber-carousel-preview-card-body">
|
|
64
|
+
<CapRow className={`viber-carousel-preview-text-wrap ${titleLineClass}`}>
|
|
65
|
+
{hasTrimmedText(card?.text) ? (
|
|
66
|
+
<CapRow
|
|
67
|
+
className="viber-carousel-preview-text-inner"
|
|
68
|
+
ref={(node) => {
|
|
69
|
+
carouselTitleRefs.current[index] = node;
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<CapLabel type="label15" className="viber-carousel-preview-text">
|
|
73
|
+
{card?.text}
|
|
74
|
+
</CapLabel>
|
|
75
|
+
</CapRow>
|
|
76
|
+
) : (
|
|
77
|
+
<CapLabel type="label15" className="viber-carousel-preview-text-placeholder" />
|
|
78
|
+
)}
|
|
79
|
+
</CapRow>
|
|
80
|
+
{carouselButtonSlotCount > 0 && (
|
|
81
|
+
<CapRow className="viber-carousel-preview-buttons">
|
|
82
|
+
{Array.from({ length: carouselButtonSlotCount }).map((_, btnIndex) => {
|
|
83
|
+
const cardButton = cardButtons[btnIndex];
|
|
84
|
+
const trimmedCardButtonTitle = cardButton
|
|
85
|
+
? getTrimmedText(cardButton?.title)
|
|
86
|
+
: '';
|
|
87
|
+
|
|
88
|
+
if (!trimmedCardButtonTitle) {
|
|
89
|
+
return (
|
|
90
|
+
<CapRow
|
|
91
|
+
className="viber-carousel-preview-button viber-carousel-preview-button-placeholder"
|
|
92
|
+
key={`viber-carousel-preview-btn-placeholder-${index}-${btnIndex}`}
|
|
93
|
+
aria-hidden="true"
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<CapLabel
|
|
100
|
+
className={`viber-carousel-preview-button ${btnIndex === 1 ? 'viber-carousel-preview-button-secondary' : ''}`}
|
|
101
|
+
key={`viber-carousel-preview-btn-${index}-${btnIndex}-${trimmedCardButtonTitle}`}
|
|
102
|
+
>
|
|
103
|
+
{trimmedCardButtonTitle}
|
|
104
|
+
</CapLabel>
|
|
105
|
+
);
|
|
106
|
+
})}
|
|
107
|
+
</CapRow>
|
|
108
|
+
)}
|
|
109
|
+
</CapRow>
|
|
110
|
+
</CapRow>
|
|
111
|
+
);
|
|
112
|
+
})}
|
|
113
|
+
</CapRow>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
ViberCarouselPreviewCards.propTypes = {
|
|
118
|
+
cards: PropTypes.arrayOf(PropTypes.shape({
|
|
119
|
+
text: PropTypes.string,
|
|
120
|
+
mediaUrl: PropTypes.string,
|
|
121
|
+
buttons: PropTypes.arrayOf(PropTypes.shape({
|
|
122
|
+
title: PropTypes.string,
|
|
123
|
+
action: PropTypes.string,
|
|
124
|
+
})),
|
|
125
|
+
})),
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
ViberCarouselPreviewCards.defaultProps = {
|
|
129
|
+
cards: [],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export default ViberCarouselPreviewCards;
|
|
@@ -14,14 +14,25 @@ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
|
14
14
|
import CapImage from '@capillarytech/cap-ui-library/CapImage';
|
|
15
15
|
import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
|
|
16
16
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
ANDROID,
|
|
19
|
+
IOS,
|
|
20
|
+
ANDROID_DEVICE_NAME,
|
|
21
|
+
IOS_DEVICE_NAME,
|
|
22
|
+
VIBER_ACCOUNT_NAME,
|
|
23
|
+
MEDIA_TYPE_CAROUSEL,
|
|
24
|
+
} from '../constants';
|
|
18
25
|
import messages from '../messages';
|
|
19
26
|
import videoPlay from '../../../assets/videoPlay.svg';
|
|
27
|
+
import ViberCarouselPreviewCards from './ViberCarouselPreviewCards';
|
|
20
28
|
|
|
21
29
|
// Import device mockup images (same as SMS)
|
|
22
30
|
const smsMobileAndroid = require('../../../assets/Android.png');
|
|
23
31
|
const smsMobileIos = require('../../../assets/iOS.png');
|
|
24
32
|
|
|
33
|
+
const getTrimmedText = (value = '') => (value ?? '').trim();
|
|
34
|
+
const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
|
|
35
|
+
|
|
25
36
|
const ViberPreviewContent = ({
|
|
26
37
|
content,
|
|
27
38
|
device,
|
|
@@ -43,7 +54,35 @@ const ViberPreviewContent = ({
|
|
|
43
54
|
imageURL = '',
|
|
44
55
|
videoParams = {},
|
|
45
56
|
buttonText = '',
|
|
57
|
+
type = '',
|
|
58
|
+
cards = [],
|
|
59
|
+
showCarouselEditorPreview = false,
|
|
46
60
|
} = viberContent;
|
|
61
|
+
const hasCarouselContent = type === MEDIA_TYPE_CAROUSEL;
|
|
62
|
+
|
|
63
|
+
const cardHasMeaningfulContent = (card) => {
|
|
64
|
+
if (!card || typeof card !== 'object') return false;
|
|
65
|
+
return (
|
|
66
|
+
hasTrimmedText(card?.text) ||
|
|
67
|
+
hasTrimmedText(card?.mediaUrl) ||
|
|
68
|
+
(card.buttons ?? []).some(button => hasTrimmedText(button?.title))
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const hasMeaningfulCarousel =
|
|
73
|
+
hasCarouselContent &&
|
|
74
|
+
Array.isArray(cards) &&
|
|
75
|
+
cards.length > 0 &&
|
|
76
|
+
cards.some(cardHasMeaningfulContent);
|
|
77
|
+
|
|
78
|
+
const showCarouselInPreview =
|
|
79
|
+
hasCarouselContent && (Boolean(showCarouselEditorPreview) || hasMeaningfulCarousel);
|
|
80
|
+
|
|
81
|
+
const previewCarouselCards =
|
|
82
|
+
hasCarouselContent && Array.isArray(cards) && cards.length ? cards : hasCarouselContent ? [{}] : [];
|
|
83
|
+
|
|
84
|
+
const trimmedMessageContent = getTrimmedText(messageContent);
|
|
85
|
+
const trimmedButtonText = getTrimmedText(buttonText);
|
|
47
86
|
|
|
48
87
|
// Get account name (first letter for icon)
|
|
49
88
|
const accountIcon = (accountName || brandName || 'V')[0]?.toUpperCase();
|
|
@@ -99,8 +138,15 @@ const ViberPreviewContent = ({
|
|
|
99
138
|
);
|
|
100
139
|
}
|
|
101
140
|
|
|
102
|
-
// Check if there's any content to display
|
|
103
|
-
const hasContent =
|
|
141
|
+
// Check if there's any content to display (whitespace-only strings do not count)
|
|
142
|
+
const hasContent = Boolean(
|
|
143
|
+
trimmedMessageContent
|
|
144
|
+
|| hasTrimmedText(imageURL)
|
|
145
|
+
|| videoParams?.viberVideoSrc
|
|
146
|
+
|| trimmedButtonText
|
|
147
|
+
|| hasMeaningfulCarousel
|
|
148
|
+
|| (hasCarouselContent && showCarouselEditorPreview)
|
|
149
|
+
);
|
|
104
150
|
|
|
105
151
|
// Render normal Viber preview
|
|
106
152
|
return (
|
|
@@ -125,23 +171,34 @@ const ViberPreviewContent = ({
|
|
|
125
171
|
|
|
126
172
|
{/* Viber Message Container */}
|
|
127
173
|
{hasContent && (
|
|
128
|
-
<CapRow className={`viber-message-container ${device !== ANDROID ? 'viber-message-container-ios' : ''}`}>
|
|
174
|
+
<CapRow className={`viber-message-container ${showCarouselInPreview ? 'viber-message-container-carousel' : ''} ${device !== ANDROID ? 'viber-message-container-ios' : ''}`}>
|
|
129
175
|
{/* Brand Name Display (from TemplatePreview line 1136) */}
|
|
130
|
-
<CapRow
|
|
176
|
+
<CapRow
|
|
177
|
+
type="flex"
|
|
178
|
+
align="middle"
|
|
179
|
+
fullWidth={showCarouselInPreview}
|
|
180
|
+
className={`msg-container viber-preview ${showCarouselInPreview ? 'viber-preview-carousel' : ''}`}
|
|
181
|
+
>
|
|
131
182
|
{/* Account Icon (from TemplatePreview line 1146-1160) */}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
183
|
+
{!hasCarouselContent && (
|
|
184
|
+
<CapRow type="flex" className="viber-account-icon">
|
|
185
|
+
{accountIcon}
|
|
186
|
+
</CapRow>
|
|
187
|
+
)}
|
|
135
188
|
|
|
136
189
|
{/* Message Bubble (from TemplatePreview line 1161-1223) */}
|
|
137
|
-
<CapRow
|
|
190
|
+
<CapRow
|
|
191
|
+
useLegacy
|
|
192
|
+
fullWidth={showCarouselInPreview}
|
|
193
|
+
className={`message-pop align-left viber-message-pop ${showCarouselInPreview ? 'viber-message-pop-carousel' : ''}`}
|
|
194
|
+
>
|
|
138
195
|
{/* Text Viber preview */}
|
|
139
|
-
{
|
|
196
|
+
{trimmedMessageContent && !hasCarouselContent && (
|
|
140
197
|
<CapLabel type="label15" className="viber-message-text">{messageContent}</CapLabel>
|
|
141
198
|
)}
|
|
142
199
|
|
|
143
200
|
{/* Image Viber preview */}
|
|
144
|
-
{imageURL && (
|
|
201
|
+
{hasTrimmedText(imageURL) && (
|
|
145
202
|
<CapImage
|
|
146
203
|
src={imageURL}
|
|
147
204
|
className="viber-image-preview"
|
|
@@ -171,16 +228,42 @@ const ViberPreviewContent = ({
|
|
|
171
228
|
)}
|
|
172
229
|
|
|
173
230
|
{/* Button Viber preview */}
|
|
174
|
-
{
|
|
231
|
+
{trimmedButtonText && (
|
|
175
232
|
<CapLabel className="viber-button-base">
|
|
176
233
|
<p className="viber-button-card-text">
|
|
177
234
|
{buttonText}
|
|
178
235
|
</p>
|
|
179
236
|
</CapLabel>
|
|
180
237
|
)}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
238
|
+
{/* Carousel Viber preview */}
|
|
239
|
+
{showCarouselInPreview && (
|
|
240
|
+
<CapRow type="flex-column" fullWidth className="viber-carousel-preview">
|
|
241
|
+
<CapRow type="flex-column" className="viber-carousel-message-pop">
|
|
242
|
+
{trimmedMessageContent ? (
|
|
243
|
+
<CapLabel
|
|
244
|
+
type="label15"
|
|
245
|
+
className="message-pop-item align-left viber-message-text viber-carousel-message-box-text"
|
|
246
|
+
>
|
|
247
|
+
{messageContent}
|
|
248
|
+
</CapLabel>
|
|
249
|
+
) : (
|
|
250
|
+
<CapRow className="viber-carousel-message-box-placeholder" />
|
|
251
|
+
)}
|
|
252
|
+
<CapLabel type="label1" className="viber-carousel-message-timestamp">
|
|
253
|
+
{timestamp}
|
|
254
|
+
</CapLabel>
|
|
255
|
+
</CapRow>
|
|
256
|
+
|
|
257
|
+
<CapRow type="flex-column" fullWidth className="viber-carousel-cards-pop">
|
|
258
|
+
<ViberCarouselPreviewCards cards={previewCarouselCards} />
|
|
259
|
+
</CapRow>
|
|
260
|
+
</CapRow>
|
|
261
|
+
)}
|
|
262
|
+
{!showCarouselInPreview && (
|
|
263
|
+
<CapLabel type="label1" className="viber-timestamp">
|
|
264
|
+
{timestamp}
|
|
265
|
+
</CapLabel>
|
|
266
|
+
)}
|
|
184
267
|
<CapRow useLegacy className="empty-placeholder" />
|
|
185
268
|
</CapRow>
|
|
186
269
|
|
|
@@ -214,6 +297,16 @@ ViberPreviewContent.propTypes = {
|
|
|
214
297
|
viberVideoPreviewImg: PropTypes.string,
|
|
215
298
|
}),
|
|
216
299
|
buttonText: PropTypes.string,
|
|
300
|
+
type: PropTypes.string,
|
|
301
|
+
cards: PropTypes.arrayOf(PropTypes.shape({
|
|
302
|
+
text: PropTypes.string,
|
|
303
|
+
mediaUrl: PropTypes.string,
|
|
304
|
+
buttons: PropTypes.arrayOf(PropTypes.shape({
|
|
305
|
+
title: PropTypes.string,
|
|
306
|
+
action: PropTypes.string,
|
|
307
|
+
})),
|
|
308
|
+
})),
|
|
309
|
+
showCarouselEditorPreview: PropTypes.bool,
|
|
217
310
|
}),
|
|
218
311
|
}),
|
|
219
312
|
device: PropTypes.oneOf([ANDROID, IOS]),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import '~@capillarytech/cap-ui-library/styles/_variables';
|
|
2
|
+
@import './_viberCarouselPreviewCards.scss';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* UnifiedPreview Styles
|
|
@@ -782,9 +783,13 @@
|
|
|
782
783
|
|
|
783
784
|
.viber-content-overlay {
|
|
784
785
|
top: 3.2rem;
|
|
785
|
-
|
|
786
|
+
overflow: hidden;
|
|
787
|
+
|
|
788
|
+
.sms-navigation-bar.viber-navigation-bar {
|
|
789
|
+
width: calc(100% - #{$CAP_SPACE_06} - #{$CAP_SPACE_08});
|
|
786
790
|
margin-left: $CAP_SPACE_06;
|
|
787
791
|
margin-right: $CAP_SPACE_08;
|
|
792
|
+
box-sizing: border-box;
|
|
788
793
|
}
|
|
789
794
|
}
|
|
790
795
|
|
|
@@ -2407,12 +2412,21 @@
|
|
|
2407
2412
|
// Body content follows TemplatePreview Viber structure
|
|
2408
2413
|
.sms-content-overlay {
|
|
2409
2414
|
&.viber-preview {
|
|
2415
|
+
overflow: hidden;
|
|
2416
|
+
|
|
2410
2417
|
// Viber message container
|
|
2411
2418
|
.viber-message-container {
|
|
2412
2419
|
position: relative;
|
|
2413
2420
|
flex: 1;
|
|
2414
2421
|
display: flex;
|
|
2415
2422
|
flex-direction: column;
|
|
2423
|
+
overflow-x: hidden;
|
|
2424
|
+
overflow-y: auto;
|
|
2425
|
+
-webkit-overflow-scrolling: touch;
|
|
2426
|
+
min-width: 0;
|
|
2427
|
+
max-width: 100%;
|
|
2428
|
+
box-sizing: border-box;
|
|
2429
|
+
width: calc(100% - #{$CAP_SPACE_06} - #{$CAP_SPACE_08});
|
|
2416
2430
|
padding: 0 $CAP_SPACE_16;
|
|
2417
2431
|
background-color: #ffffff;
|
|
2418
2432
|
margin-left: $CAP_SPACE_06;
|
|
@@ -2420,6 +2434,20 @@
|
|
|
2420
2434
|
border-bottom-left-radius: 2.6rem;
|
|
2421
2435
|
border-bottom-right-radius: 2.6rem;
|
|
2422
2436
|
|
|
2437
|
+
&.viber-message-container-carousel {
|
|
2438
|
+
padding-left: $CAP_SPACE_08;
|
|
2439
|
+
padding-right: $CAP_SPACE_08;
|
|
2440
|
+
width: calc(100% - #{$CAP_SPACE_04} - #{$CAP_SPACE_04});
|
|
2441
|
+
margin-left: $CAP_SPACE_04;
|
|
2442
|
+
margin-right: $CAP_SPACE_04;
|
|
2443
|
+
|
|
2444
|
+
> .ant-row,
|
|
2445
|
+
.ant-row.msg-container.viber-preview-carousel {
|
|
2446
|
+
margin-left: 0;
|
|
2447
|
+
margin-right: 0;
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2423
2451
|
// Brand name display (from TemplatePreview line 1136)
|
|
2424
2452
|
.viber-brand-name {
|
|
2425
2453
|
position: absolute;
|
|
@@ -2441,6 +2469,16 @@
|
|
|
2441
2469
|
flex-direction: row;
|
|
2442
2470
|
align-items: start;
|
|
2443
2471
|
|
|
2472
|
+
&.viber-preview-carousel {
|
|
2473
|
+
width: 100%;
|
|
2474
|
+
max-width: 100%;
|
|
2475
|
+
margin-left: 0;
|
|
2476
|
+
margin-right: 0;
|
|
2477
|
+
max-height: 100%;
|
|
2478
|
+
min-width: 0;
|
|
2479
|
+
box-sizing: border-box;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2444
2482
|
// Account icon (from TemplatePreview line 1146-1160)
|
|
2445
2483
|
.viber-account-icon {
|
|
2446
2484
|
width: $CAP_SPACE_20;
|
|
@@ -2465,6 +2503,22 @@
|
|
|
2465
2503
|
border-radius: $CAP_SPACE_04;
|
|
2466
2504
|
padding: $CAP_SPACE_04;
|
|
2467
2505
|
|
|
2506
|
+
&.viber-message-pop-carousel {
|
|
2507
|
+
width: 100%;
|
|
2508
|
+
max-width: 100%;
|
|
2509
|
+
min-width: 0;
|
|
2510
|
+
left: 0;
|
|
2511
|
+
margin-top: 0;
|
|
2512
|
+
padding: 0;
|
|
2513
|
+
background: transparent;
|
|
2514
|
+
display: flex;
|
|
2515
|
+
flex-direction: column;
|
|
2516
|
+
align-items: flex-start;
|
|
2517
|
+
gap: $CAP_SPACE_06;
|
|
2518
|
+
overflow: hidden;
|
|
2519
|
+
box-sizing: border-box;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2468
2522
|
// Text Viber preview (from TemplatePreview line 1166-1174)
|
|
2469
2523
|
.viber-message-text {
|
|
2470
2524
|
margin: 0.107rem $CAP_SPACE_06 $CAP_SPACE_01 0.5rem;
|
|
@@ -2536,6 +2590,85 @@
|
|
|
2536
2590
|
}
|
|
2537
2591
|
}
|
|
2538
2592
|
|
|
2593
|
+
.viber-carousel-preview {
|
|
2594
|
+
width: 100%;
|
|
2595
|
+
max-width: 100%;
|
|
2596
|
+
min-width: 0;
|
|
2597
|
+
display: flex;
|
|
2598
|
+
flex-direction: column;
|
|
2599
|
+
align-items: flex-start;
|
|
2600
|
+
gap: $CAP_SPACE_06;
|
|
2601
|
+
overflow: hidden;
|
|
2602
|
+
box-sizing: border-box;
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
.viber-carousel-message-pop,
|
|
2606
|
+
.viber-carousel-cards-pop {
|
|
2607
|
+
width: 100%;
|
|
2608
|
+
max-width: 100%;
|
|
2609
|
+
min-width: 0;
|
|
2610
|
+
background: $CAP_G08;
|
|
2611
|
+
border-radius: $CAP_SPACE_06;
|
|
2612
|
+
padding: $CAP_SPACE_08;
|
|
2613
|
+
box-sizing: border-box;
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
.viber-carousel-message-pop {
|
|
2617
|
+
margin-top: 0;
|
|
2618
|
+
width: 85%;
|
|
2619
|
+
border-radius: 0 $CAP_SPACE_06 $CAP_SPACE_06 $CAP_SPACE_06;
|
|
2620
|
+
display: flex;
|
|
2621
|
+
flex-direction: column;
|
|
2622
|
+
overflow: hidden;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
.viber-carousel-cards-pop {
|
|
2626
|
+
margin-top: 0;
|
|
2627
|
+
width: 100%;
|
|
2628
|
+
background: transparent;
|
|
2629
|
+
border: none;
|
|
2630
|
+
border-radius: 0;
|
|
2631
|
+
padding: 0;
|
|
2632
|
+
overflow: hidden;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
.viber-carousel-message-box {
|
|
2636
|
+
width: 100%;
|
|
2637
|
+
min-height: 2.25rem;
|
|
2638
|
+
height: auto;
|
|
2639
|
+
border-radius: $CAP_SPACE_04;
|
|
2640
|
+
background: transparent;
|
|
2641
|
+
padding: 0 $CAP_SPACE_08;
|
|
2642
|
+
display: flex;
|
|
2643
|
+
align-items: center;
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
.viber-carousel-message-box-text {
|
|
2647
|
+
color: $CAP_G01;
|
|
2648
|
+
margin: 0.107rem $CAP_SPACE_06 $CAP_SPACE_01 0.5rem;
|
|
2649
|
+
white-space: normal;
|
|
2650
|
+
word-break: break-word;
|
|
2651
|
+
overflow-wrap: break-word;
|
|
2652
|
+
overflow: hidden;
|
|
2653
|
+
max-width: 100%;
|
|
2654
|
+
box-sizing: border-box;
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
.viber-carousel-message-box-placeholder {
|
|
2658
|
+
width: 100%;
|
|
2659
|
+
height: 0.875rem;
|
|
2660
|
+
border-radius: $CAP_SPACE_04;
|
|
2661
|
+
background: $CAP_G07;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
.viber-carousel-message-timestamp,
|
|
2665
|
+
.viber-carousel-cards-timestamp {
|
|
2666
|
+
display: block;
|
|
2667
|
+
text-align: right;
|
|
2668
|
+
margin-top: $CAP_SPACE_06;
|
|
2669
|
+
color: $CAP_G04;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2539
2672
|
.empty-placeholder {
|
|
2540
2673
|
height: $CAP_SPACE_08;
|
|
2541
2674
|
}
|
|
@@ -2549,6 +2682,11 @@
|
|
|
2549
2682
|
.viber-message-container-ios {
|
|
2550
2683
|
margin-left: 1rem;
|
|
2551
2684
|
margin-right: 1rem;
|
|
2685
|
+
|
|
2686
|
+
&.viber-message-container-carousel {
|
|
2687
|
+
margin-left: $CAP_SPACE_04;
|
|
2688
|
+
margin-right: $CAP_SPACE_04;
|
|
2689
|
+
}
|
|
2552
2690
|
}
|
|
2553
2691
|
}
|
|
2554
2692
|
}
|