@griddo/ax 1.69.7 → 1.71.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 (109) hide show
  1. package/config/jest/componentsMock.js +0 -26
  2. package/package.json +4 -3
  3. package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +97 -0
  4. package/src/__tests__/components/EmptyState/EmptyState.test.tsx +78 -0
  5. package/src/__tests__/components/Fields/AnalyticsField/PageAnalytics/PageAnalytics.test.tsx +0 -14
  6. package/src/__tests__/components/Fields/AnalyticsField/StructuredDataAnalytics/StructuredDataAnalytics.test.tsx +0 -15
  7. package/src/__tests__/components/Fields/ArrayFieldGroup/ArrayFieldGroup.test.tsx +6 -15
  8. package/src/__tests__/components/Fields/AsyncCheckGroup/AsyncCheckGroup.test.tsx +1 -13
  9. package/src/__tests__/components/Fields/AsyncSelect/AsyncSelect.test.tsx +1 -19
  10. package/src/__tests__/components/Fields/ColorPicker/ColorPicker.test.tsx +1 -10
  11. package/src/__tests__/components/Fields/ComponentArray/ComponentArray.test.tsx +1 -22
  12. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +4 -24
  13. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +6 -12
  14. package/src/__tests__/components/Fields/ComponentArray/SameComponentArray/SameComponentArray.test.tsx +1 -20
  15. package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +559 -0
  16. package/src/__tests__/components/Fields/HiddenField/HiddenField.test.tsx +1 -7
  17. package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +471 -0
  18. package/src/__tests__/components/Fields/MultiCheckSelect/MultiCheckSelect.test.tsx +1 -15
  19. package/src/__tests__/components/Fields/NoteField/NoteField.test.tsx +1 -6
  20. package/src/__tests__/components/Fields/NumberField/NumberField.test.tsx +1 -14
  21. package/src/__tests__/components/Fields/RadioField/RadioField.test.tsx +1 -11
  22. package/src/__tests__/components/Fields/ReferenceField/ReferenceField.test.tsx +77 -13
  23. package/src/__tests__/components/Fields/RichText/RichText.test.tsx +1 -12
  24. package/src/__tests__/components/Fields/Select/Select.test.tsx +1 -21
  25. package/src/__tests__/components/Fields/SliderField/SliderField.test.tsx +1 -14
  26. package/src/__tests__/components/Fields/TagField/TagField.test.tsx +3 -3
  27. package/src/__tests__/components/Fields/TimeField/HourInput/HourInput.test.tsx +142 -0
  28. package/src/__tests__/components/Fields/TimeField/TimeField.test.tsx +100 -0
  29. package/src/__tests__/components/Fields/ToggleField/ToggleField.test.tsx +1 -9
  30. package/src/__tests__/components/Fields/Tooltip/Tooltip.test.tsx +151 -0
  31. package/src/__tests__/components/Fields/VisualUniqueSelection/ImageSelection/ImageSelection.test.tsx +1 -13
  32. package/src/__tests__/components/Fields/VisualUniqueSelection/ScrollableSelection/ScrollableSelection.test.tsx +3 -17
  33. package/src/__tests__/components/Fields/VisualUniqueSelection/VisualUniqueSelection.test.tsx +2 -28
  34. package/src/__tests__/components/TableList/TableList.test.tsx +119 -0
  35. package/src/__tests__/components/Tabs/Tabs.test.tsx +202 -0
  36. package/src/__tests__/components/Tag/Tag.test.tsx +138 -0
  37. package/src/__tests__/components/Toast/Toast.test.tsx +100 -0
  38. package/src/api/navigation.tsx +1 -1
  39. package/src/components/Browser/index.tsx +1 -1
  40. package/src/components/Button/index.tsx +3 -3
  41. package/src/components/ConfigPanel/NavigationForm/Field/index.tsx +14 -3
  42. package/src/components/ElementsTooltip/index.tsx +10 -9
  43. package/src/components/EmptyState/index.tsx +2 -2
  44. package/src/components/Fields/ArrayFieldGroup/index.tsx +1 -1
  45. package/src/components/Fields/AsyncCheckGroup/index.tsx +1 -1
  46. package/src/components/Fields/AsyncSelect/index.tsx +1 -1
  47. package/src/components/Fields/ComponentContainer/index.tsx +7 -6
  48. package/src/components/Fields/ComponentContainer/style.tsx +2 -2
  49. package/src/components/Fields/HiddenField/index.tsx +1 -1
  50. package/src/components/Fields/ImageField/index.tsx +10 -5
  51. package/src/components/Fields/MultiCheckSelect/index.tsx +3 -3
  52. package/src/components/Fields/NumberField/index.tsx +2 -1
  53. package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +5 -7
  54. package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +2 -2
  55. package/src/components/Fields/ReferenceField/ItemList/index.tsx +1 -1
  56. package/src/components/Fields/RichText/index.tsx +10 -6
  57. package/src/components/Fields/Select/index.tsx +1 -1
  58. package/src/components/Fields/SliderField/index.tsx +1 -1
  59. package/src/components/Fields/TimeField/HourInput/index.tsx +103 -0
  60. package/src/components/Fields/TimeField/HourInput/style.tsx +19 -0
  61. package/src/components/Fields/TimeField/HourInput/utils.tsx +35 -0
  62. package/src/components/Fields/TimeField/index.tsx +57 -0
  63. package/src/components/Fields/TimeField/style.tsx +37 -0
  64. package/src/components/Fields/index.tsx +2 -0
  65. package/src/components/FloatingMenu/index.tsx +1 -1
  66. package/src/components/Gallery/GalleryFilters/Type/index.tsx +50 -0
  67. package/src/components/Gallery/GalleryFilters/Type/style.tsx +39 -0
  68. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +2 -1
  69. package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/style.tsx +3 -3
  70. package/src/components/Gallery/hooks.tsx +10 -4
  71. package/src/components/Gallery/index.tsx +2 -0
  72. package/src/components/Icon/index.tsx +1 -1
  73. package/src/components/Loading/index.tsx +1 -1
  74. package/src/components/Pagination/index.tsx +1 -1
  75. package/src/components/SideModal/SideModalOption/index.tsx +4 -2
  76. package/src/components/SideModal/index.tsx +1 -1
  77. package/src/components/TableList/index.tsx +6 -6
  78. package/src/components/TableList/style.tsx +1 -1
  79. package/src/components/Tabs/index.tsx +19 -7
  80. package/src/components/Tag/index.tsx +6 -6
  81. package/src/components/Toast/index.tsx +4 -4
  82. package/src/components/Tooltip/index.tsx +5 -3
  83. package/src/components/index.tsx +2 -0
  84. package/src/containers/Navigation/Defaults/actions.tsx +10 -5
  85. package/src/containers/Navigation/Defaults/utils.tsx +13 -4
  86. package/src/containers/Sites/actions.tsx +7 -0
  87. package/src/containers/Sites/constants.tsx +1 -0
  88. package/src/containers/Sites/interfaces.tsx +6 -0
  89. package/src/containers/Sites/reducer.tsx +4 -0
  90. package/src/containers/StructuredData/actions.tsx +21 -8
  91. package/src/containers/StructuredData/constants.tsx +2 -0
  92. package/src/containers/StructuredData/interfaces.tsx +7 -1
  93. package/src/containers/StructuredData/reducer.tsx +5 -1
  94. package/src/helpers/fields.tsx +2 -2
  95. package/src/helpers/schemas.tsx +2 -2
  96. package/src/hooks/forms.tsx +2 -1
  97. package/src/modules/App/Routing/NavMenu/index.tsx +9 -1
  98. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +1 -1
  99. package/src/modules/Content/hooks.tsx +19 -12
  100. package/src/modules/Content/index.tsx +23 -14
  101. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -0
  102. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +3 -1
  103. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +16 -18
  104. package/src/modules/Navigation/Defaults/DefaultsEditor/utils.tsx +37 -0
  105. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +3 -2
  106. package/src/modules/StructuredData/Form/index.tsx +22 -17
  107. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +30 -20
  108. package/src/modules/StructuredData/StructuredDataList/index.tsx +24 -14
  109. package/src/types/index.tsx +8 -7
