@griddo/ax 1.62.6 → 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.
Files changed (84) hide show
  1. package/package.json +6 -5
  2. package/src/GlobalStore.tsx +1 -1
  3. package/src/Style/index.tsx +2 -0
  4. package/src/api/pages.tsx +20 -0
  5. package/src/api/utils.tsx +5 -2
  6. package/src/components/Browser/index.tsx +144 -39
  7. package/src/components/Browser/style.tsx +47 -11
  8. package/src/components/ConfigPanel/index.tsx +3 -3
  9. package/src/components/Fields/RichText/index.tsx +2 -2
  10. package/src/components/Fields/UrlField/utils.tsx +10 -1
  11. package/src/components/Icon/components/Desktop.js +9 -4
  12. package/src/components/Icon/components/Phone.js +4 -4
  13. package/src/components/Icon/components/Share.js +12 -0
  14. package/src/components/Icon/components/Tablet.js +4 -4
  15. package/src/components/Icon/svgs/Share.svg +3 -0
  16. package/src/components/MainWrapper/AppBar/index.tsx +19 -7
  17. package/src/components/MainWrapper/AppBar/style.tsx +20 -4
  18. package/src/components/MainWrapper/index.tsx +1 -1
  19. package/src/components/SideModal/index.tsx +1 -1
  20. package/src/components/TableFilters/DateFilter/index.tsx +48 -0
  21. package/src/components/TableFilters/DateFilter/style.tsx +29 -0
  22. package/src/components/TableFilters/index.tsx +2 -0
  23. package/src/components/Tabs/index.tsx +17 -7
  24. package/src/components/Tabs/style.tsx +29 -16
  25. package/src/components/Tooltip/index.tsx +1 -1
  26. package/src/components/Tooltip/style.tsx +2 -0
  27. package/src/components/index.tsx +2 -0
  28. package/src/containers/App/reducer.tsx +3 -1
  29. package/src/containers/Navigation/Defaults/actions.tsx +2 -1
  30. package/src/containers/PageEditor/actions.tsx +65 -10
  31. package/src/containers/Settings/DataPacks/actions.tsx +4 -1
  32. package/src/containers/Sites/actions.tsx +3 -1
  33. package/src/helpers/dates.tsx +3 -4
  34. package/src/helpers/index.tsx +2 -0
  35. package/src/helpers/strings.tsx +38 -7
  36. package/src/hooks/forms.tsx +1 -2
  37. package/src/index.tsx +2 -2
  38. package/src/modules/Content/OptionTable/index.tsx +29 -2
  39. package/src/modules/Content/PageItem/index.tsx +11 -2
  40. package/src/modules/Content/index.tsx +9 -0
  41. package/src/modules/GlobalEditor/Editor/index.tsx +7 -9
  42. package/src/modules/GlobalEditor/{Editor/PageBrowser → PageBrowser}/index.tsx +14 -6
  43. package/src/modules/GlobalEditor/Preview/index.tsx +19 -0
  44. package/src/modules/GlobalEditor/Preview/style.tsx +9 -0
  45. package/src/modules/GlobalEditor/index.tsx +41 -9
  46. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +5 -1
  47. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +9 -7
  48. package/src/modules/PageEditor/Editor/index.tsx +5 -5
  49. package/src/modules/PageEditor/{Editor/PageBrowser → PageBrowser}/index.tsx +11 -4
  50. package/src/modules/PageEditor/Preview/index.tsx +14 -0
  51. package/src/modules/PageEditor/Preview/style.tsx +9 -0
  52. package/src/modules/PageEditor/index.tsx +40 -16
  53. package/src/modules/PublicPreview/index.tsx +92 -0
  54. package/src/modules/PublicPreview/style.tsx +18 -0
  55. package/src/modules/Redirects/BulkHeader/TableHeader/index.tsx +16 -3
  56. package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +9 -3
  57. package/src/modules/Redirects/BulkHeader/index.tsx +7 -1
  58. package/src/modules/Redirects/RedirectItem/index.tsx +4 -0
  59. package/src/modules/Redirects/RedirectItem/style.tsx +19 -3
  60. package/src/modules/Redirects/atoms.tsx +0 -1
  61. package/src/modules/Redirects/hooks.tsx +67 -0
  62. package/src/modules/Redirects/index.tsx +23 -9
  63. package/src/modules/Redirects/utils.tsx +10 -0
  64. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/Field/index.tsx +107 -0
  65. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/Field/style.tsx +54 -0
  66. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/index.tsx +66 -0
  67. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/ConfigPanel/style.tsx +42 -0
  68. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/TemplateBrowser/index.tsx +58 -0
  69. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/index.tsx +41 -0
  70. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/index.tsx +93 -0
  71. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/style.tsx +25 -0
  72. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/index.tsx +48 -0
  73. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/style.tsx +53 -0
  74. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/index.tsx +40 -36
  75. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/style.tsx +4 -5
  76. package/src/modules/Settings/ContentTypes/DataPacks/Config/index.tsx +4 -4
  77. package/src/modules/Settings/ContentTypes/DataPacks/index.tsx +5 -1
  78. package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/atoms.tsx +0 -0
  79. package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/index.tsx +20 -11
  80. package/src/modules/Settings/{Analytics → SeoAnalyticsSettings/Analytics}/style.tsx +6 -0
  81. package/src/modules/Settings/{SeoSettings → SeoAnalyticsSettings}/index.tsx +11 -4
  82. package/src/routes/publicRoutes.tsx +3 -1
  83. package/src/routes/site.tsx +14 -10
  84. package/src/types/index.tsx +9 -0
