@griddo/ax 11.14.2-rc.0 → 11.14.2

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 (148) hide show
  1. package/config/jest/reactEasyCropMock.js +15 -0
  2. package/config/jest/reactTimezoneMock.js +13 -0
  3. package/package.json +221 -219
  4. package/public/img/welcome.svg +127 -0
  5. package/src/__tests__/components/Browser/Browser.test.tsx +27 -51
  6. package/src/__tests__/components/CategoryCell/CategoryCell.test.tsx +10 -5
  7. package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +27 -14
  8. package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/ErrorItem.test.tsx +2 -0
  9. package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.utils.test.tsx +138 -1
  10. package/src/__tests__/components/ImageDragAndDrop/CropStep/CropStep.test.tsx +84 -0
  11. package/src/__tests__/components/ImageDragAndDrop/ImageDragAndDrop.test.tsx +173 -0
  12. package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.test.tsx +3 -4
  13. package/src/__tests__/components/ProfileImage/ProfileImage.test.tsx +120 -0
  14. package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +8 -0
  15. package/src/__tests__/components/UserRolesAndSites/RoleItem/RoleItem.test.tsx +190 -0
  16. package/src/__tests__/components/UserRolesAndSites/UserRolesAndSites.test.tsx +471 -0
  17. package/src/__tests__/modules/FramePreview/HeadingsOverlay/HeadingsOverlay.test.tsx +15 -2
  18. package/src/__tests__/modules/Sites/Sites.test.tsx +68 -224
  19. package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +21 -17
  20. package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +65 -565
  21. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/DataStep/DataStep.test.tsx +109 -0
  22. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/FinalStep/FinalStep.test.tsx +157 -0
  23. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/CropView.test.tsx +51 -0
  24. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/ImageStep.test.tsx +70 -0
  25. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/UploadView.test.tsx +92 -0
  26. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/TimezoneStep/TimezoneStep.test.tsx +94 -0
  27. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeModal.test.tsx +78 -0
  28. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeStep/WelcomeStep.test.tsx +39 -0
  29. package/src/__tests__/modules/Sites/SitesList/WelcomeModal/utils.test.ts +55 -0
  30. package/src/api/sites.tsx +4 -4
  31. package/src/components/Avatar/index.tsx +26 -5
  32. package/src/components/Avatar/style.tsx +20 -10
  33. package/src/components/Browser/index.tsx +7 -1
  34. package/src/components/ConfigPanel/index.tsx +11 -7
  35. package/src/components/ElementsTooltip/index.tsx +96 -34
  36. package/src/components/ElementsTooltip/style.tsx +12 -1
  37. package/src/components/Fields/FileField/index.tsx +16 -18
  38. package/src/components/Fields/HeadingField/index.tsx +1 -1
  39. package/src/components/Fields/ImageField/index.tsx +9 -38
  40. package/src/components/Fields/ImageField/style.tsx +12 -1
  41. package/src/components/Fields/ToggleField/index.tsx +1 -1
  42. package/src/components/Fields/Wysiwyg/index.tsx +25 -20
  43. package/src/components/FileGallery/GalleryPanel/index.tsx +15 -7
  44. package/src/components/FileGallery/index.tsx +33 -28
  45. package/src/components/Gallery/GalleryPanel/index.tsx +5 -16
  46. package/src/components/Gallery/index.tsx +0 -2
  47. package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/index.tsx +11 -2
  48. package/src/components/HeadingsPreviewModal/ErrorsBanner/index.tsx +21 -3
  49. package/src/components/HeadingsPreviewModal/ErrorsBanner/style.tsx +2 -2
  50. package/src/components/HeadingsPreviewModal/index.tsx +13 -3
  51. package/src/components/HeadingsPreviewModal/style.tsx +18 -0
  52. package/src/components/HeadingsPreviewModal/utils.tsx +31 -3
  53. package/src/components/Image/index.tsx +2 -2
  54. package/src/components/ImageDragAndDrop/CropStep/index.tsx +95 -0
  55. package/src/components/ImageDragAndDrop/CropStep/style.tsx +101 -0
  56. package/src/{modules/MediaGallery → components}/ImageDragAndDrop/index.tsx +103 -40
  57. package/src/{modules/MediaGallery → components}/ImageDragAndDrop/style.tsx +14 -2
  58. package/src/components/KeywordsPreviewModal/atoms.tsx +2 -2
  59. package/src/components/KeywordsPreviewModal/index.tsx +6 -6
  60. package/src/components/KeywordsPreviewModal/utils.tsx +2 -2
  61. package/src/components/ProfileImage/index.tsx +55 -0
  62. package/src/components/ProfileImage/style.tsx +58 -0
  63. package/src/components/ResizePanel/ResizeHandle/index.tsx +44 -6
  64. package/src/components/ResizePanel/ResizeHandle/style.tsx +7 -0
  65. package/src/components/ResizePanel/index.tsx +25 -4
  66. package/src/components/Tabs/style.tsx +1 -1
  67. package/src/components/Tag/index.tsx +0 -1
  68. package/src/components/UserRolesAndSites/RoleItem/index.tsx +42 -0
  69. package/src/components/UserRolesAndSites/RoleItem/style.tsx +29 -0
  70. package/src/components/UserRolesAndSites/index.tsx +102 -0
  71. package/src/components/UserRolesAndSites/style.tsx +67 -0
  72. package/src/components/index.tsx +6 -0
  73. package/src/constants/index.ts +13 -1
  74. package/src/containers/App/actions.tsx +8 -1
  75. package/src/containers/Sites/actions.tsx +26 -0
  76. package/src/containers/Sites/constants.tsx +1 -0
  77. package/src/containers/Sites/interfaces.tsx +6 -0
  78. package/src/containers/Sites/reducer.tsx +5 -1
  79. package/src/containers/Users/reducer.tsx +6 -5
  80. package/src/guards/routeLeaving/index.tsx +9 -11
  81. package/src/helpers/images.tsx +50 -3
  82. package/src/helpers/index.tsx +2 -1
  83. package/src/hooks/forms.tsx +45 -48
  84. package/src/hooks/index.tsx +2 -1
  85. package/src/hooks/modals.tsx +4 -3
  86. package/src/hooks/window.ts +50 -2
  87. package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +1 -1
  88. package/src/modules/App/Routing/Logout/index.tsx +3 -5
  89. package/src/modules/App/Routing/NavMenu/NavItem/index.tsx +73 -52
  90. package/src/modules/App/Routing/NavMenu/NavItem/style.tsx +21 -7
  91. package/src/modules/App/Routing/NavMenu/index.tsx +59 -54
  92. package/src/modules/App/Routing/NavMenu/style.tsx +13 -11
  93. package/src/modules/CreatePass/index.tsx +1 -1
  94. package/src/modules/FileDrive/FileDragAndDrop/index.tsx +11 -8
  95. package/src/modules/FileDrive/FileModal/index.tsx +8 -9
  96. package/src/modules/FileDrive/index.tsx +1 -18
  97. package/src/modules/Forms/FormEditor/index.tsx +1 -1
  98. package/src/modules/FramePreview/HeadingsOverlay/index.tsx +22 -11
  99. package/src/modules/FramePreview/HeadingsOverlay/style.tsx +1 -1
  100. package/src/modules/MediaGallery/ImageModal/index.tsx +1 -5
  101. package/src/modules/MediaGallery/index.tsx +1 -3
  102. package/src/modules/Settings/Globals/constants.tsx +942 -106
  103. package/src/modules/Sites/SitesList/AllSitesHeader/index.tsx +33 -0
  104. package/src/modules/Sites/SitesList/AllSitesHeader/style.tsx +35 -0
  105. package/src/modules/Sites/SitesList/GridView/GridHeaderFilter/index.tsx +5 -5
  106. package/src/modules/Sites/SitesList/GridView/GridSiteItem/index.tsx +23 -119
  107. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +4 -4
  108. package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +4 -3
  109. package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +23 -120
  110. package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/index.tsx +4 -5
  111. package/src/modules/Sites/SitesList/RecentSites/index.tsx +49 -0
  112. package/src/modules/Sites/SitesList/RecentSites/style.tsx +92 -0
  113. package/src/modules/Sites/SitesList/SiteModal/index.tsx +8 -7
  114. package/src/modules/Sites/SitesList/WelcomeModal/DataStep/index.tsx +72 -0
  115. package/src/modules/Sites/SitesList/WelcomeModal/DataStep/style.tsx +59 -0
  116. package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/constants.tsx +78 -0
  117. package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +78 -0
  118. package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/style.tsx +141 -0
  119. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/index.tsx +93 -0
  120. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/style.tsx +77 -0
  121. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/index.tsx +100 -0
  122. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/style.tsx +94 -0
  123. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/index.tsx +44 -0
  124. package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/style.tsx +31 -0
  125. package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/index.tsx +51 -0
  126. package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/style.tsx +52 -0
  127. package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/index.tsx +40 -0
  128. package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/style.tsx +53 -0
  129. package/src/modules/Sites/SitesList/WelcomeModal/index.tsx +215 -0
  130. package/src/modules/Sites/SitesList/WelcomeModal/style.tsx +12 -0
  131. package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +26 -0
  132. package/src/modules/Sites/SitesList/atoms.tsx +4 -4
  133. package/src/modules/Sites/SitesList/hooks.tsx +149 -16
  134. package/src/modules/Sites/SitesList/index.tsx +127 -125
  135. package/src/modules/Sites/SitesList/style.tsx +1 -117
  136. package/src/modules/Sites/SitesList/utils.tsx +9 -2
  137. package/src/modules/Sites/index.tsx +19 -8
  138. package/src/modules/Users/Profile/index.tsx +169 -31
  139. package/src/modules/Users/Profile/style.tsx +81 -1
  140. package/src/modules/Users/Roles/RoleItem/index.tsx +2 -2
  141. package/src/modules/Users/UserCreate/SiteItem/index.tsx +11 -14
  142. package/src/modules/Users/UserForm/atoms.tsx +3 -3
  143. package/src/modules/Users/UserForm/index.tsx +25 -29
  144. package/src/modules/Users/UserForm/style.tsx +15 -2
  145. package/src/modules/Users/UserList/UserItem/index.tsx +4 -4
  146. package/src/routes/index.tsx +1 -0
  147. package/src/types/index.tsx +2 -0
  148. /package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/style.tsx +0 -0