@@ -0,0 +1,37 @@
1
+ import styled from "styled-components";
2
+
3
+ const FieldWrapper = styled.div<{ error?: boolean; disabled?: boolean }>`
4
+ display: flex;
5
+ height: ${(p) => p.theme.spacing.l};
6
+ max-width: ${(p) => `calc(8 * ${p.theme.spacing.l})`};
7
+ min-width: ${(p) => `calc(5 * ${p.theme.spacing.l})`};
8
+ width: 100%;
9
+ border: 1px solid
10
+ ${(p) => (p.error ? p.theme.color.error : p.disabled ? p.theme.color.interactiveDisabled : p.theme.color.uiLine)};
11
+ border-radius: ${(p) => p.theme.radii.s};
12
+ background: ${(p) => p.theme.color.uiBackground02};
13
+ padding: ${(p) => `0 ${p.theme.spacing.s}`};
14
+ align-items: center;
15
+
16
+ &:focus-within {
17
+ border-color: ${(p) => (p.error ? p.theme.color.error : p.theme.color.interactive01)};
18
+ }
19
+ `;
20
+
21
+ const IconWrapper = styled.div`
22
+ width: ${(p) => p.theme.spacing.m};
23
+ height: ${(p) => p.theme.spacing.m};
24
+ margin-left: auto;
25
+ svg {
26
+ path {
27
+ fill: ${(p) => p.theme.color.interactive01};
28
+ }
29
+ }
30
+ `;
31
+
32
+ const SelectWrapper = styled.div`
33
+ padding-top: 4px;
34
+ color: ${(p) => p.theme.color.textMediumEmphasis};
35
+ `;
36
+
37
+ export { FieldWrapper, IconWrapper, SelectWrapper };
@@ -29,6 +29,7 @@ import SliderField from "./SliderField";
29
29
  import TagField from "./TagField";
