@griddo/ax 11.14.4 → 11.14.5-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/package.json +2 -2
  2. package/src/api/sites.tsx +2 -2
  3. package/src/components/Fields/ImageField/index.tsx +52 -28
  4. package/src/components/Fields/ImageField/style.tsx +22 -13
  5. package/src/components/Fields/NoteField/index.tsx +1 -3
  6. package/src/components/Fields/NoteField/style.tsx +1 -0
  7. package/src/components/Fields/TextArea/style.tsx +5 -2
  8. package/src/components/Fields/ToggleField/index.tsx +3 -2
  9. package/src/components/FieldsBehavior/index.tsx +27 -3
  10. package/src/components/FieldsBehavior/style.tsx +9 -7
  11. package/src/components/FloatingNote/index.tsx +1 -1
  12. package/src/components/FloatingPanel/style.tsx +4 -1
  13. package/src/components/HeadingsPreviewModal/style.tsx +1 -1
  14. package/src/components/Icon/components/Party.js +16 -0
  15. package/src/components/Icon/svgs/Party.svg +3 -0
  16. package/src/components/Image/index.tsx +2 -1
  17. package/src/components/Image/utils.ts +3 -3
  18. package/src/components/MainWrapper/AppBar/atoms.tsx +118 -34
  19. package/src/components/MainWrapper/AppBar/index.tsx +64 -86
  20. package/src/components/MainWrapper/AppBar/style.tsx +5 -0
  21. package/src/components/MainWrapper/index.tsx +2 -41
  22. package/src/containers/Navigation/Defaults/reducer.tsx +2 -2
  23. package/src/containers/Sites/actions.tsx +2 -3
  24. package/src/modules/Content/index.tsx +26 -8
  25. package/src/modules/Content/style.tsx +5 -0
  26. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/index.tsx +34 -17
  27. package/src/modules/GlobalSettings/Robots/Item/RobotsPanel/style.tsx +37 -5
  28. package/src/modules/GlobalSettings/Robots/index.tsx +4 -3
  29. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +8 -17
  30. package/src/modules/Navigation/Defaults/Item/index.tsx +17 -19
  31. package/src/modules/Navigation/Defaults/index.tsx +5 -8
  32. package/src/modules/Settings/Globals/NavigationModules/index.tsx +1 -1
  33. package/src/modules/Settings/Globals/NavigationModules/style.tsx +1 -2
  34. package/src/modules/Settings/Globals/index.tsx +194 -73
  35. package/src/modules/Settings/Globals/style.tsx +67 -1
  36. package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +2 -3
  37. package/src/modules/Sites/SitesList/GridView/GridSiteItem/index.tsx +13 -5
  38. package/src/modules/Sites/SitesList/GridView/GridSiteItem/style.tsx +16 -8
  39. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +1 -0
  40. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/style.tsx +7 -1
  41. package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +8 -1
  42. package/src/modules/Sites/SitesList/ListView/ListSiteItem/style.tsx +7 -1
  43. package/src/modules/Sites/SitesList/SiteModal/index.tsx +77 -23
  44. package/src/modules/Sites/SitesList/atoms.tsx +4 -4
  45. package/src/modules/Sites/SitesList/index.tsx +9 -47
  46. package/src/modules/Sites/SitesList/style.tsx +8 -4
  47. package/src/modules/Users/UserForm/index.tsx +1 -1
  48. package/src/types/index.tsx +11 -22
@@ -68,12 +68,17 @@ const UrlCell = styled(Cell)`
68
68
  const LiveCell = styled(Cell)`
69
69
  flex: 0 0 100px;
70
70
  align-items: center;
71
- width: 100px;
72
71
  svg {
73
72
  width: ${(p) => p.theme.spacing.m};
74
73
  height: ${(p) => p.theme.spacing.m};
75
74
  }
76
75
  `;
76
+
77
+ const TagCell = styled(Cell)`
78
+ flex: 0 0 110px;
79
+ align-items: center;
80
+ `;
81
+
77
82
  const DateCell = styled(Cell)`
78
83
  flex: 0 0 200px;
79
84
  align-items: center;
@@ -109,4 +114,5 @@ export {
109
114
  DateCell,
110
115
  ActionsCell,
111
116
  ModalContent,
117
+ TagCell,
112
118
  };
