@openlettermarketing/olc-react-sdk 2.1.6-beta.2 → 2.1.6-beta.4

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 (29) hide show
  1. package/build/index.js +77 -77
  2. package/build/index.js.map +1 -1
  3. package/build/types/src/assets/images/modal-icons/checkbox-checked.d.ts +3 -0
  4. package/build/types/src/assets/images/modal-icons/checkbox-unchecked.d.ts +3 -0
  5. package/build/types/src/assets/images/modal-icons/warning.d.ts +3 -0
  6. package/build/types/src/components/GenericUIBlocks/Dialog/V2/index.d.ts +2 -0
  7. package/build/types/src/components/GenericUIBlocks/Dialog/index.d.ts +1 -0
  8. package/build/types/src/components/TopNavigation/FieldValidationModal/index.d.ts +12 -0
  9. package/build/types/src/utils/message.d.ts +8 -0
  10. package/build/types/src/utils/template-builder.d.ts +26 -0
  11. package/build/types/src/utils/templateIdentifierArea/triFold.d.ts +0 -2
  12. package/build/types/version.d.ts +1 -1
  13. package/package.json +1 -1
  14. package/src/assets/images/modal-icons/checkbox-checked.tsx +24 -0
  15. package/src/assets/images/modal-icons/checkbox-unchecked.tsx +13 -0
  16. package/src/assets/images/modal-icons/warning.tsx +15 -0
  17. package/src/components/GenericUIBlocks/Dialog/V2/index.tsx +8 -4
  18. package/src/components/GenericUIBlocks/Dialog/V2/styles.scss +10 -1
  19. package/src/components/GenericUIBlocks/Dialog/index.tsx +4 -2
  20. package/src/components/TopNavigation/FieldValidationModal/index.tsx +116 -0
  21. package/src/components/TopNavigation/FieldValidationModal/styles.scss +48 -0
  22. package/src/components/TopNavigation/index.tsx +68 -1
  23. package/src/utils/message.ts +9 -1
  24. package/src/utils/products.ts +1 -1
  25. package/src/utils/template-builder.ts +105 -3
  26. package/src/utils/templateIdentifierArea/triFold.ts +8 -26
  27. package/src/utils/templateRestrictedArea/triFold.ts +6 -8
  28. package/src/utils/templateSafetyBorders/triFold.ts +20 -27
  29. package/version.js +1 -1
@@ -84,10 +84,10 @@ export const selfMailerProduct = {
84
84
  ],
85
85
  },
86
86
  {
87
- id: "11", defaultSize: "11x8.5", title: "Self Mailer", productType: "Tri-Fold Self-Mailers", hasEnvelope: false, paper: '80# text', label: '8.5x11',
87
+ id: "11", defaultSize: "12x9", title: "Self Mailer", productType: "Tri-Fold Self-Mailers", hasEnvelope: false, paper: '80# text', label: '8.5x11',
88
88
  finish: 'Glass Coated', size: [{
89
89
  id: "11",
90
- size: "11x8.5",
90
+ size: "12x9",
91
91
  label: "8.5x11"
92
92
  }]
93
93
  },
@@ -325,4 +325,106 @@ export const isValidQR = (pages: any) => {
325
325
  }
326
326
  }
327
327
  return true;
