@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.
Files changed (133) 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 -18
  8. package/utils/common.js +0 -5
  9. package/utils/commonUtils.js +5 -28
  10. package/utils/tests/commonUtil.test.js +0 -224
  11. package/utils/transformTemplateConfig.js +10 -0
  12. package/v2Components/CapDeviceContent/index.js +56 -61
  13. package/v2Components/CapTagList/index.js +1 -6
  14. package/v2Components/CapTagListWithInput/index.js +1 -5
  15. package/v2Components/CapTagListWithInput/messages.js +1 -1
  16. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  17. package/v2Components/ErrorInfoNote/index.js +72 -447
  18. package/v2Components/ErrorInfoNote/messages.js +0 -22
  19. package/v2Components/ErrorInfoNote/style.scss +4 -280
  20. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  21. package/v2Components/HtmlEditor/HTMLEditor.js +94 -642
  22. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1135
  23. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  24. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  25. package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
  26. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
  27. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
  28. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  29. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  30. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
  31. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
  32. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  33. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  34. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  35. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  36. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  37. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  38. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
  39. package/v2Components/HtmlEditor/components/PreviewPane/index.js +13 -11
  40. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  41. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  42. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
  43. package/v2Components/HtmlEditor/constants.js +20 -29
  44. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  45. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  46. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  47. package/v2Components/HtmlEditor/hooks/useValidation.js +45 -150
  48. package/v2Components/HtmlEditor/index.js +1 -1
  49. package/v2Components/HtmlEditor/messages.js +85 -95
  50. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
  51. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  52. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  53. package/v2Components/MobilePushPreviewV2/index.js +7 -32
  54. package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
  55. package/v2Components/TemplatePreview/index.js +32 -47
  56. package/v2Components/TemplatePreview/messages.js +0 -4
  57. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  58. package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
  59. package/v2Containers/BeeEditor/index.js +90 -172
  60. package/v2Containers/CreativesContainer/SlideBoxContent.js +51 -128
  61. package/v2Containers/CreativesContainer/SlideBoxFooter.js +12 -113
  62. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
  63. package/v2Containers/CreativesContainer/constants.js +0 -1
  64. package/v2Containers/CreativesContainer/index.js +46 -238
  65. package/v2Containers/CreativesContainer/messages.js +0 -8
  66. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  67. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -38
  68. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -91
  69. package/v2Containers/Email/actions.js +0 -7
  70. package/v2Containers/Email/constants.js +1 -5
  71. package/v2Containers/Email/index.js +30 -229
  72. package/v2Containers/Email/messages.js +0 -32
  73. package/v2Containers/Email/reducer.js +1 -12
  74. package/v2Containers/Email/sagas.js +7 -61
  75. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  76. package/v2Containers/Email/tests/sagas.test.js +1 -1
  77. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +15 -210
  78. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  79. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  80. package/v2Containers/EmailWrapper/constants.js +0 -2
  81. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  82. package/v2Containers/EmailWrapper/index.js +23 -103
  83. package/v2Containers/EmailWrapper/messages.js +1 -61
  84. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  85. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -509
  86. package/v2Containers/InApp/actions.js +0 -7
  87. package/v2Containers/InApp/constants.js +4 -20
  88. package/v2Containers/InApp/index.js +357 -801
  89. package/v2Containers/InApp/index.scss +3 -4
  90. package/v2Containers/InApp/messages.js +3 -7
  91. package/v2Containers/InApp/reducer.js +3 -21
  92. package/v2Containers/InApp/sagas.js +9 -29
  93. package/v2Containers/InApp/selectors.js +5 -25
  94. package/v2Containers/InApp/tests/index.test.js +50 -154
  95. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  96. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  97. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
  98. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
  99. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
  100. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
  101. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
  102. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
  103. package/v2Containers/TagList/index.js +19 -62
  104. package/v2Containers/Templates/_templates.scss +1 -60
  105. package/v2Containers/Templates/index.js +4 -89
  106. package/v2Containers/Templates/messages.js +0 -4
  107. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -35
  108. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
  109. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
  110. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -363
  111. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  112. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +0 -630
  113. package/v2Containers/BeePopupEditor/constants.js +0 -10
  114. package/v2Containers/BeePopupEditor/index.js +0 -193
  115. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  116. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1317
  117. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1605
  118. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  119. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
  120. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  121. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  122. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  123. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
  124. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  125. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
  126. package/v2Containers/InAppWrapper/constants.js +0 -16
  127. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  128. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  129. package/v2Containers/InAppWrapper/index.js +0 -148
  130. package/v2Containers/InAppWrapper/messages.js +0 -49
  131. package/v2Containers/InappAdvance/index.js +0 -1099
  132. package/v2Containers/InappAdvance/index.scss +0 -10
  133. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
