@capillarytech/creatives-library 8.0.292-alpha.14 → 8.0.292-alpha.17
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/package.json +1 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/InAppPreviewContent.js +95 -59
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +40 -1
- package/v2Components/CommonTestAndPreview/constants.js +39 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +3 -3
- package/v2Containers/InApp/index.js +57 -37
package/package.json
CHANGED
|
@@ -15,13 +15,34 @@ import CapImage from '@capillarytech/cap-ui-library/CapImage';
|
|
|
15
15
|
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
16
16
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
17
17
|
import isEmpty from 'lodash/isEmpty';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
ANDROID,
|
|
20
|
+
IOS,
|
|
21
|
+
LAYOUT_TYPE_POPUP,
|
|
22
|
+
LAYOUT_TYPE_HEADER,
|
|
23
|
+
LAYOUT_TYPE_FOOTER,
|
|
24
|
+
LAYOUT_TYPE_FULLSCREEN,
|
|
25
|
+
ANDROID_DEVICE_NAME,
|
|
26
|
+
IOS_DEVICE_NAME,
|
|
27
|
+
CHANNELS,
|
|
28
|
+
INAPP_HTML_LAYOUT_POSITIONS,
|
|
29
|
+
} from '../constants';
|
|
19
30
|
import messages from '../messages';
|
|
20
31
|
|
|
21
32
|
// Import device mockup images (same as SMS)
|
|
22
33
|
const smsMobileAndroid = require('../../../assets/Android.png');
|
|
23
34
|
const smsMobileIos = require('../../../assets/iOS.png');
|
|
24
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Detects if a string is HTML content (e.g. from HtmlEditor InApp template).
|
|
38
|
+
* Used to render HTML in an iframe (like InAppPreviewPane/ContentOverlay) instead of as plain text.
|
|
39
|
+
*/
|
|
40
|
+
const isHtmlContent = (str) => {
|
|
41
|
+
if (typeof str !== 'string' || !str.trim()) return false;
|
|
42
|
+
const trimmed = str.trim();
|
|
43
|
+
return trimmed.startsWith('<') && (trimmed.includes('>') || trimmed.includes('/'));
|
|
44
|
+
};
|
|
45
|
+
|
|
25
46
|
const InAppPreviewContent = ({
|
|
26
47
|
content,
|
|
27
48
|
device,
|
|
@@ -51,6 +72,12 @@ const InAppPreviewContent = ({
|
|
|
51
72
|
templateLayoutType: deviceLayoutType = templateLayoutType || LAYOUT_TYPE_POPUP,
|
|
52
73
|
} = deviceContent || {};
|
|
53
74
|
|
|
75
|
+
// When templateMsg is HTML (e.g. from HtmlEditor), render it in an iframe like InAppPreviewPane/ContentOverlay
|
|
76
|
+
const renderAsHtml = isHtmlContent(templateMsg);
|
|
77
|
+
|
|
78
|
+
// Layout positioning for HTML preview (modal, top banner, bottom banner, fullscreen) - match side-by-side ContentOverlay
|
|
79
|
+
const htmlLayoutKey = deviceLayoutType || LAYOUT_TYPE_POPUP;
|
|
80
|
+
const htmlLayoutPosition = INAPP_HTML_LAYOUT_POSITIONS[htmlLayoutKey] || INAPP_HTML_LAYOUT_POSITIONS[LAYOUT_TYPE_POPUP];
|
|
54
81
|
|
|
55
82
|
// Render loading state
|
|
56
83
|
if (isUpdating) {
|
|
@@ -106,76 +133,85 @@ const InAppPreviewContent = ({
|
|
|
106
133
|
alt={`${deviceName} Device`}
|
|
107
134
|
/>
|
|
108
135
|
|
|
109
|
-
{/* Content Overlay - Use TemplatePreview's InApp structure (
|
|
136
|
+
{/* Content Overlay - Use TemplatePreview's InApp structure or iframe for HTML (like InAppPreviewPane) */}
|
|
110
137
|
<CapRow className={`sms-content-overlay inapp-content-overlay-height ${!showHeader ? 'inapp-content-overlay' : ''} sms-${device}`}>
|
|
111
|
-
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
{renderAsHtml ? (
|
|
139
|
+
/* HTML content from HtmlEditor: position by layout (modal/top/bottom/fullscreen) like side-by-side ContentOverlay */
|
|
140
|
+
<div
|
|
141
|
+
className={`inapp-html-preview-iframe-wrapper inapp-html-preview-iframe-wrapper--${(htmlLayoutKey || '').toLowerCase()}`}
|
|
142
|
+
style={{
|
|
143
|
+
position: 'absolute',
|
|
144
|
+
...htmlLayoutPosition,
|
|
145
|
+
}}
|
|
117
146
|
>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
147
|
+
<iframe
|
|
148
|
+
srcDoc={templateMsg}
|
|
149
|
+
title="InApp HTML Preview"
|
|
150
|
+
sandbox="allow-scripts allow-same-origin"
|
|
151
|
+
className="inapp-html-preview-iframe"
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
) : (
|
|
155
|
+
/* TemplatePreview InApp structure - shell-v2 wrapper (template title/message/image/CTA) */
|
|
156
|
+
<CapRow className={`inapp-shell-v2 inapp-${device}`}>
|
|
157
|
+
<CapRow
|
|
158
|
+
className={`inapp-message-container-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${!showHeader && deviceLayoutType === LAYOUT_TYPE_FOOTER ? 'inapp-message-container-FOOTER-no-header' : ''} ${CHANNELS.SMS.toLowerCase()}`}
|
|
159
|
+
>
|
|
160
|
+
<CapRow className="preview-inapp-screen">
|
|
161
|
+
<CapLabel
|
|
162
|
+
type="label16"
|
|
163
|
+
className={`inapp-title-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${
|
|
124
164
|
mediaPreview?.inAppImageSrcAndroid || mediaPreview?.inAppImageSrcIos
|
|
125
165
|
? ''
|
|
126
166
|
: `without-image-title-${deviceLayoutType || LAYOUT_TYPE_POPUP}`
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<CapLabel
|
|
149
|
-
type="label2"
|
|
150
|
-
className={`align-left inapp-content-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${
|
|
167
|
+
}`}
|
|
168
|
+
>
|
|
169
|
+
{/* eslint-disable-next-line no-unneeded-ternary */}
|
|
170
|
+
{templateTitle ? templateTitle : ' '}
|
|
171
|
+
</CapLabel>
|
|
172
|
+
|
|
173
|
+
{mediaPreview && (mediaPreview?.inAppImageSrcAndroid || mediaPreview?.inAppImageSrcIos) && (
|
|
174
|
+
<CapImage
|
|
175
|
+
src={
|
|
176
|
+
device.toLowerCase() === ANDROID
|
|
177
|
+
? mediaPreview?.inAppImageSrcAndroid
|
|
178
|
+
: mediaPreview?.inAppImageSrcIos
|
|
179
|
+
}
|
|
180
|
+
className={`inapp-image-${deviceLayoutType || LAYOUT_TYPE_POPUP}`}
|
|
181
|
+
alt={formatMessage(messages.previewGenerated)}
|
|
182
|
+
/>
|
|
183
|
+
)}
|
|
184
|
+
|
|
185
|
+
<CapLabel
|
|
186
|
+
type="label2"
|
|
187
|
+
className={`align-left inapp-content-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${
|
|
151
188
|
mediaPreview?.inAppImageSrcAndroid || mediaPreview?.inAppImageSrcIos
|
|
152
189
|
? ''
|
|
153
190
|
: `without-image-content-${deviceLayoutType || LAYOUT_TYPE_POPUP}`
|
|
154
|
-
}`}
|
|
155
|
-
>
|
|
156
|
-
{/* eslint-disable-next-line no-unneeded-ternary */}
|
|
157
|
-
{templateMsg ? templateMsg : ' '}
|
|
158
|
-
{/* this ternary is required here for preview */}
|
|
159
|
-
</CapLabel>
|
|
160
|
-
|
|
161
|
-
{/* CTA Button - Same as TemplatePreview (line 1465-1482) */}
|
|
162
|
-
{ctaData
|
|
163
|
-
&& !isEmpty(ctaData)
|
|
164
|
-
&& (ctaData[0]?.text || ctaData[0]?.actionText) && (
|
|
165
|
-
<CapButton
|
|
166
|
-
type="primary"
|
|
167
|
-
className={`inapp-button-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${
|
|
168
|
-
mediaPreview?.inAppImageSrcAndroid || mediaPreview?.inAppImageSrcIos
|
|
169
|
-
? ''
|
|
170
|
-
: `without-image-button-${deviceLayoutType || LAYOUT_TYPE_POPUP}`
|
|
171
191
|
}`}
|
|
172
192
|
>
|
|
173
|
-
{
|
|
174
|
-
|
|
175
|
-
|
|
193
|
+
{/* eslint-disable-next-line no-unneeded-ternary */}
|
|
194
|
+
{templateMsg ? templateMsg : ' '}
|
|
195
|
+
</CapLabel>
|
|
196
|
+
|
|
197
|
+
{ctaData
|
|
198
|
+
&& !isEmpty(ctaData)
|
|
199
|
+
&& (ctaData[0]?.text || ctaData[0]?.actionText) && (
|
|
200
|
+
<CapButton
|
|
201
|
+
type="primary"
|
|
202
|
+
className={`inapp-button-${deviceLayoutType || LAYOUT_TYPE_POPUP} ${
|
|
203
|
+
mediaPreview?.inAppImageSrcAndroid || mediaPreview?.inAppImageSrcIos
|
|
204
|
+
? ''
|
|
205
|
+
: `without-image-button-${deviceLayoutType || LAYOUT_TYPE_POPUP}`
|
|
206
|
+
}`}
|
|
207
|
+
>
|
|
208
|
+
{ctaData[0]?.text || ctaData[0]?.actionText}
|
|
209
|
+
</CapButton>
|
|
210
|
+
)}
|
|
211
|
+
</CapRow>
|
|
176
212
|
</CapRow>
|
|
177
213
|
</CapRow>
|
|
178
|
-
|
|
214
|
+
)}
|
|
179
215
|
</CapRow>
|
|
180
216
|
</CapRow>
|
|
181
217
|
);
|
|
@@ -760,6 +760,45 @@
|
|
|
760
760
|
.inapp-content-overlay {
|
|
761
761
|
width: 24.929rem;
|
|
762
762
|
}
|
|
763
|
+
|
|
764
|
+
// InApp HTML preview (HtmlEditor content) - positioned by layout like side-by-side ContentOverlay
|
|
765
|
+
// Position/dimensions come from inline style (INAPP_HTML_LAYOUT_POSITIONS)
|
|
766
|
+
.inapp-html-preview-iframe-wrapper {
|
|
767
|
+
background: $CAP_WHITE;
|
|
768
|
+
overflow: hidden;
|
|
769
|
+
box-shadow: 0 0.125rem 0.75rem rgba($CAP_G01, 0.15);
|
|
770
|
+
border: 0.0625rem solid $CAP_G07;
|
|
771
|
+
|
|
772
|
+
&--popup {
|
|
773
|
+
border-radius: 0.75rem;
|
|
774
|
+
box-shadow: 0 0.25rem 1.25rem rgba($CAP_G01, 0.2);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
&--header {
|
|
778
|
+
border-radius: 0.5rem 0.5rem 0.75rem 0.75rem;
|
|
779
|
+
box-shadow: 0 0.125rem 0.5rem rgba($CAP_G01, 0.15);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
&--footer {
|
|
783
|
+
border-radius: 0.75rem 0.75rem 0.5rem 0.5rem;
|
|
784
|
+
box-shadow: 0 -0.125rem 0.5rem rgba($CAP_G01, 0.15);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
&--fullscreen {
|
|
788
|
+
border-radius: 0.25rem;
|
|
789
|
+
box-shadow: none;
|
|
790
|
+
border: none;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.inapp-html-preview-iframe {
|
|
795
|
+
width: 100%;
|
|
796
|
+
height: 100%;
|
|
797
|
+
min-height: 10rem;
|
|
798
|
+
border: none;
|
|
799
|
+
display: block;
|
|
800
|
+
background: $CAP_WHITE;
|
|
801
|
+
}
|
|
763
802
|
}
|
|
764
803
|
|
|
765
804
|
// WhatsApp Preview Content Styles (Phase 8)
|
|
@@ -1078,7 +1117,7 @@
|
|
|
1078
1117
|
|
|
1079
1118
|
// InApp message container styles - copied from TemplatePreview
|
|
1080
1119
|
// POPUP/MODAL layout for Android
|
|
1081
|
-
.inapp-message-container-POPUP {
|
|
1120
|
+
.inapp-message-container-POPUP, .inapp-message-container-MODAL {
|
|
1082
1121
|
background-color: $CAP_WHITE;
|
|
1083
1122
|
position: relative;
|
|
1084
1123
|
height: 22.5rem;
|
|
@@ -125,6 +125,45 @@ export const LAYOUT_TYPE_FOOTER = 'FOOTER';
|
|
|
125
125
|
export const LAYOUT_TYPE_MODAL = 'MODAL';
|
|
126
126
|
export const LAYOUT_TYPE_BANNER = 'BANNER';
|
|
127
127
|
|
|
128
|
+
// InApp HTML preview layout positions (match HtmlEditor ContentOverlay for consistent placement)
|
|
129
|
+
// Used when rendering HTML content in Test and Preview so modal/top/bottom/fullscreen match side-by-side preview
|
|
130
|
+
export const INAPP_HTML_LAYOUT_POSITIONS = {
|
|
131
|
+
[LAYOUT_TYPE_POPUP]: {
|
|
132
|
+
top: '50%',
|
|
133
|
+
left: '50%',
|
|
134
|
+
transform: 'translate(-50%, -50%)',
|
|
135
|
+
width: '85%',
|
|
136
|
+
height: '55%',
|
|
137
|
+
maxWidth: '320px',
|
|
138
|
+
maxHeight: '380px',
|
|
139
|
+
minHeight: '180px',
|
|
140
|
+
},
|
|
141
|
+
[LAYOUT_TYPE_HEADER]: {
|
|
142
|
+
top: '2%',
|
|
143
|
+
left: '50%',
|
|
144
|
+
transform: 'translateX(-50%)',
|
|
145
|
+
width: '90%',
|
|
146
|
+
height: '22%',
|
|
147
|
+
maxHeight: '160px',
|
|
148
|
+
minHeight: '100px',
|
|
149
|
+
},
|
|
150
|
+
[LAYOUT_TYPE_FOOTER]: {
|
|
151
|
+
bottom: '2%',
|
|
152
|
+
left: '50%',
|
|
153
|
+
transform: 'translateX(-50%)',
|
|
154
|
+
width: '90%',
|
|
155
|
+
height: '22%',
|
|
156
|
+
maxHeight: '160px',
|
|
157
|
+
minHeight: '100px',
|
|
158
|
+
},
|
|
159
|
+
[LAYOUT_TYPE_FULLSCREEN]: {
|
|
160
|
+
top: '2%',
|
|
161
|
+
left: '2%',
|
|
162
|
+
width: '96%',
|
|
163
|
+
height: '96%',
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
128
167
|
// ============================================
|
|
129
168
|
// CTA TYPE CONSTANTS
|
|
130
169
|
// ============================================
|
|
@@ -191,7 +191,7 @@ const HTMLEditor = forwardRef(({
|
|
|
191
191
|
inAppContent.updateContent(newContent, true);
|
|
192
192
|
inAppLastAppliedInitialRef.current = { android: newAndroid, ios: newIos };
|
|
193
193
|
}
|
|
194
|
-
}, [initialContent, isEmailVariant, isInAppVariant
|
|
194
|
+
}, [initialContent, isEmailVariant, isInAppVariant]);
|
|
195
195
|
// Handle context change for tag API calls
|
|
196
196
|
// If variant is INAPP, use SMS layout; otherwise use the channel (EMAIL)
|
|
197
197
|
const handleContextChange = useCallback((contextData) => {
|
|
@@ -324,7 +324,7 @@ const HTMLEditor = forwardRef(({
|
|
|
324
324
|
: countIssuesBySeverity(validation.getAllIssues()),
|
|
325
325
|
})
|
|
326
326
|
,
|
|
327
|
-
}), [validation, currentContent, apiValidationErrors]);
|
|
327
|
+
}), [validation, currentContent, apiValidationErrors]); // Include apiValidationErrors so ref methods return updated counts
|
|
328
328
|
|
|
329
329
|
// Use ref to store callback to avoid infinite loops (callback in deps would cause re-runs)
|
|
330
330
|
const onValidationChangeRef = useRef(onValidationChange);
|
|
@@ -832,5 +832,5 @@ HTMLEditor.defaultProps = {
|
|
|
832
832
|
apiValidationErrors: null, // API validation errors from validateLiquidTemplateContent
|
|
833
833
|
};
|
|
834
834
|
|
|
835
|
-
// Export with injectIntl - HTMLEditor uses forwardRef internally
|
|
835
|
+
// Export with injectIntl - HTMLEditor now uses forwardRef internally
|
|
836
836
|
export default injectIntl(HTMLEditor);
|
|
@@ -142,13 +142,9 @@ export const InApp = (props) => {
|
|
|
142
142
|
const [isHTMLTemplate, setIsHTMLTemplate] = useState(false);
|
|
143
143
|
// Version to force HTMLEditor remount on layout changes
|
|
144
144
|
const [htmlEditorContentVersion, setHtmlEditorContentVersion] = useState(0);
|
|
145
|
-
// Refs to store latest content
|
|
145
|
+
// Refs to store latest content before layout changes
|
|
146
146
|
const htmlContentAndroidRef = useRef(htmlContentAndroid);
|
|
147
147
|
const htmlContentIosRef = useRef(htmlContentIos);
|
|
148
|
-
useEffect(() => {
|
|
149
|
-
htmlContentAndroidRef.current = htmlContentAndroid;
|
|
150
|
-
htmlContentIosRef.current = htmlContentIos;
|
|
151
|
-
}, [htmlContentAndroid, htmlContentIos]);
|
|
152
148
|
const [accountId, setAccountId] = useState("");
|
|
153
149
|
const [accessToken, setAccessToken] = useState("");
|
|
154
150
|
const [accountName, setAccountName] = useState("");
|
|
@@ -176,15 +172,14 @@ export const InApp = (props) => {
|
|
|
176
172
|
// TestAndPreviewSlidebox state
|
|
177
173
|
const [showTestAndPreviewSlidebox, setShowTestAndPreviewSlidebox] = useState(false);
|
|
178
174
|
|
|
179
|
-
// Get template content for TestAndPreviewSlidebox
|
|
180
|
-
//
|
|
175
|
+
// Get template content for TestAndPreviewSlidebox
|
|
176
|
+
// Returns simple structure with preview fields only
|
|
177
|
+
// Transformation to payload structure happens in prepareTestMessagePayload
|
|
178
|
+
// Reference: Based on getPreviewSection() function (lines 490-530) which prepares content for TemplatePreview
|
|
181
179
|
const getTemplateContent = useCallback(() => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const iosMsg = isHTMLTemplate
|
|
186
|
-
? (htmlContentIosRef.current ?? htmlContentIos ?? '')
|
|
187
|
-
: templateMessageIos;
|
|
180
|
+
// For HTML template, use HTML editor content so preview stays in sync with typing
|
|
181
|
+
const androidMsg = isHTMLTemplate ? (htmlContentAndroid ?? '') : templateMessageAndroid;
|
|
182
|
+
const iosMsg = isHTMLTemplate ? (htmlContentIos ?? '') : templateMessageIos;
|
|
188
183
|
|
|
189
184
|
// Prepare Android content
|
|
190
185
|
const androidMediaPreview = {};
|
|
@@ -512,11 +507,40 @@ export const InApp = (props) => {
|
|
|
512
507
|
}
|
|
513
508
|
}, [editData.templateDetails || templateData]);
|
|
514
509
|
|
|
515
|
-
// Extract editor type from defaultData
|
|
510
|
+
// Extract editor type: from defaultData (create flow) or derive from template content (edit flow)
|
|
516
511
|
const editorType = useMemo(() => {
|
|
517
|
-
const
|
|
518
|
-
return
|
|
519
|
-
|
|
512
|
+
const fromDefault = defaultData?.['editor-type'];
|
|
513
|
+
if (fromDefault) return fromDefault;
|
|
514
|
+
|
|
515
|
+
// Edit flow: derive from template content when editor-type wasn't passed from wrapper
|
|
516
|
+
const source = isFullMode ? editData?.templateDetails : templateData;
|
|
517
|
+
const versions = source?.versions;
|
|
518
|
+
const content = get(versions, 'base.content', {});
|
|
519
|
+
if (!content || isEmpty(content)) return undefined;
|
|
520
|
+
|
|
521
|
+
const androidContent = content?.ANDROID;
|
|
522
|
+
const iosContent = content?.IOS;
|
|
523
|
+
const androidTitle = (androidContent?.title ?? '').toString();
|
|
524
|
+
const iosTitle = (iosContent?.title ?? '').toString();
|
|
525
|
+
const androidType = androidContent?.type ?? '';
|
|
526
|
+
const iosType = iosContent?.type ?? '';
|
|
527
|
+
const androidStyle = get(androidContent, 'expandableDetails.style');
|
|
528
|
+
const iosStyle = get(iosContent, 'expandableDetails.style');
|
|
529
|
+
const isBEEeditorAndroid = get(androidContent, 'isBEEeditor');
|
|
530
|
+
const isBEEeditorIos = get(iosContent, 'isBEEeditor');
|
|
531
|
+
const isBeeFreeAndroid = !isEmpty(androidTitle) && androidTitle.toLowerCase() === 'bee free template';
|
|
532
|
+
const isBeeFreeIos = !isEmpty(iosTitle) && iosTitle.toLowerCase() === 'bee free template';
|
|
533
|
+
const isHTMLEditorAndroid = !isEmpty(androidTitle) && androidTitle.toLowerCase() === 'html editor template';
|
|
534
|
+
const isHTMLEditorIos = !isEmpty(iosTitle) && iosTitle.toLowerCase() === 'html editor template';
|
|
535
|
+
|
|
536
|
+
const androidIsHTML = isHTMLEditorAndroid
|
|
537
|
+
|| ((androidType === INAPP_MEDIA_TYPES.HTML || androidStyle === BIG_HTML) && !isBEEeditorAndroid && !isBeeFreeAndroid);
|
|
538
|
+
const iosIsHTML = isHTMLEditorIos
|
|
539
|
+
|| ((iosType === INAPP_MEDIA_TYPES.HTML || iosStyle === BIG_HTML) && !isBEEeditorIos && !isBeeFreeIos);
|
|
540
|
+
|
|
541
|
+
if (androidIsHTML || iosIsHTML) return INAPP_EDITOR_TYPES.HTML_EDITOR;
|
|
542
|
+
return INAPP_EDITOR_TYPES.DRAG_DROP_EDITOR;
|
|
543
|
+
}, [defaultData, isFullMode, editData?.templateDetails, templateData]);
|
|
520
544
|
|
|
521
545
|
// Separate effect for handling editor type from wrapper in create mode
|
|
522
546
|
useEffect(() => {
|
|
@@ -1013,12 +1037,11 @@ export const InApp = (props) => {
|
|
|
1013
1037
|
);
|
|
1014
1038
|
};
|
|
1015
1039
|
|
|
1016
|
-
// Handle HTML content changes from HTMLEditor
|
|
1040
|
+
// Handle HTML content changes from HTMLEditor
|
|
1017
1041
|
const handleHtmlContentChange = useCallback((deviceContent, changedDevice) => {
|
|
1018
1042
|
// When "keep content same" is on, useInAppContent passes full deviceContent with both
|
|
1019
1043
|
// android and ios set to the same value. We must update both states so preview shows
|
|
1020
1044
|
// the synced content for each device. Otherwise only update the device that changed.
|
|
1021
|
-
// Refs are updated synchronously so getTemplateContent() reads latest when opening the slidebox.
|
|
1022
1045
|
|
|
1023
1046
|
// Clear validation errors when content changes (similar to Bee Editor)
|
|
1024
1047
|
if (changedDevice) {
|
|
@@ -1041,36 +1064,33 @@ export const InApp = (props) => {
|
|
|
1041
1064
|
const isSyncUpdate = hasAndroid && hasIos;
|
|
1042
1065
|
|
|
1043
1066
|
if (isSyncUpdate) {
|
|
1067
|
+
// Sync mode: update both so preview shows same content for Android and iOS
|
|
1044
1068
|
if (hasAndroid) {
|
|
1045
|
-
|
|
1046
|
-
htmlContentAndroidRef.current = v;
|
|
1047
|
-
setHtmlContentAndroid(v);
|
|
1069
|
+
setHtmlContentAndroid(deviceContent.android || '');
|
|
1048
1070
|
}
|
|
1049
1071
|
if (hasIos) {
|
|
1050
|
-
|
|
1051
|
-
htmlContentIosRef.current = v;
|
|
1052
|
-
setHtmlContentIos(v);
|
|
1072
|
+
setHtmlContentIos(deviceContent.ios || '');
|
|
1053
1073
|
}
|
|
1054
1074
|
} else if (changedDevice) {
|
|
1075
|
+
// Only one device changed
|
|
1055
1076
|
if (changedDevice.toUpperCase() === ANDROID && hasAndroid) {
|
|
1056
|
-
|
|
1057
|
-
htmlContentAndroidRef.current = v;
|
|
1058
|
-
setHtmlContentAndroid(v);
|
|
1077
|
+
setHtmlContentAndroid(deviceContent.android || '');
|
|
1059
1078
|
} else if (changedDevice.toUpperCase() === IOS_CAPITAL && hasIos) {
|
|
1060
|
-
|
|
1061
|
-
htmlContentIosRef.current = v;
|
|
1062
|
-
setHtmlContentIos(v);
|
|
1079
|
+
setHtmlContentIos(deviceContent.ios || '');
|
|
1063
1080
|
}
|
|
1064
1081
|
} else {
|
|
1082
|
+
// Fallback: update both if changedDevice not provided
|
|
1065
1083
|
if (hasAndroid) {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1084
|
+
setHtmlContentAndroid((prev) => {
|
|
1085
|
+
const newValue = deviceContent.android || '';
|
|
1086
|
+
return prev !== newValue ? newValue : prev;
|
|
1087
|
+
});
|
|
1069
1088
|
}
|
|
1070
1089
|
if (hasIos) {
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1090
|
+
setHtmlContentIos((prev) => {
|
|
1091
|
+
const newValue = deviceContent.ios || '';
|
|
1092
|
+
return prev !== newValue ? newValue : prev;
|
|
1093
|
+
});
|
|
1074
1094
|
}
|
|
1075
1095
|
}
|
|
1076
1096
|
}, [ANDROID, IOS_CAPITAL, setErrorMessage]);
|