@@ -0,0 +1,33 @@
1
+ import { IconAction } from "@ax/components";
2
+ import type { IQueryValue, ISiteListConfig } from "@ax/types";
3
+
4
+ import GridHeaderFilter from "../GridView/GridHeaderFilter";
5
+
6
+ import * as S from "./style";
7
+
8
+ const AllSitesHeader = ({ displayMode, sortItems, sortedListStatus, changeDisplayMode }: IAllSitesHeaderProps) => (
9
+ <S.SectionHeader data-testid="all-sites-header">
10
+ <S.Title isActive={true} data-testid="all-sites-title">
11
+ All sites
12
+ </S.Title>
13
+ <S.HeaderIconsWrapper data-testid="all-sites-header-icons">
14
+ {displayMode === "grid" ? (
15
+ <S.FilterSelect data-testid="all-sites-grid-filter">
16
+ <S.FilterSelectLabel data-testid="all-sites-grid-filter-label">Sort by:</S.FilterSelectLabel>{" "}
17
+ <GridHeaderFilter sortItems={sortItems} sortedState={sortedListStatus} />{" "}
18
+ </S.FilterSelect>
19
+ ) : null}
20
+ <IconAction icon="Grid2" onClick={() => changeDisplayMode("grid")} active={displayMode === "grid"} />
21
+ <IconAction icon="BulletList" onClick={() => changeDisplayMode("list")} active={displayMode === "list"} />
22
+ </S.HeaderIconsWrapper>
23
+ </S.SectionHeader>
24
+ );
25
+
26
+ export interface IAllSitesHeaderProps {
27
+ displayMode: "list" | "grid";
28
+ sortItems: (orderPointer: IQueryValue[], isAscending: boolean) => void;
29
+ sortedListStatus: ISiteListConfig["sortedListStatus"];
30
+ changeDisplayMode: (mode: "list" | "grid") => void;
31
+ }
32
+
33
+ export default AllSitesHeader;
@@ -0,0 +1,35 @@
1
+ import styled from "styled-components";
2
+
3
+ const SectionHeader = styled.div`
4
+ display: flex;
5
+ justify-content: space-between;
6
+ margin: 0 ${(p) => p.theme.spacing.m};
7
+ margin-top: ${(p) => p.theme.spacing.m};
8
+ `;
9
+
10
+ const Title = styled.h1<{ isActive?: boolean }>`
11
+ margin: 0;
12
+ margin-right: ${(p) => p.theme.spacing.m};
13
+ ${(p) => p.theme.textStyle.headingM};
14
+ color: ${(p) => (p.isActive ? p.theme.colors.textHighEmphasis : p.theme.colors.textMediumEmphasis)};
15
+ `;
16
+
17
+ const HeaderIconsWrapper = styled.div`
18
+ display: flex;
19
+ align-items: center;
20
+ `;
21
+
22
+ const FilterSelectLabel = styled.span`
23
+ color: ${(p) => p.theme.color.interactive01};
24
+ `;
25
+
26
+ const FilterSelect = styled.div`
27
+ ${(p) => p.theme.textStyle.uiS};
28
+ line-height: 32px;
29
+ display: flex;
30
+ align-items: center;
31
+ position: relative;
32
+ color: ${(p) => p.theme.color.textLowEmphasis};
33
+ `;
34
+
35
+ export { SectionHeader, Title, HeaderIconsWrapper, FilterSelect, FilterSelectLabel };
@@ -1,7 +1,7 @@
1
- import React from "react";
1
+ import { FloatingMenu, Icon, ListItem, ListTitle } from "@ax/components";
2
+ import type { IQueryValue } from "@ax/types";
2
3
 
