@griddo/ax 11.12.0 → 11.12.1-rc.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 (100) hide show
  1. package/config/jest/componentsMock.js +7 -5
  2. package/package.json +2 -2
  3. package/src/__tests__/components/Browser/Browser.test.tsx +438 -87
  4. package/src/__tests__/components/Browser/Browser.utils.test.ts +55 -0
  5. package/src/__tests__/components/ConfigPanel/ConfigPanel.test.tsx +1 -3
  6. package/src/__tests__/components/Fields/Button/Button.test.tsx +29 -27
  7. package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/ErrorItem.test.tsx +158 -0
  8. package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorsBanner.test.tsx +90 -0
  9. package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.test.tsx +178 -0
  10. package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.utils.test.tsx +150 -0
  11. package/src/__tests__/components/KeywordsPreviewModal/KeywordItem/KeywordItem.test.tsx +91 -0
  12. package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.test.tsx +122 -0
  13. package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.utils.test.ts +15 -0
  14. package/src/__tests__/components/KeywordsPreviewModal/atoms.test.tsx +101 -0
  15. package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +1 -1
  16. package/src/__tests__/modules/FramePreview/FramePreview.test.tsx +318 -0
  17. package/src/__tests__/modules/FramePreview/FramePreview.utils.test.ts +242 -0
  18. package/src/__tests__/modules/FramePreview/HeadingsOverlay/HeadingsOverlay.test.tsx +185 -0
  19. package/src/components/Browser/index.tsx +294 -149
  20. package/src/components/Browser/style.tsx +75 -6
  21. package/src/components/Browser/utils.tsx +13 -0
  22. package/src/components/Button/index.tsx +2 -1
  23. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +2 -4
  24. package/src/components/Fields/AsyncSelect/style.tsx +13 -0
  25. package/src/components/Fields/FieldGroup/index.tsx +5 -2
  26. package/src/components/Fields/FieldGroup/style.tsx +32 -7
  27. package/src/components/Fields/HeadingField/index.tsx +22 -22
  28. package/src/components/Fields/HiddenField/style.tsx +1 -1
  29. package/src/components/Fields/NumberField/index.tsx +15 -16
  30. package/src/components/Fields/NumberField/style.tsx +2 -0
  31. package/src/components/Fields/ReferenceField/index.tsx +1 -1
  32. package/src/components/Fields/SEOPreview/index.tsx +36 -0
  33. package/src/components/Fields/SEOPreview/style.tsx +24 -0
  34. package/src/components/Fields/Select/index.tsx +5 -1
  35. package/src/components/Fields/Select/style.tsx +56 -0
  36. package/src/components/Fields/SummaryButton/index.tsx +18 -9
  37. package/src/components/Fields/SummaryButton/style.tsx +1 -2
  38. package/src/components/Fields/TagsField/index.tsx +8 -9
  39. package/src/components/Fields/UrlField/index.tsx +26 -27
  40. package/src/components/Fields/index.tsx +2 -0
  41. package/src/components/FloatingNote/index.tsx +35 -0
  42. package/src/components/FloatingNote/style.tsx +26 -0
  43. package/src/components/FloatingPanel/index.tsx +5 -2
  44. package/src/components/FloatingPanel/style.tsx +2 -1
  45. package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/index.tsx +85 -0
  46. package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/style.tsx +80 -0
  47. package/src/components/HeadingsPreviewModal/ErrorsBanner/index.tsx +57 -0
  48. package/src/components/HeadingsPreviewModal/ErrorsBanner/style.tsx +82 -0
  49. package/src/components/HeadingsPreviewModal/HeadingItem/index.tsx +71 -0
  50. package/src/components/HeadingsPreviewModal/HeadingItem/style.tsx +77 -0
  51. package/src/components/HeadingsPreviewModal/index.tsx +148 -0
  52. package/src/components/HeadingsPreviewModal/style.tsx +82 -0
  53. package/src/components/HeadingsPreviewModal/utils.tsx +329 -0
  54. package/src/components/Icon/index.tsx +1 -2
  55. package/src/components/IconAction/index.tsx +1 -1
  56. package/src/components/KeywordsPreviewModal/KeywordItem/index.tsx +46 -0
  57. package/src/components/KeywordsPreviewModal/KeywordItem/style.tsx +64 -0
  58. package/src/components/KeywordsPreviewModal/atoms.tsx +96 -0
  59. package/src/components/KeywordsPreviewModal/index.tsx +99 -0
  60. package/src/components/KeywordsPreviewModal/style.tsx +87 -0
  61. package/src/components/KeywordsPreviewModal/utils.tsx +22 -0
  62. package/src/components/MainWrapper/AppBar/index.tsx +8 -1
  63. package/src/components/MainWrapper/index.tsx +7 -1
  64. package/src/components/Notification/index.tsx +2 -2
  65. package/src/components/PageFinder/index.tsx +1 -1
  66. package/src/components/ResizePanel/index.tsx +4 -3
  67. package/src/components/ResizePanel/style.tsx +1 -1
  68. package/src/components/SearchField/style.tsx +2 -2
  69. package/src/components/SideModal/index.tsx +2 -1
  70. package/src/components/Tabs/index.tsx +13 -4
  71. package/src/components/Tabs/style.tsx +7 -8
  72. package/src/components/Toast/index.tsx +4 -2
  73. package/src/components/Tooltip/index.tsx +4 -3
  74. package/src/components/index.tsx +8 -0
  75. package/src/forms/fields.tsx +70 -68
  76. package/src/hooks/forms.tsx +22 -1
  77. package/src/hooks/index.tsx +13 -3
  78. package/src/hooks/modals.tsx +103 -15
  79. package/src/hooks/users.tsx +25 -8
  80. package/src/modules/Forms/atoms.tsx +2 -2
  81. package/src/modules/FramePreview/HeadingsOverlay/index.tsx +116 -0
  82. package/src/modules/FramePreview/HeadingsOverlay/style.tsx +34 -0
  83. package/src/modules/FramePreview/index.tsx +55 -16
  84. package/src/modules/FramePreview/style.tsx +34 -2
  85. package/src/modules/FramePreview/utils.tsx +140 -0
  86. package/src/modules/GlobalEditor/Editor/index.tsx +37 -3
  87. package/src/modules/GlobalEditor/PageBrowser/index.tsx +19 -2
  88. package/src/modules/GlobalEditor/Preview/index.tsx +0 -2
  89. package/src/modules/GlobalEditor/Preview/style.tsx +1 -1
  90. package/src/modules/GlobalEditor/index.tsx +119 -57
  91. package/src/modules/PageEditor/Editor/index.tsx +33 -2
  92. package/src/modules/PageEditor/PageBrowser/index.tsx +20 -2
  93. package/src/modules/PageEditor/Preview/index.tsx +0 -2
  94. package/src/modules/PageEditor/Preview/style.tsx +1 -1
  95. package/src/modules/PageEditor/atoms.tsx +1 -1
  96. package/src/modules/PageEditor/index.tsx +130 -66
  97. package/src/modules/PublicPreview/index.tsx +5 -2
  98. package/src/schemas/pages/GlobalPage.ts +87 -70
  99. package/src/schemas/pages/Page.ts +87 -70
  100. package/src/types/index.tsx +12 -0