328
- }
328
+ }
329
+
330
+ /**
331
+ * Interface for invalid field validation results
332
+ */
333
+ export interface InvalidField {
334
+ field: string;
335
+ issue: 'INVALID_FORMAT' | 'NOT_UPPERCASE';
336
+ pageIndex: number;
337
+ }
338
+
339
+ /**
340
+ * Validates template fields for correct format and capitalization
341
+ * Returns array of invalid fields found in the template
342
+ *
343
+ * @param pages - Template pages array from store.toJSON()
344
+ * @returns Array of objects containing invalid fields and their issues
345
+ */
346
+ export const validateTemplateFields = (pages: any): InvalidField[] => {
347
+ const invalidFields: InvalidField[] = [];
348
+
349
+ pages.forEach((page: any, pageIndex: number) => {
350
+ page.children?.forEach((child: any) => {
351
+ if (child.type === 'text' && child.text) {
352
+ const text = child.text;
353
+
354
+ // ── Step 1 - Find ALL complete brace expressions: anything from the first { to the last } on the same "group", including spaces inside.
355
+ const completePattern = /\{+[^{}]*\}+/g;
356
+ let match: RegExpExecArray | null;
357
+
358
+ // Track which character ranges are already covered so Steps 2 & 3 - don't double-report sub-strings of a complete match.
359
+ const coveredRanges: Array<[number, number]> = [];
360
+
361
+ const completeExec = new RegExp(completePattern.source, 'g');
362
+ while ((match = completeExec.exec(text)) !== null) {
363
+ coveredRanges.push([match.index, match.index + match[0].length]);
364
+ const token = match[0];
365
+ // Valid: EXACTLY {{UPPERCASE_CONTENT}} — no spaces, no lowercase
366
+ const isValidFormat = /^\{\{[A-Z0-9._]+\}\}$/.test(token);
367
+
368
+ if (!isValidFormat) {
369
+ const content = token.replace(/^\{+|\}+$/g, '');
370
+ const isDoubleBrace = /^\{\{[\s\S]+\}\}$/.test(token);
371
+ const hasOnlyValidChars = /^[A-Za-z0-9._]+$/.test(content);
372
+ if (isDoubleBrace && hasOnlyValidChars && content !== content.toUpperCase()) {
373
+ // e.g. {{c.last_name}} — correct braces but lowercase content
374
+ invalidFields.push({ field: token, issue: 'NOT_UPPERCASE', pageIndex });
375
+ } else {
376
+ invalidFields.push({ field: token, issue: 'INVALID_FORMAT', pageIndex });
377
+ }
378
+ }
379
+ }
380
+
381
+ // Helper: returns true if the character at `idx` is inside a covered range
382
+ const isCovered = (idx: number): boolean =>
383
+ coveredRanges.some(([s, e]) => idx >= s && idx < e);
384
+
385
+ // ── Step 2 ─ Find incomplete patterns that have opening brace(s) but NO closing brace.e.g. "{C.LAST_NAME" or "{{C.LAST_NAME" at end of text.
386
+ const missingClosingExec = /\{+[^{}]*/g;
387
+ while ((match = missingClosingExec.exec(text)) !== null) {
388
+ if (!isCovered(match.index) && match[0].trim().length > 0) {
389
+ invalidFields.push({ field: match[0], issue: 'INVALID_FORMAT', pageIndex });
390
+ }
391
+ }
392
+
393
+ // ── Step 3 ─ Find incomplete patterns that have closing brace(s) but NO opening brace. e.g. "C.LAST_NAME}" or "C.LAST_NAME}}".
394
+ const missingOpeningExec = /(?<!\{)[A-Z0-9][A-Z0-9._\s]*\}+/g;
395
+ while ((match = missingOpeningExec.exec(text)) !== null) {
396
+ if (!isCovered(match.index) && match[0].trim().length > 0) {
397
+ invalidFields.push({ field: match[0].trim(), issue: 'INVALID_FORMAT', pageIndex });
398
+ }
399
+ }
400
+ }
401
+ });
402
+ });
403
+
404
+ // Remove duplicates
405
+ const uniqueFields = invalidFields.filter((item: InvalidField, index: number, self: InvalidField[]) =>
406
+ index === self.findIndex((t: InvalidField) => t.field === item.field && t.issue === item.issue)
407
+ );
408
+
409
+ return uniqueFields;
410
+ };
411
+
412
+ /**
413
+ * Validates that all dynamic field tokens used in the template exist in the allowed keys list.
414
+ * Scans the entire serialized template JSON for {{...}} patterns and returns any tokens
415
+ * that are not present in the provided allowedKeys list.
416
+ *
417
+ * @param templateJSON - Full template JSON object from store.toJSON()
418
+ * @param allowedKeys - Array of allowed {{...}} token strings (predefined + custom fields)
419
+ * @returns Array of unrecognized token strings; empty array means all fields are valid
420
+ */
421
+ export const validateAllowedTemplateFields = (
422
+ templateJSON: any,
423
+ allowedKeys: string[]
424
+ ): string[] => {
425
+ const templateStr = JSON.stringify(templateJSON);
426
+ const pattern = /\{\{[^{}]+\}\}/g;
427
+ const matches = templateStr.match(pattern) || [];
428
+ const unique = Array.from(new Set(matches));
429
+ return unique.filter(token => !allowedKeys.includes(token));
430
+ };
@@ -1,5 +1,3 @@
1
- import { DPI } from "../constants";
2
-
3
1
  // Define the type for the element being added
4
2
  interface Element {
5
3
  id: string;
@@ -45,8 +43,6 @@ interface Page {
45
43
 
46
44
  // Define the type for the store
47
45
  interface Store {
48
- width: number;
49
- height: number;
50
46
  pages: Page[];
51
47
  history: {
52
48
  clear: () => void;
@@ -94,30 +90,16 @@ const createTextElement = (
94
90
 
95
91
  export const addIdentifierAreaToTriFold = (store: Store): void => {
96
92
  const page = store.pages[0];
97
- const foldSectionHeight = store.height / 3;
98
- const restrictedAreaHeight = 2.375 * DPI;
99
- const restrictedAreaY = store.height - restrictedAreaHeight - 0.125 * DPI - foldSectionHeight;
100
- const identifierY = restrictedAreaY + restrictedAreaHeight - 12;
101
-
102
- // Keep the original right-side alignment behavior, but make it responsive to page width.
103
- const contPlaceholderX = store.width - 185;
104
- const contIdX = store.width - 177;
105
- const sequencePlaceholderX = store.width - 149;
106
- const sequenceX = store.width - 140;
107
- const templatePlaceholderX = store.width - 114;
108
- const templateIdX = store.width - 101.4;
109
- const orderPlaceholderX = store.width - 72.4;
110
- const orderIdX = store.width - 61.4;
111
93
 
112
94
  const elements: Element[] = [
113
- createTextElement("cont-id-placeholder", "C:", contPlaceholderX, identifierY, 11),
114
- createTextElement("contId", "0000001", contIdX, identifierY, 30),
115
- createTextElement("sequence-id-placeholder", "| S:", sequencePlaceholderX, identifierY, 12),
116
- createTextElement("sequence", "0000001", sequenceX, identifierY, 29),
117
- createTextElement("template-id-placeholder", "| T:", templatePlaceholderX, identifierY, 14),
118
- createTextElement("templateId", "0001034", templateIdX, identifierY, 29),
119
- createTextElement("order-id-placeholder", "| O:", orderPlaceholderX, identifierY, 11),
120
- createTextElement("orderId", "0000127", orderIdX, identifierY, 29),
95
+ createTextElement("cont-id-placeholder", "C:", 679, 739, 11),
96
+ createTextElement("contId", "0000001", 687, 739, 30),
97
+ createTextElement("sequence-id-placeholder", "| S:", 715, 739, 12),
98
+ createTextElement("sequence", "0000001", 724, 739, 29),
99
+ createTextElement("template-id-placeholder", "| T:", 750, 739, 14),
100
+ createTextElement("templateId", "0001034", 762.6, 739, 29),
101
+ createTextElement("order-id-placeholder", "| O:", 791.6, 739, 11),
102
+ createTextElement("orderId", "0000127", 802.6, 739, 29),
121
103
  ];
122
104
 
123
105
  elements.forEach(element => page.addElement(element));
@@ -85,8 +85,6 @@ interface Store {
85
85
 
86
86
  export const addRestrictedAreaToTriFold = (store: Store, size: [number, number], barcodeSrc: string): void => {
87
87
  const page = store.pages[0];
88
- const foldSectionHeight = store.height / 3;
89
- const indiciaLeftShift = 8;
90
88
 
91
89
  const elements: Element[] = [
92
90
  {
@@ -100,7 +98,7 @@ export const addRestrictedAreaToTriFold = (store: Store, size: [number, number],
100
98
  alwaysOnTop: true,
101
99
  showInExport: true,
102
100
  x: store.width - size[0] * DPI - 0.15 * DPI,
103
- y: store.height - size[1] * DPI - 0.125 * DPI - foldSectionHeight,
101
+ y: store.height - size[1] * DPI - 0.125 * DPI - 4 * DPI,
104
102
  width: size[0] * DPI,
105
103
  height: size[1] * DPI,
106
104
  rotation: 0,
@@ -139,7 +137,7 @@ export const addRestrictedAreaToTriFold = (store: Store, size: [number, number],
139
137
  alwaysOnTop: true,
140
138
  showInExport: true,
141
139
  x: store.width - size[0] * DPI - 0.15 * DPI + 5,
142
- y: store.height - size[1] * DPI - 0.125 * DPI + 20 - foldSectionHeight,
140
+ y: store.height - size[1] * DPI - 0.125 * DPI + 20 - 4 * DPI,
143
141
  width: 240,
144
142
  height: 20,
145
143
  rotation: 0,
@@ -190,8 +188,8 @@ export const addRestrictedAreaToTriFold = (store: Store, size: [number, number],
190
188
  removable: false,
191
189
  alwaysOnTop: true,
192
190
  showInExport: true,
193
- x: store.width - 111 - 0.15 * DPI - indiciaLeftShift,
194
- y: store.height - size[1] * DPI + 10 - foldSectionHeight,
191
+ x: store.width - 111 - 0.15 * DPI,
192
+ y: store.height - size[1] * DPI + 10 - 4 * DPI,
195
193
  width: 111,
196
194
  height: 40,
197
195
  rotation: 0,
@@ -242,7 +240,7 @@ export const addRestrictedAreaToTriFold = (store: Store, size: [number, number],
242
240
  removable: false,
243
241
  alwaysOnTop: true,
244
242
  showInExport: true,
245
- y: store.height - 28 - size[1] * DPI + 100 - foldSectionHeight,
243
+ y: store.height - 28 - size[1] * DPI + 100 - 4 * DPI,
246
244
  x: store.width - size[0] * DPI - 0.15 * DPI + 5,
247
245
  width: size[0] * DPI - 23,
248
246
  height: 15,
@@ -284,7 +282,7 @@ export const addRestrictedAreaToTriFold = (store: Store, size: [number, number],
284
282
  alwaysOnTop: true,
285
283
  showInExport: true,
286
284
  x: store.width - size[0] * DPI - 0.15 * DPI + 5,
287
- y: store.height - size[1] * DPI - 0.125 * DPI + 120 - foldSectionHeight,
285
+ y: store.height - size[1] * DPI - 0.125 * DPI + 120 - 4 * DPI,
288
286
  width: 240,
289
287
  height: 20,
290
288
  rotation: 0,
@@ -3,13 +3,6 @@ import { Element, Store } from "./types"
3
3
 
4
4
  export const addSafetyBordersToTriFold = (store: Store): void => {
5
5
  const randomizedId = Math.random().toString(36).substring(2, 7);
6
- const borderWidth = store.width + 2;
7
- const borderHeight = store.height - 52;
8
- const foldSectionHeight = store.height / 3;
9
- const foldLineOneY = foldSectionHeight;
10
- const foldLineTwoY = foldSectionHeight * 2 - 5;
11
- const borderBottomY = store.height - 28.4;
12
- const rightBorderX = store.width - 29;
13
6
 
14
7
  const safetyBordersTextFirst = createSafetyTextElement(
15
8
  `safety-text-1-${randomizedId}`,
@@ -22,8 +15,8 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
22
15
  const safetyLineTextFirst = createSafetyTextElement(
23
16
  `safety-line-1-${randomizedId}`,
24
17
  -2,
25
- foldLineOneY - 18,
26
- borderWidth,
18
+ 366,
19
+ 866,
27
20
  "Fold Line",
28
21
  0
29
22
  );
@@ -31,8 +24,8 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
31
24
  const safetySecondLineTextFirst = createSafetyTextElement(
32
25
  `safety-line-2-${randomizedId}`,
33
26
  -2,
34
- foldLineTwoY - 19,
35
- borderWidth,
27
+ 744,
28
+ 866,
36
29
  "Fold Line",
37
30
  0
38
31
  );
@@ -47,12 +40,12 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
47
40
  alwaysOnTop: true,
48
41
  showInExport: false,
49
42
  children: [
50
- createBorder(`top-1-${randomizedId}`, 26, 23.5, borderWidth - 55, 4, 0),
51
- createBorder(`bottom-1-${randomizedId}`, 26, borderBottomY, borderWidth - 55, 4, 0),
52
- createBorder(`left-1-${randomizedId}`, 24.16, borderBottomY + 1.4, borderHeight, 4, -90),
53
- createBorder(`right-1-${randomizedId}`, rightBorderX, borderBottomY + 1.4, borderHeight, 4, -90),
54
- createBorder(`fold-line-1-${randomizedId}`, borderWidth, foldLineOneY, borderWidth, 2, 180, 'rgba(208,2,27,1)'),
55
- createBorder(`fold-line-2-${randomizedId}`, borderWidth, foldLineTwoY, borderWidth, 2, 180, 'rgba(208,2,27,1)'),
43
+ createBorder(`top-1-${randomizedId}`, 26, 23.5, 811, 4, 0),
44
+ createBorder(`bottom-1-${randomizedId}`, 26, 1123.6, 811, 4, 0),
45
+ createBorder(`left-1-${randomizedId}`, 24.16, 1125, 1100, 4, -90),
46
+ createBorder(`right-1-${randomizedId}`, 835, 1125, 1100, 4, -90),
47
+ createBorder(`fold-line-1-${randomizedId}`, 866, 384, 866, 2, 180, 'rgba(208,2,27,1)'),
48
+ createBorder(`fold-line-2-${randomizedId}`, 866, 763, 866, 2, 180, 'rgba(208,2,27,1)'),
56
49
  ],
57
50
  };
58
51
 
@@ -67,8 +60,8 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
67
60
  const safetyLineTextSecond = createSafetyTextElement(
68
61
  `safety-line-2-1-${randomizedId}`,
69
62
  -2,
70
- foldLineOneY - 18,
71
- borderWidth,
63
+ 366,
64
+ 866,
72
65
  "Fold Line",
73
66
  0
74
67
  );
@@ -76,8 +69,8 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
76
69
  const safetySecondLineTextSecond = createSafetyTextElement(
77
70
  `safety-line-2-2-${randomizedId}`,
78
71
  -2,
79
- foldLineTwoY - 19,
80
- borderWidth,
72
+ 744,
73
+ 866,
81
74
  "Fold Line",
82
75
  0
83
76
  );
@@ -93,12 +86,12 @@ export const addSafetyBordersToTriFold = (store: Store): void => {
93
86
  alwaysOnTop: true,
94
87
  showInExport: false,
95
88
  children: [
96
- createBorder(`top-2-${randomizedId}`, 26, 23.5, borderWidth - 55, 4, 0),
97
- createBorder(`bottom-2-${randomizedId}`, 26, borderBottomY, borderWidth - 55, 4, 0),
98
- createBorder(`left-2-${randomizedId}`, 24.16, borderBottomY + 1.4, borderHeight, 4, -90),
99
- createBorder(`right-2-${randomizedId}`, rightBorderX, borderBottomY + 1.4, borderHeight, 4, -90),
100
- createBorder(`fold-line-2-1-${randomizedId}`, borderWidth, foldLineOneY, borderWidth, 2, 180, 'rgba(208,2,27,1)'),
101
- createBorder(`fold-line-2-2-${randomizedId}`, borderWidth, foldLineTwoY, borderWidth, 2, 180, 'rgba(208,2,27,1)'),
89
+ createBorder(`top-2-${randomizedId}`, 26, 23.5, 811, 4, 0),
90
+ createBorder(`bottom-2-${randomizedId}`, 26, 1123.6, 811, 4, 0),
91
+ createBorder(`left-2-${randomizedId}`, 24.16, 1125, 1100, 4, -90),
92
+ createBorder(`right-2-${randomizedId}`, 835, 1125, 1100, 4, -90),
93
+ createBorder(`fold-line-2-1-${randomizedId}`, 866, 384, 866, 2, 180, 'rgba(208,2,27,1)'),
94
+ createBorder(`fold-line-2-2-${randomizedId}`, 866, 763, 866, 2, 180, 'rgba(208,2,27,1)'),
102
95
  ],
103
96
  };
104
97
 
package/version.js CHANGED
@@ -1 +1 @@
1
- export const SDK_VERSION = '2.1.6-beta.2';
1
+ export const SDK_VERSION = '2.1.6-beta.4';