3
- import { Icon, FloatingMenu, ListTitle, ListItem } from "@ax/components";
4
- import { IQueryValue } from "@ax/types";
4
+ import type { ISortedListStatus } from "../../utils";
5
5
 
6
6
  import * as S from "./style";
7
7
 
@@ -66,8 +66,8 @@ const GridHeaderFilter = ({ sortItems, sortedState }: IGridHeaderFilterProps): J
66
66
  };
67
67
 
68
68
  export interface IGridHeaderFilterProps {
69
- sortedState: any;
70
- sortItems(orderPointer: IQueryValue[], isAscending: boolean): any;
69
+ sortedState: ISortedListStatus;
70
+ sortItems(orderPointer: IQueryValue[], isAscending: boolean): void;
71
71
  }
72
72
 
73
73
  export default GridHeaderFilter;
@@ -1,132 +1,36 @@
1
- import React, { useState } from "react";
2
1
  import { connect } from "react-redux";
3
2
 
4
- import { useModal, usePermission } from "@ax/hooks";
5
- import { isDevelopment } from "@ax/helpers";
6
- import { IGetSitesParams, ISite } from "@ax/types";
3
+ import { FieldsBehavior, Icon, Modal, Tooltip } from "@ax/components";
7
4
  import { appActions } from "@ax/containers/App";