@@ -7,6 +7,8 @@ import {
7
7
  CancelScheduleModal,
8
8
  ErrorPage,
9
9
  ErrorToast,
10
+ HeadingsPreviewModal,
11
+ KeywordsPreviewModal,
10
12
  Loading,
11
13
  MainWrapper,
12
14
  Modal,
@@ -23,8 +25,9 @@ import { structuredDataActions } from "@ax/containers/StructuredData";
23
25
  import { usersActions } from "@ax/containers/Users";
24
26
  import { RouteLeavingGuard } from "@ax/guards";
25
27
  import { dateToString, getDefaultTheme } from "@ax/helpers";
26
- import { useIsDirty, useModal, usePermission } from "@ax/hooks";
28
+ import { useIsDirty, useModals, usePermissions } from "@ax/hooks";
27
29
  import type {
30
+ HeadingFilter,
28
31
  IErrorItem,
29
32
  ILanguage,
30
33
  INotification,
@@ -67,35 +70,46 @@ const GlobalEditor = (props: IProps) => {
67
70
  getUserCurrentPermissions,
68
71
  schedulePublication,
69
72
  restorePage,
73
+ updateEditorContent,
70
74
  schemaVersion,
71
75
  } = props;
72
76
 
73
- const isAllowedToPublishPages = usePermission("global.globalData.publishUnpublishAllGlobalData");
74
- const isAllowedToCreatePages = usePermission("global.globalData.createAllGlobalData");
75
- const isAllowedToDeletePage = usePermission("global.globalData.deleteAllGlobalData");
76
- const isAllowedToEditContentPage = usePermission("global.globalData.editAllGlobalData");
77
- //
78
- const defaultTab = isAllowedToEditContentPage ? "edit" : "view";
77
+ const isAllowedTo = usePermissions({
78
+ publishPages: "global.globalData.publishUnpublishAllGlobalData",
79
+ createPages: "global.globalData.createAllGlobalData",
80
+ deletePages: "global.globalData.deleteAllGlobalData",
81
+ editContentPages: "global.globalData.editAllGlobalData",
82
+ });
83
+
84
+ const defaultTab = isAllowedTo.editContentPages ? "edit" : "view";
79
85
 
80
- const { isOpen, toggleModal } = useModal();
81
- const { isOpen: isUnpublishOpen, toggleModal: toggleUnpublishModal } = useModal();
82
86
  const [isReadOnly, setIsReadOnly] = useState(false);
83
87
  const [selectedTab, setSelectedTab] = useState(defaultTab);
84
88
  const [notification, setNotification] = useState<INotification | null>(null);
85
89
  const [toastMsg, setToastMsg] = useState<string | null>(null);
86
- const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
87
90
  const [errorPagesChecked, setErrorPagesChecked] = useState(false);
91
+ const [headingsFilter, setHeadingsFilter] = useState<HeadingFilter>("all");
92
+ const [keywordsFilter, setKeywordsFilter] = useState<string[]>([]);
88
93
  const [scheduleDate, setScheduleDate] = useState({
89
94
  date: dateToString(new Date(), "yyy/MM/dd"),
90
95
  time: "12:00 am",
91
96
  });
92
- const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
93
- const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
94
- const { isOpen: isRestoreOpen, toggleModal: toggleRestoreModal } = useModal();
95
- const { isOpen: isDirtyNavigateOpen, toggleModal: toggleDirtyNavigateModal } = useModal();
96
97
  const [pendingNavigateCallback, setPendingNavigateCallback] = useState<(() => void) | null>(null);
97
98
  const browserRef = useRef<HTMLDivElement>(null);
98
99
 
100
+ const { isOpen, toggleModal } = useModals([
101
+ "userEditing",
102
+ "unpublish",
103
+ "schedule",
104
+ "cancelSchedule",
105
+ "restore",
106
+ "headingsPreview",
107
+ "keywordsPreview",
108
+ "dirtyNavigate",
109
+ ]);
110
+
111
+ const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
112
+
99
113
  const isPublished = props.pageStatus === pageStatus.PUBLISHED || props.pageStatus === pageStatus.UPLOAD_PENDING;
100
114
  const isDraft = props.pageStatus === pageStatus.MODIFIED || !!editorContent.draftFromPage;
101
115
  const hasDraft: boolean = editorContent && !!editorContent.haveDraftPage;
@@ -104,6 +118,7 @@ const GlobalEditor = (props: IProps) => {
104
118
  const isEditLive = isPublished && hasDraft;
105
119
  const isScheduled = props.pageStatus === pageStatus.SCHEDULED;
106
120
  const isDeleted = editorContent.deleted;
121
+ const defaultContentTab = "content";
107
122
 
108
123
  const errorNotificationText =
109
124
  "There are some errors on the page so you can not publish yet. Please review them in the error panel.";
@@ -122,12 +137,11 @@ const GlobalEditor = (props: IProps) => {
122
137
 
123
138
  // biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
124
139
  useEffect(() => {
125
- const { pageID, getPage, setTab, sendPagePing, setStructuredDataFilter } = props;
140
+ const { pageID, getPage, sendPagePing, setStructuredDataFilter } = props;
126
141
 
127
142
  editorContent?.structuredData && setStructuredDataFilter(editorContent.structuredData);
128
- const defaultTab = "content";
129
143
  const handleGetPage = async () => await getPage(pageID, true);
130
- setTab(defaultTab);
144
+ setTab(defaultContentTab);
131
145
  setToastMsg(null);
132
146
  handleGetPage();
133
147
  if (!pageID) {
@@ -150,11 +164,11 @@ const GlobalEditor = (props: IProps) => {
150
164
  const { pageID, sendPagePing, currentUserID } = props;
151
165
  if (userEditing && userEditing.id !== currentUserID) {
152
166
  setIsReadOnly(true);
153
- !isOpen && toggleModal();
167
+ !isOpen("userEditing") && toggleModal("userEditing");
154
168
  } else {
155
169
  setIsReadOnly(false);
156
170
  pageID && sendPagePing(pageID);
157
- isOpen && toggleModal();
171
+ isOpen("userEditing") && toggleModal("userEditing");
158
172
  }
159
173
  }, [userEditing]);
160
174
 
@@ -280,7 +294,7 @@ const GlobalEditor = (props: IProps) => {
280
294
  const saved = await schedulePublication(dateString, isDraft);
281
295
  if (saved) {
282
296
  resetDirty();
283
- toggleScheduleModal();
297
+ toggleModal("schedule");
284
298
  }
285
299
  };
286
300
 
@@ -289,7 +303,7 @@ const GlobalEditor = (props: IProps) => {
289
303
  if (saved) {
290
304
  setScheduleDate({ date: "", time: "12:00 am" });
291
305
  resetDirty();
292
- toggleCancelScheduleModal();
306
+ toggleModal("cancelSchedule");
293
307
  }
294
308
  };
295
309
 
@@ -310,7 +324,7 @@ const GlobalEditor = (props: IProps) => {
310
324
  }
311
325
  : {
312
326
  label: status === pageStatus.UPLOAD_PENDING ? "Cancel publication" : "Unpublish",
313
- action: hasDraft ? toggleUnpublishModal : unpublishPage,
327
+ action: hasDraft ? () => toggleModal("unpublish") : unpublishPage,
314
328
  };
315
329
  case pageStatus.MODIFIED:
316
330
  case pageStatus.SCHEDULED:
@@ -325,24 +339,24 @@ const GlobalEditor = (props: IProps) => {
325
339
 
326
340
  const menuOptions = [];
327
341
 
328
- if (isAllowedToPublishPages && !isScheduled && !isPublished && props.pageStatus !== pageStatus.OFFLINE_PENDING) {
342
+ if (isAllowedTo.publishPages && !isScheduled && !isPublished && props.pageStatus !== pageStatus.OFFLINE_PENDING) {
329
343
  menuOptions.push({
330
344
  label: "Schedule",
331
345
  icon: "calendar",
332
- action: toggleScheduleModal,
346
+ action: () => toggleModal("schedule"),
333
347
  });
334
348
  }
335
349
 
336
- if (isAllowedToPublishPages && isScheduled) {
350
+ if (isAllowedTo.publishPages && isScheduled) {
337
351
  menuOptions.push({
338
352
  label: "Cancel Schedule",
339
353
  icon: "cancelEvent",
340
- action: toggleCancelScheduleModal,
354
+ action: () => toggleModal("cancelSchedule"),
341
355
  });
342
356
  }
343
357
 
344
358
  if (
345
- isAllowedToEditContentPage &&
359
+ isAllowedTo.editContentPages &&
346
360
  (props.pageStatus === pageStatus.PUBLISHED ||
347
361
  props.pageStatus === pageStatus.OFFLINE ||
348
362
  props.pageStatus === pageStatus.OFFLINE_PENDING ||
@@ -356,7 +370,7 @@ const GlobalEditor = (props: IProps) => {
356
370
  });
357
371
  }
358
372
 
359
- if (isAllowedToEditContentPage && !isScheduled && (isDraft || (isPublished && isDirty))) {
373
+ if (isAllowedTo.editContentPages && !isScheduled && (isDraft || (isPublished && isDirty))) {
360
374
  menuOptions.push({
361
375
  label: "Discard changes",
362
376
  icon: "close",
@@ -364,15 +378,15 @@ const GlobalEditor = (props: IProps) => {
364
378
  });
365
379
  }
366
380
 
367
- if (props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty && isAllowedToPublishPages) {
381
+ if (props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty && isAllowedTo.publishPages) {
368
382
  menuOptions.push({
369
383
  label: "Unpublish",
370
384
  icon: "offline",
371
- action: isDraft ? toggleUnpublishModal : unpublishPage,
385
+ action: isDraft ? () => toggleModal("unpublish") : unpublishPage,
372
386
  });
373
387
  }
374
388
 
375
- if (!isDraft && isAllowedToDeletePage) {
389
+ if (!isDraft && isAllowedTo.deletePages) {
376
390
  menuOptions.push({
377
391
  label: "Delete page",
378
392
  icon: "delete",
@@ -382,7 +396,7 @@ const GlobalEditor = (props: IProps) => {
382
396
 
383
397
  const downArrowMenu = {
384
398
  displayed: !isReadOnly && !isDeleted,
385
- button: isAllowedToPublishPages ? getPublishButton(props.pageStatus) : undefined,
399
+ button: isAllowedTo.publishPages ? getPublishButton(props.pageStatus) : undefined,
386
400
  options: menuOptions,
387
401
  };
388
402
 
@@ -430,7 +444,7 @@ const GlobalEditor = (props: IProps) => {
430
444
  }
431
445
  };
432
446
 
433
- const rightButtonProps = isAllowedToEditContentPage
447
+ const rightButtonProps = isAllowedTo.editContentPages
434
448
  ? {
435
449
  label: isSaving ? "Saving" : getSaveLabel(),
436
450
  disabled: (!isDirty && pageID !== null && !isNewTranslation) || isSaving || isReadOnly,
@@ -462,11 +476,11 @@ const GlobalEditor = (props: IProps) => {
462
476
 
463
477
  const onNavigateWithDirty = (navigateCallback: () => void) => {
464
478
  setPendingNavigateCallback(() => navigateCallback);
465
- toggleDirtyNavigateModal();
479
+ toggleModal("dirtyNavigate");
466
480
  };
467
481
 
468
482
  const handleConfirmDirtyNavigation = () => {
469
- toggleDirtyNavigateModal();
483
+ toggleModal("dirtyNavigate");
470
484
  if (pendingNavigateCallback) {
471
485
  pendingNavigateCallback();
472
486
  setPendingNavigateCallback(null);
@@ -474,7 +488,7 @@ const GlobalEditor = (props: IProps) => {
474
488
  };
475
489
 
476
490
  const handleCancelDirtyNavigation = () => {
477
- toggleDirtyNavigateModal();
491
+ toggleModal("dirtyNavigate");
478
492
  setPendingNavigateCallback(null);
479
493
  };
480
494
 
@@ -518,7 +532,7 @@ const GlobalEditor = (props: IProps) => {
518
532
  const mainAction = { title: "Preview Page", onClick: toggleModal };
519
533
  const secondaryAction = { title: "Ok, go back", onClick: handleGoBack };
520
534
 
521
- const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
535
+ const mainUnpublishAction = { title: "Ok", onClick: () => toggleModal("unpublish") };
522
536
 
523
537
  const mainScheduleModalAction = {
524
538
  title: "Schedule",
@@ -527,7 +541,7 @@ const GlobalEditor = (props: IProps) => {
527
541
 
528
542
  const secondaryScheduleModalAction = {
529
543
  title: "Cancel",
530
- onClick: toggleScheduleModal,
544
+ onClick: () => toggleModal("schedule"),
531
545
  };
532
546
 
533
547
  const mainCancelScheduleModalAction = {
@@ -537,10 +551,10 @@ const GlobalEditor = (props: IProps) => {
537
551
 
538
552
  const secondaryCancelScheduleModalAction = {
539
553
  title: "Back",
540
- onClick: toggleCancelScheduleModal,
554
+ onClick: () => toggleModal("cancelSchedule"),
541
555
  };
542
556
 
543
- const tabIcons = isAllowedToEditContentPage
557
+ const tabIcons = isAllowedTo.editContentPages
544
558
  ? [
545
559
  { name: "edit", text: "Edit mode" },
546
560
  { name: "view", text: "Preview mode" },
@@ -558,6 +572,7 @@ const GlobalEditor = (props: IProps) => {
558
572
  icons: tabIcons,
559
573
  selectedTab,
560
574
  action: (tab: string) => handleSelectedTab(tab),
575
+ disabled: isOpen("headingsPreview") || isOpen("keywordsPreview"),
561
576
  };
562
577
 
563
578
  const filteredLanguages = globalLangs.filter((lang) =>
@@ -587,7 +602,7 @@ const GlobalEditor = (props: IProps) => {
587
602
  await getPage(selectedPageLanguage.pageId, true, isDraft);
588
603
  resetDirty();
589
604
  } else {
590
- isAllowedToEditContentPage && setSelectedTab("edit");
605
+ isAllowedTo.editContentPages && setSelectedTab("edit");
591
606
  createNewTranslation(true);
592
607
  await getPage(pageID, true);
593
608
  }
@@ -596,11 +611,33 @@ const GlobalEditor = (props: IProps) => {
596
611
  const handleRestorePage = async () => {
597
612
  const isRestored = await restorePage(pageID);
598
613
  if (isRestored) {
599
- isRestoreOpen && toggleRestoreModal();
614
+ isOpen("restore") && toggleModal("restore");
600
615
  await getPage(pageID);
601
616
  }
602
617
  };
603
618
 
619
+ const handleAddKeywords = (newKeywords: string[]) => {
620
+ const keywords: string[] = [...editorContent.metaKeywords, ...newKeywords];
621
+ updateEditorContent(0, "metaKeywords", keywords);
622
+ handleSavePage();
623
+ };
624
+
625
+ const handledeleteKeyword = (keyword: string) => {
626
+ const newKeywords = (editorContent.metaKeywords as string[]).filter((key) => key !== keyword);
627
+ updateEditorContent(0, "metaKeywords", newKeywords);
628
+ handleSavePage();
629
+ };
630
+
631
+ const handleToggleHeadingsEditor = () => {
632
+ toggleModal("headingsPreview");
633
+ setTab(defaultContentTab);
634
+ };
635
+
636
+ const handleToggleKeywordsEditor = () => {
637
+ toggleModal("keywordsPreview");
638
+ setTab(defaultContentTab);
639
+ };
640
+
604
641
  return isLoading ? (
605
642
  <Loading />
606
643
  ) : (
@@ -616,7 +653,7 @@ const GlobalEditor = (props: IProps) => {
616
653
  pageStatus={props.pageStatus}
617
654
  language={lang}
618
655
  languageAction={handleLanguage}
619
- availableLanguages={isAllowedToCreatePages && !isDeleted ? globalLangs : filteredLanguages}
656
+ availableLanguages={isAllowedTo.createPages && !isDeleted ? globalLangs : filteredLanguages}
620
657
  currentLanguages={contentLanguages}
621
658
  currentPageID={pageID}
622
659
  fullWidth={true}
@@ -643,7 +680,7 @@ const GlobalEditor = (props: IProps) => {
643
680
  type="error"
644
681
  text={deletedNotificationText}
645
682
  btnText="Restore page"
646
- onClick={toggleRestoreModal}
683
+ onClick={() => toggleModal("restore")}
647
684
  />
648
685
  </S.NotificationWrapper>
649
686
  )}
@@ -674,6 +711,12 @@ const GlobalEditor = (props: IProps) => {
674
711
  setNotification={setNotification}
675
712
  isEditLive={isEditLive}
676
713
  isDisabled={isDeleted}
714
+ toggleHeadingsPreview={handleToggleHeadingsEditor}
715
+ isHeadingsPreviewOpen={isOpen("headingsPreview")}
716
+ headingsFilter={headingsFilter}
717
+ toggleKeywordsPreview={handleToggleKeywordsEditor}
718
+ isKeywordsPreviewOpen={isOpen("keywordsPreview")}
719
+ keywordsFilter={keywordsFilter}
677
720
  />
678
721
  </S.Content>
679
722
  </>
@@ -684,14 +727,14 @@ const GlobalEditor = (props: IProps) => {
684
727
  </>
685
728
  )}
686
729
  <Modal
687
- isOpen={isOpen}
688
- hide={toggleModal}
730
+ isOpen={isOpen("userEditing")}
731
+ hide={() => toggleModal("userEditing")}
689
732
  size="S"
690
733
  title="This page is currently being edited"
691
734
  mainAction={mainAction}
692
735
  secondaryAction={secondaryAction}
693
736
  >
694
- {isOpen && (
737
+ {isOpen("userEditing") && (
695
738
  <S.ModalContent>
696
739
  <p>
697
740
  <strong>{userEditing?.name}</strong> is currently working on this page. You can preview the page but{" "}
@@ -701,13 +744,13 @@ const GlobalEditor = (props: IProps) => {
701
744
  )}
702
745
  </Modal>
703
746
  <Modal
704
- isOpen={isUnpublishOpen}
705
- hide={toggleUnpublishModal}
747
+ isOpen={isOpen("unpublish")}
748
+ hide={() => toggleModal("unpublish")}
706
749
  size="S"
707
750
  title="Unpublish Modified Page"
708
751
  mainAction={mainUnpublishAction}
709
752
  >
710
- {isUnpublishOpen && (
753
+ {isOpen("unpublish") && (
711
754
  <S.ModalContent>
712
755
  <p>
713
756
  There are some saved changes that are not published on this page. To Unpublish this page,{" "}
@@ -717,31 +760,48 @@ const GlobalEditor = (props: IProps) => {
717
760
  )}
718
761
  </Modal>
719
762
  <ScheduleModal
720
- isOpen={isScheduleOpen}
721
- toggleModal={toggleScheduleModal}
763
+ isOpen={isOpen("schedule")}
764
+ toggleModal={() => toggleModal("schedule")}
722
765
  mainModalAction={mainScheduleModalAction}
723
766
  secondaryModalAction={secondaryScheduleModalAction}
724
767
  scheduleDate={scheduleDate}
725
768
  setScheduleDate={setScheduleDate}
726
769
  />
727
770
  <CancelScheduleModal
728
- isOpen={isCancelScheduleOpen}
729
- toggleModal={toggleCancelScheduleModal}
771
+ isOpen={isOpen("cancelSchedule")}
772
+ toggleModal={() => toggleModal("cancelSchedule")}
730
773
  mainModalAction={mainCancelScheduleModalAction}
731
774
  secondaryModalAction={secondaryCancelScheduleModalAction}
732
775
  />
733
776
  <RestoreModal
734
- isOpen={isRestoreOpen}
735
- toggleModal={toggleRestoreModal}
777
+ isOpen={isOpen("restore")}
778
+ toggleModal={() => toggleModal("restore")}
736
779
  {...{
737
780
  isChild: false,
738
781
  hasIssues: schemaVersion !== editorContent.schemaVersionTimestamp,
739
782
  restorePage: handleRestorePage,
740
783
  }}
741
784
  />
785
+ <HeadingsPreviewModal
786
+ isOpen={isOpen("headingsPreview")}
787
+ toggleModal={handleToggleHeadingsEditor}
788
+ browserRef={browserRef}
789
+ headingsFilter={headingsFilter}
790
+ setHeadingsFilter={setHeadingsFilter}
791
+ />
792
+ <KeywordsPreviewModal
793
+ isOpen={isOpen("keywordsPreview")}
794
+ toggleModal={handleToggleKeywordsEditor}
795
+ browserRef={browserRef}
796
+ keywords={editorContent?.metaKeywords || []}
797
+ keywordsFilter={keywordsFilter}
798
+ setKeywordsFilter={setKeywordsFilter}
799
+ addKeywords={handleAddKeywords}
800
+ deleteKeyword={handledeleteKeyword}
801
+ />
742
802
  </MainWrapper>
743
803
  <Modal
744
- isOpen={isDirtyNavigateOpen}
804
+ isOpen={isOpen("dirtyNavigate")}
745
805
  hide={handleCancelDirtyNavigation}
746
806
  size="S"
747
807
  title="Unsaved changes"
@@ -818,6 +878,7 @@ const mapDispatchToProps = {
818
878
  getUserCurrentPermissions: usersActions.getUserCurrentPermissions,
819
879
  schedulePublication: pageEditorActions.schedulePublication,
820
880
  restorePage: pageEditorActions.restorePage,
881
+ updateEditorContent: pageEditorActions.updateEditorContent,
821
882
  };
822
883
 
823
884
  interface IPageEditorDispatchProps {
@@ -844,6 +905,7 @@ interface IPageEditorDispatchProps {
844
905
  getUserCurrentPermissions(): Promise<void>;
845
906
  schedulePublication(date: string | null, isDraft: boolean): Promise<boolean>;
846
907
  restorePage(id: number | number[]): Promise<boolean>;
908
+ updateEditorContent(selectedEditorID: number, key: string, value: any): void;
847
909
  }
848
910
 
849
911
  type IProps = IPageEditorStateProps & IPageEditorDispatchProps & RouteComponentProps;
@@ -4,7 +4,17 @@ import { pageEditorActions } from "@ax/containers/PageEditor";
4
4
  import { sitesActions } from "@ax/containers/Sites";
5
5
  import { appActions } from "@ax/containers/App";
6
6
  import { ConfigPanel, ResizePanel } from "@ax/components";
7
- import type { IBreadcrumbItem, IModule, INotification, IRootState, ISchema, ISite, IUserEditing } from "@ax/types";
7
+ import type {
8
+ HeadingFilter,
9
+ IBreadcrumbItem,
10
+ IModule,
11
+ INotification,
12
+ IRootState,
13
+ ISchema,
14
+ ISite,
15
+ IUserEditing,
16
+ } from "@ax/types";
17
+
8
18
  import PageBrowser from "../PageBrowser";
9
19
 
10
20
  const Editor = (props: IProps) => {
@@ -40,9 +50,15 @@ const Editor = (props: IProps) => {
40
50
  pasteModule,
41
51
  setNotification,
42
52
  restorePageNavigation,
53
+ toggleHeadingsPreview,
54
+ toggleKeywordsPreview,
43
55
  content,
44
56
  isEditLive,
45
57
  isDisabled,
58
+ isHeadingsPreviewOpen,
59
+ headingsFilter,
60
+ isKeywordsPreviewOpen,
61
+ keywordsFilter,
46
62
  isDirty,
47
63
  onNavigateWithDirty,
48
64
  } = props;
@@ -68,15 +84,24 @@ const Editor = (props: IProps) => {
68
84
  pasteModuleAction: pasteModule,
69
85
  setNotificationAction: setNotification,
70
86
  restorePageNavigationAction: restorePageNavigation,
87
+ toggleHeadingsPreviewAction: toggleHeadingsPreview,
88
+ toggleKeywordsPreviewAction: toggleKeywordsPreview,
71
89
  };
72
90
 
73
91
  return (
74
92
  <ResizePanel
93
+ disabled={isHeadingsPreviewOpen || isKeywordsPreviewOpen}
75
94
  leftPanel={
76
95
  <PageBrowser
77
96
  isTemplateActivated={isTemplateActivated}
78
97
  isReadOnly={isReadOnly || isEditLive || isDisabled}
79
98
  browserRef={browserRef}
99
+ isHeadingsPreviewOpen={isHeadingsPreviewOpen}
100
+ toggleHeadingsPreview={toggleHeadingsPreview}
101
+ headingsFilter={headingsFilter}
102
+ toggleKeywordsPreview={toggleKeywordsPreview}
103
+ isKeywordsPreviewOpen={isKeywordsPreviewOpen}
104
+ keywordsFilter={keywordsFilter}
80
105
  />
81
106
  }
82
107
  rightPanel={
@@ -142,14 +167,20 @@ interface IPageBrowserDispatchProps {
142
167
  pasteModule(editorID: number, key: string, modulesToPaste: IModule[]): Promise<{ error?: INotification }>;
143
168
  setNotification: (notification: INotification) => void;
144
169
  restorePageNavigation: (key: string) => void;
170
+ toggleHeadingsPreview: () => void;
171
+ toggleKeywordsPreview: () => void;
145
172
  isTemplateActivated: boolean;
146
173
  isGlobal: boolean;
147
174
  isEditable: boolean;
148
175
  pageTitle: string;
149
176
  isReadOnly: boolean;
150
- browserRef: any;
177
+ browserRef: React.RefObject<HTMLDivElement>;
151
178
  isEditLive: boolean;
152
179
  isDisabled: boolean;
180
+ isHeadingsPreviewOpen: boolean;
181
+ headingsFilter: HeadingFilter;
182
+ isKeywordsPreviewOpen: boolean;
183
+ keywordsFilter: string[];
153
184
  isDirty?: boolean;
154
185
  onNavigateWithDirty?: (navigateCallback: () => void) => void;
155
186
  }
@@ -2,7 +2,7 @@ import { connect } from "react-redux";
2
2
  import { pageEditorActions } from "@ax/containers/PageEditor";
3
3
 
4
4
  import { Browser } from "@ax/components";
5
- import type { ILanguage, IRootState, ISite, ISocialState } from "@ax/types";
5
+ import type { HeadingFilter, ILanguage, IRootState, ISite, ISocialState } from "@ax/types";
6
6
 
7
7
  const PageBrowser = (props: IProps) => {
8
8
  const {
@@ -16,10 +16,16 @@ const PageBrowser = (props: IProps) => {
16
16
  isReadOnly,
17
17
  isPreview,
18
18
  browserRef,
19
+ isHeadingsPreviewOpen = false,
20
+ isKeywordsPreviewOpen = false,
21
+ headingsFilter,
22
+ keywordsFilter,
19
23
  deleteModule,
20
24
  duplicateModule,
21
25
  copyModule,
22
26
  setScrollEditorID,
27
+ toggleHeadingsPreview,
28
+ toggleKeywordsPreview,
23
29
  } = props;
24
30
 
25
31
  if (!currentSiteInfo) {
@@ -31,7 +37,8 @@ const PageBrowser = (props: IProps) => {
31
37
  const slugWithSlash = slug ? (slug.startsWith("/") ? slug : `/${slug}`) : "";
32
38
  const pathWithoutSlash = path ? (path.endsWith("/") ? path.slice(0, -1) : path) : "";
33
39
  const url = `${pathWithoutSlash}${slugWithSlash}`;
34
- const disabled = isTemplateActivated === false || isReadOnly;
40
+ const disabled = isTemplateActivated === false || isReadOnly || isHeadingsPreviewOpen || isKeywordsPreviewOpen;
41
+ const editorType = isHeadingsPreviewOpen ? "headings" : isKeywordsPreviewOpen ? "keywords" : "page";
35
42
 
36
43
  const actions = {
37
44
  deleteModuleAction: deleteModule,
@@ -58,6 +65,11 @@ const PageBrowser = (props: IProps) => {
58
65
  showIframe={true}
59
66
  browserRef={browserRef}
60
67
  actions={actions}
68
+ editorType={editorType}
69
+ toggleHeadingsPreview={toggleHeadingsPreview}
70
+ toggleKeywordsPreview={toggleKeywordsPreview}
71
+ headingFilter={headingsFilter}
72
+ keywordsFilter={keywordsFilter}
61
73
  />
62
74
  );
63
75
  };
@@ -78,10 +90,16 @@ interface IPageBrowserDispatchProps {
78
90
  isReadOnly: boolean;
79
91
  isPreview?: boolean;
80
92
  browserRef?: any;
93
+ isHeadingsPreviewOpen?: boolean;
94
+ isKeywordsPreviewOpen?: boolean;
95
+ headingsFilter?: HeadingFilter;
96
+ keywordsFilter?: string[];
81
97
  deleteModule(editorID: number[]): void;
82
98
  duplicateModule(editorID: number[]): number;
83
99
  copyModule(editorID: number[]): number | boolean;
84
100
  setScrollEditorID(editorID: number | null): void;
101
+ toggleHeadingsPreview?(): void;
102
+ toggleKeywordsPreview?(): void;
85
103
  }
86
104
 
87
105
  type IProps = IPageBrowserStateProps & IPageBrowserDispatchProps;
@@ -1,5 +1,3 @@
1
- import React from "react";
2
-
3
1
  import PageBrowser from "../PageBrowser";
4
2
  import * as S from "./style";
5
3
 
@@ -2,7 +2,7 @@ import styled from "styled-components";
2
2
 
3
3
  const BrowserWrapper = styled.div`
4
4
  background-color: ${(p) => p.theme.color.uiBackground01};
5
- height: calc(100% - 44px);
5
+ height: 100%;
6
6
  width: 100%;
7
7
  `;
8
8
 
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { IModal } from "@ax/types";
3
+ import type { IModal } from "@ax/types";
4
4
  import { Modal, FieldsBehavior } from "@ax/components";
5
5
 
6
6
  import * as S from "./style";