30
30
  import TextArea from "./TextArea";
31
31
  import TextField from "./TextField";
32
+ import TimeField from "./TimeField";
32
33
  import ToggleField from "./ToggleField";
33
34
  import UniqueCheck from "./UniqueCheck";
34
35
  import UrlField from "./UrlField";
@@ -68,6 +69,7 @@ export {
68
69
  TagField,
69
70
  TextArea,
70
71
  TextField,
72
+ TimeField,
71
73
  ToggleField,
72
74
  UniqueCheck,
73
75
  UrlField,
@@ -64,7 +64,7 @@ const FloatingMenu = (props: IProps) => {
64
64
  onMouseLeave={handleMouseLeave}
65
65
  data-testid="floating-menu"
66
66
  >
67
- <S.ButtonWrapper ref={button}>
67
+ <S.ButtonWrapper ref={button} data-testid="floating-menu-button">
68
68
  <Button />
69
69
  </S.ButtonWrapper>
70
70
  {isOpen && (
@@ -0,0 +1,50 @@
1
+ import React, { useState } from "react";
2
+
3
+ import { FloatingMenu, Icon, ListTitle, ListItem } from "@ax/components";
4
+
5
+ import { areEquals } from "@ax/helpers";
6
+
7
+ import * as S from "./style";
8
+
9
+ const Type = ({ filterItems }: ITypeProps): JSX.Element => {
10
+ const initialState = ["all"];
11
+ const [selectedValue, setSelectedValue] = useState(initialState);
12
+
13
+ const setQuery = (selection: any) => {
14
+ if (!selection.length) {
15
+ selection = initialState;
16
+ }
17
+ setSelectedValue([selection]);
18
+ const pointer = "format";
19
+ filterItems(pointer, selection);
20
+ };
21
+
22
+ const isActive = !areEquals(selectedValue, initialState);
23
+
24
+ const Header = () => (
25
+ <S.Type isActive={isActive}>
26
+ Media type
27
+ <S.IconsWrapper>
28
+ {isActive && <Icon name="Filter" size="16" />}
29
+ <S.InteractiveArrow>
30
+ <Icon name="DownArrow" size="16" />
31
+ </S.InteractiveArrow>
32
+ </S.IconsWrapper>
33
+ </S.Type>
34
+ );
35
+
36
+ return (
37
+ <FloatingMenu Button={Header} position="center" closeOnSelect={true}>
38
+ <ListTitle>Filter by type</ListTitle>
39
+ <ListItem isSelected={selectedValue.includes("all")} onClick={() => setQuery("all")}>All</ListItem>
40
+ <ListItem isSelected={selectedValue.includes("bitmap")} onClick={() => setQuery("bitmap")}>Image</ListItem>
41
+ <ListItem isSelected={selectedValue.includes("vectorial")} onClick={() => setQuery("vectorial")}>Icons</ListItem>
42
+ </FloatingMenu>
43
+ );
44
+ };
45
+
46
+ interface ITypeProps {
47
+ filterItems(pointer: string, filter: string): void;
48
+ }
49
+
50
+ export default Type;
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import styled from "styled-components";
3
+ import { Header } from "@ax/components/TableList/style";
4
+
5
+ const Type = styled((props) => <Header {...props} />)<{ isActive: boolean }>`
6
+ width: 90px;
7
+ white-space: nowrap;
8
+ justify-content: center;
9
+ flex-wrap: nowrap;
10
+ align-items: center;
11
+ cursor: pointer;
12
+ &:hover {
13
+ color: ${(p) => p.theme.color.interactive01};
14
+ }
15
+ `;
16
+
17
+ const IconsWrapper = styled.div`
18
+ display: flex;
19
+ align-items: center;
20
+ flex-direction: row;
21
+ svg {
22
+ margin-left: 4px;
23
+ }
24
+ `;
25
+
26
+ const InteractiveArrow = styled.div`
27
+ display: flex;
28
+ svg {
29
+ path {
30
+ fill: ${(p) => p.theme.color.interactive01};
31
+ }
32
+ }
33
+ `;
34
+
35
+ const ChecksWrapper = styled.div`
36
+ padding: ${(p) => p.theme.spacing.xs} ${(p) => p.theme.spacing.s};
37
+ `;
38
+
39
+ export { Type, IconsWrapper, InteractiveArrow, ChecksWrapper };
@@ -71,7 +71,8 @@ const GalleryDetailPanel = (props: IProps) => {
71
71
 
72
72
  const handleSetAsGlobal = async () => {
73
73
  const saveAsGlobal = !isGlobalTab && addToGlobal.isChecked && imageSelected?.file;
74
- const image = saveAsGlobal && imageSelected && (await uploadImage(imageSelected.file, "global"));
74
+ const image =
75
+ saveAsGlobal && imageSelected && imageSelected.file && (await uploadImage(imageSelected.file, "global"));
75
76
  if (image && image.id) await updateImage(image.id, imageForm);
76
77
  setAddToGlobal({ value: "addToGlobal", isChecked: false });
77
78
  };
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import styled from "styled-components";
2
3
  import { Button } from "@ax/components";
3
4
 
@@ -163,9 +164,8 @@ export const FilesInput = styled.input<{ ref: any }>`
163
164
  display: none;
164
165
  `;
165
166
 
166
- export const FilesButton = styled(Button).attrs((props: any) => ({
167
- ref: props.ref,
168
- }))<{ ref: any }>`
167
+ const _Button: any = React.forwardRef((props: any, ref?: React.Ref<HTMLDivElement>) => <Button {...props} />);
168
+ export const FilesButton = styled(_Button)`
169
169
  margin-top: ${(p) => p.theme.spacing.xs};
170
170
  margin-bottom: ${(p) => p.theme.spacing.xs};
171
171
  `;
@@ -21,13 +21,14 @@ const useSortedListStatus = () => {
21
21
  const useFilterQuery = () => {
22
22
  const initialQueryValues = {
23
23
  orientation: "",
24
- order: ""
24
+ order: "",
25
+ format: ""
25
26
  };
26
27
 
27
28
  const [query, setQuery] = useState(initialQueryValues);
28
29
 
29
30
  const setFilterQuery = (filterValues: any) => {
30
- const { orientation, order } = filterValues;
31
+ const { orientation, order, format } = filterValues;
31
32
  let filterQuery = "";
32
33
 
33
34
  const currentQuery = (pointer: string, values: string) => {
@@ -44,15 +45,20 @@ const useFilterQuery = () => {
44
45
  filterQuery = currentQuery("order", order);
45
46
  }
46
47
 
48
+ if (format) {
49
+ filterQuery = currentQuery("format", format);
50
+ }
51
+
47
52
  return filterQuery;
48
53
  };
49
54
 
50
55
  const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
51
- const { orientation, order } = query;
56
+ const { orientation, order, format } = query;
52
57
  const orderMethod = isAscendent ? "asc" : "desc";
53
58
  const filterValues = {
54
59
  orientation: pointer === "orientation" ? filter : orientation,
55
- order: pointer === "order" ? `${filter}-${orderMethod}` : order
60
+ order: pointer === "order" ? `${filter}-${orderMethod}` : order,
61
+ format: pointer === "format" ? filter : format,
56
62
  };
57
63
 
58
64
  setQuery(filterValues);
@@ -8,6 +8,7 @@ import { Icon, Loader, Tabs, SearchField, EmptyState, ErrorToast, Notification }
8
8
 
9
9
  import Orientation from "./GalleryFilters/Orientation";
10
10
  import SortBy from "./GalleryFilters/SortBy";
11
+ import Type from "./GalleryFilters/Type";
11
12
  import GalleryPanel from "./GalleryPanel";
12
13
  import * as S from "./style";
13
14
  import { useFilterQuery, useSortedListStatus } from "./hooks";
@@ -136,6 +137,7 @@ const Gallery = (props: IProps): JSX.Element => {
136
137
  )}
137
138
  <S.Filters>
138
139
  <Orientation filterItems={filterItems} />
140
+ <Type filterItems={filterItems} />
139
141
  <SortBy sortItems={sortItems} sortedState={sortedListStatus} />
140
142
  </S.Filters>
141
143
  </S.Header>
@@ -22,7 +22,7 @@ const Icon = (props: IProps) => {
22
22
  const Svg = getImage(name);
23
23
 
24
24
  if (Svg) {
25
- return <Svg data-testid="iconComponent" height={size} width={size} viewBox="0 0 24 24" fill={fill} />;
25
+ return <Svg data-testid="icon-component" height={size} width={size} viewBox="0 0 24 24" fill={fill} />;
26
26
  }
27
27
 
28
28
  return null;
@@ -5,7 +5,7 @@ import * as S from "./style";
5
5
 
6
6
  const Loading = (): JSX.Element => {
7
7
  return (
8
- <S.Wrapper>
8
+ <S.Wrapper data-testid="loading-wrapper">
9
9
  <S.LoadingWrapper>
10
10
  <Loader name="circle" />
11
11
  </S.LoadingWrapper>
@@ -36,7 +36,7 @@ const Pagination = (props: IProps) => {
36
36
  const CurrentPage = size === "S" ? currPage : <S.Input type="text" value={currPage} onChange={_handleChange} />;
37
37
 
38
38
  return (
39
- <S.Wrapper>
39
+ <S.Wrapper data-testid="pagination-wrapper">
40
40
  <S.Literal size={size}>
41
41
  Page {CurrentPage} of {lastPage}
42
42
  </S.Literal>
@@ -14,7 +14,9 @@ const SideModalOption = (props: IProps) => {
14
14
 
15
15
  const isNavigationDefault = ["header", "footer"].includes(option.type);
16
16
 
17
- const thumbnailProps = getThumbnailData(option, theme);
17
+ const navigationThumbnail = isNavigationDefault &&
18
+ option.thumbnail && { alt: option.title, src: option.thumbnail.url };
19
+ const thumbnailProps = navigationThumbnail || getThumbnailData(option, theme);
18
20
 
19
21
  const optionParam = option.component || option;
20
22
  const label = isNavigationDefault ? option.title : getDisplayName(optionParam);
@@ -25,7 +27,7 @@ const SideModalOption = (props: IProps) => {
25
27
  };
26
28
 
27
29
  return (
28
- <S.Item onClick={setOption}>
30
+ <S.Item onClick={setOption} data-testid="side-modal-option">
29
31
  <S.Thumbnail {...thumbnailProps} />
30
32
  {label}
31
33
  </S.Item>
@@ -137,7 +137,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
137
137
 
138
138
  return isOpen
139
139
  ? createPortal(
140
- <S.Wrapper ref={node} optionsType={optionsType}>
140
+ <S.Wrapper ref={node} optionsType={optionsType} data-testid="side-modal">
141
141
  <S.Header>
142
142
  <S.Title>{optionsType}</S.Title>
143
143
  {showSearch && optionsType !== "components" && (
@@ -5,7 +5,7 @@ import { Loading, Pagination } from "@ax/components";
5
5
 
6
6
  import * as S from "./style";
7
7
 
8
- const TableList = (props: IPagesProps): JSX.Element => {
8
+ const TableList = (props: ITableListProps): JSX.Element => {
9
9
  const { tableHeader, children, pagination, isLoading, onScroll, hasFixedHeader, tableRef } = props;
10
10
 
11
11
  const { totalItems, setPage, itemsPerPage, currPage } = pagination;
@@ -13,11 +13,11 @@ const TableList = (props: IPagesProps): JSX.Element => {
13
13
  const showPagination = totalItems > itemsPerPage;
14
14
 
15
15
  return (
16
- <S.TableList onScroll={onScroll} ref={tableRef}>
17
- <S.Table hasFixedHeader={hasFixedHeader}>
16
+ <S.TableList onScroll={onScroll} ref={tableRef} data-testid="table-list">
17
+ <S.Table>
18
18
  <>
19
- <S.TableHeader hasFixedHeader={hasFixedHeader}>{tableHeader}</S.TableHeader>
20
- {isLoading ? <Loading /> : <S.TableBody>{children}</S.TableBody>}
19
+ <S.TableHeader hasFixedHeader={hasFixedHeader} data-testid="table-list-header">{tableHeader}</S.TableHeader>
20
+ {isLoading ? <Loading /> : <S.TableBody data-testid="table-body">{children}</S.TableBody>}
21
21
  </>
22
22
  </S.Table>
23
23
  <S.PaginationWrapper>
@@ -33,7 +33,7 @@ const mapStateToProps = (state: IRootState) => ({
33
33
  isLoading: state.app.isLoading,
34
34
  });
35
35
 
36
- interface IPagesProps {
36
+ export interface ITableListProps {
37
37
  tableHeader: JSX.Element | JSX.Element[];
38
38
  children: JSX.Element | JSX.Element[];
39
39
  pagination: {
@@ -6,7 +6,7 @@ const TableList = styled.div`
6
6
  overflow: auto;
7
7
  `;
8
8
 
9
- const Table = styled.div<{hasFixedHeader?: boolean}>`
9
+ const Table = styled.div`
10
10
  width: 100%;
11
11
  min-height: calc(100% - ${(p) => p.theme.spacing.l} - ${(p) => p.theme.spacing.m});
12
12
  padding-bottom: ${(p) => p.theme.spacing.m};
@@ -12,11 +12,17 @@ const Tabs = (props: ITabsProps): JSX.Element => {
12
12
 
13
13
  if (tabs) {
14
14
  return (
15
- <S.TabsRow isInAppBar={isInAppBar} noMargins={noMargins}>
15
+ <S.TabsRow isInAppBar={isInAppBar} noMargins={noMargins} data-testid="tabs-row">
16
16
  {tabs.map((tab: any) => {
17
17
  const handleClick = () => setSelectedTab(tab);
18
18
  return (
19
- <S.TabItem isInAppBar={isInAppBar} key={tab} active={tab === active} onClick={handleClick}>
19
+ <S.TabItem
20
+ isInAppBar={isInAppBar}
21
+ key={tab}
22
+ active={tab === active}
23
+ onClick={handleClick}
24
+ data-testid="tab"
25
+ >
20
26
  {tab}
21
27
  </S.TabItem>
22
28
  );
@@ -27,11 +33,17 @@ const Tabs = (props: ITabsProps): JSX.Element => {
27
33
 
28
34
  if (icons) {
29
35
  return (
30
- <S.TabsRow icons={true} isInAppBar={isInAppBar}>
36
+ <S.TabsRow icons={true} isInAppBar={isInAppBar} data-testid="icons-tabs-row">
31
37
  {icons.map((tab: ITabIcon) => {
32
38
  const handleClick = () => setSelectedTab(tab.name);
33
39
  return (
34
- <S.TabItem key={tab.name} active={tab.name === active} onClick={handleClick} inversed={inversed}>
40
+ <S.TabItem
41
+ key={tab.name}
42
+ active={tab.name === active}
43
+ onClick={handleClick}
44
+ inversed={inversed}
45
+ data-testid="icon-tab"
46
+ >
35
47
  <S.TabIcon>
36
48
  <Tooltip content={tab.text} bottom>
37
49
  <Icon name={tab.name} />
@@ -44,10 +56,10 @@ const Tabs = (props: ITabsProps): JSX.Element => {
44
56
  );
45
57
  }
46
58
 
47
- return <S.TabsRow />;
59
+ return <S.TabsRow data-testid="empty-tabs-row"/>;
48
60
  };
49
61
 
50
- interface ITabsProps {
62
+ export interface ITabsProps {
51
63
  tabs?: any[];
52
64
  icons?: ITabIcon[];
53
65
  isInAppBar?: boolean;
@@ -57,7 +69,7 @@ interface ITabsProps {
57
69
  inversed?: boolean;
58
70
  }
59
71
 
60
- interface ITabIcon {
72
+ export interface ITabIcon {
61
73
  name: string;
62
74
  text: string;
63
75
  }
@@ -13,7 +13,7 @@ const Tag = (props: ITagProps): JSX.Element => {
13
13
  };
14
14
 
15
15
  const deleteIcon = onDeleteAction ? (
16
- <S.IconWrapper onClick={handleClick} data-testid="tagComponent">
16
+ <S.IconWrapper onClick={handleClick} data-testid="delete-icon-wrapper">
17
17
  <Icon name="close" size="16" />
18
18
  </S.IconWrapper>
19
19
  ) : null;
@@ -21,18 +21,18 @@ const Tag = (props: ITagProps): JSX.Element => {
21
21
  switch (type) {
22
22
  case "status":
23
23
  return (
24
- <S.TagStatus>
24
+ <S.TagStatus data-testid="tag-status">
25
25
  <S.Bullet color={color} />
26
26
  {text}
27
27
  </S.TagStatus>
28
28
  );
29
29
  case "square":
30
- return <S.TagSquare color={color}>{text}</S.TagSquare>;
30
+ return <S.TagSquare color={color} data-testid="tag-square">{text}</S.TagSquare>;
31
31
  default:
32
32
  return (
33
- <S.TagFixed color={color}>
33
+ <S.TagFixed color={color} data-testid="tag-fixed">
34
34
  <S.TagText>
35
- <S.Title>{text}</S.Title>
35
+ <S.Title data-testid="tag-fixed-title">{text}</S.Title>
36
36
  {deleteIcon}
37
37
  </S.TagText>
38
38
  </S.TagFixed>
@@ -40,7 +40,7 @@ const Tag = (props: ITagProps): JSX.Element => {
40
40
  }
41
41
  };
42
42
 
43
- interface ITagProps {
43
+ export interface ITagProps {
44
44
  type?: "status" | "fixed" | "interactive" | "square" | undefined;
45
45
  text: string;
46
46
  color?: string;
@@ -5,7 +5,7 @@ import { Button, IconAction } from "@ax/components";
5
5
 
6
6
  import * as S from "./style";
7
7
 
8
- const Toast = (props: IProps) => {
8
+ const Toast = (props: IToastProps) => {
9
9
  const { action, message, setIsVisible } = props;
10
10
  const toast = useRef<any>(null);
11
11
 
@@ -24,8 +24,8 @@ const Toast = (props: IProps) => {
24
24
  }, []);
25
25
 
26
26
  return createPortal(
27
- <S.Wrapper ref={toast}>
28
- <S.Text data-testid="toastMessage">{message}</S.Text>
27
+ <S.Wrapper ref={toast} data-testid="toast-wrapper">
28
+ <S.Text data-testid="toast-message">{message}</S.Text>
29
29
  <S.Buttons>
30
30
  {action &&
31
31
  <Button type="button" buttonStyle="lineInverse" onClick={action}>
@@ -39,7 +39,7 @@ const Toast = (props: IProps) => {
39
39
  );
40
40
  };
41
41
 
42
- interface IProps {
42
+ export interface IToastProps {
43
43
  action?: () => void;
44
44
  message: string;
45
45
  setIsVisible: (visibility: boolean) => void;
@@ -3,7 +3,7 @@ import { useHandleClickOutside } from "@ax/hooks";
3
3
 
4
4
  import * as S from "./style";
5
5
 
6
- const Tooltip = (props: IProps): JSX.Element => {
6
+ const Tooltip = (props: ITooltipProps): JSX.Element => {
7
7
  const { content, children, hideOnClick = true, bottom, left } = props;
8
8
 
9
9
  const initialState: IState = {
@@ -64,6 +64,7 @@ const Tooltip = (props: IProps): JSX.Element => {
64
64
  useEffect(() => {
65
65
  if (active && tipRef.current) {
66
66
  const clientRect = tipRef.current.getBoundingClientRect();
67
+
67
68
  const { left, right } = clientRect;
68
69
  const windowSize = window.innerWidth;
69
70
  if (left < 0) {
@@ -78,9 +79,10 @@ const Tooltip = (props: IProps): JSX.Element => {
78
79
  if (!content) return children;
79
80
 
80
81
  return (
81
- <S.Tooltip data-testid="tooltipComponent" onMouseEnter={showTip} onMouseLeave={hideTip} onMouseDown={handleClick}>
82
+ <S.Tooltip data-testid="tooltip-component" onMouseEnter={showTip} onMouseLeave={hideTip} onMouseDown={handleClick}>
82
83
  <div ref={childrenRef}>{children}</div>
83
84
  <S.Tip
85
+ data-testid="tipComponent"
84
86
  active={active}
85
87
  childrenWidth={childrenWidth}
86
88
  bottom={bottom}
@@ -101,7 +103,7 @@ interface IState {
101
103
  fixOutOfBounds: number;
102
104
  }
103
105
 
104
- interface IProps {
106
+ export interface ITooltipProps {
105
107
  content: string | boolean | undefined;
106
108
  children: any;
107
109
  hideOnClick?: boolean;
@@ -23,6 +23,7 @@ import {
23
23
  Select,
24
24
  TextArea,
25
25
  TextField,
26
+ TimeField,
26
27
  ToggleField,
27
28
  UniqueCheck,
28
29
  UrlField,
@@ -117,6 +118,7 @@ export {
117
118
  Select,
118
119
  TextArea,
119
120
  TextField,
121
+ TimeField,
120
122
  ToggleField,
121
123
  UniqueCheck,
122
124
  UrlField,
@@ -24,7 +24,7 @@ import {
24
24
 
25
25
  import { appActions } from "@ax/containers/App";
26
26
 
27
- import { getStateValues } from "./utils";
27
+ import { getFormData, getStateValues } from "./utils";
28
28
 
29
29
  import {
30
30
  SET_EDITOR_CONTENT,
@@ -221,7 +221,7 @@ function getNavigationByType(type: string): (dispatch: Dispatch, getState: any)
221
221
  };
222
222
  }
223
223
 
224
- function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<boolean> {
224
+ function createNavigation(image: File | null): (dispatch: Dispatch, getState: any) => Promise<boolean> {
225
225
  return async (dispatch, getState) => {
226
226
  try {
227
227
  const {
@@ -237,6 +237,8 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
237
237
  const navigationValues = { ...editorContent, site: currentSiteInfo.id, language: lang.id };
238
238
  const cleanValues = removeEditorIds(navigationValues);
239
239
 
240
+ const form = getFormData(cleanValues, image);
241
+
240
242
  const successAction = async (response: any) => {
241
243
  const updatedContent = { ...editorContent, ...response };
242
244
  generateContent(updatedContent, dispatch, getState);
@@ -248,7 +250,7 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
248
250
  handleError: (response: any) => appActions.handleError(response)(dispatch),
249
251
  };
250
252
 
251
- const callback = async () => navigation.createNavigation(cleanValues);
253
+ const callback = async () => navigation.createNavigation(form);
252
254
 
253
255
  return await handleRequest(callback, responseActions, [appActions.setIsSaving])(dispatch);
254
256
  } catch (e) {
@@ -261,7 +263,8 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
261
263
  function updateNavigation(
262
264
  navID: number,
263
265
  data: any,
264
- fromEditor?: boolean
266
+ fromEditor?: boolean,
267
+ image?: File | null
265
268
  ): (dispatch: Dispatch, getState: any) => Promise<boolean> {
266
269
  return async (dispatch, getState) => {
267
270
  try {
@@ -272,6 +275,8 @@ function updateNavigation(
272
275
 
273
276
  const cleanValues = removeEditorIds(data);
274
277
 
278
+ const form = getFormData(cleanValues, image);
279
+
275
280
  const successAction = async (response: any) => {
276
281
  if (fromEditor) {
277
282
  generateContent(response, dispatch, getState);
@@ -284,7 +289,7 @@ function updateNavigation(
284
289
  handleError: (response: any) => appActions.handleError(response)(dispatch),
285
290
  };
286
291
 
287
- const callback = async () => navigation.updateNavigation(navID, cleanValues);
292
+ const callback = async () => navigation.updateNavigation(navID, form);
288
293
 
289
294
  return await handleRequest(callback, responseActions, [appActions.setIsSaving])(dispatch);
290
295
  } catch (e) {
@@ -1,4 +1,4 @@
1
- export const getStateValues = (getState: any) => {
1
+ const getStateValues = (getState: any) => {
2
2
  const {
3
3
  sites: { currentSiteInfo },
4
4
  navigation: {
@@ -10,9 +10,9 @@ export const getStateValues = (getState: any) => {
10
10
  footer,
11
11
  isNewTranslation,
12
12
  currentDefaultsContent,
13
- selectedContent
13
+ selectedContent,
14
14
  },
15
- app: { isSaving, isLoading }
15
+ app: { isSaving, isLoading },
16
16
  } = getState();
17
17
  const section = editorContent && editorContent[0];
18
18
  const { modules } = !!section && section;
@@ -31,6 +31,15 @@ export const getStateValues = (getState: any) => {
31
31
  isLoading,
32
32
  section,
33
33
  modules,
34
- selectedContent
34
+ selectedContent,
35
35
  };
36
36
  };
37
+
38
+ const getFormData = (values: any, image?: File | null): FormData => {
39
+ const form = new FormData();
40
+ form.append("navigation", JSON.stringify(values));
41
+ image && form.append("file", image);
42
+ return form;
43
+ };
44
+
45
+ export { getStateValues, getFormData };
@@ -10,6 +10,7 @@ import {
10
10
  SET_SAVED_SITE_INFO,
11
11
  DEFAULT_PARAMS,
12
12
  SET_CURRENT_SITE_ERROR_PAGES,
13
+ SET_CONTENT_FILTERS,
13
14
  } from "./constants";
14
15
  import {
15
16
  ISetSitesAction,
@@ -21,6 +22,7 @@ import {
21
22
  ISetCurrentSiteLanguagesAction,
22
23
  ISetSavedSiteInfoAction,
23
24
  ISetCurrentSiteErrorPages,
25
+ ISetContentFilters,
24
26
  } from "./interfaces";
25
27
 
26
28
  import { ISite, IGetSitePagesParams, ISettingsForm, IGetGlobalPagesParams, IPage } from "@ax/types";
@@ -77,6 +79,10 @@ function setCurrentSiteErrorPages(currentSiteErrorPages: number[]): ISetCurrentS
77
79
  return { type: SET_CURRENT_SITE_ERROR_PAGES, payload: { currentSiteErrorPages } };
78
80
  }
79
81
 
82
+ function setContentFilters(contentFilters: Record<string, string> | null): ISetContentFilters {
83
+ return { type: SET_CONTENT_FILTERS, payload: { contentFilters } };
84
+ }
85
+
80
86
  // TODO: hay que controlar que cuando da error la API borrar los sites ya guardados y sacar el error (ver los siguientes FIXME)
81
87
  function getSites(): (dispatch: Dispatch) => Promise<void> {
82
88
  return async (dispatch) => {
@@ -507,4 +513,5 @@ export {
507
513
  removeUsersBulk,
508
514
  setCurrentSiteErrorPages,
509
515
  resetCurrentSiteErrorPages,
516
+ setContentFilters,
510
517
  };