@@ -1,254 +0,0 @@
1
- /**
2
- * ValidationTabs Styles
3
- */
4
-
5
- @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
6
-
7
- .validation-tabs {
8
- overflow-y: hidden;
9
- width: 100%;
10
- background-color: $CAP_COLOR_05; // Light pink background
11
- border-radius: 0.25rem;
12
- padding: 1rem 1rem;
13
- box-sizing: border-box;
14
-
15
- &__header {
16
- display: flex;
17
- align-items: flex-start;
18
- justify-content: space-between;
19
- width: 100%;
20
- }
21
-
22
- &__tabs {
23
- flex: 1;
24
-
25
- // Override CapTab styles for proper spacing
26
- .cap-tab-v2 {
27
- .ant-tabs-nav {
28
- margin-bottom: 0;
29
-
30
- &::before {
31
- border-bottom: none;
32
- }
33
- }
34
-
35
- .ant-tabs-tab {
36
- padding: 0.5rem 0.75rem; // Add horizontal padding for spacing
37
- margin-right: 0; // Remove margin, use padding instead
38
- color: $CAP_G03;
39
- font-size: 0.875rem;
40
- font-weight: 500;
41
-
42
- & + .ant-tabs-tab {
43
- margin-left: 1.5rem; // Add space between tabs
44
- }
45
-
46
- &:hover {
47
- color: $CAP_COLOR_05;
48
- background: transparent;
49
- }
50
-
51
- &.ant-tabs-tab-active {
52
- .ant-tabs-tab-btn {
53
- color: $CAP_COLOR_05;
54
- font-weight: 600;
55
- }
56
- }
57
- }
58
-
59
- .ant-tabs-ink-bar {
60
- background-color: $CAP_COLOR_05;
61
- height: 0.125rem;
62
- }
63
-
64
- .ant-tabs-content-holder {
65
- padding-top: 0.25rem; // Reduced from 0.5rem
66
- padding-bottom: 0; // No bottom padding
67
- }
68
- }
69
- }
70
-
71
- &__tab-label {
72
- display: flex;
73
- align-items: center;
74
- gap: 0.25rem;
75
- }
76
-
77
- &__tab-count {
78
- color: inherit;
79
- }
80
-
81
- &__actions {
82
- display: flex;
83
- align-items: center;
84
- gap: 0.5rem;
85
- flex-shrink: 0;
86
- padding-top: 0.5rem;
87
- }
88
-
89
- &__close {
90
- display: flex;
91
- align-items: center;
92
- justify-content: center;
93
- width: 1.5rem;
94
- height: 1.5rem;
95
- padding: 0;
96
- background: transparent;
97
- border: none;
98
- border-radius: 0.25rem;
99
- cursor: pointer;
100
- color: $CAP_G03;
101
- transition: all 0.2s ease;
102
-
103
- &:hover {
104
- background-color: rgba($CAP_COLOR_05, 0.1);
105
- color: $CAP_COLOR_05;
106
- }
107
-
108
- .cap-icon-v2 {
109
- font-size: 0.875rem;
110
- }
111
- }
112
-
113
- &__content {
114
- max-height: 15rem; // Limit height for many errors
115
- overflow-y: auto;
116
- padding-right: 0.25rem;
117
- padding-bottom: 0; // Remove bottom padding completely
118
-
119
- // Custom scrollbar
120
- &::-webkit-scrollbar {
121
- width: 0.375rem;
122
- }
123
-
124
- &::-webkit-scrollbar-track {
125
- background: transparent;
126
- }
127
-
128
- &::-webkit-scrollbar-thumb {
129
- background-color: $CAP_G06;
130
- border-radius: 0.1875rem;
131
-
132
- &:hover {
133
- background-color: $CAP_G04;
134
- }
135
- }
136
- }
137
-
138
- &__item {
139
- display: flex;
140
- align-items: flex-start;
141
- gap: 0.5rem;
142
- padding: 0.25rem 0; // Reduced from 0.375rem
143
- border-bottom: 1px solid rgba($CAP_G06, 0.3);
144
-
145
- &:last-child {
146
- border-bottom: none;
147
- padding-bottom: 0.25rem; // Minimal padding on last item
148
- }
149
-
150
- &--error {
151
- .validation-tabs__icon--error {
152
- color: $CAP_RED;
153
- }
154
- }
155
-
156
- &--warning {
157
- .validation-tabs__icon--warning {
158
- color: $CAP_YELLOW;
159
- }
160
- }
161
- }
162
-
163
- &__item-icon {
164
- flex-shrink: 0;
165
- display: flex;
166
- align-items: center;
167
- padding-top: 0.125rem;
168
- }
169
-
170
- &__icon {
171
- font-size: 0.875rem;
172
-
173
- &--error {
174
- color: $CAP_RED;
175
- }
176
-
177
- &--warning {
178
- color: $CAP_YELLOW;
179
- }
180
- }
181
-
182
- &__item-content {
183
- flex: 1;
184
- display: flex;
185
- flex-wrap: wrap;
186
- align-items: baseline;
187
- gap: 0.25rem;
188
- font-size: 0.75rem;
189
- line-height: 1.4;
190
- color: $CAP_G01;
191
- }
192
-
193
- &__item-message {
194
- color: $CAP_G01;
195
- }
196
-
197
- &__item-location {
198
- color: $CAP_G03;
199
- white-space: nowrap;
200
- }
201
-
202
- &__item-rule {
203
- color: $CAP_G04;
204
- font-family: monospace;
205
- font-size: 0.6875rem;
206
- }
207
-
208
- &__item-navigate {
209
- flex-shrink: 0;
210
- display: flex;
211
- align-items: center;
212
- justify-content: center;
213
- width: 1.25rem;
214
- height: 1.25rem;
215
- padding: 0;
216
- background: transparent;
217
- border: none;
218
- border-radius: 0.25rem;
219
- cursor: pointer;
220
- color: $CAP_G04;
221
- transition: all 0.2s ease;
222
-
223
- &:hover {
224
- background-color: rgba($CAP_G01, 0.1);
225
- color: $CAP_G01;
226
- }
227
-
228
- .anticon {
229
- font-size: 0.75rem;
230
- }
231
- }
232
- }
233
-
234
- // Responsive adjustments
235
- @media (max-width: 768px) {
236
- .validation-tabs {
237
- padding: 0.375rem 0.5rem;
238
-
239
- &__tabs {
240
- .ant-tabs-tab {
241
- margin-right: 1rem;
242
- font-size: 0.8125rem;
243
- }
244
- }
245
-
246
- &__content {
247
- max-height: 10rem;
248
- }
249
-
250
- &__item-content {
251
- font-size: 0.6875rem;
252
- }
253
- }
254
- }
@@ -1,363 +0,0 @@
1
- /**
2
- * ValidationTabs Component
3
- *
4
- * Displays validation errors in a tabbed interface with 3 categories:
5
- * - HTML issues: General HTML/CSS validation errors and warnings
6
- * - Label issues: Tag syntax errors (open/close tags, attributes, brackets)
7
- * - Liquid issues: Liquid expression errors (only when liquid feature enabled)
8
- */
9
-
10
- import React, { useState, useMemo } from 'react';
11
- import PropTypes from 'prop-types';
12
- import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
13
-
14
- // Cap UI Library
15
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
16
- import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
17
- import CapTab from '@capillarytech/cap-ui-library/CapTab';
18
- import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
19
-
20
- // Messages
21
- import messages from './messages';
22
-
23
- // Styles
24
- import './_validationTabs.scss';
25
-
26
- // Constants for issue sources
27
- const ISSUE_SOURCES = {
28
- HTMLHINT: 'htmlhint',
29
- CSS_VALIDATOR: 'css-validator',
30
- CUSTOM: 'custom',
31
- SECURITY: 'security',
32
- LIQUID: 'liquid-validator',
33
- };
34
-
35
- // Label issue patterns - syntax errors related to tags
36
- const LABEL_ISSUE_PATTERNS = [
37
- 'tag must be paired',
38
- 'open tag match failed',
39
- 'closed tag match failed',
40
- 'unclosed',
41
- 'missing required',
42
- 'tag-pair',
43
- 'attr-value-not-empty',
44
- 'attr-no-duplication',
45
- 'tag-self-close',
46
- 'spec-char-escape',
47
- 'tagname-lowercase',
48
- 'attr-lowercase',
49
- 'id-unique',
50
- 'src-not-empty',
51
- 'alt-require',
52
- ];
53
-
54
- /**
55
- * Categorize issues into HTML, Label, and Liquid categories
56
- */
57
- const categorizeIssues = (allIssues) => {
58
- const htmlIssues = [];
59
- const labelIssues = [];
60
- const liquidIssues = [];
61
-
62
- allIssues.forEach((issue) => {
63
- const { source, rule, message } = issue;
64
- const messageLower = (message || '').toLowerCase();
65
- const ruleLower = (rule || '').toLowerCase();
66
-
67
- // Check if it's a Liquid issue - ONLY by source, not by message content
68
- // This prevents false positives where HTML errors mention liquid syntax
69
- if (source === ISSUE_SOURCES.LIQUID) {
70
- liquidIssues.push(issue);
71
- return;
72
- }
73
-
74
- // Check if it's a Label (tag syntax) issue
75
- const isLabelIssue = LABEL_ISSUE_PATTERNS.some(
76
- (pattern) => messageLower.includes(pattern.toLowerCase())
77
- || ruleLower.includes(pattern.toLowerCase()),
78
- );
79
-
80
- if (isLabelIssue) {
81
- labelIssues.push(issue);
82
- return;
83
- }
84
-
85
- // Default to HTML issues
86
- htmlIssues.push(issue);
87
- });
88
-
89
- return { htmlIssues, labelIssues, liquidIssues };
90
- };
91
-
92
- /**
93
- * Get icon based on severity
94
- */
95
- const getSeverityIcon = (severity) => {
96
- if (severity === 'warning') {
97
- return <CapIcon type="alert-warning" className="validation-tabs__icon validation-tabs__icon--warning" />;
98
- }
99
- return <CapIcon type="warning-circle" className="validation-tabs__icon validation-tabs__icon--error" />;
100
- };
101
-
102
- /**
103
- * ValidationTabContent - Renders the content for each tab
104
- */
105
- const ValidationTabContent = ({
106
- issues,
107
- onErrorClick,
108
- }) => {
109
- if (!issues || issues.length === 0) {
110
- return null;
111
- }
112
-
113
- const handleNavigateClick = (issue, e) => {
114
- e.stopPropagation();
115
- if (onErrorClick) {
116
- // Always call onErrorClick to acknowledge the error (enables buttons)
117
- // If line number exists, navigate to it; otherwise just acknowledge and focus editor
118
- onErrorClick({
119
- line: issue.line || 1, // Default to line 1 if no line number (for API errors)
120
- column: issue.column || 1,
121
- message: issue.message,
122
- severity: issue.severity,
123
- });
124
- }
125
- };
126
-
127
- return (
128
- <div className="validation-tabs__content">
129
- {issues.map((issue, index) => {
130
- const {
131
- severity, message, line, column,
132
- } = issue;
133
- const key = `${message}-${line}-${column}-${index}`;
134
-
135
- return (
136
- <div
137
- key={key}
138
- className={`validation-tabs__item validation-tabs__item--${severity || 'error'}`}
139
- >
140
- <div className="validation-tabs__item-icon">
141
- {getSeverityIcon(severity)}
142
- </div>
143
- <div className="validation-tabs__item-content">
144
- <span className="validation-tabs__item-message">
145
- {message}
146
- </span>
147
- {line && (
148
- <span className="validation-tabs__item-location">
149
- <FormattedMessage
150
- {...messages.lineChar}
151
- values={{ line, char: column || 1 }}
152
- />
153
- </span>
154
- )}
155
- </div>
156
- {/* Always show redirection icon for errors (even API errors without line numbers) */}
157
- {/* Clicking it acknowledges the error and enables buttons */}
158
- <CapTooltip title={line ? `Line ${line}, Char ${column || 1}` : 'Click to acknowledge error and focus editor'}>
159
- <button
160
- type="button"
161
- className="validation-tabs__item-navigate"
162
- onClick={(e) => handleNavigateClick(issue, e)}
163
- aria-label={line ? `Line ${line}, Char ${column || 1}` : 'Acknowledge error'}
164
- >
165
- <CapIcon type="redirection" />
166
- </button>
167
- </CapTooltip>
168
- </div>
169
- );
170
- })}
171
- </div>
172
- );
173
- };
174
-
175
- ValidationTabContent.propTypes = {
176
- issues: PropTypes.array,
177
- onErrorClick: PropTypes.func,
178
- intl: intlShape.isRequired,
179
- };
180
-
181
- ValidationTabContent.defaultProps = {
182
- issues: [],
183
- onErrorClick: null,
184
- };
185
-
186
- /**
187
- * ValidationTabs Component
188
- */
189
- const ValidationTabs = ({
190
- intl,
191
- validation,
192
- onErrorClick,
193
- onClose,
194
- isLiquidEnabled,
195
- className,
196
- }) => {
197
- const [activeKey, setActiveKey] = useState(null);
198
-
199
- // Categorize issues
200
- const { htmlIssues, labelIssues, liquidIssues } = useMemo(() => {
201
- if (!validation) {
202
- return { htmlIssues: [], labelIssues: [], liquidIssues: [] };
203
- }
204
-
205
- // Get all issues from validation
206
- const allIssues = validation.getAllIssues ? validation.getAllIssues() : [];
207
- const categorized = categorizeIssues(allIssues);
208
- return categorized;
209
- }, [validation]);
210
-
211
- // Calculate counts
212
- const htmlCount = htmlIssues.length;
213
- const labelCount = labelIssues.length;
214
- const liquidCount = liquidIssues.length;
215
- const totalCount = htmlCount + labelCount + (isLiquidEnabled ? liquidCount : 0);
216
-
217
- // Set default active key when issues change
218
- useMemo(() => {
219
- if (htmlCount > 0 && !activeKey) {
220
- setActiveKey('html');
221
- } else if (labelCount > 0 && !activeKey) {
222
- setActiveKey('label');
223
- } else if (liquidCount > 0 && isLiquidEnabled && !activeKey) {
224
- setActiveKey('liquid');
225
- }
226
- }, [htmlCount, labelCount, liquidCount, isLiquidEnabled, activeKey]);
227
-
228
- // Don't render if no issues
229
- if (totalCount === 0) {
230
- return null;
231
- }
232
-
233
- // Build tab panes (CapTab uses 'panes' with 'tab' and 'content' properties)
234
- const tabPanes = [];
235
-
236
- if (htmlCount > 0) {
237
- tabPanes.push({
238
- key: 'html',
239
- tab: (
240
- <CapTooltip title={`${intl.formatMessage(messages.htmlIssues)} (${htmlCount})`}>
241
- <span className="validation-tabs__tab-label">
242
- <FormattedMessage {...messages.htmlIssues} />
243
- <span className="validation-tabs__tab-count">
244
- (
245
- {htmlCount}
246
- )
247
- </span>
248
- </span>
249
- </CapTooltip>
250
- ),
251
- content: (
252
- <ValidationTabContent
253
- issues={htmlIssues}
254
- onErrorClick={onErrorClick}
255
- intl={intl}
256
- />
257
- ),
258
- });
259
- }
260
-
261
- if (labelCount > 0) {
262
- tabPanes.push({
263
- key: 'label',
264
- tab: (
265
- <CapTooltip title={`${intl.formatMessage(messages.labelIssues)} (${labelCount})`}>
266
- <span className="validation-tabs__tab-label">
267
- <FormattedMessage {...messages.labelIssues} />
268
- <span className="validation-tabs__tab-count">
269
- (
270
- {labelCount}
271
- )
272
- </span>
273
- </span>
274
- </CapTooltip>
275
- ),
276
- content: (
277
- <ValidationTabContent
278
- issues={labelIssues}
279
- onErrorClick={onErrorClick}
280
- intl={intl}
281
- />
282
- ),
283
- });
284
- }
285
-
286
- if (isLiquidEnabled && liquidCount > 0) {
287
- tabPanes.push({
288
- key: 'liquid',
289
- tab: (
290
- <CapTooltip title={`${intl.formatMessage(messages.liquidIssues)} (${liquidCount})`}>
291
- <span className="validation-tabs__tab-label">
292
- <FormattedMessage {...messages.liquidIssues} />
293
- <span className="validation-tabs__tab-count">
294
- (
295
- {liquidCount}
296
- )
297
- </span>
298
- </span>
299
- </CapTooltip>
300
- ),
301
- content: (
302
- <ValidationTabContent
303
- issues={liquidIssues}
304
- onErrorClick={onErrorClick}
305
- intl={intl}
306
- />
307
- ),
308
- });
309
- }
310
-
311
- // Handle close
312
- const handleClose = () => {
313
- if (onClose) {
314
- onClose();
315
- }
316
- };
317
-
318
- return (
319
- <div className={`validation-tabs ${className || ''}`}>
320
- <CapRow className="validation-tabs__header">
321
- <CapTab
322
- activeKey={activeKey || (tabPanes[0]?.key)}
323
- onChange={setActiveKey}
324
- panes={tabPanes}
325
- className="validation-tabs__tabs"
326
- />
327
- <CapRow className="validation-tabs__actions">
328
- <CapTooltip title={intl.formatMessage(messages.closePanel)}>
329
- <button
330
- type="button"
331
- className="validation-tabs__close"
332
- onClick={handleClose}
333
- aria-label={intl.formatMessage(messages.closePanel)}
334
- >
335
- <CapIcon type="close" />
336
- </button>
337
- </CapTooltip>
338
- </CapRow>
339
- </CapRow>
340
- </div>
341
- );
342
- };
343
-
344
- ValidationTabs.propTypes = {
345
- intl: intlShape.isRequired,
346
- validation: PropTypes.shape({
347
- getAllIssues: PropTypes.func,
348
- }),
349
- onErrorClick: PropTypes.func,
350
- onClose: PropTypes.func,
351
- isLiquidEnabled: PropTypes.bool,
352
- className: PropTypes.string,
353
- };
354
-
355
- ValidationTabs.defaultProps = {
356
- validation: null,
357
- onErrorClick: null,
358
- onClose: null,
359
- isLiquidEnabled: false,
360
- className: '',
361
- };
362
-
363
- export default injectIntl(ValidationTabs);
@@ -1,51 +0,0 @@
1
- /**
2
- * ValidationTabs Messages
3
- *
4
- * Internationalization messages for the ValidationTabs component
5
- */
6
-
7
- import { defineMessages } from 'react-intl';
8
-
9
- const scope = 'app.components.HtmlEditor.ValidationTabs';
10
-
11
- export default defineMessages({
12
- // Tab labels
13
- htmlIssues: {
14
- id: `${scope}.htmlIssues`,
15
- defaultMessage: 'HTML issues',
16
- },
17
- labelIssues: {
18
- id: `${scope}.labelIssues`,
19
- defaultMessage: 'Label issues',
20
- },
21
- liquidIssues: {
22
- id: `${scope}.liquidIssues`,
23
- defaultMessage: 'Liquid issues',
24
- },
25
-
26
- // Error item labels
27
- syntaxError: {
28
- id: `${scope}.syntaxError`,
29
- defaultMessage: 'Syntax Error',
30
- },
31
- lineChar: {
32
- id: `${scope}.lineChar`,
33
- defaultMessage: 'Line {line}, Char {char}.',
34
- },
35
-
36
- // Tooltips
37
- navigateToError: {
38
- id: `${scope}.navigateToError`,
39
- defaultMessage: 'Go to error location',
40
- },
41
- closePanel: {
42
- id: `${scope}.closePanel`,
43
- defaultMessage: 'Close validation panel',
44
- },
45
-
46
- // Liquid documentation
47
- liquidDocumentation: {
48
- id: `${scope}.liquidDocumentation`,
49
- defaultMessage: 'Liquid documentation',
50
- },
51
- });