@capillarytech/creatives-library 8.0.259 → 8.0.260-alpha.0

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 (157) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +1 -2
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +0 -10
  7. package/services/tests/api.test.js +0 -34
  8. package/translations/en.json +3 -4
  9. package/utils/common.js +0 -12
  10. package/utils/commonUtils.js +5 -28
  11. package/utils/tests/commonUtil.test.js +0 -224
  12. package/utils/transformTemplateConfig.js +10 -0
  13. package/v2Components/CapDeviceContent/index.js +56 -61
  14. package/v2Components/CapTagList/index.js +1 -6
  15. package/v2Components/CapTagListWithInput/index.js +1 -5
  16. package/v2Components/CapTagListWithInput/messages.js +1 -1
  17. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  18. package/v2Components/ErrorInfoNote/index.js +72 -457
  19. package/v2Components/ErrorInfoNote/messages.js +6 -36
  20. package/v2Components/ErrorInfoNote/style.scss +6 -282
  21. package/v2Components/FormBuilder/index.js +4 -4
  22. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  23. package/v2Components/HtmlEditor/HTMLEditor.js +94 -547
  24. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1441
  25. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  26. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  27. package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
  28. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +102 -23
  29. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -148
  30. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  31. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  32. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
  33. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +4 -4
  34. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  35. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  36. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  37. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  38. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  39. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  40. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
  41. package/v2Components/HtmlEditor/components/PreviewPane/index.js +43 -22
  42. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  43. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  44. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +0 -1
  45. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
  46. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -50
  47. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +41 -70
  48. package/v2Components/HtmlEditor/constants.js +20 -42
  49. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  50. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +16 -120
  51. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  52. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  53. package/v2Components/HtmlEditor/hooks/useValidation.js +53 -189
  54. package/v2Components/HtmlEditor/index.js +1 -1
  55. package/v2Components/HtmlEditor/messages.js +94 -92
  56. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -94
  57. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  58. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  59. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  60. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
  61. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  62. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  63. package/v2Components/MobilePushPreviewV2/index.js +7 -32
  64. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  65. package/v2Components/TemplatePreview/index.js +32 -47
  66. package/v2Components/TemplatePreview/messages.js +0 -4
  67. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  68. package/v2Containers/BeeEditor/index.js +90 -172
  69. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +3 -4
  70. package/v2Containers/CreativesContainer/SlideBoxContent.js +52 -128
  71. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  72. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
  73. package/v2Containers/CreativesContainer/constants.js +0 -1
  74. package/v2Containers/CreativesContainer/index.js +46 -240
  75. package/v2Containers/CreativesContainer/messages.js +0 -8
  76. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  77. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -38
  78. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -106
  79. package/v2Containers/Email/actions.js +0 -7
  80. package/v2Containers/Email/constants.js +1 -5
  81. package/v2Containers/Email/index.js +30 -239
  82. package/v2Containers/Email/messages.js +0 -32
  83. package/v2Containers/Email/reducer.js +1 -12
  84. package/v2Containers/Email/sagas.js +7 -61
  85. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  86. package/v2Containers/Email/tests/reducer.test.js +0 -46
  87. package/v2Containers/Email/tests/sagas.test.js +29 -320
  88. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +21 -211
  89. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  90. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  91. package/v2Containers/EmailWrapper/constants.js +0 -2
  92. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  93. package/v2Containers/EmailWrapper/index.js +23 -103
  94. package/v2Containers/EmailWrapper/messages.js +1 -65
  95. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  96. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  97. package/v2Containers/InApp/actions.js +0 -7
  98. package/v2Containers/InApp/constants.js +4 -20
  99. package/v2Containers/InApp/index.js +360 -804
  100. package/v2Containers/InApp/index.scss +3 -4
  101. package/v2Containers/InApp/messages.js +3 -7
  102. package/v2Containers/InApp/reducer.js +3 -21
  103. package/v2Containers/InApp/sagas.js +9 -29
  104. package/v2Containers/InApp/selectors.js +5 -25
  105. package/v2Containers/InApp/tests/index.test.js +71 -152
  106. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  107. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  108. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -39
  109. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +6 -10
  110. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +75 -102
  111. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +54 -81
  112. package/v2Containers/MobilePushNew/index.js +2 -3
  113. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +178 -262
  114. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +12 -16
  115. package/v2Containers/SmsTrai/Edit/index.js +1 -2
  116. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +111 -468
  117. package/v2Containers/TagList/index.js +19 -62
  118. package/v2Containers/Templates/_templates.scss +1 -60
  119. package/v2Containers/Templates/index.js +4 -89
  120. package/v2Containers/Templates/messages.js +0 -4
  121. package/v2Containers/WebPush/Create/messages.js +8 -0
  122. package/v2Containers/WebPush/Create/preview/PreviewControls.js +2 -2
  123. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +3 -1
  124. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +5 -1
  125. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +5 -1
  126. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +5 -1
  127. package/v2Containers/WebPush/Create/preview/preview.scss +7 -0
  128. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +734 -1306
  129. package/v2Components/ErrorInfoNote/constants.js +0 -1
  130. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
  131. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  132. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -255
  133. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -364
  134. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  135. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -40
  136. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  137. package/v2Containers/BeePopupEditor/constants.js +0 -10
  138. package/v2Containers/BeePopupEditor/index.js +0 -194
  139. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  140. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1285
  141. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1880
  142. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  143. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
  144. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  145. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  146. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  147. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  148. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  149. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  150. package/v2Containers/InAppWrapper/constants.js +0 -16
  151. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  152. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  153. package/v2Containers/InAppWrapper/index.js +0 -148
  154. package/v2Containers/InAppWrapper/messages.js +0 -49
  155. package/v2Containers/InappAdvance/index.js +0 -1099
  156. package/v2Containers/InappAdvance/index.scss +0 -10
  157. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