@@ -0,0 +1,9 @@
1
+ import styled from "styled-components";
2
+
3
+ const BrowserWrapper = styled.div`
4
+ background-color: ${(p) => p.theme.color.uiBackground01};
5
+ height: calc(100% - 44px);
6
+ width: 100%;
7
+ `;
8
+
9
+ export { BrowserWrapper };
@@ -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 [isPreviewMode, setIsPreviewMode] = useState(false);
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
- setIsPreviewMode(true);
83
+ setIsReadOnly(true);
81
84
  !isOpen && toggleModal();
82
85
  } else {
83
- setIsPreviewMode(false);
86
+ setIsReadOnly(false);
84
87
  pageID && sendPagePing(pageID);
85
88
  isOpen && toggleModal();
86
89
  }
@@ -89,6 +92,7 @@ const PageEditor = (props: IProps) => {
89
92
 
90
93
  useEffect(() => {
91
94
  getDefaults();
95
+ resetDirty();
92
96
  // eslint-disable-next-line react-hooks/exhaustive-deps
93
97
  }, [lang]);
94
98
 
@@ -204,9 +208,14 @@ const PageEditor = (props: IProps) => {
204
208
  }
205
209
  };
206
210
 
211
+ const handleNewTranlation = (isNewTranslation: boolean) => {
212
+ setSelectedTab("edit");
213
+ createNewTranslation && createNewTranslation(isNewTranslation);
214
+ };
215
+
207
216
  const languageActions = {
208
217
  setLanguage,
209
- createNewTranslation,
218
+ createNewTranslation: handleNewTranlation,
210
219
  getContent: getPage,
211
220
  };
212
221
 
@@ -246,7 +255,7 @@ const PageEditor = (props: IProps) => {
246
255
  : [];
247
256
 
248
257
  const downArrowMenu = {
249
- displayed: !isPreviewMode,
258
+ displayed: !isReadOnly,
250
259
  button: getPublishButton(props.pageStatus),
251
260
  options: menuOptions,
252
261
  };
@@ -316,7 +325,7 @@ const PageEditor = (props: IProps) => {
316
325
  disabled:
317
326
  (!isDirty && pageID !== null && !isNewTranslation) ||
318
327
  isSaving ||
319
- isPreviewMode ||
328
+ isReadOnly ||
320
329
  (!isTemplateActivated && !isGlobal),
321
330
  action: handleSavePage,
322
331
  };
@@ -392,6 +401,15 @@ const PageEditor = (props: IProps) => {
392
401
 
393
402
  const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
394
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
+
395
413
  return isLoading ? (
396
414
  <Loading />
397
415
  ) : (
@@ -399,6 +417,7 @@ const PageEditor = (props: IProps) => {
399
417
  <RouteLeavingGuard when={isDirty} action={goToPages} text={modalText} />
400
418
  <MainWrapper
401
419
  title={pageName}
420
+ subtitle={structuredData}
402
421
  backLink={backLinkRoute}
403
422
  rightButton={rightButtonProps}
404
423
  downArrowMenu={downArrowMenu}
@@ -414,6 +433,7 @@ const PageEditor = (props: IProps) => {
414
433
  errors={errors}
415
434
  errorActions={{ goToError }}
416
435
  isFromEditor={true}
436
+ tabs={tabsPreview}
417
437
  >
418
438
  {(!isTemplateActivated || hasDeactivatedModules) && !isGlobal && (
419
439
  <S.NotificationWrapper>
@@ -441,15 +461,19 @@ const PageEditor = (props: IProps) => {
441
461
  </S.NotificationWrapper>
442
462
  )}
443
463
  <ErrorToast size="l" />
444
- <S.Content>
445
- <Editor
446
- isTemplateActivated={isTemplateActivated}
447
- isGlobal={isGlobal}
448
- isEditable={isEditable}
449
- pageTitle={pageName}
450
- isPreviewMode={isPreviewMode}
451
- />
452
- </S.Content>
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
+ )}
453
477
  <Modal
454
478
  isOpen={isOpen}
455
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 { totalItems, selectAllItems, isScrolling, filterItems, filterValues, isSiteItem } = props;
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: 270px;
18
+ width: 200px;
19
19
  `;
20
20
 
21
21
  const UrlHeader = styled(Header)`
22
- width: 50%;
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 { TableHeader, CheckHeader, SiteHeader, UrlHeader, ActionsHeader };
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: 270px;
15
+ width: 200px;
16
16
  `;
17
17
 
18
18
  const UrlCell = styled(Cell)`
19
19
  ${(p) => p.theme.textStyle.uiXS};
20
- width: 50%;
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 { CheckCell, SiteCell, ActionsCell, UrlCell, StyledActionMenu, ItemRow, ModalContent };
57
+ export {
58
+ CheckCell,
59
+ SiteCell,
60
+ ActionsCell,
61
+ UrlCell,
62
+ StyledActionMenu,
63
+ ItemRow,
64
+ ModalContent,
65
+ DateCell,
66
+ };
@@ -2,7 +2,6 @@ import React, { useRef } from "react";
2
2
 
3
3
  import { IModal, IRedirect } from "@ax/types";
4
4
  import { Button, Icon, Modal } from "@ax/components";
5
- import { trimText } from "@ax/helpers";
6
5
 
7
6
  import * as S from "./style";
8
7
 
@@ -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 [currentFilterQuery, setCurrentFilterQuery] = useState("");
40
- const [filterValues, setFilterValues] = useState({ sites: "all" });
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
- const siteFilterQuery = currentSiteID ? `&sites=${currentSiteID}` : currentFilterQuery;
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
- let filterQuery = "";
108
- if (filtersSelected !== "all") {
109
- filterQuery = `&${filterPointer}=${filtersSelected}`;
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 }