8
5
  import { sitesActions } from "@ax/containers/Sites";
9
- import { FieldsBehavior, Icon, Modal, Tooltip } from "@ax/components";
6
+ import { isDevelopment } from "@ax/helpers";
7
+ import type { IGetSitesParams, ISite } from "@ax/types";
10
8
 
11
9
  import { ItemName, ItemThumbnail } from "./../../atoms";
10
+ import { useSiteActions } from "./../../hooks";
12
11
 
13
12
  import * as S from "./style";
14
13
 
15
14
  const GridSiteItem = (props: IGridSiteItemProps): JSX.Element => {
16
15
  const { site, setSiteInfo, setHistoryPush, deleteSite, publishSite, unpublishSite, getParams } = props;
17
- const { isOpen: isOpenDelete, toggleModal: toggleDeleteModal } = useModal();
18
- const { isOpen: isOpenPublish, toggleModal: togglePublishModal } = useModal();
19
- const [inputValue, setInputValue] = useState("");
20
- const { updated, isPublished } = site;
21
-
22
- const allowedToDeleteSite = usePermission("general.deleteSite");
23
- const allowedToPublishSite = usePermission("general.publishSite");
24
- const allowedToUnpublishSite = usePermission("general.unpublishSite");
25
-
26
- const getPublishedState = (isPublished: boolean, updated: boolean) => {
27
- switch (isPublished) {
28
- case true:
29
- return updated ? "active" : "upload-pending";
30
- case false:
31
- return updated ? "offline" : "offline-pending";
32
- }
33
- };
34
-
35
- const publishedState = getPublishedState(isPublished, updated);
36
-
37
- const publishedTooltip = {
38
- active: "Live",
39
- "upload-pending": "Publication pending",
40
- offline: "Offline",
41
- "offline-pending": "Offline pending",
42
- };
43
-
44
- const setSite = async () => {
45
- await setSiteInfo(site);
46
- const contentPath = "/sites/pages";
47
- setHistoryPush(contentPath, false);
48
- };
49
-
50
- const getPublishOption = (isPublished: boolean) =>
51
- isPublished && allowedToUnpublishSite
52
- ? { label: "Unpublish", icon: "offlinePending" }
53
- : !isPublished && allowedToPublishSite
54
- ? { label: "Publish", icon: "uploadPending" }
55
- : null;
56
-
57
- const publishOptionProps = getPublishOption(isPublished);
58
-
59
- const deleteOption = allowedToDeleteSite
60
- ? {
61
- label: "delete",
62
- icon: "delete",
63
- action: toggleDeleteModal,
64
- }
65
- : undefined;
66
-
67
- const publishOption = publishOptionProps
68
- ? {
69
- label: publishOptionProps.label,
70
- icon: publishOptionProps.icon,
71
- action: togglePublishModal,
72
- }
73
- : undefined;
74
-
75
- const menuOptions = [deleteOption, publishOption];
76
-
77
- const handleDeleteSite = async () => {
78
- const params = getParams();
79
- await deleteSite(site.id, params);
80
- toggleDeleteModal();
81
- };
82
-
83
- const mainDeleteAction = {
84
- title: "Delete Site",
85
- onClick: handleDeleteSite,
86
- disabled: inputValue !== site.name.toUpperCase(),
87
- };
88
- const secondaryDeleteAction = { title: "Cancel", onClick: toggleDeleteModal };
89
-
90
- const handlePublishSite = async () => {
91
- const params = getParams();
92
- await publishSite(site.id, params);
93
- togglePublishModal();
94
- };
95
-
96
- const handleUnpublishSite = async () => {
97
- const params = getParams();
98
- await unpublishSite(site.id, params);
99
- togglePublishModal();
100
- };
101
-
102
- const getPublishModal = (isPublished: boolean) =>
103
- isPublished
104
- ? {
105
- mainAction: { title: "Unpublish Site", onClick: handleUnpublishSite },
106
- secondaryAction: { title: "Cancel", onClick: togglePublishModal },
107
- title: "Unpublish Site",
108
- content: (
109
- <p>
110
- You are going to unpublish <strong>{site.name}</strong> site.
111
- <br />
112
- This action can take several minutes.
113
- </p>
114
- ),
115
- }
116
- : {
117
- mainAction: { title: "Publish Site", onClick: handlePublishSite },
118
- secondaryAction: { title: "Cancel", onClick: togglePublishModal },
119
- title: "Publish Site",
120
- content: (
121
- <p>
122
- You are going to publish <strong>{site.name}</strong> site.
123
- <br />
124
- Make sure everything is ok before you do it.
125
- </p>
126
- ),
127
- };
128
16
 
129
- const { title, mainAction, secondaryAction, content } = getPublishModal(site.isPublished);
17
+ const {
18
+ publishedState,
19
+ publishedTooltip,
20
+ setSite,
21
+ menuOptions,
22
+ inputValue,
23
+ setInputValue,
24
+ isOpenDelete,
25
+ toggleDeleteModal,
26
+ mainDeleteAction,
27
+ secondaryDeleteAction,
28
+ isOpenPublish,
29
+ togglePublishModal,
30
+ publishModal,
31
+ } = useSiteActions({ site, setSiteInfo, setHistoryPush, deleteSite, publishSite, unpublishSite, getParams });
32
+
33
+ const { title, mainAction, secondaryAction, content } = publishModal;
130
34
 
131
35
  const siteTooltip = isDevelopment() && `Site id: ${site.id}`;
132
36
 
@@ -134,7 +38,7 @@ const GridSiteItem = (props: IGridSiteItemProps): JSX.Element => {
134
38
  <>
135
39
  <S.SiteWrapper key={site.id} onClick={setSite} data-testid="grid-site-item">
136
40
  <Tooltip content={siteTooltip}>
137
- <ItemThumbnail src={site.thumbnail} width={280} height={199} />
41
+ <ItemThumbnail src={site.thumbnail} width={290} height={199} />
138
42
  </Tooltip>
139
43
  <S.Wrapper>
140
44
  <S.Title>
@@ -158,7 +62,7 @@ const GridSiteItem = (props: IGridSiteItemProps): JSX.Element => {
158
62
  {isOpenDelete ? (
159
63
  <S.ModalContent data-testid="delete-modal">
160
64
  <p>
161
- Are you sure you want to delete <strong>‘{site.name}’</strong> site?
65
+ Are you sure you want to delete <strong>'{site.name}'</strong> site?
162
66
  <br />
163
67
  This action <strong>cannot be undone</strong>.
164
68
  </p>
@@ -1,7 +1,7 @@
1
- import React from "react";
1
+ import { CheckField, LastAccessFilter, LiveFilter, NameFilter, TableCounter, Tooltip } from "@ax/components";
2
+ import type { IQueryValue } from "@ax/types";
2
3
 
3
- import { CheckField, TableCounter, LastAccessFilter, NameFilter, LiveFilter, Tooltip } from "@ax/components";
4
- import { IQueryValue } from "@ax/types";
4
+ import type { ISortedListStatus } from "../../../utils";
5
5
 
6
6
  import * as S from "./style";
7
7
 
@@ -66,7 +66,7 @@ interface IProps {
66
66
  checkState: Record<string, boolean>;
67
67
  sortItems: (orderPointer: IQueryValue[], isAscending: boolean) => void;
68
68
  filterItems: (filterPointer: string, filtersSelected: IQueryValue[]) => void;
69
- sortedListStatus: { isAscending: boolean; sortedByDate: boolean; sortedByTitle: boolean; sortedByURL: boolean };
69
+ sortedListStatus: ISortedListStatus;
70
70
  filterValues: Record<string, IQueryValue[]>;
71
71
  setHoverCheck: (state: boolean) => void;
72
72
  }
@@ -4,6 +4,7 @@ import type { IBulkSelectedItems } from "@ax/hooks";
4
4
  import { usePermission } from "@ax/hooks";
5
5
  import type { IQueryValue } from "@ax/types";
6
6
 
7
+ import type { ISortedListStatus } from "../../utils";
7
8
  import TableHeader from "./TableHeader";
8
9
 
9
10
  import * as S from "./style";
@@ -77,15 +78,15 @@ const BulkHeader = (props: IBulkHeaderProps): JSX.Element => {
77
78
 
78
79
  export interface IBulkHeaderProps {
79
80
  showBulk: boolean;
80
- checkState: any;
81
+ checkState: Record<string, boolean>;
81
82
  bulkPublish: () => void;
82
83
  bulkUnpublish: () => void;
83
84
  selectItems: () => void;
84
85
  selectAllItems: () => void;
85
86
  totalItems: number;
86
- sortItems: (orderPointer: IQueryValue[], isAscending: any) => void;
87
+ sortItems: (orderPointer: IQueryValue[], isAscending: boolean) => void;
87
88
  filterItems: (filterPointer: string, filtersSelected: IQueryValue[]) => void;
88
- sortedListStatus: any;
89
+ sortedListStatus: ISortedListStatus;
89
90
  filterValues: Record<string, IQueryValue[]>;
90
91
  setHoverCheck: (state: boolean) => void;
91
92
  selectedItems: IBulkSelectedItems;
@@ -1,14 +1,13 @@
1
- import React, { useState } from "react";
2
1
  import { connect } from "react-redux";
3
2
 
4
- import { useModal, usePermission } from "@ax/hooks";
5
- import { getFormattedDateWithTimezone } from "@ax/helpers";
6
- import { ICheck, IGetSitesParams, ISite } from "@ax/types";
3
+ import { CheckField, FieldsBehavior, Icon, Modal, Tooltip } from "@ax/components";
7
4
  import { appActions } from "@ax/containers/App";
8
5
  import { sitesActions } from "@ax/containers/Sites";
9
- import { FieldsBehavior, Icon, Modal, Tooltip, CheckField } from "@ax/components";
6
+ import { getFormattedDateWithTimezone } from "@ax/helpers";
7
+ import type { ICheck, IGetSitesParams, ISite } from "@ax/types";
10
8
 
11
9
  import { ItemName, ItemThumbnail } from "./../../atoms";
10
+ import { useSiteActions } from "./../../hooks";
12
11
 
13
12
  import * as S from "./style";
14
13
 
@@ -26,119 +25,23 @@ const ListSiteItem = (props: IListSiteItemProps): JSX.Element => {
26
25
  hoverCheck,
27
26
  } = props;
28
27
 
29
- const { isOpen: isOpenDelete, toggleModal: toggleDeleteModal } = useModal();
30
- const { isOpen: isOpenPublish, toggleModal: togglePublishModal } = useModal();
31
- const [inputValue, setInputValue] = useState("");
32
- const { updated, isPublished } = site;
33
-
34
- const allowedToDeleteSite = usePermission("general.deleteSite");
35
- const allowedToPublishSite = usePermission("general.publishSite");
36
- const allowedToUnpublishSite = usePermission("general.unpublishSite");
37
-
38
- const getPublishedState = (isPublished: boolean, updated: boolean) => {
39
- switch (isPublished) {
40
- case true:
41
- return updated ? "active" : "upload-pending";
42
- case false:
43
- return updated ? "offline" : "offline-pending";
44
- }
45
- };
46
-
47
- const publishedState = getPublishedState(isPublished, updated);
48
-
49
- const publishedTooltip = {
50
- active: "Live",
51
- "upload-pending": "Publication pending",
52
- offline: "Offline",
53
- "offline-pending": "Offline pending",
54
- };
55
-
56
- const setSite = async () => {
57
- await setSiteInfo(site);
58
- const contentPath = "/sites/pages";
59
- setHistoryPush(contentPath, false);
60
- };
61
-
62
- const getPublishOption = (isPublished: boolean) =>
63
- isPublished && allowedToUnpublishSite
64
- ? { label: "Unpublish", icon: "offlinePending" }
65
- : allowedToPublishSite
66
- ? { label: "Publish", icon: "uploadPending" }
67
- : null;
68
-
69
- const publishOptionProps = getPublishOption(isPublished);
70
-
71
- const deleteOption = allowedToDeleteSite
72
- ? {
73
- label: "delete",
74
- icon: "delete",
75
- action: toggleDeleteModal,
76
- }
77
- : undefined;
78
-
79
- const publishOption = publishOptionProps
80
- ? {
81
- label: publishOptionProps.label,
82
- icon: publishOptionProps.icon,
83
- action: togglePublishModal,
84
- }
85
- : undefined;
86
-
87
- const menuOptions = [deleteOption, publishOption];
88
-
89
- const handleDeleteSite = async () => {
90
- const params = getParams();
91
- await deleteSite(site.id, params);
92
- toggleDeleteModal();
93
- };
94
-
95
- const mainDeleteAction = {
96
- title: "Delete Site",
97
- onClick: handleDeleteSite,
98
- disabled: inputValue !== site.name.toUpperCase(),
99
- };
100
- const secondaryDeleteAction = { title: "Cancel", onClick: toggleDeleteModal };
101
-
102
- const handlePublishSite = async () => {
103
- const params = getParams();
104
- await publishSite(site.id, params);
105
- togglePublishModal();
106
- };
107
-
108
- const handleUnpublishSite = async () => {
109
- const params = getParams();
110
- await unpublishSite(site.id, params);
111
- togglePublishModal();
112
- };
113
-
114
- const getPublishModal = (isPublished: boolean) =>
115
- isPublished
116
- ? {
117
- mainAction: { title: "Unpublish Site", onClick: handleUnpublishSite },
118
- secondaryAction: { title: "Cancel", onClick: togglePublishModal },
119
- title: "Unpublish Site",
120
- content: (
121
- <p>
122
- You are going to unpublish <strong>{site.name}</strong> site.
123
- <br />
124
- This action can take several minutes.
125
- </p>
126
- ),
127
- }
128
- : {
129
- mainAction: { title: "Publish Site", onClick: handlePublishSite },
130
- secondaryAction: { title: "Cancel", onClick: togglePublishModal },
131
- title: "Publish Site",
132
- content: (
133
- <p>
134
- You are going to publish <strong>{site.name}</strong> site.
135
- <br />
136
- Make sure everything is ok before you do it.
137
- </p>
138
- ),
139
- };
140
-
141
- const { title, mainAction, secondaryAction, content } = getPublishModal(site.isPublished);
28
+ const {
29
+ publishedState,
30
+ publishedTooltip,
31
+ setSite,
32
+ menuOptions,
33
+ inputValue,
34
+ setInputValue,
35
+ isOpenDelete,
36
+ toggleDeleteModal,
37
+ mainDeleteAction,
38
+ secondaryDeleteAction,
39
+ isOpenPublish,
40
+ togglePublishModal,
41
+ publishModal,
42
+ } = useSiteActions({ site, setSiteInfo, setHistoryPush, deleteSite, publishSite, unpublishSite, getParams });
43
+
44
+ const { title, mainAction, secondaryAction, content } = publishModal;
142
45
 
143
46
  const handleOnChange = (value: ICheck) => onCheck(value);
144
47
 
@@ -181,7 +84,7 @@ const ListSiteItem = (props: IListSiteItemProps): JSX.Element => {
181
84
  {isOpenDelete ? (
182
85
  <S.ModalContent data-testid="delete-modal">
183
86
  <p>
184
- Are you sure you want to delete <strong>‘{site.name}’</strong> site?
87
+ Are you sure you want to delete <strong>'{site.name}'</strong> site?
185
88
  <br />
186
89
  This action <strong>cannot be undone</strong>.
187
90
  </p>
@@ -214,7 +117,7 @@ interface IListSiteItemProps {
214
117
  deleteSite(siteID: number, params?: IGetSitesParams): Promise<void>;
215
118
  publishSite(siteID: number, params?: IGetSitesParams): Promise<void>;
216
119
  unpublishSite(siteID: number, params?: IGetSitesParams): Promise<void>;
217
- onCheck: (e: any) => void;
120
+ onCheck: (e: ICheck) => void;
218
121
  getParams: () => IGetSitesParams;
219
122
  }
220
123
 
@@ -1,13 +1,12 @@
1
- import React from "react";
2
1
  import { connect } from "react-redux";
3
2
 
4
- import { isDevelopment } from "@ax/helpers";
5
- import { ISite } from "@ax/types";
3
+ import { Tooltip } from "@ax/components";
6
4
  import { appActions } from "@ax/containers/App";
7
5
  import { sitesActions } from "@ax/containers/Sites";
8
- import { Tooltip } from "@ax/components";
6
+ import { isDevelopment } from "@ax/helpers";
7
+ import type { ISite } from "@ax/types";
9
8
 
10
- import { ItemName, ItemThumbnail } from "./../atoms";
9
+ import { ItemName, ItemThumbnail } from "../../atoms";
11
10
 
12
11
  import * as S from "./style";
13
12
 
@@ -0,0 +1,49 @@
1
+ import { Icon } from "@ax/components";
2
+ import type { ISite } from "@ax/types";
3
+
4
+ import RecentSiteItem from "./RecentSiteItem";
5
+
6
+ import * as S from "./style";
7
+
8
+ const RecentSitesHeader = ({ isRecentSitesListDisplayed, toggleRecentSites }: IRecentSitesHeaderProps) => (
9
+ <S.SectionHeader data-testid="recent-sites-header" isRecentSites={true}>
10
+ <S.Title data-testid="recent-sites-title" isActive={isRecentSitesListDisplayed}>
11
+ Recent sites
12
+ </S.Title>
13
+ <S.CollapseButton data-testid="recent-sites-collapse-button" onClick={toggleRecentSites}>
14
+ {isRecentSitesListDisplayed ? (
15
+ <>
16
+ <S.Label data-testid="recent-sites-hide-label">Hide recent sites </S.Label> <Icon name="UpArrow" />
17
+ </>
18
+ ) : (
19
+ <>
20
+ <S.Label data-testid="recent-sites-show-label">Show recent sites </S.Label> <Icon name="DownArrow" />
21
+ </>
22
+ )}
23
+ </S.CollapseButton>
24
+ </S.SectionHeader>
25
+ );
26
+
27
+ const RecentSitesList = ({ recentSites, isRecentSitesListDisplayed, toggleRecentSites }: IRecentSitesListProps) => (
28
+ <S.RecentSites data-testid="recent-sites-list" fullWidth={recentSites.length >= 5}>
29
+ <RecentSitesHeader isRecentSitesListDisplayed={isRecentSitesListDisplayed} toggleRecentSites={toggleRecentSites} />
30
+ <S.RecentSitesItemsWrapper data-testid="recent-sites-items-wrapper" isHidden={!isRecentSitesListDisplayed}>
31
+ {recentSites.map((site: ISite) => (
32
+ <RecentSiteItem key={site.id} site={site} />
33
+ ))}
34
+ </S.RecentSitesItemsWrapper>
35
+ </S.RecentSites>
36
+ );
37
+
38
+ interface IRecentSitesHeaderProps {
39
+ isRecentSitesListDisplayed: boolean;
40
+ toggleRecentSites: () => void;
41
+ }
42
+
43
+ export interface IRecentSitesListProps {
44
+ recentSites: ISite[];
45
+ isRecentSitesListDisplayed: boolean;
46
+ toggleRecentSites: () => void;
47
+ }
48
+
49
+ export default RecentSitesList;
@@ -0,0 +1,92 @@
1
+ import styled, { css } from "styled-components";
2
+
3
+ const SectionHeader = styled.div<{ isRecentSites?: boolean }>`
4
+ display: flex;
5
+ justify-content: space-between;
6
+ margin: 0 ${(p) => (p.isRecentSites ? p.theme.spacing.s : p.theme.spacing.m)};
7
+ margin-top: ${(p) => p.theme.spacing.m};
8
+ `;
9
+
10
+ const Title = styled.h1<{ isActive?: boolean }>`
11
+ margin: 0;
12
+ margin-right: ${(p) => p.theme.spacing.m};
13
+ ${(p) => p.theme.textStyle.headingM};
14
+ color: ${(p) => (p.isActive ? p.theme.colors.textHighEmphasis : p.theme.colors.textMediumEmphasis)};
15
+ `;
16
+
17
+ const CollapseButton = styled.div`
18
+ display: flex;
19
+ align-items: center;
20
+ ${(p) => p.theme.textStyle.uiS};
21
+ color: ${(p) => p.theme.colors.textMediumEmphasis};
22
+ padding: 0;
23
+ margin: 0;
24
+ cursor: pointer;
25
+ `;
26
+
27
+ const Label = styled.span`
28
+ margin-right: 14px;
29
+ `;
30
+
31
+ const RecentSites = styled.div<{ fullWidth: boolean }>`
32
+ display: ${(p) => (p.fullWidth ? "block" : "inline-block")};
33
+ padding-bottom: ${(p) => p.theme.spacing.s};
34
+ border-radius: ${(p) => p.theme.radii.s};
35
+ background: ${(p) => p.theme.color.uiBackground02};
36
+ min-height: 56px;
37
+ overflow: hidden;
38
+ margin: ${(p) => p.theme.spacing.m};
39
+ margin-bottom: 0;
40
+ flex-shrink: 0;
41
+
42
+ h1 {
43
+ padding-left: 0;
44
+ }
45
+ `;
46
+
47
+ const RecentSitesItemsWrapper = styled.div<{ isHidden: boolean }>`
48
+ display: grid;
49
+ grid-auto-flow: column;
50
+ overflow: auto;
51
+ grid-gap: ${(p) => p.theme.spacing.m};
52
+ padding: ${(p) => p.theme.spacing.s} ${(p) => p.theme.spacing.s} 0px ${(p) => p.theme.spacing.s};
53
+ overflow: hidden;
54
+
55
+ div {
56
+ min-width: 100%;
57
+ }
58
+
59
+ ${(props) =>
60
+ props.isHidden &&
61
+ css`
62
+ height: 0;
63
+ padding: 0;
64
+ padding-left: ${(p) => p.theme.spacing.s};
65
+ padding-top: ${(p) => p.theme.spacing.xs};
66
+ `};
67
+
68
+ @media (min-width: 1200px) {
69
+ div:nth-child(6),
70
+ div:nth-child(7) {
71
+ display: none;
72
+ }
73
+ }
74
+
75
+ @media (min-width: 1600px) {
76
+ div:nth-child(6) {
77
+ display: block;
78
+ }
79
+ div:nth-child(7) {
80
+ display: none;
81
+ }
82
+ }
83
+
84
+ @media (min-width: 1750px) {
85
+ div:nth-child(6),
86
+ div:nth-child(7) {
87
+ display: block;
88
+ }
89
+ }
90
+ `;
91
+
92
+ export { SectionHeader, Title, CollapseButton, Label, RecentSites, RecentSitesItemsWrapper };
@@ -1,7 +1,7 @@
1
- import React, { useEffect } from "react";
1
+ import { useEffect } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import { IRootState, ILanguage, ISettingsForm } from "@ax/types";
4
+ import type { ILanguage, IRootState, ISettingsForm } from "@ax/types";
5
5
  import { slugify } from "@ax/helpers";
6
6
  import { ErrorToast, FieldsBehavior } from "@ax/components";
7
7
 
@@ -20,10 +20,11 @@ const SiteModal = (props: ISiteModalProps): JSX.Element => {
20
20
  const setPathValue = (value: string) => updateForm({ path: value });
21
21
  const setDomainValue = (value: number) => updateForm({ domain: value });
22
22
 
23
- // biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
24
23
  useEffect(() => {
25
- globalDefaultLang && setLangValue(globalDefaultLang.id);
26
- }, []);
24
+ if (globalDefaultLang) {
25
+ setForm((state: ISettingsForm) => ({ ...state, defaultLanguage: globalDefaultLang.id }));
26
+ }
27
+ }, [globalDefaultLang, setForm]);
27
28
 
28
29
  const slugHelpText =
29
30
  "The path is for the site on this language. Please, fill with the name of the site. Example: /the-site-url";
@@ -84,8 +85,8 @@ const mapStateToProps = (state: IRootState) => ({
84
85
 
85
86
  interface IStateProps {
86
87
  languages?: ILanguage[];
87
- form: { name: string; defaultLanguage: number | null; path: string; domain: string | null };
88
- setForm: React.Dispatch<React.SetStateAction<any>>;
88
+ form: ISettingsForm;
89
+ setForm: React.Dispatch<React.SetStateAction<ISettingsForm>>;
89
90
  }
90
91
 
91
92
  type ISiteModalProps = IStateProps;