@capillarytech/creatives-library 8.0.246-alpha.0 → 8.0.246
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/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +1 -2
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +0 -10
- package/services/tests/api.test.js +0 -18
- package/utils/common.js +0 -5
- package/utils/commonUtils.js +5 -28
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapTagList/index.js +1 -6
- package/v2Components/CapTagListWithInput/index.js +1 -5
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/ErrorInfoNote/index.js +72 -447
- package/v2Components/ErrorInfoNote/messages.js +0 -22
- package/v2Components/ErrorInfoNote/style.scss +4 -280
- package/v2Components/FormBuilder/tests/index.test.js +4 -13
- package/v2Components/HtmlEditor/HTMLEditor.js +94 -642
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1135
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
- package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +13 -11
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
- package/v2Components/HtmlEditor/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
- package/v2Components/HtmlEditor/hooks/useValidation.js +45 -150
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -95
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
- package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
- package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
- package/v2Containers/BeeEditor/index.js +90 -172
- package/v2Containers/CreativesContainer/SlideBoxContent.js +51 -128
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +12 -113
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
- package/v2Containers/CreativesContainer/constants.js +0 -1
- package/v2Containers/CreativesContainer/index.js +46 -238
- package/v2Containers/CreativesContainer/messages.js +0 -8
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -38
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -91
- package/v2Containers/Email/actions.js +0 -7
- package/v2Containers/Email/constants.js +1 -5
- package/v2Containers/Email/index.js +30 -229
- package/v2Containers/Email/messages.js +0 -32
- package/v2Containers/Email/reducer.js +1 -12
- package/v2Containers/Email/sagas.js +7 -61
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/Email/tests/sagas.test.js +1 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +15 -210
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/EmailWrapper/constants.js +0 -2
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
- package/v2Containers/EmailWrapper/index.js +23 -103
- package/v2Containers/EmailWrapper/messages.js +1 -61
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -509
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +357 -801
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/TagList/index.js +19 -62
- package/v2Containers/Templates/_templates.scss +1 -60
- package/v2Containers/Templates/index.js +4 -89
- package/v2Containers/Templates/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -35
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -363
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +0 -630
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -193
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1317
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1605
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1099
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -48,14 +48,13 @@ export const CapTagListWithInput = (props) => {
|
|
|
48
48
|
showTagList = true,
|
|
49
49
|
showInput = true,
|
|
50
50
|
inputProps = {},
|
|
51
|
-
popoverPlacement,
|
|
52
51
|
} = props;
|
|
53
52
|
|
|
54
53
|
const { formatMessage } = intl;
|
|
55
54
|
|
|
56
55
|
return (
|
|
57
56
|
<CapColumn style={containerStyle}>
|
|
58
|
-
<CapRow
|
|
57
|
+
<CapRow style={{display: 'flex', flexDirection: 'row'}}>
|
|
59
58
|
{showHeading && headingText && (
|
|
60
59
|
<CapHeading type={headingType} style={headingStyle}>
|
|
61
60
|
{headingText}
|
|
@@ -77,7 +76,6 @@ export const CapTagListWithInput = (props) => {
|
|
|
77
76
|
selectedOfferDetails={selectedOfferDetails}
|
|
78
77
|
eventContextTags={eventContextTags}
|
|
79
78
|
style={tagListStyle}
|
|
80
|
-
popoverPlacement={popoverPlacement}
|
|
81
79
|
/>
|
|
82
80
|
)}
|
|
83
81
|
</CapRow>
|
|
@@ -138,7 +136,6 @@ CapTagListWithInput.propTypes = {
|
|
|
138
136
|
showHeading: PropTypes.bool,
|
|
139
137
|
showTagList: PropTypes.bool,
|
|
140
138
|
showInput: PropTypes.bool,
|
|
141
|
-
popoverPlacement: PropTypes.string,
|
|
142
139
|
};
|
|
143
140
|
|
|
144
141
|
CapTagListWithInput.defaultProps = {
|
|
@@ -167,7 +164,6 @@ CapTagListWithInput.defaultProps = {
|
|
|
167
164
|
showTagList: true,
|
|
168
165
|
showInput: true,
|
|
169
166
|
inputProps: {},
|
|
170
|
-
popoverPlacement: undefined,
|
|
171
167
|
};
|
|
172
168
|
|
|
173
169
|
export default injectIntl(CapTagListWithInput);
|
|
@@ -4,11 +4,6 @@ import '@testing-library/jest-dom';
|
|
|
4
4
|
import { render, screen, fireEvent } from '../../../utils/test-utils';
|
|
5
5
|
import { CapWhatsappCTA } from '../index';
|
|
6
6
|
|
|
7
|
-
// Mock the missing reducer
|
|
8
|
-
jest.mock('@capillarytech/cap-ui-library/CapCollapsibleLeftNavigation/reducer', () => {
|
|
9
|
-
return (state = {}) => state;
|
|
10
|
-
}, { virtual: true });
|
|
11
|
-
|
|
12
7
|
const updateHandler = jest.fn();
|
|
13
8
|
const deleteHandler = jest.fn();
|
|
14
9
|
const initializeComponent = (
|
|
@@ -1,435 +1,21 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import PropTypes from
|
|
3
|
-
import CapRow from
|
|
4
|
-
import CapButton from
|
|
5
|
-
import CapIcon from
|
|
6
|
-
import CapLabel from
|
|
7
|
-
import
|
|
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
|
|
13
|
-
import
|
|
14
|
-
import messages from
|
|
15
|
-
import { processErrors } from
|
|
16
|
-
import ErrorTypeRenderer from
|
|
17
|
-
import { ANDROID, GENERIC, IOS } from
|
|
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
18
|
|
|
19
|
-
// Label issue patterns - syntax errors related to tags
|
|
20
|
-
const LABEL_ISSUE_PATTERNS = [
|
|
21
|
-
'tag must be paired',
|
|
22
|
-
'open tag match failed',
|
|
23
|
-
'closed tag match failed',
|
|
24
|
-
'unclosed',
|
|
25
|
-
'missing required',
|
|
26
|
-
'tag-pair',
|
|
27
|
-
'attr-value-not-empty',
|
|
28
|
-
'attr-no-duplication',
|
|
29
|
-
'tag-self-close',
|
|
30
|
-
'spec-char-escape',
|
|
31
|
-
'</html>',
|
|
32
|
-
'<html>',
|
|
33
|
-
'</div>',
|
|
34
|
-
'<div>',
|
|
35
|
-
'{{',
|
|
36
|
-
'}}',
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Categorize error messages into HTML, Label, and Liquid categories
|
|
41
|
-
*/
|
|
42
|
-
const categorizeErrorMessages = (standardErrors, liquidErrors) => {
|
|
43
|
-
const htmlIssues = [];
|
|
44
|
-
const labelIssues = [];
|
|
45
|
-
const liquidIssues = [];
|
|
46
|
-
|
|
47
|
-
// Process standard errors
|
|
48
|
-
(standardErrors || []).forEach((error, index) => {
|
|
49
|
-
const errorLower = (error || '').toLowerCase();
|
|
50
|
-
|
|
51
|
-
// Check if it's a Label (tag syntax) issue
|
|
52
|
-
const isLabelIssue = LABEL_ISSUE_PATTERNS.some(
|
|
53
|
-
(pattern) => errorLower.includes(pattern.toLowerCase()),
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
if (isLabelIssue) {
|
|
57
|
-
labelIssues.push({
|
|
58
|
-
message: error,
|
|
59
|
-
severity: 'error',
|
|
60
|
-
index,
|
|
61
|
-
source: 'label',
|
|
62
|
-
});
|
|
63
|
-
} else {
|
|
64
|
-
htmlIssues.push({
|
|
65
|
-
message: error,
|
|
66
|
-
severity: 'error',
|
|
67
|
-
index,
|
|
68
|
-
source: 'html',
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Process liquid errors
|
|
74
|
-
(liquidErrors || []).forEach((error, index) => {
|
|
75
|
-
liquidIssues.push({
|
|
76
|
-
message: error,
|
|
77
|
-
severity: 'error',
|
|
78
|
-
index,
|
|
79
|
-
source: 'liquid',
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return { htmlIssues, labelIssues, liquidIssues };
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Get icon based on severity
|
|
88
|
-
*/
|
|
89
|
-
const getSeverityIcon = (severity) => {
|
|
90
|
-
if (severity === 'warning') {
|
|
91
|
-
return <CapIcon type="alert-warning" className="error-info-note__icon error-info-note__icon--warning" />;
|
|
92
|
-
}
|
|
93
|
-
return <CapIcon type="warning-circle" className="error-info-note__icon error-info-note__icon--error" />;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Tab content component
|
|
98
|
-
*/
|
|
99
|
-
const TabContent = ({ issues, onErrorClick, intl }) => {
|
|
100
|
-
if (!issues || issues.length === 0) {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const handleNavigateClick = (issue, e) => {
|
|
105
|
-
e.stopPropagation();
|
|
106
|
-
if (onErrorClick) {
|
|
107
|
-
onErrorClick(issue);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<div className="error-info-note__content">
|
|
113
|
-
{issues.map((issue, index) => {
|
|
114
|
-
const { severity, message } = issue;
|
|
115
|
-
const key = `${message}-${index}`;
|
|
116
|
-
|
|
117
|
-
// Parse line and char from message if present (format: "... Line X, Char Y.")
|
|
118
|
-
const lineMatch = message.match(/Line\s+(\d+)/i);
|
|
119
|
-
const charMatch = message.match(/Char\s+(\d+)/i);
|
|
120
|
-
const line = lineMatch ? parseInt(lineMatch[1], 10) : null;
|
|
121
|
-
const char = charMatch ? parseInt(charMatch[1], 10) : null;
|
|
122
|
-
|
|
123
|
-
// Extract rule from message (format: "... • rule-name")
|
|
124
|
-
const ruleMatch = message.match(/•\s*([a-z-]+)$/i);
|
|
125
|
-
const rule = ruleMatch ? ruleMatch[1] : null;
|
|
126
|
-
|
|
127
|
-
// Clean message (remove line/char and rule parts for display)
|
|
128
|
-
let displayMessage = message;
|
|
129
|
-
if (lineMatch) {
|
|
130
|
-
displayMessage = displayMessage.replace(/Line\s+\d+,?\s*/gi, '');
|
|
131
|
-
}
|
|
132
|
-
if (charMatch) {
|
|
133
|
-
displayMessage = displayMessage.replace(/Char\s+\d+\.?\s*/gi, '');
|
|
134
|
-
}
|
|
135
|
-
if (ruleMatch) {
|
|
136
|
-
displayMessage = displayMessage.replace(/•\s*[a-z-]+$/i, '');
|
|
137
|
-
}
|
|
138
|
-
displayMessage = displayMessage.trim();
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<div
|
|
142
|
-
key={key}
|
|
143
|
-
className={`error-info-note__item error-info-note__item--${severity || 'error'}`}
|
|
144
|
-
>
|
|
145
|
-
<div className="error-info-note__item-icon">
|
|
146
|
-
{getSeverityIcon(severity)}
|
|
147
|
-
</div>
|
|
148
|
-
<div className="error-info-note__item-content">
|
|
149
|
-
<span className="error-info-note__item-message">
|
|
150
|
-
{displayMessage}
|
|
151
|
-
</span>
|
|
152
|
-
{line && (
|
|
153
|
-
<span className="error-info-note__item-location">
|
|
154
|
-
Line
|
|
155
|
-
{' '}
|
|
156
|
-
{line}
|
|
157
|
-
{char ? `, Char ${char}` : ''}
|
|
158
|
-
.
|
|
159
|
-
</span>
|
|
160
|
-
)}
|
|
161
|
-
{rule && (
|
|
162
|
-
<span className="error-info-note__item-rule">
|
|
163
|
-
•
|
|
164
|
-
{' '}
|
|
165
|
-
{rule}
|
|
166
|
-
</span>
|
|
167
|
-
)}
|
|
168
|
-
</div>
|
|
169
|
-
{onErrorClick && (
|
|
170
|
-
<CapTooltip title={intl?.formatMessage ? intl.formatMessage({ id: 'errorInfoNote.navigateToError', defaultMessage: 'Go to error location' }) : 'Go to error location'}>
|
|
171
|
-
<button
|
|
172
|
-
type="button"
|
|
173
|
-
className="error-info-note__item-navigate"
|
|
174
|
-
onClick={(e) => handleNavigateClick({ ...issue, line, column: char }, e)}
|
|
175
|
-
aria-label="Go to error location"
|
|
176
|
-
>
|
|
177
|
-
<CapIcon type="redirection" />
|
|
178
|
-
</button>
|
|
179
|
-
</CapTooltip>
|
|
180
|
-
)}
|
|
181
|
-
</div>
|
|
182
|
-
);
|
|
183
|
-
})}
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
TabContent.propTypes = {
|
|
189
|
-
issues: PropTypes.array,
|
|
190
|
-
onErrorClick: PropTypes.func,
|
|
191
|
-
intl: PropTypes.object,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
TabContent.defaultProps = {
|
|
195
|
-
issues: [],
|
|
196
|
-
onErrorClick: null,
|
|
197
|
-
intl: null,
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* ErrorInfoNote Component with Tabbed Interface
|
|
202
|
-
* @param {boolean} useLegacyDisplay - If true, uses simple list display instead of tabbed interface (for BEE Editor)
|
|
203
|
-
*/
|
|
204
|
-
export const ErrorInfoNote = (props) => {
|
|
205
|
-
const {
|
|
206
|
-
errorMessages,
|
|
207
|
-
onErrorClick,
|
|
208
|
-
onClose,
|
|
209
|
-
isLiquidEnabled = true,
|
|
210
|
-
intl,
|
|
211
|
-
useLegacyDisplay = false, // Use simple list display instead of tabs (for BEE Editor)
|
|
212
|
-
} = props;
|
|
213
|
-
|
|
214
|
-
const [isDismissed, setIsDismissed] = useState(false);
|
|
215
|
-
const [activeKey, setActiveKey] = useState(null);
|
|
216
|
-
|
|
217
|
-
const {
|
|
218
|
-
LIQUID_ERROR_MSG: rawLiquidErrors = [],
|
|
219
|
-
STANDARD_ERROR_MSG: rawStandardErrors = [],
|
|
220
|
-
} = errorMessages || {};
|
|
221
|
-
|
|
222
|
-
// Detect if platform-specific (ANDROID/IOS) or GENERIC
|
|
223
|
-
const isObject = typeof rawStandardErrors === 'object' && rawStandardErrors !== null;
|
|
224
|
-
const isNotArray = !Array.isArray(rawLiquidErrors);
|
|
225
|
-
const hasPlatformKeys = isObject && isNotArray && [ANDROID, IOS, GENERIC].some((key) => key in rawLiquidErrors);
|
|
226
|
-
|
|
227
|
-
// For platform-specific errors or when useLegacyDisplay is true, use the legacy renderer
|
|
228
|
-
if (hasPlatformKeys) {
|
|
229
|
-
const androidErrors = {
|
|
230
|
-
STANDARD: processErrors(rawStandardErrors, 'standard', ANDROID, messages),
|
|
231
|
-
LIQUID: processErrors(rawLiquidErrors, 'liquid', ANDROID, messages),
|
|
232
|
-
};
|
|
233
|
-
const iosErrors = {
|
|
234
|
-
STANDARD: processErrors(rawStandardErrors, 'standard', IOS, messages),
|
|
235
|
-
LIQUID: processErrors(rawLiquidErrors, 'liquid', IOS, messages),
|
|
236
|
-
};
|
|
237
|
-
return (
|
|
238
|
-
<ErrorTypeRenderer
|
|
239
|
-
genericErrors={null}
|
|
240
|
-
androidErrors={androidErrors}
|
|
241
|
-
iosErrors={iosErrors}
|
|
242
|
-
ErrorSectionComponent={ErrorSection}
|
|
243
|
-
/>
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// For BEE Editor (useLegacyDisplay=true), use simple list display without tabs
|
|
248
|
-
if (useLegacyDisplay) {
|
|
249
|
-
const standardErrors = Array.isArray(rawStandardErrors) ? rawStandardErrors : [];
|
|
250
|
-
const liquidErrors = Array.isArray(rawLiquidErrors) ? rawLiquidErrors : [];
|
|
251
|
-
const hasStandardErrors = standardErrors.length > 0;
|
|
252
|
-
const hasLiquidErrors = liquidErrors.length > 0 && isLiquidEnabled;
|
|
253
|
-
|
|
254
|
-
if (!hasStandardErrors && !hasLiquidErrors) {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return (
|
|
259
|
-
<div className="error-container error-container--legacy">
|
|
260
|
-
{hasStandardErrors && (
|
|
261
|
-
<ErrorSection
|
|
262
|
-
title={<FormattedMessage {...messages.standardErrorHeader} />}
|
|
263
|
-
errors={standardErrors}
|
|
264
|
-
liquidError={false}
|
|
265
|
-
/>
|
|
266
|
-
)}
|
|
267
|
-
{hasLiquidErrors && (
|
|
268
|
-
<ErrorSection
|
|
269
|
-
title={<FormattedMessage {...messages.dynamicErrorHeader} />}
|
|
270
|
-
errors={liquidErrors}
|
|
271
|
-
liquidError
|
|
272
|
-
/>
|
|
273
|
-
)}
|
|
274
|
-
</div>
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Categorize errors for tabbed interface
|
|
279
|
-
const { htmlIssues, labelIssues, liquidIssues } = useMemo(() => categorizeErrorMessages(
|
|
280
|
-
Array.isArray(rawStandardErrors) ? rawStandardErrors : [],
|
|
281
|
-
Array.isArray(rawLiquidErrors) ? rawLiquidErrors : [],
|
|
282
|
-
), [rawStandardErrors, rawLiquidErrors]);
|
|
283
|
-
|
|
284
|
-
// Calculate counts
|
|
285
|
-
const htmlCount = htmlIssues.length;
|
|
286
|
-
const labelCount = labelIssues.length;
|
|
287
|
-
const liquidCount = liquidIssues.length;
|
|
288
|
-
const totalCount = htmlCount + labelCount + (isLiquidEnabled ? liquidCount : 0);
|
|
289
|
-
|
|
290
|
-
// Set default active key
|
|
291
|
-
useMemo(() => {
|
|
292
|
-
if (!activeKey) {
|
|
293
|
-
if (htmlCount > 0) {
|
|
294
|
-
setActiveKey('html');
|
|
295
|
-
} else if (labelCount > 0) {
|
|
296
|
-
setActiveKey('label');
|
|
297
|
-
} else if (liquidCount > 0 && isLiquidEnabled) {
|
|
298
|
-
setActiveKey('liquid');
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}, [htmlCount, labelCount, liquidCount, isLiquidEnabled, activeKey]);
|
|
302
|
-
|
|
303
|
-
// Handle close
|
|
304
|
-
const handleClose = () => {
|
|
305
|
-
setIsDismissed(true);
|
|
306
|
-
if (onClose) {
|
|
307
|
-
onClose();
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
// Handle liquid documentation click
|
|
312
|
-
const handleLiquidDocClick = () => {
|
|
313
|
-
window.open(
|
|
314
|
-
'https://docs.capillarytech.com/docs/liquid-language-in-messages',
|
|
315
|
-
'_blank',
|
|
316
|
-
);
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
// Don't render if no issues or dismissed
|
|
320
|
-
if (totalCount === 0 || isDismissed) {
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Build tab panes (CapTab uses 'panes' with 'tab' and 'content' properties)
|
|
325
|
-
const tabPanes = [];
|
|
326
|
-
|
|
327
|
-
if (htmlCount > 0) {
|
|
328
|
-
tabPanes.push({
|
|
329
|
-
key: 'html',
|
|
330
|
-
tab: (
|
|
331
|
-
<span className="error-info-note__tab-label">
|
|
332
|
-
<FormattedMessage {...messages.htmlIssues} />
|
|
333
|
-
<span className="error-info-note__tab-count">
|
|
334
|
-
(
|
|
335
|
-
{htmlCount}
|
|
336
|
-
)
|
|
337
|
-
</span>
|
|
338
|
-
</span>
|
|
339
|
-
),
|
|
340
|
-
content: (
|
|
341
|
-
<TabContent
|
|
342
|
-
issues={htmlIssues}
|
|
343
|
-
onErrorClick={onErrorClick}
|
|
344
|
-
intl={intl}
|
|
345
|
-
/>
|
|
346
|
-
),
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
if (labelCount > 0) {
|
|
351
|
-
tabPanes.push({
|
|
352
|
-
key: 'label',
|
|
353
|
-
tab: (
|
|
354
|
-
<span className="error-info-note__tab-label">
|
|
355
|
-
<FormattedMessage {...messages.labelIssues} />
|
|
356
|
-
<span className="error-info-note__tab-count">
|
|
357
|
-
(
|
|
358
|
-
{labelCount}
|
|
359
|
-
)
|
|
360
|
-
</span>
|
|
361
|
-
</span>
|
|
362
|
-
),
|
|
363
|
-
content: (
|
|
364
|
-
<TabContent
|
|
365
|
-
issues={labelIssues}
|
|
366
|
-
onErrorClick={onErrorClick}
|
|
367
|
-
intl={intl}
|
|
368
|
-
/>
|
|
369
|
-
),
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (isLiquidEnabled && liquidCount > 0) {
|
|
374
|
-
tabPanes.push({
|
|
375
|
-
key: 'liquid',
|
|
376
|
-
tab: (
|
|
377
|
-
<span className="error-info-note__tab-label">
|
|
378
|
-
<FormattedMessage {...messages.liquidIssues} />
|
|
379
|
-
<span className="error-info-note__tab-count">
|
|
380
|
-
(
|
|
381
|
-
{liquidCount}
|
|
382
|
-
)
|
|
383
|
-
</span>
|
|
384
|
-
</span>
|
|
385
|
-
),
|
|
386
|
-
content: (
|
|
387
|
-
<TabContent
|
|
388
|
-
issues={liquidIssues}
|
|
389
|
-
onErrorClick={onErrorClick}
|
|
390
|
-
intl={intl}
|
|
391
|
-
/>
|
|
392
|
-
),
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return (
|
|
397
|
-
<div className="error-container error-container--tabs">
|
|
398
|
-
<CapRow className="error-info-note__header">
|
|
399
|
-
<CapTab
|
|
400
|
-
activeKey={activeKey || (tabPanes[0]?.key)}
|
|
401
|
-
onChange={setActiveKey}
|
|
402
|
-
panes={tabPanes}
|
|
403
|
-
className="error-info-note__tabs"
|
|
404
|
-
/>
|
|
405
|
-
<CapRow className="error-info-note__actions">
|
|
406
|
-
{activeKey === 'liquid' && isLiquidEnabled && (
|
|
407
|
-
<CapButton
|
|
408
|
-
type="flat"
|
|
409
|
-
className="error-info-note__liquid-doc"
|
|
410
|
-
onClick={handleLiquidDocClick}
|
|
411
|
-
>
|
|
412
|
-
<FormattedMessage {...messages.liquidDoc} />
|
|
413
|
-
<CapIcon size="s" type="launch" />
|
|
414
|
-
</CapButton>
|
|
415
|
-
)}
|
|
416
|
-
<CapTooltip title={intl?.formatMessage ? intl.formatMessage({ id: 'errorInfoNote.closePanel', defaultMessage: 'Close validation panel' }) : 'Close validation panel'}>
|
|
417
|
-
<button
|
|
418
|
-
type="button"
|
|
419
|
-
className="error-info-note__close"
|
|
420
|
-
onClick={handleClose}
|
|
421
|
-
aria-label="Close validation panel"
|
|
422
|
-
>
|
|
423
|
-
<CapIcon type="close" />
|
|
424
|
-
</button>
|
|
425
|
-
</CapTooltip>
|
|
426
|
-
</CapRow>
|
|
427
|
-
</CapRow>
|
|
428
|
-
</div>
|
|
429
|
-
);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// Legacy ErrorSection component for platform-specific errors (backwards compatibility)
|
|
433
19
|
const ErrorSection = ({
|
|
434
20
|
title,
|
|
435
21
|
errors,
|
|
@@ -440,7 +26,7 @@ const ErrorSection = ({
|
|
|
440
26
|
{title && (
|
|
441
27
|
<CapRow
|
|
442
28
|
className={`error-header ${
|
|
443
|
-
!liquidError ?
|
|
29
|
+
!liquidError ? "standard-error-header" : ""
|
|
444
30
|
}`}
|
|
445
31
|
>
|
|
446
32
|
<>
|
|
@@ -452,7 +38,8 @@ const ErrorSection = ({
|
|
|
452
38
|
<CapButton
|
|
453
39
|
type="flat"
|
|
454
40
|
className="add-btn"
|
|
455
|
-
onClick={() => window.open(
|
|
41
|
+
onClick={() => window.open("https://docs.capillarytech.com/docs/liquid-language-in-messages", "_blank")
|
|
42
|
+
}
|
|
456
43
|
>
|
|
457
44
|
<FormattedMessage {...messages.liquidDoc} />
|
|
458
45
|
<CapIcon size="s" type="launch" />
|
|
@@ -466,15 +53,21 @@ const ErrorSection = ({
|
|
|
466
53
|
<CapLabel type="label2">{platformLabel}</CapLabel>
|
|
467
54
|
</CapRow>
|
|
468
55
|
)}
|
|
469
|
-
<
|
|
470
|
-
|
|
471
|
-
|
|
56
|
+
<CapList
|
|
57
|
+
className="error-list"
|
|
58
|
+
size="small"
|
|
59
|
+
dataSource={errors}
|
|
60
|
+
renderItem={(error, index) => (
|
|
61
|
+
<CapList.Item>
|
|
472
62
|
<CapLabel type="label2" className="cap-list-v2-error-item">
|
|
63
|
+
<CapLabel type="label2">
|
|
64
|
+
<FormattedNumber value={index + 1} />.
|
|
65
|
+
</CapLabel>
|
|
473
66
|
<CapLabel type="label2">{error}</CapLabel>
|
|
474
67
|
</CapLabel>
|
|
475
|
-
</
|
|
476
|
-
)
|
|
477
|
-
|
|
68
|
+
</CapList.Item>
|
|
69
|
+
)}
|
|
70
|
+
/>
|
|
478
71
|
</>
|
|
479
72
|
);
|
|
480
73
|
|
|
@@ -491,16 +84,54 @@ ErrorSection.defaultProps = {
|
|
|
491
84
|
platformLabel: null,
|
|
492
85
|
};
|
|
493
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
|
+
|
|
494
130
|
ErrorInfoNote.defaultProps = {
|
|
495
131
|
errorMessages: {
|
|
496
132
|
LIQUID_ERROR_MSG: [],
|
|
497
133
|
STANDARD_ERROR_MSG: [],
|
|
498
134
|
},
|
|
499
|
-
onErrorClick: null,
|
|
500
|
-
onClose: null,
|
|
501
|
-
isLiquidEnabled: true,
|
|
502
|
-
intl: null,
|
|
503
|
-
useLegacyDisplay: false, // Use simple list display for BEE Editor
|
|
504
135
|
};
|
|
505
136
|
|
|
506
137
|
ErrorInfoNote.propTypes = {
|
|
@@ -522,11 +153,5 @@ ErrorInfoNote.propTypes = {
|
|
|
522
153
|
}),
|
|
523
154
|
]),
|
|
524
155
|
}),
|
|
525
|
-
onErrorClick: PropTypes.func,
|
|
526
|
-
onClose: PropTypes.func,
|
|
527
|
-
isLiquidEnabled: PropTypes.bool,
|
|
528
|
-
intl: PropTypes.object,
|
|
529
|
-
useLegacyDisplay: PropTypes.bool, // Use simple list display for BEE Editor
|
|
530
156
|
};
|
|
531
|
-
|
|
532
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:
|