@@ -1,445 +1,21 @@
1
- import React, { useState, useMemo } from 'react';
2
- import PropTypes from 'prop-types';
3
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
4
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
5
- import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
6
- import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
7
- import CapTab from '@capillarytech/cap-ui-library/CapTab';
8
- import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import CapRow from "@capillarytech/cap-ui-library/CapRow";
4
+ import CapButton from "@capillarytech/cap-ui-library/CapButton";
5
+ import CapIcon from "@capillarytech/cap-ui-library/CapIcon";
6
+ import CapLabel from "@capillarytech/cap-ui-library/CapLabel";
7
+ import CapList from "@capillarytech/cap-ui-library/CapList";
9
8
  import {
10
9
  FormattedMessage,
10
+ FormattedNumber,
11
11
  injectIntl,
12
- } from 'react-intl';
13
- import './style.scss';
14
- import messages from './messages';
15
- import { processErrors } from './utils';
16
- import ErrorTypeRenderer from './ErrorTypeRenderer';
17
- import { ANDROID, GENERIC, IOS } from '../../v2Containers/CreativesContainer/constants';
18
- import { LABEL_ISSUE_PATTERNS, ERROR_TAB_KEYS } from '../HtmlEditor/utils/validationConstants';
19
- import { SEVERITY } from '../HtmlEditor/components/ValidationPanel/constants';
20
- import { LIQUID_DOC_URL } from './constants';
12
+ } from "react-intl";
13
+ import "./style.scss";
14
+ import messages from "./messages";
15
+ import { processErrors } from "./utils";
16
+ import ErrorTypeRenderer from "./ErrorTypeRenderer";
17
+ import { ANDROID, GENERIC, IOS } from "../../v2Containers/CreativesContainer/constants";
21
18
 