@@ -1,36 +1,85 @@
1
- import { useEffect } from "react";
1
+ import { useCallback, useEffect, useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import type { ILanguage, IRootState, ISettingsForm } from "@ax/types";
4
+ import { ErrorToast, FieldsBehavior, Modal } from "@ax/components";
5
5
  import { slugify } from "@ax/helpers";
6
- import { ErrorToast, FieldsBehavior } from "@ax/components";
6
+ import type { ILanguage, IModal, IRootState, ISite } from "@ax/types";
7
7
 
8
8
  import * as S from "./style";
9
9
 
10
+ const INITIAL_FORM_STATE: Partial<ISite> = {
11
+ name: "",
12
+ defaultLanguage: null,
13
+ path: "",
14
+ domain: null,
15
+ hidden: true,
16
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
17
+ };
18
+
19
+ const REQUIRED_MODAL_FIELDS = ["name", "defaultLanguage", "domain", "path"] as const;
20
+
10
21
  const SiteModal = (props: ISiteModalProps): JSX.Element => {
11
- const { languages, form, setForm } = props;
22
+ const { languages, isOpen, toggleModal, saveSettings, setHistoryPush, isSaving } = props;
23
+
24
+ const [form, setForm] = useState(INITIAL_FORM_STATE);
12
25
  const { name, defaultLanguage, path, domain } = form;
13
26
  const globalDefaultLang = languages?.find((lang: ILanguage) => lang.isDefault);
14
27
 
15
- const updateForm = (newValue: Record<string, string | number>) =>
16
- setForm((state: ISettingsForm) => ({ ...state, ...newValue }));
28
+ const updateForm = useCallback(
29
+ (newValue: Record<string, string | number>) => setForm((state: Partial<ISite>) => ({ ...state, ...newValue })),
30
+ [],
31
+ );
17
32
 
18
- const setNameValue = (value: string) => updateForm({ name: value, path: slugify(value) });
19
- const setLangValue = (value: number) => updateForm({ defaultLanguage: value });
20
- const setPathValue = (value: string) => updateForm({ path: value });
21
- const setDomainValue = (value: number) => updateForm({ domain: value });
33
+ const setNameValue = useCallback((value: string) => updateForm({ name: value, path: slugify(value) }), [updateForm]);
34
+ const setLangValue = useCallback((value: number) => updateForm({ defaultLanguage: value }), [updateForm]);
35
+ const setPathValue = useCallback((value: string) => updateForm({ path: value }), [updateForm]);
36
+ const setDomainValue = useCallback((value: number) => updateForm({ domain: value }), [updateForm]);
22
37
 
23
38
  useEffect(() => {
24
- if (globalDefaultLang) {
25
- setForm((state: ISettingsForm) => ({ ...state, defaultLanguage: globalDefaultLang.id }));
39
+ if (isOpen && globalDefaultLang) {
40
+ setLangValue(globalDefaultLang.id);
41
+ } else if (!isOpen) {
42
+ setForm(INITIAL_FORM_STATE);
43
+ }
44
+ }, [isOpen, globalDefaultLang, setLangValue]);
45
+
46
+ const isFieldValid = (value: any): boolean => {
47
+ return typeof value === "string" ? value.trim().length > 0 : value !== null && value !== undefined;
48
+ };
49
+
50
+ const isSubmitDisabled =
51
+ isSaving || !REQUIRED_MODAL_FIELDS.every((field) => isFieldValid(form[field as keyof typeof form]));
52
+
53
+ const saveSiteSettings = useCallback(async () => {
54
+ const result = await saveSettings(form);
55
+ if (result) {
56
+ const contentPath = "/sites/settings/globals";
57
+ setHistoryPush(contentPath, false);
58
+ setForm(INITIAL_FORM_STATE);
26
59
  }
27
- }, [globalDefaultLang, setForm]);
60
+ }, [form, saveSettings, setHistoryPush]);
28
61
 
29
- const slugHelpText =
30
- "The path is for the site on this language. Please, fill with the name of the site. Example: /the-site-url";
62
+ const handleClose = useCallback(() => {
63
+ setForm(INITIAL_FORM_STATE);
64
+ toggleModal();
65
+ }, [toggleModal]);
66
+
67
+ const mainAction = {
68
+ title: isSaving ? "Creating..." : "Create site",
69
+ onClick: saveSiteSettings,
70
+ disabled: isSubmitDisabled,
71
+ };
72
+ const secondaryAction = { title: "Cancel", onClick: handleClose };
31
73
 
32
74
  return (
33
- <>
75
+ <Modal
76
+ isOpen={isOpen}
77
+ hide={handleClose}
78
+ size="M"
79
+ title="New Site"
80
+ mainAction={mainAction}
81
+ secondaryAction={secondaryAction}
82
+ >
34
83
  <ErrorToast size="l" />
35
84
  <S.Form data-testid="site-modal-form">
36
85
  <S.FieldsWrapper>
@@ -71,24 +120,29 @@ const SiteModal = (props: ISiteModalProps): JSX.Element => {
71
120
  mandatory={true}
72
121
  placeholder="/site"
73
122
  onChange={setPathValue}
74
- helptext={slugHelpText}
123
+ helptext="The path is for the site on this language. Please, fill with the name of the site. Example: /the-site-url"
75
124
  />
76
125
  </S.FieldsWrapper>
77
126
  </S.Form>
78
- </>
127
+ </Modal>
79
128
  );
80
129
  };
81
130
 
82
131
  const mapStateToProps = (state: IRootState) => ({
83
132
  languages: state.app.globalLangs,
133
+ isSaving: state.app.isSaving,
84
134
  });
85
135
 
86
- interface IStateProps {
136
+ interface IReduxProps {
87
137
  languages?: ILanguage[];
88
- form: ISettingsForm;
89
- setForm: React.Dispatch<React.SetStateAction<ISettingsForm>>;
138
+ isSaving: boolean;
139
+ }
140
+
141
+ interface IOwnProps extends IModal {
142
+ saveSettings: (form: Partial<ISite>) => Promise<boolean>;
143
+ setHistoryPush: (path: string, isEditor?: boolean) => void;
90
144
  }
91
145
 
92
- type ISiteModalProps = IStateProps;
146
+ type ISiteModalProps = IReduxProps & IOwnProps;
93
147
 
94
- export default connect(mapStateToProps, null)(SiteModal);
148
+ export default connect(mapStateToProps)(SiteModal);
@@ -1,5 +1,5 @@
1
+ import { Image, Tooltip } from "@ax/components";
1
2
  import { trimText } from "@ax/helpers";
2
- import { Tooltip, Image } from "@ax/components";
3
3
 
4
4
  import * as S from "./style";
5
5
 
@@ -15,7 +15,7 @@ const ItemName = (props: IItemNameProps): JSX.Element => {
15
15
  };
16
16
 
17
17
  const ItemThumbnail = (props: IItemThumbnailProps): JSX.Element => {
18
- const { src, width, height, borderRadius } = props;
18
+ const { src, width = 295, height, borderRadius } = props;
19
19
  const thumbnailPlaceholder = "/img/placeholder/thumbnail@1x.png";
20
20
  return src ? (
21
21
  <S.ImageWrapper data-testid="sites-item-thumbnail-wrapper" borderRadius={borderRadius} height={height}>
@@ -38,8 +38,8 @@ interface IItemNameProps {
38
38
  }
39
39
 
40
40
  interface IItemThumbnailProps {
41
- src?: string;
42
- width: number;
41
+ src?: string | null;
42
+ width?: number;
43
43
  height: number;
44
44
  borderRadius?: boolean;
45
45
  }
@@ -7,7 +7,6 @@ import {
7
7
  FilterTagsBar,
8
8
  Loading,
9
9
  MainWrapper,
10
- Modal,
11
10
  Pagination,
12
11
  SearchTagsBar,
13
12
  TableList,
@@ -16,16 +15,7 @@ import { appActions } from "@ax/containers/App";
16
15
  import type { IError } from "@ax/containers/App/reducer";
17
16
  import { sitesActions } from "@ax/containers/Sites";
18
17
  import { useBulkSelection, useModal, usePermission } from "@ax/hooks";
19
- import type {
20
- ICheck,
21
- IGetSitesParams,
22
- IQueryValue,
23
- IRootState,
24
- ISettingsForm,
25
- ISite,
26
- ISiteListConfig,
27
- IUser,
28
- } from "@ax/types";
18
+ import type { ICheck, IGetSitesParams, IQueryValue, IRootState, ISite, ISiteListConfig, IUser } from "@ax/types";
29
19
 
30
20
  import AllSitesHeader from "./AllSitesHeader";
31
21
  import GridSiteItem from "./GridView/GridSiteItem";
@@ -39,13 +29,6 @@ import WelcomeModal from "./WelcomeModal";
39
29
 
40
30
  import * as S from "./style";
41
31
 
42
- const initialState = {
43
- name: "",
44
- defaultLanguage: null,
45
- path: "",
46
- domain: null,
47
- };
48
-
49
32
  const itemsPerPage = 30;
50
33
  const firstPage = 1;
51
34
 
@@ -77,7 +60,6 @@ const SitesList = (props: ISitesListProps) => {
77
60
  const isMount = useIsMount();
78
61
 
79
62
  const [page, setPage] = useState(firstPage);
80
- const [form, setForm] = useState<ISettingsForm>(initialState);
81
63
 
82
64
  const currentConfig = useMemo(() => {
83
65
  const raw = localStorage.getItem("sitesConfig");
@@ -99,6 +81,8 @@ const SitesList = (props: ISitesListProps) => {
99
81
  const [isBulkLoading, setIsBulkLoading] = useState(false);
100
82
  const tableRef = useRef<HTMLDivElement>(null);
101
83
  const errorRef = useRef<HTMLDivElement>(null);
84
+ const { isOpen, toggleModal } = useModal();
85
+ const { isOpen: isWelcomeOpen, toggleModal: toggleWelcomeModal } = useModal();
102
86
 
103
87
  const scrollToTop = useCallback(() => {
104
88
  if (tableRef.current) {
@@ -125,9 +109,6 @@ const SitesList = (props: ISitesListProps) => {
125
109
  currPage: page,
126
110
  };
127
111
 
128
- const { isOpen, toggleModal } = useModal();
129
- const { isOpen: isWelcomeOpen, toggleModal: toggleWelcomeModal } = useModal();
130
-
131
112
  const rightButtonProps = allowedToCreateSite
132
113
  ? {
133
114
  label: "New",
@@ -186,21 +167,6 @@ const SitesList = (props: ISitesListProps) => {
186
167
  }
187
168
  }, [error]);
188
169
 
189
- const saveSiteSettings = async () => {
190
- const result = await saveSettings(form);
191
- if (result) {
192
- const contentPath = "/sites/settings/globals";
193
- setHistoryPush(contentPath, false);
194
- }
195
- };
196
-
197
- const isSubmitDisabled =
198
- Object.values(form).filter((el) => (typeof el === "string" ? el.trim().length : el)).length !==
199
- Object.keys(initialState).length;
200
-
201
- const mainAction = { title: "Create site", onClick: saveSiteSettings, disabled: isSubmitDisabled };
202
- const secondaryAction = { title: "Cancel", onClick: toggleModal };
203
-
204
170
  const toggleRecentSites = () => {
205
171
  const updatedConfig = { ...currentConfig, displayRecentSites: !isRecentSitesListDisplayed };
206
172
  setListConfig(updatedConfig);
@@ -401,16 +367,12 @@ const SitesList = (props: ISitesListProps) => {
401
367
  </S.AllSitesListWrapper>
402
368
  )}
403
369
  </S.SitesListWrapper>
404
- <Modal
370
+ <SiteModal
405
371
  isOpen={isOpen}
406
- hide={toggleModal}
407
- size="M"
408
- title="New Site"
409
- mainAction={mainAction}
410
- secondaryAction={secondaryAction}
411
- >
412
- <SiteModal form={form} setForm={setForm} />
413
- </Modal>
372
+ toggleModal={toggleModal}
373
+ saveSettings={saveSettings}
374
+ setHistoryPush={setHistoryPush}
375
+ />
414
376
  <WelcomeModal isOpen={isWelcomeOpen} toggleModal={toggleWelcomeModal} />
415
377
  </MainWrapper>
416
378
  );
@@ -444,7 +406,7 @@ const mapStateToProps = (state: IRootState) => ({
444
406
 
445
407
  interface IDispatchProps {
446
408
  setHistoryPush(path: string, isEditor?: boolean): void;
447
- saveSettings(form: ISettingsForm): Promise<boolean>;
409
+ saveSettings(form: Partial<ISite>): Promise<boolean>;
448
410
  getSites(params: IGetSitesParams): Promise<void>;
449
411
  publishSitesBulk(ids: number[], params?: IGetSitesParams): Promise<void>;
450
412
  unpublishSitesBulk(ids: number[], params?: IGetSitesParams): Promise<void>;
@@ -51,19 +51,23 @@ const EmptyStateWrapper = styled.div`
51
51
  `;
52
52
 
53
53
  const ImageWrapper = styled.div<{ borderRadius?: boolean; height: number }>`
54
- height: ${(p) => (p.height ? p.height : 199)}px;
54
+ width: 100%;
55
+ overflow: hidden;
55
56
  img {
57
+ max-width: 100%;
58
+ width: 100%;
59
+ display: block;
56
60
  border-radius: ${(p) => (p.borderRadius ? p.theme.spacing.xs : 0)};
57
61
  object-fit: cover;
58
- height: 100%;
62
+ height: ${(p) => (p.height ? p.height : 199)}px;
59
63
  }
60
64
  `;
61
65
 
62
- const Thumbnail = styled.div<{ backgroundUrl: string; height: number; width: number; borderRadius?: boolean }>`
66
+ const Thumbnail = styled.div<{ backgroundUrl: string; height: number; width?: number; borderRadius?: boolean }>`
63
67
  background: url(${(p) => p.backgroundUrl}) no-repeat center;
64
68
  background-size: cover;
65
69
  height: ${(p) => p.height}px;
66
- width: ${(p) => p.width}px;
70
+ width: ${(p) => (p.width ? `${p.width}px` : "100%")};
67
71
  border-radius: ${(p) => (p.borderRadius ? p.theme.spacing.xs : 0)};
68
72
  `;
69
73
 
@@ -48,7 +48,7 @@ const UserForm = (props: IProps) => {
48
48
  const { isDirty } = shouldBeSaved(user, form);
49
49
 
50
50
  const isSameUser = currentUser && currentUser.id === user.id;
51
- const isEditDisabled = currentUser && !currentUser.isSuperAdmin && isSiteView && !isSameUser;
51
+ const isEditDisabled = !!currentUser && !currentUser.isSuperAdmin && isSiteView && !isSameUser;
52
52
 
53
53
  useEffect(() => {
54
54
  if (form.roles.length === 0) {
@@ -156,13 +156,18 @@ export interface ISite {
156
156
  defaultLanguage: number | null;
157
157
  path: string;
158
158
  timezone: string;
159
- favicon: string;
160
- smallAvatar: string;
161
- bigAvatar: string;
162
- thumbnail: string;
159
+ favicon: string | null;
160
+ smallAvatar: string | null;
161
+ bigAvatar: string | null;
162
+ thumbnail: string | null;
163
163
  domain: number | null;
164
164
  lastAccess?: string;
165
- navigationModules: any;
165
+ navigationModules: {
166
+ header: string;
167
+ footer: string;
168
+ } | null;
169
+ hidden: boolean;
170
+ showSitemapInRobots: boolean;
166
171
  }
167
172
 
168
173
  export interface IRecentSite {
@@ -657,23 +662,6 @@ export interface ISiteLanguage {
657
662
  isDefault: boolean;
658
663
  }
659
664
 
660
- export interface ISettingsForm {
661
- name: string;
662
- defaultLanguage: number | null;
663
- path: string;
664
- domain: number | null;
665
- timezone?: string;
666
- theme?: string;
667
- favicon?: IImage | string | null;
668
- smallAvatar?: IImage | string | null;
669
- bigAvatar?: IImage | string | null;
670
- thumbnail?: IImage | string | null;
671
- navigationModules?: {
672
- header: string;
673
- footer: string;
674
- };
675
- }
676
-
677
665
  export interface IDataSource {
678
666
  id: string;
679
667
  title: string;
@@ -910,6 +898,7 @@ export interface IDomainRobot {
910
898
  path: string;
911
899
  fullUrl: string;
912
900
  content: string;
901
+ computedContent: string;
913
902
  }
914
903
 
915
904
  export interface IRedirect {