@griddo/ax 1.62.8 → 1.63.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.
- package/package.json +6 -5
- package/src/GlobalStore.tsx +1 -1
- package/src/Style/index.tsx +2 -0
- package/src/api/pages.tsx +20 -0
- package/src/api/utils.tsx +5 -2
- package/src/components/Browser/index.tsx +144 -39
- package/src/components/Browser/style.tsx +47 -11
- package/src/components/ConfigPanel/index.tsx +3 -3
- package/src/components/Fields/RichText/index.tsx +2 -2
- package/src/components/Fields/UrlField/utils.tsx +10 -1
- package/src/components/Icon/components/Desktop.js +9 -4
- package/src/components/Icon/components/Phone.js +4 -4
- package/src/components/Icon/components/Share.js +12 -0
- package/src/components/Icon/components/Tablet.js +4 -4
- package/src/components/Icon/svgs/Share.svg +3 -0
- package/src/components/MainWrapper/AppBar/index.tsx +19 -7
- package/src/components/MainWrapper/AppBar/style.tsx +20 -4
- package/src/components/MainWrapper/index.tsx +1 -1
- package/src/components/SideModal/index.tsx +1 -1
- package/src/components/TableFilters/DateFilter/index.tsx +48 -0
- package/src/components/TableFilters/DateFilter/style.tsx +29 -0
- package/src/components/TableFilters/index.tsx +2 -0
- package/src/components/Tabs/index.tsx +17 -7
- package/src/components/Tabs/style.tsx +29 -16
- package/src/components/Tooltip/index.tsx +1 -1
- package/src/components/Tooltip/style.tsx +2 -0
- package/src/components/index.tsx +2 -0
- package/src/containers/App/reducer.tsx +3 -1
- package/src/containers/PageEditor/actions.tsx +65 -10
- package/src/containers/Settings/DataPacks/actions.tsx +4 -1
- package/src/containers/Sites/actions.tsx +3 -1
- package/src/helpers/dates.tsx +3 -4
- package/src/helpers/index.tsx +2 -0
- package/src/helpers/strings.tsx +38 -7
- package/src/index.tsx +2 -2
- package/src/modules/Content/OptionTable/index.tsx +29 -2
- package/src/modules/Content/PageItem/index.tsx +11 -2
- package/src/modules/Content/index.tsx +9 -0
- package/src/modules/GlobalEditor/Editor/index.tsx +7 -9
- package/src/modules/GlobalEditor/{Editor/PageBrowser → PageBrowser}/index.tsx +14 -6
- package/src/modules/GlobalEditor/Preview/index.tsx +19 -0
- package/src/modules/GlobalEditor/Preview/style.tsx +9 -0
- package/src/modules/GlobalEditor/index.tsx +36 -9
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +5 -1
- package/src/modules/PageEditor/Editor/index.tsx +5 -5
- package/src/modules/PageEditor/{Editor/PageBrowser → PageBrowser}/index.tsx +11 -4
- package/src/modules/PageEditor/Preview/index.tsx +14 -0
- package/src/modules/PageEditor/Preview/style.tsx +9 -0
- package/src/modules/PageEditor/index.tsx +39 -16
- package/src/modules/PublicPreview/index.tsx +92 -0
- package/src/modules/PublicPreview/style.tsx +18 -0
- package/src/modules/Redirects/BulkHeader/TableHeader/index.tsx +16 -3
- package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +9 -3
- package/src/modules/Redirects/BulkHeader/index.tsx +7 -1
- package/src/modules/Redirects/RedirectItem/index.tsx +4 -0
- package/src/modules/Redirects/RedirectItem/style.tsx +19 -3
- package/src/modules/Redirects/atoms.tsx +0 -1
- package/src/modules/Redirects/hooks.tsx +67 -0
- package/src/modules/Redirects/index.tsx +23 -9
- package/src/modules/Redirects/utils.tsx +10 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/Field/index.tsx +107 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/Field/style.tsx +54 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/index.tsx +66 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/style.tsx +42 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/TemplateBrowser/index.tsx +58 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/index.tsx +41 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/index.tsx +93 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/style.tsx +25 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/index.tsx +48 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/style.tsx +53 -0
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/index.tsx +40 -36
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/style.tsx +4 -5
- package/src/modules/Settings/ContentTypes/DataPacks/Config/index.tsx +4 -4
- package/src/modules/Settings/ContentTypes/DataPacks/index.tsx +5 -1
- package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/atoms.tsx +0 -0
- package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/index.tsx +20 -11
- package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/style.tsx +6 -0
- package/src/modules/Settings/{SeoSettings → SeoAnalyticsSettings}/index.tsx +11 -4
- package/src/routes/publicRoutes.tsx +3 -1
- package/src/routes/site.tsx +14 -10
- package/src/types/index.tsx +9 -0
|
@@ -9,10 +9,11 @@ import { appActions } from "@ax/containers/App";
|
|
|
9
9
|
import { navigationActions } from "@ax/containers/Navigation";
|
|
10
10
|
import { pageStatus } from "@ax/containers/PageEditor/interfaces";
|
|
11
11
|
import { RouteLeavingGuard } from "@ax/guards";
|
|
12
|
-
import { useIsDirty, useModal } from "@ax/hooks";
|
|
12
|
+
import { useIsDirty, useModal, useToast } from "@ax/hooks";
|
|
13
13
|
import { isModuleDisabled } from "@ax/helpers";
|
|
14
14
|
import { dataPacksActions } from "@ax/containers/Settings/DataPacks";
|
|
15
15
|
import Editor from "./Editor";
|
|
16
|
+
import Preview from "./Preview";
|
|
16
17
|
|
|
17
18
|
import * as S from "./style";
|
|
18
19
|
|
|
@@ -44,7 +45,8 @@ const PageEditor = (props: IProps) => {
|
|
|
44
45
|
isNewTranslation,
|
|
45
46
|
} = props;
|
|
46
47
|
|
|
47
|
-
const [
|
|
48
|
+
const [isReadOnly, setIsReadOnly] = useState(false);
|
|
49
|
+
const [selectedTab, setSelectedTab] = useState("edit");
|
|
48
50
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent.editorContent, isNewTranslation);
|
|
49
51
|
const { isOpen, toggleModal } = useModal();
|
|
50
52
|
const { isOpen: isUnpublishOpen, toggleModal: toggleUnpublishModal } = useModal();
|
|
@@ -55,6 +57,7 @@ const PageEditor = (props: IProps) => {
|
|
|
55
57
|
const isDraft = props.pageStatus === pageStatus.MODIFIED;
|
|
56
58
|
const hasDraft = editorContent.editorContent && editorContent.editorContent.haveDraftPage;
|
|
57
59
|
const isLivePageChanged = editorContent.editorContent && editorContent.editorContent.liveChanged;
|
|
60
|
+
const structuredData = editorContent.editorContent ? editorContent.editorContent.structuredData : "";
|
|
58
61
|
|
|
59
62
|
useEffect(() => {
|
|
60
63
|
const { pageID, getPage, setTab, sendPagePing } = props;
|
|
@@ -77,10 +80,10 @@ const PageEditor = (props: IProps) => {
|
|
|
77
80
|
useEffect(() => {
|
|
78
81
|
const { pageID, sendPagePing, currentUserID } = props;
|
|
79
82
|
if (userEditing && userEditing.id !== currentUserID) {
|
|
80
|
-
|
|
83
|
+
setIsReadOnly(true);
|
|
81
84
|
!isOpen && toggleModal();
|
|
82
85
|
} else {
|
|
83
|
-
|
|
86
|
+
setIsReadOnly(false);
|
|
84
87
|
pageID && sendPagePing(pageID);
|
|
85
88
|
isOpen && toggleModal();
|
|
86
89
|
}
|
|
@@ -205,9 +208,14 @@ const PageEditor = (props: IProps) => {
|
|
|
205
208
|
}
|
|
206
209
|
};
|
|
207
210
|
|
|
211
|
+
const handleNewTranlation = (isNewTranslation: boolean) => {
|
|
212
|
+
setSelectedTab("edit");
|
|
213
|
+
createNewTranslation && createNewTranslation(isNewTranslation);
|
|
214
|
+
};
|
|
215
|
+
|
|
208
216
|
const languageActions = {
|
|
209
217
|
setLanguage,
|
|
210
|
-
createNewTranslation,
|
|
218
|
+
createNewTranslation: handleNewTranlation,
|
|
211
219
|
getContent: getPage,
|
|
212
220
|
};
|
|
213
221
|
|
|
@@ -247,7 +255,7 @@ const PageEditor = (props: IProps) => {
|
|
|
247
255
|
: [];
|
|
248
256
|
|
|
249
257
|
const downArrowMenu = {
|
|
250
|
-
displayed: !
|
|
258
|
+
displayed: !isReadOnly,
|
|
251
259
|
button: getPublishButton(props.pageStatus),
|
|
252
260
|
options: menuOptions,
|
|
253
261
|
};
|
|
@@ -317,7 +325,7 @@ const PageEditor = (props: IProps) => {
|
|
|
317
325
|
disabled:
|
|
318
326
|
(!isDirty && pageID !== null && !isNewTranslation) ||
|
|
319
327
|
isSaving ||
|
|
320
|
-
|
|
328
|
+
isReadOnly ||
|
|
321
329
|
(!isTemplateActivated && !isGlobal),
|
|
322
330
|
action: handleSavePage,
|
|
323
331
|
};
|
|
@@ -393,6 +401,15 @@ const PageEditor = (props: IProps) => {
|
|
|
393
401
|
|
|
394
402
|
const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
|
|
395
403
|
|
|
404
|
+
const tabsPreview = {
|
|
405
|
+
icons: [
|
|
406
|
+
{ name: "edit", text: "Edit mode" },
|
|
407
|
+
{ name: "view", text: "Preview mode" },
|
|
408
|
+
],
|
|
409
|
+
selectedTab,
|
|
410
|
+
action: (tab: string) => setSelectedTab(tab),
|
|
411
|
+
};
|
|
412
|
+
|
|
396
413
|
return isLoading ? (
|
|
397
414
|
<Loading />
|
|
398
415
|
) : (
|
|
@@ -400,6 +417,7 @@ const PageEditor = (props: IProps) => {
|
|
|
400
417
|
<RouteLeavingGuard when={isDirty} action={goToPages} text={modalText} />
|
|
401
418
|
<MainWrapper
|
|
402
419
|
title={pageName}
|
|
420
|
+
subtitle={structuredData}
|
|
403
421
|
backLink={backLinkRoute}
|
|
404
422
|
rightButton={rightButtonProps}
|
|
405
423
|
downArrowMenu={downArrowMenu}
|
|
@@ -415,6 +433,7 @@ const PageEditor = (props: IProps) => {
|
|
|
415
433
|
errors={errors}
|
|
416
434
|
errorActions={{ goToError }}
|
|
417
435
|
isFromEditor={true}
|
|
436
|
+
tabs={tabsPreview}
|
|
418
437
|
>
|
|
419
438
|
{(!isTemplateActivated || hasDeactivatedModules) && !isGlobal && (
|
|
420
439
|
<S.NotificationWrapper>
|
|
@@ -442,15 +461,19 @@ const PageEditor = (props: IProps) => {
|
|
|
442
461
|
</S.NotificationWrapper>
|
|
443
462
|
)}
|
|
444
463
|
<ErrorToast size="l" />
|
|
445
|
-
|
|
446
|
-
<
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
464
|
+
{selectedTab === "edit" ? (
|
|
465
|
+
<S.Content>
|
|
466
|
+
<Editor
|
|
467
|
+
isTemplateActivated={isTemplateActivated}
|
|
468
|
+
isGlobal={isGlobal}
|
|
469
|
+
isEditable={isEditable}
|
|
470
|
+
pageTitle={pageName}
|
|
471
|
+
isReadOnly={isReadOnly}
|
|
472
|
+
/>
|
|
473
|
+
</S.Content>
|
|
474
|
+
) : (
|
|
475
|
+
<Preview />
|
|
476
|
+
)}
|
|
454
477
|
<Modal
|
|
455
478
|
isOpen={isOpen}
|
|
456
479
|
hide={toggleModal}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { useParams } from "react-router-dom";
|
|
3
|
+
|
|
4
|
+
import * as components from "components";
|
|
5
|
+
import { providers, translations, cloudinaryDefaults, themes, griddoDamDefaults } from "components";
|
|
6
|
+
import { Preview } from "@griddo/core";
|
|
7
|
+
import { pages } from "@ax/api";
|
|
8
|
+
import { isReqOk } from "@ax/helpers";
|
|
9
|
+
import { Loading } from "@ax/components";
|
|
10
|
+
|
|
11
|
+
import * as S from "./style";
|
|
12
|
+
|
|
13
|
+
const PublicPreview = () => {
|
|
14
|
+
const { id: pageID, entity } = useParams<{ id: string; entity: string }>();
|
|
15
|
+
const [state, setState] = useState<any>(null);
|
|
16
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let isMounted = true;
|
|
20
|
+
document.body.classList.add("preview");
|
|
21
|
+
|
|
22
|
+
const getPage = async () => {
|
|
23
|
+
if (!isMounted) return;
|
|
24
|
+
|
|
25
|
+
setIsLoading(true);
|
|
26
|
+
const response = await pages.getPublicPage(parseInt(pageID), entity);
|
|
27
|
+
if (isReqOk(response.status)) {
|
|
28
|
+
setState(response.data);
|
|
29
|
+
} else {
|
|
30
|
+
console.log("Error en getPublicPage");
|
|
31
|
+
}
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
getPage();
|
|
36
|
+
|
|
37
|
+
return function cleanup() {
|
|
38
|
+
isMounted = false;
|
|
39
|
+
document.body.classList.remove("preview");
|
|
40
|
+
};
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
const API_URL = process.env.REACT_APP_API_ENDPOINT;
|
|
45
|
+
const PUBLIC_API_URL = process.env.REACT_APP_PUBLIC_API_ENDPOINT;
|
|
46
|
+
const { SiteProvider, AnimationProvider } = providers;
|
|
47
|
+
|
|
48
|
+
const defaultTheme = themes.find((theme: any) => theme.default);
|
|
49
|
+
const globalTheme = defaultTheme ? defaultTheme.value : themes[0].value;
|
|
50
|
+
const theme = state && state.site ? state.siteInfo.theme : globalTheme;
|
|
51
|
+
const socials = state && state.site ? state.siteInfo.socials : [];
|
|
52
|
+
const langs = state && state.site ? state.siteInfo.siteLanguages : [];
|
|
53
|
+
|
|
54
|
+
if (isLoading) return <Loading />;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<SiteProvider
|
|
58
|
+
cloudinaryCloudName={state && state.cloudinaryName}
|
|
59
|
+
damDomain={state && state.damDomain}
|
|
60
|
+
theme={theme}
|
|
61
|
+
socials={socials}
|
|
62
|
+
siteLangs={langs}
|
|
63
|
+
translations={translations}
|
|
64
|
+
selectEditorID={0}
|
|
65
|
+
cloudinaryDefaults={cloudinaryDefaults}
|
|
66
|
+
griddoDamDefaults={griddoDamDefaults}
|
|
67
|
+
renderer="editor"
|
|
68
|
+
apiUrl={API_URL}
|
|
69
|
+
publicApiUrl={PUBLIC_API_URL}
|
|
70
|
+
siteId={state && state.site}
|
|
71
|
+
>
|
|
72
|
+
<AnimationProvider showOnScroll={{ active: false }}>
|
|
73
|
+
<S.Wrapper ref={(ref: any) => ((window as any).browserRef = ref)}>
|
|
74
|
+
{state && (
|
|
75
|
+
<Preview
|
|
76
|
+
isPage={true}
|
|
77
|
+
apiUrl={API_URL}
|
|
78
|
+
library={components}
|
|
79
|
+
content={state}
|
|
80
|
+
header={state && state.headerContent}
|
|
81
|
+
footer={state && state.footerContent}
|
|
82
|
+
languageId={state && state.language}
|
|
83
|
+
pageLanguages={state && state.pageLanguages}
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
</S.Wrapper>
|
|
87
|
+
</AnimationProvider>
|
|
88
|
+
</SiteProvider>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default PublicPreview;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
overflow: auto;
|
|
5
|
+
scroll-behavior: smooth;
|
|
6
|
+
height: 100%;
|
|
7
|
+
position: relative;
|
|
8
|
+
|
|
9
|
+
.headroom {
|
|
10
|
+
position: relative !important;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body.preview:not(&) {
|
|
14
|
+
min-width: 0 !important;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
export { Wrapper };
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { CheckField, SiteFilter, TableCounter } from "@ax/components";
|
|
3
|
+
import { CheckField, SiteFilter, TableCounter, DateFilter } from "@ax/components";
|
|
4
4
|
import * as S from "./style";
|
|
5
5
|
|
|
6
|
-
const TableHeader = (props: IProps) => {
|
|
7
|
-
const {
|
|
6
|
+
const TableHeader = (props: IProps): JSX.Element => {
|
|
7
|
+
const {
|
|
8
|
+
totalItems,
|
|
9
|
+
selectAllItems,
|
|
10
|
+
isScrolling,
|
|
11
|
+
filterItems,
|
|
12
|
+
filterValues,
|
|
13
|
+
isSiteItem,
|
|
14
|
+
sortItems,
|
|
15
|
+
sortedListStatus,
|
|
16
|
+
} = props;
|
|
17
|
+
|
|
8
18
|
return (
|
|
9
19
|
<S.TableHeader isScrolling={isScrolling}>
|
|
10
20
|
<S.CheckHeader>
|
|
@@ -25,6 +35,7 @@ const TableHeader = (props: IProps) => {
|
|
|
25
35
|
)}
|
|
26
36
|
<S.UrlHeader>Old URL</S.UrlHeader>
|
|
27
37
|
<S.UrlHeader>New URL</S.UrlHeader>
|
|
38
|
+
<DateFilter sortItems={sortItems} sortedState={sortedListStatus} />
|
|
28
39
|
<S.ActionsHeader>
|
|
29
40
|
<TableCounter totalItems={totalItems} />
|
|
30
41
|
</S.ActionsHeader>
|
|
@@ -39,6 +50,8 @@ interface IProps {
|
|
|
39
50
|
filterItems: (filterPointer: string, filtersSelected: string) => void;
|
|
40
51
|
filterValues: any;
|
|
41
52
|
isSiteItem: boolean;
|
|
53
|
+
sortItems: (orderPointer: string, isAscending: boolean) => void;
|
|
54
|
+
sortedListStatus: { isAscending: boolean; sortedByDate: boolean };
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
export default TableHeader;
|
|
@@ -15,11 +15,11 @@ const CheckHeader = styled(Header)`
|
|
|
15
15
|
`;
|
|
16
16
|
|
|
17
17
|
const SiteHeader = styled(Header)`
|
|
18
|
-
width:
|
|
18
|
+
width: 200px;
|
|
19
19
|
`;
|
|
20
20
|
|
|
21
21
|
const UrlHeader = styled(Header)`
|
|
22
|
-
|
|
22
|
+
flex: 1;
|
|
23
23
|
`;
|
|
24
24
|
|
|
25
25
|
const ActionsHeader = styled(Header)`
|
|
@@ -28,4 +28,10 @@ const ActionsHeader = styled(Header)`
|
|
|
28
28
|
justify-content: flex-end;
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
|
-
export {
|
|
31
|
+
export {
|
|
32
|
+
TableHeader,
|
|
33
|
+
CheckHeader,
|
|
34
|
+
SiteHeader,
|
|
35
|
+
UrlHeader,
|
|
36
|
+
ActionsHeader,
|
|
37
|
+
};
|
|
@@ -14,6 +14,8 @@ const BulkHeader = (props: IProps): JSX.Element => {
|
|
|
14
14
|
filterItems,
|
|
15
15
|
filterValues,
|
|
16
16
|
isSiteItem,
|
|
17
|
+
sortItems,
|
|
18
|
+
sortedListStatus,
|
|
17
19
|
} = props;
|
|
18
20
|
|
|
19
21
|
const bulkActions = [
|
|
@@ -39,7 +41,9 @@ const BulkHeader = (props: IProps): JSX.Element => {
|
|
|
39
41
|
filterItems={filterItems}
|
|
40
42
|
filterValues={filterValues}
|
|
41
43
|
isSiteItem={isSiteItem}
|
|
42
|
-
|
|
44
|
+
sortItems={sortItems}
|
|
45
|
+
sortedListStatus={sortedListStatus}
|
|
46
|
+
/>
|
|
43
47
|
);
|
|
44
48
|
};
|
|
45
49
|
|
|
@@ -54,6 +58,8 @@ interface IProps {
|
|
|
54
58
|
filterItems: (filterPointer: string, filtersSelected: string) => void;
|
|
55
59
|
filterValues: any;
|
|
56
60
|
isSiteItem: boolean;
|
|
61
|
+
sortItems: (orderPointer: string, isAscending: boolean) => void;
|
|
62
|
+
sortedListStatus: { isAscending: boolean; sortedByDate: boolean };
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
export default BulkHeader;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
+
import { format } from "date-fns";
|
|
3
4
|
|
|
4
5
|
import { useModal } from "@ax/hooks";
|
|
5
6
|
import { ICheck, IRedirect } from "@ax/types";
|
|
@@ -84,6 +85,9 @@ const RedirectItem = (props: IRedirectItemProps): JSX.Element => {
|
|
|
84
85
|
<S.UrlCell role="cell" onClick={handleClick}>
|
|
85
86
|
{redirect.to?.url.replace(regex, "")}
|
|
86
87
|
</S.UrlCell>
|
|
88
|
+
<S.DateCell role="cell" onClick={handleClick}>
|
|
89
|
+
{redirect.date && format(new Date(redirect.date), "dd MMM yyyy")}
|
|
90
|
+
</S.DateCell>
|
|
87
91
|
<S.ActionsCell role="cell">
|
|
88
92
|
<S.StyledActionMenu icon="more" options={menuOptions} tooltip="Actions" />
|
|
89
93
|
</S.ActionsCell>
|
|
@@ -12,12 +12,19 @@ const CheckCell = styled(Cell)`
|
|
|
12
12
|
`;
|
|
13
13
|
|
|
14
14
|
const SiteCell = styled(Cell)`
|
|
15
|
-
width:
|
|
15
|
+
width: 200px;
|
|
16
16
|
`;
|
|
17
17
|
|
|
18
18
|
const UrlCell = styled(Cell)`
|
|
19
19
|
${(p) => p.theme.textStyle.uiXS};
|
|
20
|
-
|
|
20
|
+
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
21
|
+
flex: 1;
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
const DateCell = styled(Cell)`
|
|
25
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
26
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
27
|
+
width: 100px;
|
|
21
28
|
`;
|
|
22
29
|
|
|
23
30
|
const ActionsCell = styled(Cell)`
|
|
@@ -47,4 +54,13 @@ const ModalContent = styled.div`
|
|
|
47
54
|
}
|
|
48
55
|
`;
|
|
49
56
|
|
|
50
|
-
export {
|
|
57
|
+
export {
|
|
58
|
+
CheckCell,
|
|
59
|
+
SiteCell,
|
|
60
|
+
ActionsCell,
|
|
61
|
+
UrlCell,
|
|
62
|
+
StyledActionMenu,
|
|
63
|
+
ItemRow,
|
|
64
|
+
ModalContent,
|
|
65
|
+
DateCell,
|
|
66
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
const useSortedListStatus = () => {
|
|
4
|
+
const sortedInitialState: { isAscending: boolean; sortedByDate: boolean; } = {
|
|
5
|
+
isAscending: false,
|
|
6
|
+
sortedByDate: false,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const [sortedListStatus, setSortedListStatus] = useState(sortedInitialState);
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
sortedListStatus,
|
|
13
|
+
setSortedListStatus,
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const useFilterQuery = (currentSiteID: number | null) => {
|
|
18
|
+
const initialQueryValues = {
|
|
19
|
+
sites: currentSiteID || "all",
|
|
20
|
+
order: "",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const [query, setQuery] = useState(initialQueryValues);
|
|
24
|
+
|
|
25
|
+
const setFilterQuery = (filterValues: any) => {
|
|
26
|
+
const { sites, order } = filterValues;
|
|
27
|
+
let filterQuery = "";
|
|
28
|
+
|
|
29
|
+
const currentQuery = (pointer: string, values: string) => {
|
|
30
|
+
return filterQuery.concat(`&${pointer}=${values}`);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (sites) {
|
|
34
|
+
filterQuery = currentQuery("sites", sites);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (order) {
|
|
38
|
+
filterQuery = currentQuery("order", order);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return filterQuery;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
|
|
45
|
+
const { sites, order } = query;
|
|
46
|
+
const orderMethod = isAscendent ? "asc" : "desc";
|
|
47
|
+
const filterValues = {
|
|
48
|
+
sites: pointer === "sites" ? filter : sites,
|
|
49
|
+
order: pointer === "order" ? `${filter}-${orderMethod}` : order,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
setQuery(filterValues);
|
|
53
|
+
|
|
54
|
+
return filterValues;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const resetFilterQuery = () => setQuery(initialQueryValues);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
setFiltersSelection,
|
|
61
|
+
setFilterQuery,
|
|
62
|
+
resetFilterQuery,
|
|
63
|
+
filterValues: query,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export { useSortedListStatus, useFilterQuery };
|
|
@@ -6,10 +6,13 @@ import { appActions } from "@ax/containers/App";
|
|
|
6
6
|
import { redirectsActions } from "@ax/containers/Redirects";
|
|
7
7
|
import { MainWrapper, ErrorToast, Nav, TableList, EmptyState, Toast } from "@ax/components";
|
|
8
8
|
import { useBulkSelection, useModal, useToast } from "@ax/hooks";
|
|
9
|
+
|
|
9
10
|
import BulkHeader from "./BulkHeader";
|
|
10
11
|
import RedirectItem from "./RedirectItem";
|
|
11
12
|
import RedirectPanel from "./RedirectPanel";
|
|
12
13
|
import { DeleteModal, ImportCheckModal, ImportModal, OverwriteModal } from "./atoms";
|
|
14
|
+
import { getSortedListStatus } from "./utils";
|
|
15
|
+
import { useSortedListStatus, useFilterQuery } from "./hooks";
|
|
13
16
|
|
|
14
17
|
import * as S from "./style";
|
|
15
18
|
|
|
@@ -30,14 +33,16 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
30
33
|
} = props;
|
|
31
34
|
|
|
32
35
|
const itemsPerPage = 50;
|
|
36
|
+
const firstPage = 1;
|
|
33
37
|
const [page, setPage] = useState(1);
|
|
34
38
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
35
39
|
const [isOpenedSecond, setIsOpenedSecond] = useState(false);
|
|
36
40
|
const { isOpen, toggleModal } = useModal();
|
|
37
41
|
const { isOpen: isOpenDelete, toggleModal: toggleModalDelete } = useModal();
|
|
38
42
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
39
|
-
const
|
|
40
|
-
const
|
|
43
|
+
const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
|
|
44
|
+
const { setFiltersSelection, setFilterQuery, filterValues } = useFilterQuery(currentSiteID);
|
|
45
|
+
const [currentFilterQuery, setCurrentFilterQuery] = useState(`&sites=${currentSiteID}`);
|
|
41
46
|
const { isVisible, toggleToast, setIsVisible } = useToast();
|
|
42
47
|
const { isVisible: isImportVisible, toggleToast: toggleImportToast, setIsVisible: setIsImportVisible } = useToast();
|
|
43
48
|
const { isOpen: isOpenOverwrite, toggleModal: toggleOverwriteModal } = useModal();
|
|
@@ -71,8 +76,7 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
71
76
|
|
|
72
77
|
useEffect(() => {
|
|
73
78
|
const params = getParams();
|
|
74
|
-
|
|
75
|
-
getRedirects(params, siteFilterQuery);
|
|
79
|
+
getRedirects(params, currentFilterQuery);
|
|
76
80
|
if (tableRef.current) {
|
|
77
81
|
tableRef.current.scrollTo(0, 0);
|
|
78
82
|
}
|
|
@@ -103,12 +107,20 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
103
107
|
|
|
104
108
|
const handleSelectAll = () => selectAllItems();
|
|
105
109
|
|
|
110
|
+
const sortItems = async (orderPointer: string, isAscending: boolean) => {
|
|
111
|
+
setPage(firstPage);
|
|
112
|
+
const sortedState = getSortedListStatus(orderPointer, isAscending);
|
|
113
|
+
setSortedListStatus(sortedState);
|
|
114
|
+
|
|
115
|
+
const filtersSelection = setFiltersSelection("order", orderPointer, isAscending);
|
|
116
|
+
const filterQuery = setFilterQuery(filtersSelection);
|
|
117
|
+
setCurrentFilterQuery(filterQuery);
|
|
118
|
+
};
|
|
119
|
+
|
|
106
120
|
const filterItems = async (filterPointer: string, filtersSelected: string) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
setFilterValues({ sites: filtersSelected });
|
|
121
|
+
setPage(firstPage);
|
|
122
|
+
const filtersSelection = setFiltersSelection(filterPointer, filtersSelected);
|
|
123
|
+
const filterQuery = setFilterQuery(filtersSelection);
|
|
112
124
|
setCurrentFilterQuery(filterQuery);
|
|
113
125
|
};
|
|
114
126
|
|
|
@@ -124,6 +136,8 @@ const Redirects = (props: IProps): JSX.Element => {
|
|
|
124
136
|
filterItems={filterItems}
|
|
125
137
|
filterValues={filterValues}
|
|
126
138
|
isSiteItem={!!currentSiteID}
|
|
139
|
+
sortItems={sortItems}
|
|
140
|
+
sortedListStatus={sortedListStatus}
|
|
127
141
|
/>
|
|
128
142
|
);
|
|
129
143
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const getSortedListStatus = (orderPointer: string, isAscending: boolean): { isAscending: boolean, sortedByDate: boolean } => {
|
|
2
|
+
const sortedListStatus = {
|
|
3
|
+
isAscending,
|
|
4
|
+
sortedByDate: orderPointer === "date",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
return sortedListStatus;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { getSortedListStatus }
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { useModal } from "@ax/hooks";
|
|
4
|
+
import { SideModal, ActionMenu } from "@ax/components";
|
|
5
|
+
|
|
6
|
+
import * as S from "./style";
|
|
7
|
+
|
|
8
|
+
const pageEditorID = 0;
|
|
9
|
+
|
|
10
|
+
const Field = (props: IField): JSX.Element => {
|
|
11
|
+
const {
|
|
12
|
+
type,
|
|
13
|
+
template,
|
|
14
|
+
defaults,
|
|
15
|
+
updateEditorContent,
|
|
16
|
+
content,
|
|
17
|
+
updateDataPackFormValue,
|
|
18
|
+
dataPackConfigFormData,
|
|
19
|
+
theme,
|
|
20
|
+
} = props;
|
|
21
|
+
const { isOpen, toggleModal } = useModal();
|
|
22
|
+
const options = defaults.filter((component: any) =>
|
|
23
|
+
component.type === type && content[component.type]?.id !== component.id && !component.setAsDefault
|
|
24
|
+
);
|
|
25
|
+
const optionsType = `${type}s`;
|
|
26
|
+
|
|
27
|
+
const actionMenuOptions = [
|
|
28
|
+
{
|
|
29
|
+
label: "replace",
|
|
30
|
+
icon: "change",
|
|
31
|
+
action: toggleModal,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const actionMenuIcon = "more";
|
|
36
|
+
|
|
37
|
+
const handleReplace = (option: any) => {
|
|
38
|
+
const configFormData = {
|
|
39
|
+
...dataPackConfigFormData,
|
|
40
|
+
templates: {
|
|
41
|
+
...dataPackConfigFormData.templates,
|
|
42
|
+
[template]: {
|
|
43
|
+
...(!!dataPackConfigFormData.templates && dataPackConfigFormData.templates[template]),
|
|
44
|
+
...(type === "header" && { defaultHeader: option.id }),
|
|
45
|
+
...(type === "footer" && { defaultFooter: option.id }),
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
updateDataPackFormValue(configFormData);
|
|
50
|
+
updateEditorContent(pageEditorID, type, option.id);
|
|
51
|
+
toggleModal();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const isDefaultNavigation = () => {
|
|
55
|
+
const defaultType = type === "header" ? "defaultHeader" : "defaultFooter";
|
|
56
|
+
const templateNavigation = dataPackConfigFormData.templates && dataPackConfigFormData.templates[template]
|
|
57
|
+
const templateDefaultNavigation = templateNavigation && templateNavigation[defaultType];
|
|
58
|
+
if (!templateDefaultNavigation) return true;
|
|
59
|
+
const siteDefaultNavigation = defaults.find((navigation: any) => navigation.id === templateDefaultNavigation);
|
|
60
|
+
return !!siteDefaultNavigation?.isDefault;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const setDefault = {
|
|
64
|
+
title: `Put the default ${type}`,
|
|
65
|
+
action: () => handleReplace({ id: null }),
|
|
66
|
+
checked: isDefaultNavigation(),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const hasOptions: boolean | undefined = options?.length > 0 || !isDefaultNavigation();
|
|
70
|
+
|
|
71
|
+
if (!content[type]) return <></>;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
<S.Component isArray disabled>
|
|
76
|
+
<S.Label>{content[type].title}</S.Label>
|
|
77
|
+
<S.HiddenButtonsWrapper>
|
|
78
|
+
{hasOptions && <ActionMenu options={actionMenuOptions} icon={actionMenuIcon} />}
|
|
79
|
+
</S.HiddenButtonsWrapper>
|
|
80
|
+
</S.Component>
|
|
81
|
+
{hasOptions && (
|
|
82
|
+
<SideModal
|
|
83
|
+
optionsType={optionsType}
|
|
84
|
+
whiteList={options}
|
|
85
|
+
handleClick={handleReplace}
|
|
86
|
+
toggleModal={toggleModal}
|
|
87
|
+
isOpen={isOpen}
|
|
88
|
+
setDefault={setDefault}
|
|
89
|
+
theme={theme}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
</>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface IField {
|
|
97
|
+
type: string;
|
|
98
|
+
template: string;
|
|
99
|
+
defaults: any;
|
|
100
|
+
content: any,
|
|
101
|
+
dataPackConfigFormData: any;
|
|
102
|
+
theme: string;
|
|
103
|
+
updateEditorContent: (selectedEditorID: number, key: string, value: any) => void;
|
|
104
|
+
updateDataPackFormValue: (value: any) => void;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { Field }
|