@griddo/ax 1.55.14 → 1.56.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/package.json +2 -2
  2. package/src/GlobalStore.tsx +3 -0
  3. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +6 -0
  4. package/src/components/Fields/ArrayFieldGroup/ArrayFieldInline/index.tsx +16 -12
  5. package/src/components/Fields/ArrayFieldGroup/ArrayFieldItem/index.tsx +17 -15
  6. package/src/components/Fields/ConditionalField/index.tsx +1 -3
  7. package/src/components/Fields/FileField/index.tsx +1 -1
  8. package/src/components/Fields/Wysiwyg/config.tsx +0 -1
  9. package/src/components/Fields/Wysiwyg/index.tsx +16 -5
  10. package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +110 -99
  11. package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/index.tsx +75 -55
  12. package/src/components/Gallery/GalleryPanel/index.tsx +14 -8
  13. package/src/components/Gallery/index.tsx +113 -151
  14. package/src/components/Gallery/style.tsx +40 -10
  15. package/src/components/MainWrapper/AppBar/index.tsx +1 -0
  16. package/src/components/Toast/index.tsx +15 -9
  17. package/src/components/Toast/style.tsx +2 -2
  18. package/src/containers/Gallery/actions.tsx +171 -0
  19. package/src/containers/Gallery/constants.tsx +18 -0
  20. package/src/containers/Gallery/index.tsx +7 -0
  21. package/src/containers/Gallery/interfaces.tsx +41 -0
  22. package/src/containers/Gallery/reducer.tsx +78 -0
  23. package/src/containers/PageEditor/actions.tsx +15 -5
  24. package/src/containers/StructuredData/actions.tsx +4 -21
  25. package/src/forms/fields.tsx +19 -6
  26. package/src/guards/error/index.tsx +3 -1
  27. package/src/modules/Content/HeaderMenus/Live/index.tsx +6 -5
  28. package/src/modules/Sites/SitesList/index.tsx +1 -1
  29. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +2 -4
  30. package/src/modules/StructuredData/Form/index.tsx +10 -6
  31. package/src/modules/StructuredData/StructuredDataList/HeaderMenus/Live/index.tsx +1 -1
  32. package/src/types/index.tsx +20 -0
  33. package/src/components/Gallery/store.tsx +0 -186
@@ -1,43 +1,46 @@
1
- import React, { memo, useReducer, useRef } from "react";
2
-
3
- import { IImage } from "@ax/types";
4
- import {
5
- reducer,
6
- initialState,
7
- setDropDepth,
8
- setInDropZone,
9
- setIsUploading,
10
- setUploadSuccess,
11
- setUploadError,
12
- uploadImage,
13
- } from "../../store";
1
+ import React, { memo, useRef, useState } from "react";
2
+ import { connect } from "react-redux";
3
+
4
+ import { galleryActions } from "@ax/containers/Gallery";
5
+ import { IGetSiteImages, IImage, IRootState } from "@ax/types";
14
6
  import { Icon, DragAndDrop } from "@ax/components";
15
7
 
16
8
  import * as S from "./style";
17
9
 
18
10
  const GalleryDragAndDrop = (props: IProps) => {
19
- const { isImageSelected, validFormats, addImage, site, allowUpload } = props;
20
-
11
+ const { isImageSelected,
12
+ validFormats,
13
+ site,
14
+ allowUpload,
15
+ refreshImages,
16
+ uploadError,
17
+ isUploading,
18
+ isSuccess,
19
+ isError,
20
+ errorMsg,
21
+ uploadImage,
22
+ selectImage,
23
+ } = props;
21
24
  const validExtensions = validFormats.map((format) => `.${format}`).join(",");
22
25
 
23
- const filesInputRef = useRef<any>(null);
24
- const filesButtonRef = useRef<any>(null);
25
-
26
- const [state, dispatch] = useReducer(reducer, initialState);
26
+ const filesInputRef = useRef<HTMLInputElement>(null);
27
+ const filesButtonRef = useRef<HTMLButtonElement>(null);
28
+ const [inDropZone, setInDropZone] = useState(false);
29
+ const [dropDepth, setDropDepth] = useState(0);
27
30
 
28
31
  const handleDragEnter = () => {
29
- dispatch(setDropDepth(state.dropDepth + 1));
32
+ setDropDepth((depth) => depth + 1);
30
33
  };
31
34
 
32
35
  const handleDragLeave = () => {
33
- dispatch(setDropDepth(state.dropDepth - 1));
34
- if (state.dropDepth > 1) return;
35
- dispatch(setInDropZone(false));
36
+ setDropDepth((depth) => depth - 1);
37
+ if (dropDepth > 1) return;
38
+ setInDropZone(false);
36
39
  };
37
40
 
38
41
  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
39
42
  e.dataTransfer.dropEffect = "copy";
40
- dispatch(setInDropZone(true));
43
+ setInDropZone(true);
41
44
  };