22
- const { CapLabelInline } = CapLabel;
23
-
24
- /**
25
- * Categorize error messages into HTML, Label, and Liquid categories
26
- */
27
- const categorizeErrorMessages = (standardErrors, liquidErrors) => {
28
- const htmlIssues = [];
29
- const labelIssues = [];
30
- const liquidIssues = [];
31
-
32
- // Process standard errors
33
- (standardErrors || []).forEach((error, index) => {
34
- const errorLower = (error || '').toLowerCase();
35
-
36
- // Check if it's a Label (tag syntax) issue
37
- const isLabelIssue = LABEL_ISSUE_PATTERNS.some(
38
- (pattern) => errorLower.includes(pattern.toLowerCase()),
39
- );
40
-
41
- if (isLabelIssue) {
42
- labelIssues.push({
43
- message: error,
44
- severity: SEVERITY.ERROR,
45
- index,
46
- source: 'label',
47
- });
48
- } else {
49
- htmlIssues.push({
50
- message: error,
51
- severity: SEVERITY.ERROR,
52
- index,
53
- source: 'html',
54
- });
55
- }
56
- });
57
-
58
- // Process liquid errors
59
- (liquidErrors || []).forEach((error, index) => {
60
- liquidIssues.push({
61
- message: error,
62
- severity: SEVERITY.ERROR,
63
- index,
64
- source: 'liquid',
65
- });
66
- });
67
-
68
- return { htmlIssues, labelIssues, liquidIssues };
69
- };
70
-
71
- /**
72
- * Clean error message by removing line/char and rule parts
73
- * @param {string} message - Original error message
74
- * @param {RegExpMatchArray|null} lineMatch - Line number match result
75
- * @param {RegExpMatchArray|null} charMatch - Character number match result
76
- * @param {RegExpMatchArray|null} ruleMatch - Rule name match result
77
- * @returns {string} Cleaned message without line/char/rule information
78
- */
79
- const cleanErrorMessage = (message, lineMatch, charMatch, ruleMatch) => {
80
- let displayMessage = message;
81
- if (lineMatch) {
82
- displayMessage = displayMessage.replace(/Line\s+\d+,?\s*/gi, '');
83
- }
84
- if (charMatch) {
85
- displayMessage = displayMessage.replace(/Char\s+\d+\.?\s*/gi, '');
86
- }
87
- if (ruleMatch) {
88
- displayMessage = displayMessage.replace(/•\s*[a-z-]+$/i, '');
89
- }
90
- return displayMessage.trim();
91
- };
92
-
93
- /**
94
- * Get icon based on severity
95
- */
96
- const getSeverityIcon = (severity) => {
97
- if (severity === SEVERITY.WARNING) {
98
- return <CapIcon type="alert-warning" className="error-info-note__icon error-info-note__icon--warning" />;
99
- }
100
- return <CapIcon type="warning-circle" className="error-info-note__icon error-info-note__icon--error" />;
101
- };
102
-
103
- /**
104
- * Tab content component
105
- */
106
- const TabContent = ({ issues, onErrorClick, intl }) => {
107
- if (!issues || issues.length === 0) {
108
- return null;
109
- }
110
-
111
- const handleNavigateClick = (issue, e) => {
112
- e.stopPropagation();
113
- if (onErrorClick) {
114
- onErrorClick(issue);
115
- }
116
- };
117
-
118
- return (
119
- <CapRow className="error-info-note__content">
120
- {issues.map((issue, index) => {
121
- const { severity, message } = issue;
122
- const key = `${message}-${index}`;
123
-
124
- // Parse line and char from message if present (format: "... Line X, Char Y.")
125
- const lineMatch = message.match(/Line\s+(\d+)/i);
126
- const charMatch = message.match(/Char\s+(\d+)/i);
127
- const line = lineMatch ? parseInt(lineMatch[1], 10) : null;
128
- const char = charMatch ? parseInt(charMatch[1], 10) : null;
129
-
130
- // Extract rule from message (format: "... • rule-name")
131
- const ruleMatch = message.match(/•\s*([a-z-]+)$/i);
132
- const rule = ruleMatch ? ruleMatch[1] : null;
133
-
134
- // Clean message (remove line/char and rule parts for display)
135
- const displayMessage = cleanErrorMessage(message, lineMatch, charMatch, ruleMatch);
136
-
137
- return (
138
- <CapRow
139
- key={key}
140
- className={`error-info-note__item error-info-note__item--${severity || 'error'}`}
141
- >
142
- <CapRow className="error-info-note__item-icon">
143
- {getSeverityIcon(severity)}
144
- </CapRow>
145
- <CapRow className="error-info-note__item-content">
146
- <CapLabelInline type="label2" className="error-info-note__item-message">
147
- {displayMessage}
148
- </CapLabelInline>
149
- {line && (
150
- <CapLabelInline type="label2" className="error-info-note__item-location">
151
- <FormattedMessage {...messages.line} />
152
- {' '}
153
- {line}
154
- {char ? (
155
- <>
156
- ,
157
- {' '}
158
- <FormattedMessage {...messages.char} />
159
- {' '}
160
- {char}
161
- </>
162
- ) : ''}
163
- .
164
- </CapLabelInline>
165
- )}
166
- {rule && (
167
- <CapLabelInline type="label2" className="error-info-note__item-rule">
168
-
169
- {' '}
170
- {rule}
171
- </CapLabelInline>
172
- )}
173
- </CapRow>
174
- {onErrorClick && (
175
- <CapTooltip title={intl?.formatMessage ? intl.formatMessage(messages.navigateToError) : 'Go to error location'}>
176
- <CapButton
177
- type="flat"
178
- className="error-info-note__item-navigate"
179
- onClick={(e) => handleNavigateClick({ ...issue, line, column: char }, e)}
180
- aria-label={intl?.formatMessage ? intl.formatMessage(messages.navigateToError) : 'Go to error location'}
181
- >
182
- <CapIcon type="redirection" />
183
- </CapButton>
184
- </CapTooltip>
185
- )}
186
- </CapRow>
187
- );
188
- })}
189
- </CapRow>
190
- );
191
- };
192
-
193
- TabContent.propTypes = {
194
- issues: PropTypes.array,
195
- onErrorClick: PropTypes.func,
196
- intl: PropTypes.object,
197
- };
198
-
199
- TabContent.defaultProps = {
200
- issues: [],
201
- onErrorClick: null,
202
- intl: null,
203
- };
204
-
205
- /**
206
- * ErrorInfoNote Component with Tabbed Interface
207
- * @param {boolean} useLegacyDisplay - If true, uses simple list display instead of tabbed interface (for BEE Editor)
208
- */
209
- export const ErrorInfoNote = (props) => {
210
- const {
211
- errorMessages,
212
- onErrorClick,
213
- onClose,
214
- isLiquidEnabled = true,
215
- intl,
216
- useLegacyDisplay = false, // Use simple list display instead of tabs (for BEE Editor)
217
- } = props;
218
-
219
- const [isDismissed, setIsDismissed] = useState(false);
220
- const [activeKey, setActiveKey] = useState(null);
221
-
222
- const {
223
- LIQUID_ERROR_MSG: rawLiquidErrors = [],
224
- STANDARD_ERROR_MSG: rawStandardErrors = [],
225
- } = errorMessages || {};
226
-
227
- // Detect if platform-specific (ANDROID/IOS) or GENERIC
228
- const isObject = typeof rawStandardErrors === 'object' && rawStandardErrors !== null;
229
- const isNotArray = !Array.isArray(rawLiquidErrors);
230
- const hasPlatformKeys = isObject && isNotArray && [ANDROID, IOS, GENERIC].some((key) => key in rawLiquidErrors);
231
-
232
- // For platform-specific errors or when useLegacyDisplay is true, use the legacy renderer
233
- if (hasPlatformKeys) {
234
- // Process errors for both platforms - they use the same structure but different platform parameters
235
- const createPlatformErrors = (platform) => ({
236
- STANDARD: processErrors(rawStandardErrors, 'standard', platform, messages),
237
- LIQUID: processErrors(rawLiquidErrors, 'liquid', platform, messages),
238
- });
239
-
240
- const androidErrors = createPlatformErrors(ANDROID);
241
- const iosErrors = createPlatformErrors(IOS);
242
- return (
243
- <ErrorTypeRenderer
244
- genericErrors={null}
245
- androidErrors={androidErrors}
246
- iosErrors={iosErrors}
247
- ErrorSectionComponent={ErrorSection}
248
- />
249
- );
250
- }
251
-
252
- // For BEE Editor (useLegacyDisplay=true), use simple list display without tabs
253
- if (useLegacyDisplay) {
254
- const standardErrors = Array.isArray(rawStandardErrors) ? rawStandardErrors : [];
255
- const liquidErrors = Array.isArray(rawLiquidErrors) ? rawLiquidErrors : [];
256
- const hasStandardErrors = standardErrors.length > 0;
257
- const hasLiquidErrors = liquidErrors.length > 0 && isLiquidEnabled;
258
-
259
- if (!hasStandardErrors && !hasLiquidErrors) {
260
- return null;
261
- }
262
-
263
- return (
264
- <CapRow className="error-container error-container--legacy">
265
- {hasStandardErrors && (
266
- <ErrorSection
267
- title={<FormattedMessage {...messages.standardErrorHeader} />}
268
- errors={standardErrors}
269
- liquidError={false}
270
- />
271
- )}
272
- {hasLiquidErrors && (
273
- <ErrorSection
274
- title={<FormattedMessage {...messages.dynamicErrorHeader} />}
275
- errors={liquidErrors}
276
- liquidError
277
- />
278
- )}
279
- </CapRow>
280
- );
281
- }
282
-
283
- // Categorize errors for tabbed interface
284
- const { htmlIssues, labelIssues, liquidIssues } = useMemo(() => categorizeErrorMessages(
285
- Array.isArray(rawStandardErrors) ? rawStandardErrors : [],
286
- Array.isArray(rawLiquidErrors) ? rawLiquidErrors : [],
287
- ), [rawStandardErrors, rawLiquidErrors]);
288
-
289
- // Calculate counts
290
- const htmlCount = htmlIssues.length;
291
- const labelCount = labelIssues.length;
292
- const liquidCount = liquidIssues.length;
293
- // Include liquid issues in total count even when liquid is disabled
294
- // This ensures liquid errors are shown when liquid content is detected but feature is disabled
295
- const totalCount = htmlCount + labelCount + liquidCount;
296
-
297
- // Set default active key
298
- useMemo(() => {
299
- if (!activeKey) {
300
- if (htmlCount > 0) {
301
- setActiveKey(ERROR_TAB_KEYS.HTML);
302
- } else if (labelCount > 0) {
303
- setActiveKey(ERROR_TAB_KEYS.LABEL);
304
- } else if (liquidCount > 0) {
305
- // Show liquid tab even when liquid is disabled if liquid content is detected
306
- setActiveKey(ERROR_TAB_KEYS.LIQUID);
307
- }
308
- }
309
- }, [htmlCount, labelCount, liquidCount, activeKey]);
310
-
311
- // Handle close
312
- const handleClose = () => {
313
- setIsDismissed(true);
314
- if (onClose) {
315
- onClose();
316
- }
317
- };
318
-
319
- // Handle liquid documentation click
320
- const handleLiquidDocClick = () => {
321
- window.open(
322
- LIQUID_DOC_URL,
323
- '_blank',
324
- );
325
- };
326
-
327
- // Don't render if no issues or dismissed
328
- if (totalCount === 0 || isDismissed) {
329
- return null;
330
- }
331
-
332
- // Build tab panes (CapTab uses 'panes' with 'tab' and 'content' properties)
333
- const tabPanes = [];
334
-
335
- if (htmlCount > 0) {
336
- tabPanes.push({
337
- key: ERROR_TAB_KEYS.HTML,
338
- tab: (
339
- <CapLabelInline type="label2" className="error-info-note__tab-label">
340
- <FormattedMessage {...messages.htmlIssues} />
341
- <CapLabelInline type="label2" className="error-info-note__tab-count">
342
- (
343
- {htmlCount}
344
- )
345
- </CapLabelInline>
346
- </CapLabelInline>
347
- ),
348
- content: (
349
- <TabContent
350
- issues={htmlIssues}
351
- onErrorClick={onErrorClick}
352
- intl={intl}
353
- />
354
- ),
355
- });
356
- }
357
-
358
- if (labelCount > 0) {
359
- tabPanes.push({
360
- key: ERROR_TAB_KEYS.LABEL,
361
- tab: (
362
- <CapLabelInline type="label2" className="error-info-note__tab-label">
363
- <FormattedMessage {...messages.labelIssues} />
364
- <CapLabelInline type="label2" className="error-info-note__tab-count">
365
- (
366
- {labelCount}
367
- )
368
- </CapLabelInline>
369
- </CapLabelInline>
370
- ),
371
- content: (
372
- <TabContent
373
- issues={labelIssues}
374
- onErrorClick={onErrorClick}
375
- intl={intl}
376
- />
377
- ),
378
- });
379
- }
380
-
381
- // Show liquid issues tab even when liquid is disabled if liquid content is detected
382
- // This allows users to see errors when they add liquid content but liquid feature is not enabled
383
- if (liquidCount > 0) {
384
- tabPanes.push({
385
- key: ERROR_TAB_KEYS.LIQUID,
386
- tab: (
387
- <CapLabelInline type="label2" className="error-info-note__tab-label">
388
- <FormattedMessage {...messages.liquidIssues} />
389
- <CapLabelInline type="label2" className="error-info-note__tab-count">
390
- (
391
- {liquidCount}
392
- )
393
- </CapLabelInline>
394
- </CapLabelInline>
395
- ),
396
- content: (
397
- <TabContent
398
- issues={liquidIssues}
399
- onErrorClick={onErrorClick}
400
- intl={intl}
401
- />
402
- ),
403
- });
404
- }
405
-
406
- return (
407
- <CapRow className="error-container error-container--tabs">
408
- <CapRow className="error-info-note__header">
409
- <CapTab
410
- activeKey={activeKey || (tabPanes[0]?.key)}
411
- onChange={setActiveKey}
412
- panes={tabPanes}
413
- className="error-info-note__tabs"
414
- />
415
- <CapRow className="error-info-note__actions">
416
- {activeKey === ERROR_TAB_KEYS.LIQUID && isLiquidEnabled && (
417
- <CapButton
418
- type="flat"
419
- className="error-info-note__liquid-doc"
420
- onClick={handleLiquidDocClick}
421
- >
422
- <FormattedMessage {...messages.liquidDoc} />
423
- <CapIcon size="s" type="launch" />
424
- </CapButton>
425
- )}
426
- <CapTooltip title={intl?.formatMessage ? intl.formatMessage(messages.closePanel) : 'Close validation panel'}>
427
- <CapButton
428
- type="flat"
429
- className="error-info-note__close"
430
- onClick={handleClose}
431
- aria-label={intl?.formatMessage ? intl.formatMessage(messages.closePanel) : 'Close validation panel'}
432
- >
433
- <CapIcon type="close" />
434
- </CapButton>
435
- </CapTooltip>
436
- </CapRow>
437
- </CapRow>
438
- </CapRow>
439
- );
440
- };
441
-
442
- // Legacy ErrorSection component for platform-specific errors (backwards compatibility)
443
19
  const ErrorSection = ({
444
20
  title,
445
21
  errors,
@@ -450,7 +26,7 @@ const ErrorSection = ({
450
26
  {title && (
451
27
  <CapRow
452
28
  className={`error-header ${
453
- !liquidError ? 'standard-error-header' : ''
29
+ !liquidError ? "standard-error-header" : ""
454
30
  }`}
455
31
  >
456
32
  <>
@@ -462,7 +38,8 @@ const ErrorSection = ({
462
38
  <CapButton
463
39
  type="flat"
464
40
  className="add-btn"
465
- onClick={() => window.open('https://docs.capillarytech.com/docs/liquid-language-in-messages', '_blank')}
41
+ onClick={() => window.open("https://docs.capillarytech.com/docs/liquid-language-in-messages", "_blank")
42
+ }
466
43
  >
467
44
  <FormattedMessage {...messages.liquidDoc} />
468
45
  <CapIcon size="s" type="launch" />
@@ -476,15 +53,21 @@ const ErrorSection = ({
476
53
  <CapLabel type="label2">{platformLabel}</CapLabel>
477
54
  </CapRow>
478
55
  )}
479
- <CapRow className="error-list-legacy">
480
- {(errors || []).map((error) => (
481
- <CapRow key={`${error}`} className="error-list-legacy__item">
56
+ <CapList
57
+ className="error-list"
58
+ size="small"
59
+ dataSource={errors}
60
+ renderItem={(error, index) => (
61
+ <CapList.Item>
482
62
  <CapLabel type="label2" className="cap-list-v2-error-item">
63
+ <CapLabel type="label2">
64
+ <FormattedNumber value={index + 1} />.
65
+ </CapLabel>
483
66
  <CapLabel type="label2">{error}</CapLabel>
484
67
  </CapLabel>
485
- </CapRow>
486
- ))}
487
- </CapRow>
68
+ </CapList.Item>
69
+ )}
70
+ />
488
71
  </>
489
72
  );
490
73
 
@@ -501,16 +84,54 @@ ErrorSection.defaultProps = {
501
84
  platformLabel: null,
502
85
  };
503
86
 
87
+ export const ErrorInfoNote = (props) => {
88
+ const { errorMessages } = props;
89
+
90
+ const {
91
+ LIQUID_ERROR_MSG: rawLiquidErrors = [],
92
+ STANDARD_ERROR_MSG: rawStandardErrors = [],
93
+ } = errorMessages || {};
94
+
95
+ // Detect if platform-specific (ANDROID/IOS) or GENERIC
96
+ const isObject = typeof rawStandardErrors === 'object' && rawStandardErrors !== null;
97
+ const isNotArray = !Array.isArray(rawLiquidErrors);
98
+ const hasPlatformKeys = isObject && isNotArray && [ANDROID, IOS, GENERIC].some((key) => key in rawLiquidErrors);
99
+
100
+ if (hasPlatformKeys) {
101
+ // Platform-specific
102
+ const androidErrors = {
103
+ STANDARD: processErrors(rawStandardErrors, 'standard', ANDROID, messages),
104
+ LIQUID: processErrors(rawLiquidErrors, 'liquid', ANDROID, messages),
105
+ };
106
+ const iosErrors = {
107
+ STANDARD: processErrors(rawStandardErrors, 'standard', IOS, messages),
108
+ LIQUID: processErrors(rawLiquidErrors, 'liquid', IOS, messages),
109
+ };
110
+ return (
111
+ <ErrorTypeRenderer
112
+ genericErrors={null}
113
+ androidErrors={androidErrors}
114
+ iosErrors={iosErrors}
115
+ ErrorSectionComponent={ErrorSection}
116
+ />
117
+ );
118
+ }
119
+ // GENERIC (not platform-specific)
120
+ const genericStandard = processErrors(rawStandardErrors, 'standard', null, messages);
121
+ const genericLiquid = processErrors(rawLiquidErrors, 'liquid', null, messages);
122
+ return (
123
+ <ErrorTypeRenderer
124
+ genericErrors={{ standard: genericStandard, liquid: genericLiquid }}
125
+ ErrorSectionComponent={ErrorSection}
126
+ />
127
+ );
128
+ };
129
+
504
130
  ErrorInfoNote.defaultProps = {
505
131
  errorMessages: {
506
132
  LIQUID_ERROR_MSG: [],
507
133
  STANDARD_ERROR_MSG: [],
508
134
  },
509
- onErrorClick: null,
510
- onClose: null,
511
- isLiquidEnabled: true,
512
- intl: null,
513
- useLegacyDisplay: false, // Use simple list display for BEE Editor
514
135
  };
515
136
 
516
137
  ErrorInfoNote.propTypes = {
@@ -532,11 +153,5 @@ ErrorInfoNote.propTypes = {
532
153
  }),
533
154
  ]),
534
155
  }),
535
- onErrorClick: PropTypes.func,
536
- onClose: PropTypes.func,
537
- isLiquidEnabled: PropTypes.bool,
538
- intl: PropTypes.object,
539
- useLegacyDisplay: PropTypes.bool, // Use simple list display for BEE Editor
540
156
  };
541
-
542
157
  export default injectIntl(ErrorInfoNote);
@@ -6,28 +6,6 @@
6
6
  import { defineMessages } from "react-intl";
7
7
  const scope = "creatives.componentsV2.ErrorInfoNote";
8
8
  export default defineMessages({
9
- // Tab labels for new tabbed interface
10
- htmlIssues: {
11
- id: `${scope}.htmlIssues`,
12
- defaultMessage: "HTML issues",
13
- },
14
- labelIssues: {
15
- id: `${scope}.labelIssues`,
16
- defaultMessage: "Label issues",
17
- },
18
- liquidIssues: {
19
- id: `${scope}.liquidIssues`,
20
- defaultMessage: "Liquid issues",
21
- },
22
- navigateToError: {
23
- id: `${scope}.navigateToError`,
24
- defaultMessage: "Go to error location",
25
- },
26
- closePanel: {
27
- id: `${scope}.closePanel`,
28
- defaultMessage: "Close validation panel",
29
- },
30
- // Legacy messages (kept for backwards compatibility)
31
9
  dynamicErrorHeader: {
32
10
  id: `${scope}.dynamicErrorHeader`,
33
11
  defaultMessage:
@@ -46,39 +24,31 @@ export default defineMessages({
46
24
  ariaFooter: {
47
25
  id: `${scope}.ariaFooter`,
48
26
  defaultMessage:
49
- "Aira can make mistakes. Please verify the suggestions before applying them",
27
+ "Aira can make mistakes. Please verify the suggestions before applying them"
50
28
  },
51
29
  liquidDocLink: {
52
30
  id: `${scope}.liquidDocLink`,
53
31
  defaultMessage:
54
- "https://docs.capillarytech.com/docs/liquid-language-in-messages",
32
+ "https://docs.capillarytech.com/docs/liquid-language-in-messages"
55
33
  },
56
34
  androidDynamicErrorHeader: {
57
35
  id: `${scope}.androidDynamicErrorHeader`,
58
36
  defaultMessage:
59
- "Errors found in Android Dynamic Tags",
37
+ "Errors found in Android Dynamic Tags"
60
38
  },
61
39
  iosDynamicErrorHeader: {
62
40
  id: `${scope}.iosDynamicErrorHeader`,
63
41
  defaultMessage:
64
- "Errors found in iOS Dynamic Tags",
42
+ "Errors found in iOS Dynamic Tags"
65
43
  },
66
44
  androidStandardErrorHeader: {
67
45
  id: `${scope}.androidStandardErrorHeader`,
68
46
  defaultMessage:
69
- "Errors found in Android Standard Tags",
47
+ "Errors found in Android Standard Tags"
70
48
  },
71
49
  iosStandardErrorHeader: {
72
50
  id: `${scope}.iosStandardErrorHeader`,
73
51
  defaultMessage:
74
- "Errors found in iOS Standard Tags",
75
- },
76
- line: {
77
- id: `${scope}.line`,
78
- defaultMessage: "Line",
79
- },
80
- char: {
81
- id: `${scope}.char`,
82
- defaultMessage: "Char",
52
+ "Errors found in iOS Standard Tags"
83
53
  },
84
54
  });