@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.
- package/config/jest/reactEasyCropMock.js +15 -0
- package/config/jest/reactTimezoneMock.js +13 -0
- package/package.json +221 -219
- package/public/img/welcome.svg +127 -0
- package/src/__tests__/components/Browser/Browser.test.tsx +27 -51
- package/src/__tests__/components/CategoryCell/CategoryCell.test.tsx +10 -5
- package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +27 -14
- package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/ErrorItem.test.tsx +2 -0
- package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.utils.test.tsx +138 -1
- package/src/__tests__/components/ImageDragAndDrop/CropStep/CropStep.test.tsx +84 -0
- package/src/__tests__/components/ImageDragAndDrop/ImageDragAndDrop.test.tsx +173 -0
- package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.test.tsx +3 -4
- package/src/__tests__/components/ProfileImage/ProfileImage.test.tsx +120 -0
- package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +8 -0
- package/src/__tests__/components/UserRolesAndSites/RoleItem/RoleItem.test.tsx +190 -0
- package/src/__tests__/components/UserRolesAndSites/UserRolesAndSites.test.tsx +471 -0
- package/src/__tests__/modules/FramePreview/HeadingsOverlay/HeadingsOverlay.test.tsx +15 -2
- package/src/__tests__/modules/Sites/Sites.test.tsx +68 -224
- package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +21 -17
- package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +65 -565
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/DataStep/DataStep.test.tsx +109 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/FinalStep/FinalStep.test.tsx +157 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/CropView.test.tsx +51 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/ImageStep.test.tsx +70 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/UploadView.test.tsx +92 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/TimezoneStep/TimezoneStep.test.tsx +94 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeModal.test.tsx +78 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeStep/WelcomeStep.test.tsx +39 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/utils.test.ts +55 -0
- package/src/api/sites.tsx +4 -4
- package/src/components/Avatar/index.tsx +26 -5
- package/src/components/Avatar/style.tsx +20 -10
- package/src/components/Browser/index.tsx +7 -1
- package/src/components/ConfigPanel/index.tsx +11 -7
- package/src/components/ElementsTooltip/index.tsx +96 -34
- package/src/components/ElementsTooltip/style.tsx +12 -1
- package/src/components/Fields/FileField/index.tsx +16 -18
- package/src/components/Fields/HeadingField/index.tsx +1 -1
- package/src/components/Fields/ImageField/index.tsx +9 -38
- package/src/components/Fields/ImageField/style.tsx +12 -1
- package/src/components/Fields/ToggleField/index.tsx +1 -1
- package/src/components/Fields/Wysiwyg/index.tsx +25 -20
- package/src/components/FileGallery/GalleryPanel/index.tsx +15 -7
- package/src/components/FileGallery/index.tsx +33 -28
- package/src/components/Gallery/GalleryPanel/index.tsx +5 -16
- package/src/components/Gallery/index.tsx +0 -2
- package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/index.tsx +11 -2
- package/src/components/HeadingsPreviewModal/ErrorsBanner/index.tsx +21 -3
- package/src/components/HeadingsPreviewModal/ErrorsBanner/style.tsx +2 -2
- package/src/components/HeadingsPreviewModal/index.tsx +13 -3
- package/src/components/HeadingsPreviewModal/style.tsx +18 -0
- package/src/components/HeadingsPreviewModal/utils.tsx +31 -3
- package/src/components/Image/index.tsx +2 -2
- package/src/components/ImageDragAndDrop/CropStep/index.tsx +95 -0
- package/src/components/ImageDragAndDrop/CropStep/style.tsx +101 -0
- package/src/{modules/MediaGallery → components}/ImageDragAndDrop/index.tsx +103 -40
- package/src/{modules/MediaGallery → components}/ImageDragAndDrop/style.tsx +14 -2
- package/src/components/KeywordsPreviewModal/atoms.tsx +2 -2
- package/src/components/KeywordsPreviewModal/index.tsx +6 -6
- package/src/components/KeywordsPreviewModal/utils.tsx +2 -2
- package/src/components/ProfileImage/index.tsx +55 -0
- package/src/components/ProfileImage/style.tsx +58 -0
- package/src/components/ResizePanel/ResizeHandle/index.tsx +44 -6
- package/src/components/ResizePanel/ResizeHandle/style.tsx +7 -0
- package/src/components/ResizePanel/index.tsx +25 -4
- package/src/components/Tabs/style.tsx +1 -1
- package/src/components/Tag/index.tsx +0 -1
- package/src/components/UserRolesAndSites/RoleItem/index.tsx +42 -0
- package/src/components/UserRolesAndSites/RoleItem/style.tsx +29 -0
- package/src/components/UserRolesAndSites/index.tsx +102 -0
- package/src/components/UserRolesAndSites/style.tsx +67 -0
- package/src/components/index.tsx +6 -0
- package/src/constants/index.ts +13 -1
- package/src/containers/App/actions.tsx +8 -1
- package/src/containers/Sites/actions.tsx +26 -0
- package/src/containers/Sites/constants.tsx +1 -0
- package/src/containers/Sites/interfaces.tsx +6 -0
- package/src/containers/Sites/reducer.tsx +5 -1
- package/src/containers/Users/reducer.tsx +6 -5
- package/src/guards/routeLeaving/index.tsx +9 -11
- package/src/helpers/images.tsx +50 -3
- package/src/helpers/index.tsx +2 -1
- package/src/hooks/forms.tsx +45 -48
- package/src/hooks/index.tsx +2 -1
- package/src/hooks/modals.tsx +4 -3
- package/src/hooks/window.ts +50 -2
- package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +1 -1
- package/src/modules/App/Routing/Logout/index.tsx +3 -5
- package/src/modules/App/Routing/NavMenu/NavItem/index.tsx +73 -52
- package/src/modules/App/Routing/NavMenu/NavItem/style.tsx +21 -7
- package/src/modules/App/Routing/NavMenu/index.tsx +59 -54
- package/src/modules/App/Routing/NavMenu/style.tsx +13 -11
- package/src/modules/CreatePass/index.tsx +1 -1
- package/src/modules/FileDrive/FileDragAndDrop/index.tsx +11 -8
- package/src/modules/FileDrive/FileModal/index.tsx +8 -9
- package/src/modules/FileDrive/index.tsx +1 -18
- package/src/modules/Forms/FormEditor/index.tsx +1 -1
- package/src/modules/FramePreview/HeadingsOverlay/index.tsx +22 -11
- package/src/modules/FramePreview/HeadingsOverlay/style.tsx +1 -1
- package/src/modules/MediaGallery/ImageModal/index.tsx +1 -5
- package/src/modules/MediaGallery/index.tsx +1 -3
- package/src/modules/Settings/Globals/constants.tsx +942 -106
- package/src/modules/Sites/SitesList/AllSitesHeader/index.tsx +33 -0
- package/src/modules/Sites/SitesList/AllSitesHeader/style.tsx +35 -0
- package/src/modules/Sites/SitesList/GridView/GridHeaderFilter/index.tsx +5 -5
- package/src/modules/Sites/SitesList/GridView/GridSiteItem/index.tsx +23 -119
- package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +4 -4
- package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +4 -3
- package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +23 -120
- package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/index.tsx +4 -5
- package/src/modules/Sites/SitesList/RecentSites/index.tsx +49 -0
- package/src/modules/Sites/SitesList/RecentSites/style.tsx +92 -0
- package/src/modules/Sites/SitesList/SiteModal/index.tsx +8 -7
- package/src/modules/Sites/SitesList/WelcomeModal/DataStep/index.tsx +72 -0
- package/src/modules/Sites/SitesList/WelcomeModal/DataStep/style.tsx +59 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/constants.tsx +78 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +78 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/style.tsx +141 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/index.tsx +93 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/style.tsx +77 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/index.tsx +100 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/style.tsx +94 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/index.tsx +44 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/style.tsx +31 -0
- package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/index.tsx +51 -0
- package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/style.tsx +52 -0
- package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/index.tsx +40 -0
- package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/style.tsx +53 -0
- package/src/modules/Sites/SitesList/WelcomeModal/index.tsx +215 -0
- package/src/modules/Sites/SitesList/WelcomeModal/style.tsx +12 -0
- package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +26 -0
- package/src/modules/Sites/SitesList/atoms.tsx +4 -4
- package/src/modules/Sites/SitesList/hooks.tsx +149 -16
- package/src/modules/Sites/SitesList/index.tsx +127 -125
- package/src/modules/Sites/SitesList/style.tsx +1 -117
- package/src/modules/Sites/SitesList/utils.tsx +9 -2
- package/src/modules/Sites/index.tsx +19 -8
- package/src/modules/Users/Profile/index.tsx +169 -31
- package/src/modules/Users/Profile/style.tsx +81 -1
- package/src/modules/Users/Roles/RoleItem/index.tsx +2 -2
- package/src/modules/Users/UserCreate/SiteItem/index.tsx +11 -14
- package/src/modules/Users/UserForm/atoms.tsx +3 -3
- package/src/modules/Users/UserForm/index.tsx +25 -29
- package/src/modules/Users/UserForm/style.tsx +15 -2
- package/src/modules/Users/UserList/UserItem/index.tsx +4 -4
- package/src/routes/index.tsx +1 -0
- package/src/types/index.tsx +2 -0
- /package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/style.tsx +0 -0
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { IQueryValue } from "@ax/types";
|
|
3
|
-
|
|
4
|
-
const useSortedListStatus = () => {
|
|
5
|
-
const sortedInitialState: {
|
|
6
|
-
isAscending: boolean;
|
|
7
|
-
sortedByTitle: boolean;
|
|
8
|
-
sortedByLastAccess: boolean;
|
|
9
|
-
sortedByDateCreated: boolean;
|
|
10
|
-
} = {
|
|
11
|
-
isAscending: false,
|
|
12
|
-
sortedByTitle: false,
|
|
13
|
-
sortedByLastAccess: true,
|
|
14
|
-
sortedByDateCreated: false,
|
|
15
|
-
};
|
|
16
2
|
|
|
17
|
-
|
|
3
|
+
import { useModal, usePermission } from "@ax/hooks";
|
|
4
|
+
import type { IGetSitesParams, IQueryValue, ISite } from "@ax/types";
|
|
5
|
+
|
|
6
|
+
import type { ISortedListStatus } from "./utils";
|
|
7
|
+
|
|
8
|
+
const sortedListDefaultState: ISortedListStatus = {
|
|
9
|
+
isAscending: false,
|
|
10
|
+
sortedByTitle: false,
|
|
11
|
+
sortedByLastAccess: true,
|
|
12
|
+
sortedByDateCreated: false,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const useSortedListStatus = (initialValue?: ISortedListStatus) => {
|
|
16
|
+
const [sortedListStatus, setSortedListStatus] = useState<ISortedListStatus>(initialValue || sortedListDefaultState);
|
|
18
17
|
|
|
19
18
|
return {
|
|
20
19
|
sortedListStatus,
|
|
@@ -111,4 +110,138 @@ interface ISitesFilterQuery {
|
|
|
111
110
|
filterQuery: string;
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
interface IUseSiteActionsParams {
|
|
114
|
+
site: ISite;
|
|
115
|
+
setSiteInfo(currentSiteInfo: ISite): Promise<void>;
|
|
116
|
+
setHistoryPush(page: string, isEditor: boolean): void;
|
|
117
|
+
deleteSite(siteID: number, params?: IGetSitesParams): Promise<void>;
|
|
118
|
+
publishSite(siteID: number, params?: IGetSitesParams): Promise<void>;
|
|
119
|
+
unpublishSite(siteID: number, params?: IGetSitesParams): Promise<void>;
|
|
120
|
+
getParams: () => IGetSitesParams;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const publishedTooltip: Record<string, string> = {
|
|
124
|
+
active: "Live",
|
|
125
|
+
"upload-pending": "Publication pending",
|
|
126
|
+
offline: "Offline",
|
|
127
|
+
"offline-pending": "Offline pending",
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const getPublishedState = (isPublished: boolean, updated: boolean): string => {
|
|
131
|
+
switch (isPublished) {
|
|
132
|
+
case true:
|
|
133
|
+
return updated ? "active" : "upload-pending";
|
|
134
|
+
case false:
|
|
135
|
+
return updated ? "offline" : "offline-pending";
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const useSiteActions = ({
|
|
140
|
+
site,
|
|
141
|
+
setSiteInfo,
|
|
142
|
+
setHistoryPush,
|
|
143
|
+
deleteSite,
|
|
144
|
+
publishSite,
|
|
145
|
+
unpublishSite,
|
|
146
|
+
getParams,
|
|
147
|
+
}: IUseSiteActionsParams) => {
|
|
148
|
+
const { isOpen: isOpenDelete, toggleModal: toggleDeleteModal } = useModal();
|
|
149
|
+
const { isOpen: isOpenPublish, toggleModal: togglePublishModal } = useModal();
|
|
150
|
+
const [inputValue, setInputValue] = useState("");
|
|
151
|
+
|
|
152
|
+
const allowedToDeleteSite = usePermission("general.deleteSite");
|
|
153
|
+
const allowedToPublishSite = usePermission("general.publishSite");
|
|
154
|
+
const allowedToUnpublishSite = usePermission("general.unpublishSite");
|
|
155
|
+
|
|
156
|
+
const { updated, isPublished } = site;
|
|
157
|
+
const publishedState = getPublishedState(isPublished, updated);
|
|
158
|
+
|
|
159
|
+
const setSite = async () => {
|
|
160
|
+
await setSiteInfo(site);
|
|
161
|
+
setHistoryPush("/sites/pages", false);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const deleteOption = allowedToDeleteSite ? { label: "delete", icon: "delete", action: toggleDeleteModal } : undefined;
|
|
165
|
+
|
|
166
|
+
const publishOptionProps =
|
|
167
|
+
isPublished && allowedToUnpublishSite
|
|
168
|
+
? { label: "Unpublish", icon: "offlinePending" }
|
|
169
|
+
: !isPublished && allowedToPublishSite
|
|
170
|
+
? { label: "Publish", icon: "uploadPending" }
|
|
171
|
+
: null;
|
|
172
|
+
|
|
173
|
+
const publishOption = publishOptionProps
|
|
174
|
+
? { label: publishOptionProps.label, icon: publishOptionProps.icon, action: togglePublishModal }
|
|
175
|
+
: undefined;
|
|
176
|
+
|
|
177
|
+
const menuOptions = [deleteOption, publishOption];
|
|
178
|
+
|
|
179
|
+
const handleDeleteSite = async () => {
|
|
180
|
+
const params = getParams();
|
|
181
|
+
await deleteSite(site.id, params);
|
|
182
|
+
toggleDeleteModal();
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const mainDeleteAction = {
|
|
186
|
+
title: "Delete Site",
|
|
187
|
+
onClick: handleDeleteSite,
|
|
188
|
+
disabled: inputValue !== site.name.toUpperCase(),
|
|
189
|
+
};
|
|
190
|
+
const secondaryDeleteAction = { title: "Cancel", onClick: toggleDeleteModal };
|
|
191
|
+
|
|
192
|
+
const handlePublishSite = async () => {
|
|
193
|
+
const params = getParams();
|
|
194
|
+
await publishSite(site.id, params);
|
|
195
|
+
togglePublishModal();
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const handleUnpublishSite = async () => {
|
|
199
|
+
const params = getParams();
|
|
200
|
+
await unpublishSite(site.id, params);
|
|
201
|
+
togglePublishModal();
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const publishModal = isPublished
|
|
205
|
+
? {
|
|
206
|
+
mainAction: { title: "Unpublish Site", onClick: handleUnpublishSite },
|
|
207
|
+
secondaryAction: { title: "Cancel", onClick: togglePublishModal },
|
|
208
|
+
title: "Unpublish Site",
|
|
209
|
+
content: (
|
|
210
|
+
<p>
|
|
211
|
+
You are going to unpublish <strong>{site.name}</strong> site.
|
|
212
|
+
<br />
|
|
213
|
+
This action can take several minutes.
|
|
214
|
+
</p>
|
|
215
|
+
),
|
|
216
|
+
}
|
|
217
|
+
: {
|
|
218
|
+
mainAction: { title: "Publish Site", onClick: handlePublishSite },
|
|
219
|
+
secondaryAction: { title: "Cancel", onClick: togglePublishModal },
|
|
220
|
+
title: "Publish Site",
|
|
221
|
+
content: (
|
|
222
|
+
<p>
|
|
223
|
+
You are going to publish <strong>{site.name}</strong> site.
|
|
224
|
+
<br />
|
|
225
|
+
Make sure everything is ok before you do it.
|
|
226
|
+
</p>
|
|
227
|
+
),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
publishedState,
|
|
232
|
+
publishedTooltip,
|
|
233
|
+
setSite,
|
|
234
|
+
menuOptions,
|
|
235
|
+
inputValue,
|
|
236
|
+
setInputValue,
|
|
237
|
+
isOpenDelete,
|
|
238
|
+
toggleDeleteModal,
|
|
239
|
+
mainDeleteAction,
|
|
240
|
+
secondaryDeleteAction,
|
|
241
|
+
isOpenPublish,
|
|
242
|
+
togglePublishModal,
|
|
243
|
+
publishModal,
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export { useSortedListStatus, useFilterQuery, useIsMount, useSiteActions };
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
EmptyState,
|
|
6
6
|
ErrorToast,
|
|
7
7
|
FilterTagsBar,
|
|
8
|
-
Icon,
|
|
9
|
-
IconAction,
|
|
10
8
|
Loading,
|
|
11
9
|
MainWrapper,
|
|
12
10
|
Modal,
|
|
@@ -26,20 +24,36 @@ import type {
|
|
|
26
24
|
ISettingsForm,
|
|
27
25
|
ISite,
|
|
28
26
|
ISiteListConfig,
|
|
27
|
+
IUser,
|
|
29
28
|
} from "@ax/types";
|
|
30
29
|
|
|
31
|
-
import
|
|
30
|
+
import AllSitesHeader from "./AllSitesHeader";
|
|
32
31
|
import GridSiteItem from "./GridView/GridSiteItem";
|
|
33
32
|
import { useFilterQuery, useIsMount, useSortedListStatus } from "./hooks";
|
|
34
33
|
import BulkHeader from "./ListView/BulkHeader";
|
|
35
34
|
import ListSiteItem from "./ListView/ListSiteItem";
|
|
36
|
-
import
|
|
35
|
+
import RecentSitesList from "./RecentSites";
|
|
37
36
|
import SiteModal from "./SiteModal";
|
|
38
37
|
import { filterByStatus, getSortedListStatus } from "./utils";
|
|
38
|
+
import WelcomeModal from "./WelcomeModal";
|
|
39
39
|
|
|
40
40
|
import * as S from "./style";
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const initialState = {
|
|
43
|
+
name: "",
|
|
44
|
+
defaultLanguage: null,
|
|
45
|
+
path: "",
|
|
46
|
+
domain: null,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const itemsPerPage = 30;
|
|
50
|
+
const firstPage = 1;
|
|
51
|
+
|
|
52
|
+
const filterLabels = {
|
|
53
|
+
liveStatus: "Live",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const SitesList = (props: ISitesListProps) => {
|
|
43
57
|
const {
|
|
44
58
|
token,
|
|
45
59
|
sites,
|
|
@@ -57,55 +71,71 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
57
71
|
setHasAnimation,
|
|
58
72
|
isLoading,
|
|
59
73
|
isSitesLoading,
|
|
74
|
+
currentUser,
|
|
60
75
|
} = props;
|
|
61
76
|
|
|
62
77
|
const isMount = useIsMount();
|
|
63
|
-
const initialState = {
|
|
64
|
-
name: "",
|
|
65
|
-
defaultLanguage: null,
|
|
66
|
-
path: "",
|
|
67
|
-
domain: null,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const itemsPerPage = 30;
|
|
71
|
-
const firstPage = 1;
|
|
72
78
|
|
|
73
79
|
const [page, setPage] = useState(firstPage);
|
|
74
|
-
const [form, setForm] = useState(initialState);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
const [form, setForm] = useState<ISettingsForm>(initialState);
|
|
81
|
+
|
|
82
|
+
const currentConfig = useMemo(() => {
|
|
83
|
+
const raw = localStorage.getItem("sitesConfig");
|
|
84
|
+
return raw ? JSON.parse(raw) : config;
|
|
85
|
+
}, [config]);
|
|
86
|
+
|
|
87
|
+
const initialHasAnimation = useRef(hasAnimation);
|
|
88
|
+
const currentConfigRef = useRef(currentConfig);
|
|
89
|
+
useLayoutEffect(() => {
|
|
90
|
+
currentConfigRef.current = currentConfig;
|
|
91
|
+
}, [currentConfig]);
|
|
92
|
+
|
|
78
93
|
const [isRecentSitesListDisplayed, setIsRecentSitesListDisplayed] = useState<boolean>(
|
|
79
94
|
currentConfig.displayRecentSites,
|
|
80
95
|
);
|
|
81
|
-
|
|
96
|
+
|
|
97
|
+
const [displayMode, setDisplayMode] = useState<"list" | "grid">(currentConfig.mode);
|
|
82
98
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
83
99
|
const [isBulkLoading, setIsBulkLoading] = useState(false);
|
|
84
100
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
85
101
|
const errorRef = useRef<HTMLDivElement>(null);
|
|
86
102
|
|
|
103
|
+
const scrollToTop = useCallback(() => {
|
|
104
|
+
if (tableRef.current) {
|
|
105
|
+
tableRef.current.scrollTo(0, 0);
|
|
106
|
+
}
|
|
107
|
+
}, []);
|
|
108
|
+
|
|
109
|
+
const handlePageChange = useCallback(
|
|
110
|
+
(newPage: number) => {
|
|
111
|
+
scrollToTop();
|
|
112
|
+
setPage(newPage);
|
|
113
|
+
},
|
|
114
|
+
[scrollToTop],
|
|
115
|
+
);
|
|
116
|
+
|
|
87
117
|
const sitesIds = sites?.map((site: ISite) => site.id);
|
|
88
118
|
|
|
89
119
|
const allowedToCreateSite = usePermission("general.createSite");
|
|
90
120
|
|
|
91
121
|
const pagination = {
|
|
92
|
-
setPage,
|
|
122
|
+
setPage: handlePageChange,
|
|
93
123
|
itemsPerPage,
|
|
94
124
|
totalItems,
|
|
95
125
|
currPage: page,
|
|
96
126
|
};
|
|
97
127
|
|
|
98
128
|
const { isOpen, toggleModal } = useModal();
|
|
129
|
+
const { isOpen: isWelcomeOpen, toggleModal: toggleWelcomeModal } = useModal();
|
|
99
130
|
|
|
100
|
-
const openModal = () => toggleModal();
|
|
101
131
|
const rightButtonProps = allowedToCreateSite
|
|
102
132
|
? {
|
|
103
133
|
label: "New",
|
|
104
|
-
action:
|
|
134
|
+
action: toggleModal,
|
|
105
135
|
}
|
|
106
136
|
: undefined;
|
|
107
137
|
|
|
108
|
-
const { setSortedListStatus } = useSortedListStatus();
|
|
138
|
+
const { sortedListStatus, setSortedListStatus } = useSortedListStatus(currentConfig.sortedListStatus);
|
|
109
139
|
const { setFiltersSelection, resetFilterQuery, filterValues, filterQuery } = useFilterQuery(
|
|
110
140
|
currentConfig.filterValues,
|
|
111
141
|
);
|
|
@@ -126,6 +156,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
126
156
|
const getSiteList = useCallback(async () => {
|
|
127
157
|
if (token) {
|
|
128
158
|
const params = getParams();
|
|
159
|
+
// On first mount, token is required for initial authentication
|
|
129
160
|
if (isMount) {
|
|
130
161
|
await getSites({ ...params, token });
|
|
131
162
|
} else {
|
|
@@ -134,19 +165,19 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
134
165
|
}
|
|
135
166
|
}, [getParams, getSites, isMount, token]);
|
|
136
167
|
|
|
137
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
138
168
|
useEffect(() => {
|
|
139
169
|
getSiteList();
|
|
140
|
-
}, [
|
|
170
|
+
}, [getSiteList]);
|
|
141
171
|
|
|
142
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
|
|
143
172
|
useEffect(() => {
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
const updatedConfig = { ...currentConfig, filterValues };
|
|
147
|
-
setListConfig(updatedConfig);
|
|
173
|
+
if (!initialHasAnimation.current && !currentUser.profileCreated) {
|
|
174
|
+
toggleWelcomeModal();
|
|
148
175
|
}
|
|
149
|
-
}, [
|
|
176
|
+
}, [toggleWelcomeModal, currentUser]);
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
setListConfig({ ...currentConfigRef.current, filterValues });
|
|
180
|
+
}, [filterValues, setListConfig]);
|
|
150
181
|
|
|
151
182
|
useEffect(() => {
|
|
152
183
|
const errorCode = error?.code;
|
|
@@ -163,27 +194,27 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
163
194
|
}
|
|
164
195
|
};
|
|
165
196
|
|
|
166
|
-
const mandatoryKeysLength = 4;
|
|
167
197
|
const isSubmitDisabled =
|
|
168
|
-
Object.values(form).filter((el
|
|
169
|
-
|
|
198
|
+
Object.values(form).filter((el) => (typeof el === "string" ? el.trim().length : el)).length !==
|
|
199
|
+
Object.keys(initialState).length;
|
|
170
200
|
|
|
171
201
|
const mainAction = { title: "Create site", onClick: saveSiteSettings, disabled: isSubmitDisabled };
|
|
172
202
|
const secondaryAction = { title: "Cancel", onClick: toggleModal };
|
|
173
203
|
|
|
174
204
|
const toggleRecentSites = () => {
|
|
175
|
-
const updatedConfig = { ...
|
|
205
|
+
const updatedConfig = { ...currentConfig, displayRecentSites: !isRecentSitesListDisplayed };
|
|
176
206
|
setListConfig(updatedConfig);
|
|
177
207
|
setIsRecentSitesListDisplayed(!isRecentSitesListDisplayed);
|
|
178
208
|
};
|
|
179
209
|
|
|
180
210
|
const changeDisplayMode = (mode: "grid" | "list") => {
|
|
181
|
-
const updatedConfig = { ...
|
|
211
|
+
const updatedConfig = { ...currentConfig, mode };
|
|
182
212
|
setListConfig(updatedConfig);
|
|
183
213
|
setDisplayMode(mode);
|
|
184
214
|
};
|
|
185
215
|
|
|
186
216
|
const sortItems = (orderPointer: IQueryValue[], isAscending: boolean) => {
|
|
217
|
+
scrollToTop();
|
|
187
218
|
setPage(firstPage);
|
|
188
219
|
const orderString = orderPointer[0].value.toString();
|
|
189
220
|
const sortedState = getSortedListStatus(orderString, isAscending);
|
|
@@ -195,62 +226,13 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
195
226
|
};
|
|
196
227
|
|
|
197
228
|
const filterItems = async (filterPointer: string, filtersSelected: IQueryValue[]) => {
|
|
229
|
+
scrollToTop();
|
|
198
230
|
setPage(firstPage);
|
|
199
231
|
setFiltersSelection(filterPointer, filtersSelected);
|
|
200
232
|
const updatedConfig = { ...currentConfig, filter: filterQuery };
|
|
201
233
|
setListConfig(updatedConfig);
|
|
202
234
|
};
|
|
203
235
|
|
|
204
|
-
const RecentSitesHeader = () => (
|
|
205
|
-
<S.SectionHeader data-testid="recent-sites-header" isRecentSites={true}>
|
|
206
|
-
<S.Title data-testid="recent-sites-title" isActive={isRecentSitesListDisplayed}>
|
|
207
|
-
Recent sites
|
|
208
|
-
</S.Title>
|
|
209
|
-
<S.CollapseButton data-testid="recent-sites-collapse-button" onClick={toggleRecentSites}>
|
|
210
|
-
{isRecentSitesListDisplayed ? (
|
|
211
|
-
<>
|
|
212
|
-
<S.Label data-testid="recent-sites-hide-label">Hide recent sites </S.Label> <Icon name="UpArrow" />
|
|
213
|
-
</>
|
|
214
|
-
) : (
|
|
215
|
-
<>
|
|
216
|
-
<S.Label data-testid="recent-sites-show-label">Show recent sites </S.Label> <Icon name="DownArrow" />
|
|
217
|
-
</>
|
|
218
|
-
)}
|
|
219
|
-
</S.CollapseButton>
|
|
220
|
-
</S.SectionHeader>
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
const RecentSitesList = () => {
|
|
224
|
-
return (
|
|
225
|
-
<S.RecentSites data-testid="recent-sites-list" fullWidth={recentSites.length >= 5}>
|
|
226
|
-
<RecentSitesHeader />
|
|
227
|
-
<S.RecentSitesItemsWrapper data-testid="recent-sites-items-wrapper" isHidden={!isRecentSitesListDisplayed}>
|
|
228
|
-
{recentSites.map((site: ISite, i: number) => (
|
|
229
|
-
<RecentSiteItem key={i} site={site} />
|
|
230
|
-
))}
|
|
231
|
-
</S.RecentSitesItemsWrapper>
|
|
232
|
-
</S.RecentSites>
|
|
233
|
-
);
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const AllSitesHeader = () => (
|
|
237
|
-
<S.SectionHeader data-testid="all-sites-header">
|
|
238
|
-
<S.Title isActive={true} data-testid="all-sites-title">
|
|
239
|
-
All sites
|
|
240
|
-
</S.Title>
|
|
241
|
-
<S.HeaderIconsWrapper data-testid="all-sites-header-icons">
|
|
242
|
-
{displayMode === "grid" ? (
|
|
243
|
-
<S.FilterSelect data-testid="all-sites-grid-filter">
|
|
244
|
-
<S.FilterSelectLabel data-testid="all-sites-grid-filter-label">Sort by:</S.FilterSelectLabel>{" "}
|
|
245
|
-
<GridHeaderFilter sortItems={sortItems} sortedState={currentConfig.sortedListStatus} />{" "}
|
|
246
|
-
</S.FilterSelect>
|
|
247
|
-
) : null}
|
|
248
|
-
<IconAction icon="Grid2" onClick={() => changeDisplayMode("grid")} active={displayMode === "grid"} />
|
|
249
|
-
<IconAction icon="BulletList" onClick={() => changeDisplayMode("list")} active={displayMode === "list"} />
|
|
250
|
-
</S.HeaderIconsWrapper>
|
|
251
|
-
</S.SectionHeader>
|
|
252
|
-
);
|
|
253
|
-
|
|
254
236
|
const {
|
|
255
237
|
resetBulkSelection,
|
|
256
238
|
selectedItems,
|
|
@@ -262,15 +244,16 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
262
244
|
setHoverCheck,
|
|
263
245
|
} = useBulkSelection(sitesIds);
|
|
264
246
|
|
|
265
|
-
const bulkFilter = (bulkSelection: number[]) => filterByStatus(bulkSelection, sites);
|
|
247
|
+
const bulkFilter = useCallback((bulkSelection: number[]) => filterByStatus(bulkSelection, sites), [sites]);
|
|
266
248
|
|
|
267
|
-
const handleAddToBulk = (
|
|
249
|
+
const handleAddToBulk = useCallback(
|
|
250
|
+
(item: ICheck) => addToBulkSelection(item, bulkFilter),
|
|
251
|
+
[addToBulkSelection, bulkFilter],
|
|
252
|
+
);
|
|
268
253
|
|
|
269
254
|
const handleSelectAll = () => selectAllItems(bulkFilter);
|
|
270
255
|
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
const selectItems = () => (checkState.isAllSelected ? unselectAllItems() : handleSelectAll());
|
|
256
|
+
const selectItems = () => (checkState.isAllSelected ? resetBulkSelection() : handleSelectAll());
|
|
274
257
|
|
|
275
258
|
const bulkPublishAction = async (isPublish: boolean) => {
|
|
276
259
|
setIsBulkLoading(true);
|
|
@@ -283,7 +266,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
283
266
|
if (published.length > 0 && !isPublish) {
|
|
284
267
|
await unpublishSitesBulk(published, params);
|
|
285
268
|
}
|
|
286
|
-
|
|
269
|
+
resetBulkSelection();
|
|
287
270
|
setIsBulkLoading(false);
|
|
288
271
|
};
|
|
289
272
|
|
|
@@ -300,7 +283,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
300
283
|
totalItems={totalItems}
|
|
301
284
|
selectItems={selectItems}
|
|
302
285
|
sortItems={sortItems}
|
|
303
|
-
sortedListStatus={
|
|
286
|
+
sortedListStatus={sortedListStatus}
|
|
304
287
|
filterItems={filterItems}
|
|
305
288
|
filterValues={currentConfig.filterValues}
|
|
306
289
|
setHoverCheck={setHoverCheck}
|
|
@@ -309,28 +292,31 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
309
292
|
/>
|
|
310
293
|
);
|
|
311
294
|
|
|
312
|
-
const mappedSites =
|
|
313
|
-
|
|
314
|
-
sites.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<
|
|
332
|
-
|
|
333
|
-
|
|
295
|
+
const mappedSites = useMemo(
|
|
296
|
+
() =>
|
|
297
|
+
sites.length > 0 ? (
|
|
298
|
+
sites.map((site: ISite) => {
|
|
299
|
+
const isItemSelected = isSelected(site.id);
|
|
300
|
+
return displayMode === "grid" ? (
|
|
301
|
+
<GridSiteItem key={site.id} site={site} getParams={getParams} />
|
|
302
|
+
) : (
|
|
303
|
+
<ListSiteItem
|
|
304
|
+
key={site.id}
|
|
305
|
+
site={site}
|
|
306
|
+
isSelected={isItemSelected}
|
|
307
|
+
onCheck={handleAddToBulk}
|
|
308
|
+
getParams={getParams}
|
|
309
|
+
hoverCheck={checkState.hoverCheck}
|
|
310
|
+
/>
|
|
311
|
+
);
|
|
312
|
+
})
|
|
313
|
+
) : (
|
|
314
|
+
<S.EmptyStateWrapper data-testid="empty-state">
|
|
315
|
+
<EmptyState icon="search" message="We couldn't find what you are looking for. Please, try another search." />
|
|
316
|
+
</S.EmptyStateWrapper>
|
|
317
|
+
),
|
|
318
|
+
[sites, displayMode, isSelected, handleAddToBulk, getParams, checkState.hoverCheck],
|
|
319
|
+
);
|
|
334
320
|
|
|
335
321
|
const showPagination = totalItems > itemsPerPage;
|
|
336
322
|
|
|
@@ -344,17 +330,14 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
344
330
|
</S.GridList>
|
|
345
331
|
{showPagination && (
|
|
346
332
|
<S.PaginationWrapper>
|
|
347
|
-
<Pagination totalItems={totalItems} setPage={
|
|
333
|
+
<Pagination totalItems={totalItems} setPage={handlePageChange} itemsPerPage={itemsPerPage} currPage={page} />
|
|
348
334
|
</S.PaginationWrapper>
|
|
349
335
|
)}
|
|
350
336
|
</>
|
|
351
337
|
);
|
|
352
338
|
|
|
353
|
-
const filterLabels = {
|
|
354
|
-
liveStatus: "Live",
|
|
355
|
-
};
|
|
356
|
-
|
|
357
339
|
const handleSearch = (query: string) => {
|
|
340
|
+
scrollToTop();
|
|
358
341
|
setSearchQuery(query);
|
|
359
342
|
setPage(1);
|
|
360
343
|
};
|
|
@@ -376,7 +359,12 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
376
359
|
</TableList>
|
|
377
360
|
);
|
|
378
361
|
|
|
379
|
-
const handleAnimationEnd = () =>
|
|
362
|
+
const handleAnimationEnd = () => {
|
|
363
|
+
setHasAnimation(false);
|
|
364
|
+
if (!currentUser.profileCreated) {
|
|
365
|
+
toggleWelcomeModal();
|
|
366
|
+
}
|
|
367
|
+
};
|
|
380
368
|
|
|
381
369
|
if (isLoading && !hasAnimation) {
|
|
382
370
|
return <Loading />;
|
|
@@ -392,13 +380,24 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
392
380
|
>
|
|
393
381
|
<ErrorToast ref={errorRef} />
|
|
394
382
|
<S.SitesListWrapper className={hasAnimation ? "animate" : ""}>
|
|
395
|
-
{recentSites?.length > 0 ?
|
|
396
|
-
|
|
383
|
+
{recentSites?.length > 0 ? (
|
|
384
|
+
<RecentSitesList
|
|
385
|
+
recentSites={recentSites}
|
|
386
|
+
isRecentSitesListDisplayed={isRecentSitesListDisplayed}
|
|
387
|
+
toggleRecentSites={toggleRecentSites}
|
|
388
|
+
/>
|
|
389
|
+
) : null}
|
|
390
|
+
<AllSitesHeader
|
|
391
|
+
displayMode={displayMode}
|
|
392
|
+
sortItems={sortItems}
|
|
393
|
+
sortedListStatus={sortedListStatus}
|
|
394
|
+
changeDisplayMode={changeDisplayMode}
|
|
395
|
+
/>
|
|
397
396
|
{isSitesLoading && !hasAnimation ? (
|
|
398
397
|
<Loading />
|
|
399
398
|
) : (
|
|
400
399
|
<S.AllSitesListWrapper className={hasAnimation ? "animate" : ""} onAnimationEnd={handleAnimationEnd}>
|
|
401
|
-
{displayMode === "grid" ?
|
|
400
|
+
{displayMode === "grid" ? gridList : listTable}
|
|
402
401
|
</S.AllSitesListWrapper>
|
|
403
402
|
)}
|
|
404
403
|
</S.SitesListWrapper>
|
|
@@ -412,6 +411,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
412
411
|
>
|
|
413
412
|
<SiteModal form={form} setForm={setForm} />
|
|
414
413
|
</Modal>
|
|
414
|
+
<WelcomeModal isOpen={isWelcomeOpen} toggleModal={toggleWelcomeModal} />
|
|
415
415
|
</MainWrapper>
|
|
416
416
|
);
|
|
417
417
|
};
|
|
@@ -426,6 +426,7 @@ interface ISitesProps {
|
|
|
426
426
|
hasAnimation: boolean;
|
|
427
427
|
isLoading: boolean;
|
|
428
428
|
isSitesLoading: boolean;
|
|
429
|
+
currentUser: IUser;
|
|
429
430
|
}
|
|
430
431
|
|
|
431
432
|
const mapStateToProps = (state: IRootState) => ({
|
|
@@ -438,6 +439,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
438
439
|
hasAnimation: state.app.hasAnimation,
|
|
439
440
|
isLoading: state.app.isLoading,
|
|
440
441
|
isSitesLoading: state.sites.isSitesLoading,
|
|
442
|
+
currentUser: state.users.currentUser!,
|
|
441
443
|
});
|
|
442
444
|
|
|
443
445
|
interface IDispatchProps {
|