42
45
 
43
46
  const checkType = (type: string) => {
@@ -51,7 +54,7 @@ const GalleryDragAndDrop = (props: IProps) => {
51
54
  const files = Array.from(e.dataTransfer.files);
52
55
  e.dataTransfer.clearData();
53
56
  await handleUploadFile(files);
54
- dispatch(setDropDepth(0));
57
+ setDropDepth(0);
55
58
  };
56
59
 
57
60
  const handleFilesUpload = (e: any) => {
@@ -61,23 +64,15 @@ const GalleryDragAndDrop = (props: IProps) => {
61
64
 
62
65
  const handleUploadFile = async (files: Array<any>) => {
63
66
  if (files[0]) {
64
- dispatch(setIsUploading());
65
-
66
67
  if (!checkType(files[0].type)) {
67
- dispatch(setUploadError("Invalid format"));
68
+ uploadError("Invalid format");
68
69
  } else {
69
70
  try {
70
- const value = await uploadImage(files[0], site);
71
- if (value) {
72
- dispatch(setUploadSuccess());
73
- value.file = files[0];
74
- addImage(value);
75
- dispatch(setInDropZone(false));
76
- } else {
77
- dispatch(setUploadError("Error uploading image"));
78
- }
71
+ const newImage = await uploadImage(files[0], site);
72
+ setInDropZone(false);
73
+ await refreshImages();
74
+ selectImage(newImage);
79
75
  } catch (error) {
80
- dispatch(setUploadError("Error uploading image"));
81
76
  console.log(error);
82
77
  }
83
78
  }
@@ -85,16 +80,14 @@ const GalleryDragAndDrop = (props: IProps) => {
85
80
  };
86
81
 
87
82
  const handleTryAgain = () => {
88
- dispatch(setInDropZone(false));
83
+ setInDropZone(false);
89
84
  };
90
85
 
91
86
  const handleFileClick = () => {
92
- if (filesInputRef) {
93
- filesInputRef.current.click();
94
- }
87
+ filesInputRef && filesInputRef.current && filesInputRef.current.click();
95
88
  };
96
89
 
97
- const errorWrapper = state.errorMsg ? <S.ErrorMsg>{state.errorMsg}</S.ErrorMsg> : null;
90
+ const errorWrapper = errorMsg ? <S.ErrorMsg>{errorMsg}</S.ErrorMsg> : null;
98
91
 
99
92
  const renderDragAndDrop = () => (
100
93
  <DragAndDrop
@@ -135,7 +128,7 @@ const GalleryDragAndDrop = (props: IProps) => {
135
128
  <S.DragIcon>
136
129
  <Icon name="image" size="36" />
137
130
  </S.DragIcon>
138
- <S.DragTitle>Select and image to see details</S.DragTitle>
131
+ <S.DragTitle>Select an image to see details</S.DragTitle>
139
132
  </S.StatusWrapper>
140
133
 
141
134
  );
@@ -143,18 +136,18 @@ const GalleryDragAndDrop = (props: IProps) => {
143
136
  return (
144
137
  <S.Wrapper hidden={isImageSelected}>
145
138
  <S.DragAndDropWrapper
146
- inDropZone={state.inDropZone}
147
- uploading={state.isUploading}
148
- success={state.isSuccess}
149
- error={state.isError}
139
+ inDropZone={inDropZone}
140
+ uploading={isUploading}
141
+ success={isSuccess}
142
+ error={isError}
150
143
  >
151
144
  {allowUpload ? renderDragAndDrop() : renderPlaceholder()}
152
145
  </S.DragAndDropWrapper>
153
146
  <S.UploadingWrapper
154
- inDropZone={state.inDropZone}
155
- uploading={state.isUploading}
156
- success={state.isSuccess}
157
- error={state.isError}
147
+ inDropZone={inDropZone}
148
+ uploading={isUploading}
149
+ success={isSuccess}
150
+ error={isError}
158
151
  >
159
152
  <S.StatusWrapper>
160
153
  <S.UploadingStatus>
@@ -185,12 +178,39 @@ const GalleryDragAndDrop = (props: IProps) => {
185
178
  );
186
179
  };
187
180
 
188
- interface IProps {
181
+ interface IGalleryDragAndDropProps {
189
182
  isImageSelected: boolean;
190
183
  validFormats: string[];
191
- addImage: (image: IImage) => void;
192
184
  site: number | string;
193
185
  allowUpload: boolean;
186
+ refreshImages: () => Promise<void>;
187
+ isUploading: boolean,
188
+ isSuccess: boolean,
189
+ isError: boolean,
190
+ errorMsg: string;
194
191
  }
195
192
 
196
- export default memo(GalleryDragAndDrop);
193
+ const mapStateToProps = (state: IRootState) => ({
194
+ isUploading: state.gallery.isUploading,
195
+ isSuccess: state.gallery.isSuccess,
196
+ isError: state.gallery.isError,
197
+ errorMsg: state.gallery.errorMsg,
198
+ });
199
+
200
+ interface IDispatchProps {
201
+ getSiteImages(params: IGetSiteImages): Promise<void>;
202
+ selectImage(item: IImage): void;
203
+ uploadError: (error: string) => Promise<void>;
204
+ uploadImage: (imageFile: File, site: number | string) => Promise<IImage>;
205
+ }
206
+
207
+ const mapDispatchToProps = {
208
+ getSiteImages: galleryActions.getSiteImages,
209
+ selectImage: galleryActions.selectImage,
210
+ uploadError: galleryActions.uploadError,
211
+ uploadImage: galleryActions.uploadImage,
212
+ };
213
+
214
+ type IProps = IGalleryDragAndDropProps & IDispatchProps;
215
+
216
+ export default connect(mapStateToProps, mapDispatchToProps)(memo(GalleryDragAndDrop));
@@ -1,24 +1,31 @@
1
1
  import React, { memo } from "react";
2
+
2
3
  import { IImage } from "@ax/types";
4
+
3
5
  import GalleryDragAndDrop from "./GalleryDragAndDrop";
4
6
  import DetailPanel from "./DetailPanel";
5
-
6
7
  import * as S from "./style";
7
8
 
8
9
  const GalleryPanel = (props: IGalleryPanelProps) => {
9
- const { isImageSelected, imageSelected, updateItems, validFormats, setImage, addImage, isGlobalTab, site, selectedTab } = props;
10
+ const { isImageSelected, imageSelected, validFormats, setImage, isGlobalTab, site, selectedTab, refreshImages } =
11
+ props;
10
12
  const allowUpload = !isGlobalTab || !selectedTab;
11
13
 
12
14
  return (
13
15
  <S.GalleryPanel>
14
- <GalleryDragAndDrop isImageSelected={isImageSelected} validFormats={validFormats} addImage={addImage} site={site} allowUpload={allowUpload} />
16
+ <GalleryDragAndDrop
17
+ isImageSelected={isImageSelected}
18
+ validFormats={validFormats}
19
+ site={site}
20
+ allowUpload={allowUpload}
21
+ refreshImages={refreshImages}
22
+ />
15
23
  <DetailPanel
16
24
  imageSelected={imageSelected}
17
25
  isImageSelected={isImageSelected}
18
26
  setImage={setImage}
19
- updateImage={updateItems}
20
- deleteImage={updateItems}
21
27
  isGlobalTab={isGlobalTab}
28
+ refreshImages={refreshImages}
22
29
  />
23
30
  </S.GalleryPanel>
24
31
  );
@@ -28,12 +35,11 @@ interface IGalleryPanelProps {
28
35
  isImageSelected: boolean;
29
36
  imageSelected: IImage | null;
30
37
  validFormats: string[];
31
- updateItems: () => void;
32
- setImage: () => void;
33
- addImage: (image: IImage) => void;
38
+ setImage: (imageData: any) => void;
34
39
  isGlobalTab: boolean;
35
40
  site: number | string;
36
41
  selectedTab: string;
42
+ refreshImages: () => Promise<void>;
37
43
  }
38
44
 
39
45
  export default memo(GalleryPanel);
@@ -1,36 +1,31 @@
1
1
  import React, { useEffect, useState, memo, useRef } from "react";
2
+ import { connect } from "react-redux";
2
3
 
3
- import { getSiteImages, ITEMS_PER_PAGE } from "./store";
4
- import { IImage, ISite } from "@ax/types";
5
- import { Icon, Loader, Tabs, SearchField, EmptyState } from "@ax/components";
4
+ import { galleryActions } from "@ax/containers/Gallery";
5
+ import { IData, IIsLoading } from "@ax/containers/Gallery/reducer";
6
+ import { IGetSiteImages, IImage, IRootState, ISite } from "@ax/types";
7
+ import { Icon, Loader, Tabs, SearchField, EmptyState, ErrorToast, Notification } from "@ax/components";
6
8
 
7
- import Orientation from "./GalleryFilters/Orientation"
8
- import SortBy from "./GalleryFilters/SortBy"
9
+ import Orientation from "./GalleryFilters/Orientation";
10
+ import SortBy from "./GalleryFilters/SortBy";
9
11
  import GalleryPanel from "./GalleryPanel";
10
12
  import * as S from "./style";
11
13
  import { useFilterQuery, useSortedListStatus } from "./hooks";
12
- import { getSortedListStatus } from "./utils"
14
+ import { getSortedListStatus } from "./utils";
13
15
 
14
- const Gallery = (props: IGalleryProps): JSX.Element => {
15
- const { getImageSelected, toggleModal, site } = props;
16
+ const itemsPerPage = 50;
17
+ const firstPage = 1;
18
+
19
+ const Gallery = (props: IProps): JSX.Element => {
20
+ const { data, isLoading, getSiteImages, selectImage, getImageSelected, toggleModal, site } = props;
16
21
 
17
22
  const tabs = [];
18
23
  if (site) tabs.unshift(...["Local", "Global"]);
19
24
  const [selectedTab, setSelectedTab] = useState(tabs[0]);
20
25
  const isLocalTab = selectedTab === "Local";
26
+ const isGlobalTab = selectedTab === "Global";
21
27
  const galleryScope = isLocalTab ? site.id : "global";
22
28
 
23
- const initialState: IGalleryState = {
24
- items: [],
25
- isImageSelected: false,
26
- imageSelected: null,
27
- page: 1,
28
- isFinished: false,
29
- };
30
-
31
- const [data, setData] = useState(initialState);
32
- const [isLoading, setIsLoading] = useState({ init: false, more: false });
33
-
34
29
  const validFormats = ["jpeg", "jpg", "png", "svg"];
35
30
 
36
31
  const galleryRef = useRef<HTMLDivElement>(null);
@@ -40,125 +35,67 @@ const Gallery = (props: IGalleryProps): JSX.Element => {
40
35
  const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
41
36
  const [searchQuery, setSearchQuery] = useState<string>("");
42
37
  const isSearching = searchQuery.length > 0;
38
+ const pageRef = useRef(firstPage);
43
39
 
44
40
  const getParams = () => ({
45
41
  site: galleryScope,
46
- page: data.page,
47
- items: ITEMS_PER_PAGE,
42
+ page: data?.page,
43
+ items: itemsPerPage,
48
44
  query: currentFilterQuery,
49
- search: searchQuery
45
+ search: searchQuery,
50
46
  });
51
47
 
48
+ pageRef.current = getParams().page;
49
+
52
50
  useEffect(() => {
53
51
  const params = getParams();
54
- const getAndSetImages = () => {
55
- getSiteImages({ ...params, page: 1 })
56
- .then((result) => {
57
- setData({ items: result, page: 1, isImageSelected: false, imageSelected: null, isFinished: false });
58
- setIsLoading({ init: false, more: false });
59
- })
60
- .catch((error) => console.log(error));
61
- };
62
- setIsLoading({ init: true, more: false });
63
- getAndSetImages();
64
- // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ getSiteImages({ ...params, page: firstPage });
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
65
54
  }, [galleryScope]);
66
55
 
67
56
  useEffect(() => {
68
57
  const handleScroll = () => {
69
- if (
70
- galleryRef.current && galleryRef.current.getBoundingClientRect().top + galleryRef.current.scrollTop + 60 <=
71
- galleryRef.current.getBoundingClientRect().height
72
- ) {
73
- return;
74
- }
58
+ const loadMore =
59
+ galleryRef.current &&
60
+ galleryRef.current.scrollHeight -
61
+ (galleryRef.current.scrollTop + galleryRef.current.getBoundingClientRect().height) <
62
+ 60 &&
63
+ galleryRef.current.scrollTop > 0;
64
+ if (!loadMore) return;
75
65
  if (!data.isFinished) {
76
- setIsLoading({ init: false, more: true });
66
+ const params = getParams();
67
+ getSiteImages({ ...params, page: pageRef.current + 1, more: true });
77
68
  }
78
69
  };
79
70
  window.addEventListener("scroll", handleScroll, true);
80
71
  return () => window.removeEventListener("scroll", handleScroll, true);
81
- }, [data.isFinished]);
82
-
83
- const getAndSetMoreImages = async () => {
84
- const params = getParams();
85
- const result = await getSiteImages({ ...params, page: params.page + 1 });
86
- try {
87
- setData({
88
- ...data,
89
- items: [...data.items, ...result],
90
- page: data.page + 1,
91
- isFinished: result.length < ITEMS_PER_PAGE,
92
- });
93
- setIsLoading({ init: false, more: false });
94
- } catch (error) {
95
- console.log(error);
96
- }
97
- };
72
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
+ }, [data?.isFinished]);
98
74
 
99
- const getAndSetImages = async () => {
75
+ const refreshImages = async (page = firstPage) => {
100
76
  const params = getParams();
101
- const result = await getSiteImages(params);
102
- try {
103
- setData({ ...data, items: result, isFinished: result.length < ITEMS_PER_PAGE });
104
- setIsLoading({ init: false, more: false });
105
- galleryRef && galleryRef.current && galleryRef.current.scrollTo(0, 0);
106
- } catch (error) {
107
- console.log(error);
108
- }
77
+ const more = page !== firstPage;
78
+ await getSiteImages({ ...params, page, more });
79
+ if (page < params.page) refreshImages(page + 1);
109
80
  };
110
81
 
111
82
  useEffect(() => {
112
- if (!isLoading.more) return;
113
- setTimeout(() => {
114
- getAndSetMoreImages();
115
- }, 2000);
116
- // eslint-disable-next-line react-hooks/exhaustive-deps
117
- }, [isLoading.more]);
118
-
119
- useEffect(() => {
120
- setIsLoading({ init: true, more: false });
121
- getAndSetImages();
83
+ const params = getParams();
84
+ getSiteImages({ ...params, page: firstPage });
122
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
123
86
  }, [currentFilterQuery, searchQuery]);
124
87
 
125
- const _handleClick = (item: IImage) => (e: React.MouseEvent<HTMLDivElement>) => {
126
- if (data.imageSelected === item) {
127
- setData({ ...data, imageSelected: null, isImageSelected: false });
128
- } else {
129
- setData({ ...data, imageSelected: item, isImageSelected: true });
130
- }
88
+ const handleClick = (item: IImage) => (e: React.MouseEvent<HTMLDivElement>) => {
89
+ selectImage(item);
131
90
  };
132
91
 
133
- const setImage = () => {
134
- getImageSelected(data.imageSelected);
92
+ const setImage = (imageData: any) => {
93
+ const updatedImage = { ...data.imageSelected, ...imageData };
94
+ getImageSelected(updatedImage);
135
95
  toggleModal();
136
96
  };
137
97
 
138
- const updateItems = () => {
139
- setIsLoading({ init: true, more: false });
140
- const params = getParams();
141
- getSiteImages({ ...params, page: 1 })
142
- .then((result) => {
143
- setData({ items: result, isImageSelected: false, imageSelected: null, page: 1, isFinished: false });
144
- setIsLoading({ init: false, more: false });
145
- })
146
- .catch((error) => console.log(error));
147
- };
148
-
149
- const addImage = (item: IImage) => {
150
- setIsLoading({ init: true, more: false });
151
- const params = getParams();
152
- getSiteImages({ ...params, page: 1 })
153
- .then((result) => {
154
- setData({ items: result, isImageSelected: true, imageSelected: item, page: 1, isFinished: false });
155
- setIsLoading({ init: false, more: false });
156
- })
157
- .catch((error) => console.log(error));
158
- };
159
-
160
98
  const sortItems = async (orderPointer: string, isAscending: boolean) => {
161
- setData((data) => ({ ...data, page: 1 }));
162
99
  const sortedState = getSortedListStatus(orderPointer, isAscending);
163
100
  setSortedListStatus(sortedState);
164
101
 
@@ -168,7 +105,6 @@ const Gallery = (props: IGalleryProps): JSX.Element => {
168
105
  };
169
106
 
170
107
  const filterItems = async (filterPointer: string, filtersSelected: string) => {
171
- setData((data) => ({ ...data, page: 1 }));
172
108
  const filtersSelection = setFiltersSelection(filterPointer, filtersSelected);
173
109
  const filterQuery = setFilterQuery(filtersSelection);
174
110
  setCurrentFilterQuery(filterQuery);
@@ -178,9 +114,9 @@ const Gallery = (props: IGalleryProps): JSX.Element => {
178
114
  icon: "search",
179
115
  title: "Oh! No Results Found",
180
116
  message: "We couldn’t find what you are looking for. Please, try another search.",
181
- }
117
+ };
182
118
 
183
- const noSearchResults = !data.items.length && isSearching;
119
+ const noSearchResults = !data?.items?.length && isSearching;
184
120
 
185
121
  return (
186
122
  <S.Wrapper>
@@ -195,76 +131,102 @@ const Gallery = (props: IGalleryProps): JSX.Element => {
195
131
  <Orientation filterItems={filterItems} />
196
132
  <SortBy sortItems={sortItems} sortedState={sortedListStatus} />
197
133
  </S.Filters>
198
- </ S.Header>
134
+ </S.Header>
199
135
  <S.Search>
200
136
  <SearchField onChange={setSearchQuery} placeholder="Type an image’s name, title, or #tag" />
201
- </ S.Search>
137
+ </S.Search>
202
138
  <S.GalleryWrapper ref={galleryRef}>
139
+ {isGlobalTab && (
140
+ <S.NotificationWrapper>
141
+ <Notification
142
+ type="info"
143
+ text="This is a global Library. All the changes you make will be applied to all the sites."
144
+ />
145
+ </S.NotificationWrapper>
146
+ )}
147
+ <ErrorToast size="l" />
203
148
  {isLoading.init ? (
204
149
  <S.LoadingWrapper>
205
150
  <Loader name="circle" />
206
151
  </S.LoadingWrapper>
207
152
  ) : (
208
- <S.Grid>
209
- {data.items &&
210
- data.items.map((item: IImage, index: number) => {
211
- const isSelected = data.imageSelected ? item.id === data.imageSelected.id : false;
212
- return (
213
- <S.GridItem key={item.name + index}>
214
- <S.ImageWrapper onClick={_handleClick(item)} selected={isSelected}>
215
- <img src={item.thumb} alt={item.alt} />
216
- <S.IconUnchecked>
217
- <Icon name="emptyCheck" size="24" />
218
- </S.IconUnchecked>
219
- <S.IconChecked>
220
- <Icon name="success" size="24" />
221
- </S.IconChecked>
222
- </S.ImageWrapper>
223
- </S.GridItem>
224
- );
225
- })
226
- }
153
+ <>
154
+ {noSearchResults ? (
155
+ <S.EmptyWrapper>
156
+ <EmptyState {...emptyStateProps} />
157
+ </S.EmptyWrapper>
158
+ ) : (
159
+ <S.Grid>
160
+ {data &&
161
+ data.items &&
162
+ data.items.map((item: IImage, index: number) => {
163
+ const isSelected = data.imageSelected ? item.id === data.imageSelected.id : false;
164
+ return (
165
+ <S.GridItem key={item.name + index} orientation={item.orientation}>
166
+ <S.ImageWrapper
167
+ onClick={handleClick(item)}
168
+ selected={isSelected}
169
+ orientation={item.orientation}
170
+ >
171
+ <img src={item.thumb} alt={item.alt} />
172
+ <S.IconUnchecked>
173
+ <Icon name="emptyCheck" size="24" />
174
+ </S.IconUnchecked>
175
+ <S.IconChecked>
176
+ <Icon name="success" size="24" />
177
+ </S.IconChecked>
178
+ </S.ImageWrapper>
179
+ </S.GridItem>
180
+ );
181
+ })}
182
+ </S.Grid>
183
+ )}
227
184
  {isLoading.more && (
228
185
  <S.LoaderWrapper>
229
186
  <Loader name="dots" />
230
187
  </S.LoaderWrapper>
231
188
  )}
232
- {noSearchResults && (
233
- <S.EmptyWrapper>
234
- <EmptyState {...emptyStateProps} />
235
- </S.EmptyWrapper>)
236
- }
237
- </S.Grid>
189
+ </>
238
190
  )}
239
191
  </S.GalleryWrapper>
240
- </ S.GalleryTabs>
192
+ </S.GalleryTabs>
241
193
  <GalleryPanel
242
- isImageSelected={data.isImageSelected}
243
- imageSelected={data.imageSelected}
194
+ isImageSelected={data?.isImageSelected}
195
+ imageSelected={data?.imageSelected}
244
196
  validFormats={validFormats}
245
- addImage={addImage}
246
- updateItems={updateItems}
247
197
  setImage={setImage}
248
198
  isGlobalTab={!isLocalTab}
249
199
  site={galleryScope}
250
200
  selectedTab={selectedTab}
201
+ refreshImages={refreshImages}
251
202
  />
252
203
  </S.Wrapper>
253
204
  );
254
205
  };
255
206
 
256
- interface IGalleryState {
257
- items: IImage[];
258
- isImageSelected: boolean;
259
- imageSelected: IImage | null;
260
- page: number;
261
- isFinished: boolean;
262
- }
263
-
264
207
  interface IGalleryProps {
265
208
  getImageSelected: (img: IImage | null) => void;
266
209
  toggleModal: () => void;
267
210
  site: ISite;
211
+ data: IData;
212
+ isLoading: IIsLoading;
213
+ }
214
+
215
+ const mapStateToProps = (state: IRootState) => ({
216
+ data: state.gallery.data,
217
+ isLoading: state.gallery.isLoading,
218
+ });
219
+
220
+ interface IDispatchProps {
221
+ getSiteImages(params: IGetSiteImages): Promise<void>;
222
+ selectImage(item: IImage): void;
268
223
  }
269
224
 
270
- export default memo(Gallery);
225
+ const mapDispatchToProps = {
226
+ getSiteImages: galleryActions.getSiteImages,
227
+ selectImage: galleryActions.selectImage,
228
+ };
229
+
230
+ type IProps = IGalleryProps & IDispatchProps;
231
+
232
+ export default connect(mapStateToProps, mapDispatchToProps)(memo(Gallery));