@griddo/ax 10.3.3 → 10.3.5

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 (42) hide show
  1. package/package.json +2 -2
  2. package/src/api/files.tsx +20 -4
  3. package/src/api/utils.tsx +4 -2
  4. package/src/components/Fields/FileField/index.tsx +1 -1
  5. package/src/components/FileGallery/index.tsx +101 -70
  6. package/src/components/FileGallery/style.tsx +19 -3
  7. package/src/components/Icon/components/Download.js +7 -0
  8. package/src/components/Icon/svgs/Download.svg +3 -0
  9. package/src/components/SearchField/index.tsx +17 -1
  10. package/src/components/SearchField/style.tsx +4 -1
  11. package/src/components/Tag/index.tsx +12 -2
  12. package/src/components/Tag/style.tsx +19 -9
  13. package/src/containers/FileDrive/actions.tsx +26 -0
  14. package/src/containers/Sites/actions.tsx +26 -13
  15. package/src/hooks/index.tsx +2 -0
  16. package/src/hooks/resize.ts +57 -0
  17. package/src/modules/Content/PageItem/index.tsx +1 -0
  18. package/src/modules/Content/index.tsx +23 -6
  19. package/src/modules/FileDrive/BulkListHeader/TableHeader/index.tsx +3 -1
  20. package/src/modules/FileDrive/BulkListHeader/TableHeader/style.tsx +16 -2
  21. package/src/modules/FileDrive/BulkListHeader/index.tsx +9 -2
  22. package/src/modules/FileDrive/FileDragAndDrop/index.tsx +4 -2
  23. package/src/modules/FileDrive/FileFilters/SortBy/index.tsx +60 -0
  24. package/src/modules/FileDrive/FileFilters/SortBy/style.tsx +31 -0
  25. package/src/modules/FileDrive/FileFilters/Type/index.tsx +77 -0
  26. package/src/modules/FileDrive/FileFilters/Type/style.tsx +39 -0
  27. package/src/modules/FileDrive/FileFilters/Usage/index.tsx +66 -0
  28. package/src/modules/FileDrive/FileFilters/Usage/style.tsx +30 -0
  29. package/src/modules/FileDrive/FileModal/DetailPanel/index.tsx +26 -7
  30. package/src/modules/FileDrive/FileModal/index.tsx +81 -15
  31. package/src/modules/FileDrive/GridItem/index.tsx +24 -5
  32. package/src/modules/FileDrive/GridItem/style.tsx +9 -4
  33. package/src/modules/FileDrive/ListItem/index.tsx +22 -4
  34. package/src/modules/FileDrive/ListItem/style.tsx +7 -1
  35. package/src/modules/FileDrive/atoms.tsx +27 -4
  36. package/src/modules/FileDrive/helpers.tsx +17 -17
  37. package/src/modules/FileDrive/hooks.tsx +77 -0
  38. package/src/modules/FileDrive/index.tsx +145 -23
  39. package/src/modules/FileDrive/style.tsx +40 -6
  40. package/src/modules/FileDrive/utils.tsx +19 -0
  41. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +1 -1
  42. package/src/types/index.tsx +2 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "10.3.3",
4
+ "version": "10.3.5",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Carlos Torres <carlos.torres@secuoyas.com>",
@@ -230,5 +230,5 @@
230
230
  "publishConfig": {
231
231
  "access": "public"
232
232
  },
233
- "gitHead": "674cca843cbca18a7c8c4e40a3da49815b08c468"
233
+ "gitHead": "0608fd5d1b2149a0dbfbaad156b3a46727a3e673"
234
234
  }
package/src/api/files.tsx CHANGED
@@ -64,6 +64,12 @@ const SERVICES: { [key: string]: IServiceConfig } = {
64
64
  endpoint: ["/files/", "/replace"],
65
65
  method: "PUT",
66
66
  },
67
+ DOWNLOAD_FILES: {
68
+ ...template,
69
+ endpoint: "/files/download/",
70
+ method: "POST",
71
+ responseType: "blob",
72
+ },
67
73
  };
68
74
 
69
75
  const uploadFile = async (data: FormData) => {
@@ -76,17 +82,16 @@ const getFolderContent = async (params: IGetFolderParams) => {
76
82
  endpoint: [prefix, suffix],
77
83
  } = SERVICES.GET_FOLDER_CONTENT;
78
84
 
79
- const { siteID, folderID, search, filter, order } = params;
85
+ const { siteID, folderID, search, query: filters = "" } = params;
80
86
 
81
87
  const data = {
82
88
  ...(folderID && { folder: folderID }),
83
89
  ...(search && { search }),
84
- ...(order && { order }),
85
- ...(filter && { filterType: filter }),
86
90
  };
87
91
 
88
92
  const queryParams = encodeData(data);
89
- const query = queryParams.length ? `?${queryParams}` : "";
93
+ const queryFilters = queryParams.length ? `${queryParams}&${filters}` : filters;
94
+ const query = queryFilters.length ? `?${queryFilters}` : "";
90
95
 
91
96
  SERVICES.GET_FOLDER_CONTENT.dynamicUrl = `${host}${prefix}${siteID}${suffix}${query}`;
92
97
 
@@ -170,6 +175,16 @@ const replaceFile = async (data: FormData, fileID: number, keepUrl: boolean) =>
170
175
  return sendRequest(SERVICES.REPLACE_FILE, data as any);
171
176
  };
172
177
 
178
+ const downloadFiles = async (fileID: number | number[], zip: boolean) => {
179
+ const { host, endpoint } = SERVICES.DOWNLOAD_FILES;
180
+
181
+ const query = zip ? "?zip=on" : "";
182
+
183
+ SERVICES.DOWNLOAD_FILES.dynamicUrl = `${host}${endpoint}${fileID}${query}`;
184
+
185
+ return sendRequest(SERVICES.DOWNLOAD_FILES);
186
+ };
187
+
173
188
  export default {
174
189
  uploadFile,
175
190
  getFolderContent,
@@ -183,4 +198,5 @@ export default {
183
198
  moveFile,
184
199
  moveFilesBulk,
185
200
  replaceFile,
201
+ downloadFiles,
186
202
  };
package/src/api/utils.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import axios, { AxiosRequestConfig, AxiosResponse, Method } from "axios";
1
+ import axios, { AxiosRequestConfig, AxiosResponse, Method, ResponseType } from "axios";
2
2
  import { SET_ERROR } from "./../containers/App/constants";
3
3
 
4
4
  export interface IServiceConfig {
@@ -8,6 +8,7 @@ export interface IServiceConfig {
8
8
  headers: { "Content-type": string; accept: string; site?: number | null; lang?: number };
9
9
  hasToken: boolean;
10
10
  dynamicUrl?: string;
11
+ responseType?: ResponseType;
11
12
  }
12
13
 
13
14
  const getToken = (): Record<string, unknown> | null => {
@@ -43,7 +44,7 @@ const getHeaders = (headers: Record<string, unknown>, hasToken: boolean): Record
43
44
  };
44
45
 
45
46
  const wrapConfig = (serviceConfig: IServiceConfig): AxiosRequestConfig => {
46
- const { host, endpoint, method, headers: configHeaders, hasToken, dynamicUrl } = serviceConfig;
47
+ const { host, endpoint, method, headers: configHeaders, hasToken, dynamicUrl, responseType } = serviceConfig;
47
48
 
48
49
  const headers = getHeaders(configHeaders, hasToken);
49
50
 
@@ -51,6 +52,7 @@ const wrapConfig = (serviceConfig: IServiceConfig): AxiosRequestConfig => {
51
52
  url: dynamicUrl ? dynamicUrl : `${host}${endpoint}`,
52
53
  method,
53
54
  headers,
55
+ responseType,
54
56
  };
55
57
  };
56
58
 
@@ -12,7 +12,7 @@ const FileField = (props: IFileFieldProps): JSX.Element => {
12
12
 
13
13
  const { isOpen, toggleModal } = useModal(false);
14
14
 
15
- const validFormats = ["pdf", "doc", "docx", "xls", "xlsx", "zip"];
15
+ const validFormats = ["pdf", "doc", "docx", "xls", "xlsx", "zip", "csv"];
16
16
 
17
17
  const handleClick = () => {
18
18
  if (!disabled) {
@@ -14,7 +14,7 @@ import {
14
14
  BackFolder,
15
15
  } from "@ax/components";
16
16
  import { fileDriveActions } from "@ax/containers/FileDrive";
17
- import { usePermission } from "@ax/hooks";
17
+ import { usePermission, useResizable } from "@ax/hooks";
18
18
 
19
19
  import GalleryPanel from "./GalleryPanel";
20
20
  import GridItem from "./GridItem";
@@ -25,6 +25,10 @@ import * as S from "./style";
25
25
  // refactor
26
26
  import Breadcrumb from "@ax/modules/FileDrive/Breadcrumb";
27
27
  import FolderTree from "@ax/modules/FileDrive/FolderTree";
28
+ import Type from "@ax/modules/FileDrive/FileFilters/Type";
29
+ import SortBy from "@ax/modules/FileDrive/FileFilters/SortBy";
30
+ import { useFilterQuery, useSortedListStatus } from "@ax/modules/FileDrive/hooks";
31
+ import { getSortedListStatus } from "@ax/modules/FileDrive/utils";
28
32
 
29
33
  const FileGallery = (props: IProps): JSX.Element => {
30
34
  const {
@@ -57,6 +61,11 @@ const FileGallery = (props: IProps): JSX.Element => {
57
61
 
58
62
  const galleryRef = useRef<HTMLDivElement>(null);
59
63
 
64
+ const [ref] = useResizable();
65
+
66
+ const { setFiltersSelection, setFilterQuery, filterValues } = useFilterQuery();
67
+ const { sortedListStatus, setSortedListStatus } = useSortedListStatus();
68
+ const [currentFilterQuery, setCurrentFilterQuery] = useState("");
60
69
  const [searchQuery, setSearchQuery] = useState<string>("");
61
70
  const isSearching = searchQuery.length > 0;
62
71
 
@@ -95,10 +104,11 @@ const FileGallery = (props: IProps): JSX.Element => {
95
104
  folderID: currentFolderID,
96
105
  search: searchQuery,
97
106
  loading: false,
107
+ query: currentFilterQuery,
98
108
  };
99
109
 
100
110
  return params;
101
- }, [currentFolderID, searchQuery, selectedTab]);
111
+ }, [currentFolderID, searchQuery, selectedTab, currentFilterQuery]);
102
112
 
103
113
  useLayoutEffect(() => {
104
114
  return () => {
@@ -158,6 +168,21 @@ const FileGallery = (props: IProps): JSX.Element => {
158
168
  await getFolderContent(params);
159
169
  };
160
170
 
171
+ const sortItems = async (orderPointer: string, isAscending: boolean) => {
172
+ const sortedState = getSortedListStatus(orderPointer, isAscending);
173
+ setSortedListStatus(sortedState);
174
+
175
+ const filtersSelection = setFiltersSelection("order", orderPointer, isAscending);
176
+ const filterQuery = setFilterQuery(filtersSelection);
177
+ setCurrentFilterQuery(filterQuery);
178
+ };
179
+
180
+ const filterItems = async (filterPointer: string, filtersSelected: string) => {
181
+ const filtersSelection = setFiltersSelection(filterPointer, filtersSelected);
182
+ const filterQuery = setFilterQuery(filtersSelection);
183
+ setCurrentFilterQuery(filterQuery);
184
+ };
185
+
161
186
  const foldersIcon = isPanelOpen ? <Icon name="closePanel" size="24" /> : <Icon name="openPanel" size="24" />;
162
187
 
163
188
  const emptySearchStateProps = {
@@ -173,87 +198,93 @@ const FileGallery = (props: IProps): JSX.Element => {
173
198
 
174
199
  return (
175
200
  <S.Wrapper data-testid="file-gallery-wrapper">
176
- <S.FolderPanel isOpen={isPanelOpen}>
201
+ <S.FolderPanel isOpen={isPanelOpen} ref={ref}>
177
202
  <S.FolderPanelContent>
178
- <FolderTree folderID={currentFolderID || 0} onClick={updateCurrentFolder} title="Folders" trimNames={true} />
203
+ <FolderTree folderID={currentFolderID || 0} onClick={updateCurrentFolder} title="Folders" />
179
204
  </S.FolderPanelContent>
205
+ <S.ResizeHandle className="resizer" />
180
206
  </S.FolderPanel>
181
207
  <S.ContentWrapper>
182
- {!!tabs.length && <S.Header>
208
+ {!!tabs.length && (
209
+ <S.Header>
183
210
  {!!tabs.length && (
184
211
  <S.TabsWrapper>
185
212
  <Tabs tabs={tabs} active={selectedTab} setSelectedTab={handleSelectedTab} noMargins />
186
213
  </S.TabsWrapper>
187
214
  )}
188
- <S.Filters></S.Filters>
189
- </S.Header>}
190
- <S.Search>
191
- <SearchField onChange={setSearchQuery} placeholder="Type file’s name, title, or #tag" />
192
- </S.Search>
193
- <S.GalleryWrapper ref={galleryRef}>
194
- {isGlobalTab && isSiteView && (
195
- <S.NotificationWrapper>
196
- <Notification
197
- type="info"
198
- text="This is a global Library. All the changes you make will be applied to all the sites."
199
- />
200
- </S.NotificationWrapper>
201
- )}
202
- <ErrorToast size="l" />
203
- {isLoading ? (
204
- <S.LoadingWrapper>
205
- <Loader name="circle" />
206
- </S.LoadingWrapper>
207
- ) : (
208
- <>
209
- {!isRoot && !isSearching && <Breadcrumb breadcrumb={breadcrumb} onClick={updateCurrentFolder} />}
210
- {(hasFolders || (!isRoot && !isSearching)) && (
211
- <S.SectionWrapper>
212
- <S.SectionHeader>
213
- <S.SectionTitle>
214
- <div>Folders</div>
215
- <S.FoldersIconWrapper onClick={togglePanel}>
216
- <Tooltip content="Open folder panel">{foldersIcon}</Tooltip>
217
- </S.FoldersIconWrapper>
218
- </S.SectionTitle>
219
- </S.SectionHeader>
220
- <S.FoldersWrapper>
221
- {!isRoot && !isSearching && <BackFolder onClick={handleBackClick} size="S" />}
222
- <S.FoldersGrid>
223
- {folders.map((folder: IFolder) => (
224
- <FolderItem folder={folder} onClick={updateCurrentFolder} key={folder.folderName} />
225
- ))}
226
- </S.FoldersGrid>
227
- </S.FoldersWrapper>
228
- </S.SectionWrapper>
229
- )}
215
+ <S.Filters>
216
+ <Type filterItems={filterItems} value={filterValues["filterType"]} />
217
+ <SortBy sortItems={sortItems} sortedState={sortedListStatus} />
218
+ </S.Filters>
219
+ </S.Header>
220
+ )}
221
+ <S.Search>
222
+ <SearchField onChange={setSearchQuery} placeholder="Type file’s name, title, or #tag" autoFocus={false} />
223
+ </S.Search>
224
+ <S.GalleryWrapper ref={galleryRef}>
225
+ {isGlobalTab && isSiteView && (
226
+ <S.NotificationWrapper>
227
+ <Notification
228
+ type="info"
229
+ text="This is a global Library. All the changes you make will be applied to all the sites."
230
+ />
231
+ </S.NotificationWrapper>
232
+ )}
233
+ <ErrorToast size="l" />
234
+ {isLoading ? (
235
+ <S.LoadingWrapper>
236
+ <Loader name="circle" />
237
+ </S.LoadingWrapper>
238
+ ) : (
239
+ <>
240
+ {!isRoot && !isSearching && <Breadcrumb breadcrumb={breadcrumb} onClick={updateCurrentFolder} />}
241
+ {(hasFolders || (!isRoot && !isSearching)) && (
230
242
  <S.SectionWrapper>
231
243
  <S.SectionHeader>
232
- <S.SectionTitle>Documents</S.SectionTitle>
244
+ <S.SectionTitle>
245
+ <div>Folders</div>
246
+ <S.FoldersIconWrapper onClick={togglePanel}>
247
+ <Tooltip content="Open folder panel">{foldersIcon}</Tooltip>
248
+ </S.FoldersIconWrapper>
249
+ </S.SectionTitle>
233
250
  </S.SectionHeader>
234
- {!items.length ? (
235
- <S.EmptyWrapper>
236
- {isSearching ? (
237
- <EmptyState {...emptySearchStateProps} />
238
- ) : (
239
- <EmptyState {...emptyFolderStateProps} />
240
- )}
241
- </S.EmptyWrapper>
242
- ) : (
243
- <S.Grid>
244
- {items &&
245
- items.map((item: IFile) => {
246
- const isSelected = item.id === selectedFile?.id;
247
- return (
248
- <GridItem file={item} onClick={handleClick} key={item.fileName} isSelected={isSelected} />
249
- );
250
- })}
251
- </S.Grid>
252
- )}
251
+ <S.FoldersWrapper>
252
+ {!isRoot && !isSearching && <BackFolder onClick={handleBackClick} size="S" />}
253
+ <S.FoldersGrid>
254
+ {folders.map((folder: IFolder) => (
255
+ <FolderItem folder={folder} onClick={updateCurrentFolder} key={folder.folderName} />
256
+ ))}
257
+ </S.FoldersGrid>
258
+ </S.FoldersWrapper>
253
259
  </S.SectionWrapper>
254
- </>
255
- )}
256
- </S.GalleryWrapper>
260
+ )}
261
+ <S.SectionWrapper>
262
+ <S.SectionHeader>
263
+ <S.SectionTitle>Documents</S.SectionTitle>
264
+ </S.SectionHeader>
265
+ {!items.length ? (
266
+ <S.EmptyWrapper>
267
+ {isSearching ? (
268
+ <EmptyState {...emptySearchStateProps} />
269
+ ) : (
270
+ <EmptyState {...emptyFolderStateProps} />
271
+ )}
272
+ </S.EmptyWrapper>
273
+ ) : (
274
+ <S.Grid>
275
+ {items &&
276
+ items.map((item: IFile) => {
277
+ const isSelected = item.id === selectedFile?.id;
278
+ return (
279
+ <GridItem file={item} onClick={handleClick} key={item.fileName} isSelected={isSelected} />
280
+ );
281
+ })}
282
+ </S.Grid>
283
+ )}
284
+ </S.SectionWrapper>
285
+ </>
286
+ )}
287
+ </S.GalleryWrapper>
257
288
  </S.ContentWrapper>
258
289
  <GalleryPanel
259
290
  selectedFile={selectedFile}
@@ -7,11 +7,13 @@ const Wrapper = styled.div`
7
7
  `;
8
8
 
9
9
  const FolderPanel = styled.div<{ isOpen: boolean }>`
10
+ position: relative;
10
11
  background-color: ${(p) => p.theme.color.uiBackground02};
11
12
  border-right: ${(p) => `1px solid ${p.theme.color.uiLine}`};
12
13
  width: ${(p) => (p.isOpen ? "192px" : "0")};
14
+ min-width: ${(p) => (p.isOpen ? "192px" : "0")};
15
+ max-width: ${(p) => (p.isOpen ? "370px" : "0")};
13
16
  overflow: hidden;
14
- transition: width 0.8s ease-out;
15
17
  flex-shrink: 0;
16
18
  `;
17
19
 
@@ -55,7 +57,7 @@ const Filters = styled.div`
55
57
 
56
58
  & > * {
57
59
  &:not(:last-child) {
58
- margin-right: ${(p) => p.theme.spacing.l};
60
+ margin-right: ${(p) => p.theme.spacing.m};
59
61
  }
60
62
  }
61
63
  `;
@@ -150,6 +152,19 @@ const FoldersIconWrapper = styled.div`
150
152
  cursor: pointer;
151
153
  `;
152
154
 
155
+ const ResizeHandle = styled.div`
156
+ position: absolute;
157
+ width: 2px;
158
+ right: 0;
159
+ top: 0;
160
+ bottom: 0;
161
+ cursor: col-resize;
162
+
163
+ &:hover {
164
+ background-color: ${(p) => p.theme.color.interactive01};
165
+ }
166
+ `;
167
+
153
168
  export {
154
169
  Wrapper,
155
170
  FolderPanel,
@@ -169,5 +184,6 @@ export {
169
184
  SectionTitle,
170
185
  FoldersGrid,
171
186
  FoldersWrapper,
172
- FoldersIconWrapper
187
+ FoldersIconWrapper,
188
+ ResizeHandle,
173
189
  };
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ const SvgDownload = (props) => (
3
+ <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} fill="none" {...props}>
4
+ <path fill="#5057FF" fillRule="evenodd" d="M15 9h4l-7 7-7-7h4V3h6v6ZM5 20v-2h14v2H5Z" clipRule="evenodd" />
5
+ </svg>
6
+ );
7
+ export default SvgDownload;
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M15 9H19L12 16L5 9H9V3H15V9ZM5 20V18H19V20H5Z" fill="#5057FF"/>
3
+ </svg>
@@ -16,12 +16,27 @@ const SearchField = (props: ISearchFieldProps): JSX.Element => {
16
16
  small,
17
17
  autoFocus = true,
18
18
  size = "M",
19
+ value,
19
20
  } = props;
20
21
 
21
22
  const [isOpen, setIsOpen] = useState(false);
22
- const [inputValue, setInputValue] = useState("");
23
+ const [inputValue, setInputValue] = useState(value || "");
23
24
  const [selectValue, setSelectValue] = useState<string>("");
24
25
 
26
+ useEffect(() => {
27
+ if (inputValue.length === 0) {
28
+ setIsOpen(false);
29
+ }
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, [inputValue]);
32
+
33
+ useEffect(() => {
34
+ if (value !== inputValue) {
35
+ setInputValue(value || "");
36
+ }
37
+ // eslint-disable-next-line react-hooks/exhaustive-deps
38
+ }, [value]);
39
+
25
40
  const toggleField = () => setIsOpen(!isOpen);
26
41
 
27
42
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -123,6 +138,7 @@ export interface ISearchFieldProps {
123
138
  small?: boolean;
124
139
  autoFocus?: boolean;
125
140
  size?: "M" | "S" | "XS";
141
+ value?: string;
126
142
  }
127
143
 
128
144
  export default SearchField;
@@ -17,6 +17,9 @@ const FieldWrapper = styled.div<{ closeOnInactive: boolean; disabled: boolean }>
17
17
  border-width: ${(p) => (p.closeOnInactive ? "0 0 1px" : "1px")};
18
18
  border-style: solid;
19
19
  border-radius: ${(p) => (p.closeOnInactive ? 0 : p.theme.radii.s)};
20
+ &:focus-within {
21
+ border-color: ${(p) => (p.disabled ? p.theme.color.interactiveDisabled : p.theme.color.interactive01)};
22
+ }
20
23
  `;
21
24
 
22
25
  const Input = styled.input<{
@@ -32,13 +35,13 @@ const Input = styled.input<{
32
35
  height: ${(p) => (p.inputSize === "XS" ? "40px" : p.theme.spacing.l)};
33
36
  padding-left: ${(p) => p.theme.spacing.xs};
34
37
  border: none;
38
+ border-radius: ${(p) => (p.closeOnInactive ? 0 : p.theme.radii.s)};
35
39
  width: ${(p) =>
36
40
  p.small || p.inputSize !== "M" ? `calc(${p.theme.spacing.xl} * 2)` : `calc(${p.theme.spacing.xl} * 4)`};
37
41
 
38
42
  &:active,
39
43
  &:focus {
40
44
  outline: none;
41
- border-color: ${(p) => (p.disabled ? p.theme.color.interactiveDisabled : p.theme.color.interactive01)};
42
45
  }
43
46
  `;
44
47
 
@@ -4,7 +4,7 @@ import { Icon } from "@ax/components";
4
4
  import * as S from "./style";
5
5
 
6
6
  const Tag = (props: ITagProps): JSX.Element => {
7
- const { type, text, color, onDeleteAction } = props;
7
+ const { type, text, color, icon, onDeleteAction } = props;
8
8
 
9
9
  const handleClick = () => {
10
10
  if (onDeleteAction) {
@@ -27,7 +27,16 @@ const Tag = (props: ITagProps): JSX.Element => {
27
27
  </S.TagStatus>
28
28
  );
29
29
  case "square":
30
- return <S.TagSquare color={color} data-testid="tag-square">{text}</S.TagSquare>;
30
+ return (
31
+ <S.TagSquare color={color} data-testid="tag-square">
32
+ {icon && (
33
+ <S.IconTag>
34
+ <Icon name={icon} size="16" />
35
+ </S.IconTag>
36
+ )}
37
+ <div>{text}</div>
38
+ </S.TagSquare>
39
+ );
31
40
  default:
32
41
  return (
33
42
  <S.TagFixed color={color} data-testid="tag-fixed">
@@ -44,6 +53,7 @@ export interface ITagProps {
44
53
  type?: "status" | "fixed" | "interactive" | "square" | undefined;
45
54
  text: string;
46
55
  color?: string;
56
+ icon?: string;
47
57
  onDeleteAction?: () => void;
48
58
  }
49
59
 
@@ -14,12 +14,12 @@ export const TagStatus = styled.div`
14
14
 
15
15
  export const TagSquare = styled.div<{ color: string | undefined }>`
16
16
  ${(p) => p.theme.textStyle.uiXS};
17
+ display: flex;
17
18
  background-color: ${(p) => (p.color ? p.color : p.theme.colors.uiBackground01)};
18
19
  box-sizing: border-box;
19
20
  border-radius: ${(p) => p.theme.radii.xs};
20
21
  color: ${(p) => (p.color ? p.theme.color.textMediumEmphasisInverse : p.theme.color.textMediumEmphasis)};
21
22
  white-space: nowrap;
22
- display: inline-block;
23
23
  padding: 3px 8px;
24
24
  text-transform: capitalize;
25
25
  `;
@@ -34,26 +34,36 @@ export const Bullet = styled.span<{ color: string | undefined }>`
34
34
  `;
35
35
 
36
36
  export const TagFixed = styled.div<{ color: string | undefined }>`
37
- ${(p) => p.theme.textStyle?.uiS};
38
- background-color: ${(p) => (p.color ? p.color : p.theme.color?.interactive02)};
39
- border-radius: ${(p) => p.theme.spacing?.s};
37
+ ${(p) => p.theme.textStyle.uiS};
38
+ background-color: ${(p) => (p.color ? p.color : p.theme.color.interactive02)};
39
+ border-radius: ${(p) => p.theme.spacing.s};
40
40
  box-sizing: border-box;
41
- color: ${(p) => p.theme.color?.textMediumEmphasis};
41
+ color: ${(p) => p.theme.color.textMediumEmphasis};
42
42
  display: inline-block;
43
43
  padding: 3px 8px;
44
- margin-right: ${(p) => p.theme.spacing?.xxs};
45
- margin-bottom: ${(p) => p.theme.spacing?.xxs};
44
+ margin-right: ${(p) => p.theme.spacing.xxs};
45
+ margin-bottom: ${(p) => p.theme.spacing.xxs};
46
46
  `;
47
47
 
48
48
  export const Title = styled.div``;
49
49
 
50
50
  export const IconWrapper = styled.div`
51
51
  height: 16px;
52
- margin-left: ${(p) => p.theme.spacing?.xxs};
52
+ margin-left: ${(p) => p.theme.spacing.xxs};
53
53
  cursor: pointer;
54
54
  svg {
55
55
  path {
56
- fill: ${(p) => p.theme.color?.textMediumEmphasis};
56
+ fill: ${(p) => p.theme.color.textMediumEmphasis};
57
+ }
58
+ }
59
+ `;
60
+
61
+ export const IconTag = styled.div`
62
+ height: 16px;
63
+ margin-right: ${(p) => p.theme.spacing.xs};
64
+ svg {
65
+ path {
66
+ fill: ${(p) => p.theme.color.textMediumEmphasis};
57
67
  }
58
68
  }
59
69
  `;
@@ -367,6 +367,31 @@ function replaceFile(
367
367
  };
368
368
  }
369
369
 
370
+ function downloadFiles(fileID: number | number[], zip: boolean, fileName?: string): (dispatch: Dispatch) => Promise<void> {
371
+ return async (dispatch) => {
372
+ try {
373
+ const responseActions = {
374
+ handleSuccess: (response: any) => {
375
+ const url = window.URL.createObjectURL(new Blob([response]));
376
+ const a = document.createElement('a');
377
+ a.href = url;
378
+ a.download = fileName ? fileName : "download.zip"
379
+ document.body.appendChild(a);
380
+ a.click();
381
+ window.URL.revokeObjectURL(url);
382
+ },
383
+ handleError: (response: any) => appActions.handleError(response)(dispatch),
384
+ };
385
+
386
+ const callback = async () => files.downloadFiles(fileID, zip);
387
+
388
+ await handleRequest(callback, responseActions, [])(dispatch);
389
+ } catch (e) {
390
+ console.log(e);
391
+ }
392
+ };
393
+ }
394
+
370
395
  export {
371
396
  getFolderContent,
372
397
  updateCurrentFolder,
@@ -383,4 +408,5 @@ export {
383
408
  updateDisplayMode,
384
409
  updateTab,
385
410
  replaceFile,
411
+ downloadFiles,
386
412
  };
@@ -279,7 +279,6 @@ function setSiteInfo(currentSiteInfo: ISite): (dispatch: any, getState: any) =>
279
279
  }
280
280
 
281
281
  getUserCurrentPermissions()(dispatch, getState);
282
-
283
282
  } catch (e) {
284
283
  console.log(e); // FIXME: capturar errores
285
284
  }
@@ -456,8 +455,8 @@ function resetSiteValues(siteID: number): (dispatch: Dispatch) => void {
456
455
  dispatch(setCurrentSitePages([]));
457
456
  dispatch(setTotalItems(0));
458
457
  getAnalytics(siteID)(dispatch);
459
- }
460
- };
458
+ };
459
+ }
461
460
 
462
461
  function saveCurrentSiteInfo(): (dispatch: Dispatch, getState: any) => Promise<void> {
463
462
  return async (dispatch, getState) => {
@@ -584,13 +583,6 @@ function deleteAndRemoveFromSiteBulk(
584
583
 
585
584
  let responseErrorPages: any = { data: { code: null, message: null } };
586
585
 
587
- const responsePageActions = {
588
- handleSuccess: () => true,
589
- handleError: (response: any) => {
590
- responseErrorPages = response;
591
- },
592
- };
593
-
594
586
  const getMessageErrors = () => {
595
587
  const {
596
588
  data: { message },
@@ -601,6 +593,14 @@ function deleteAndRemoveFromSiteBulk(
601
593
  appActions.handleError(responseErrorPages, isMultiple, msg)(dispatch);
602
594
  };
603
595
 
596
+ const responsePageActions = {
597
+ handleSuccess: () => true,
598
+ handleError: (response: any) => {
599
+ responseErrorPages = response;
600
+ getMessageErrors();
601
+ },
602
+ };
603
+
604
604
  const responseGlobalPageActions = {
605
605
  handleSuccess: () => {
606
606
  if (responseErrorPages.data.message?.length > 0) {
@@ -624,10 +624,23 @@ function deleteAndRemoveFromSiteBulk(
624
624
  const callbackPages = async () => pages.bulkDelete(pageIds);
625
625
  const callbackGlobalPages = async () => sites.removePageBulk(currentSiteInfo.id, globalPageIds);
626
626
 
627
- const resultPages = pageIds.length > 0 ? await handleRequest(callbackPages, responsePageActions, [])(dispatch) : true;
628
- const resultGlobalPages = globalPageIds.length > 0 ? await handleRequest(callbackGlobalPages, responseGlobalPageActions, [])(dispatch) : true;
627
+ let errors = 0;
628
+
629
+ if (pageIds.length > 0) {
630
+ const result = await handleRequest(callbackPages, responsePageActions, [])(dispatch);
631
+ if (!result) {
632
+ errors = errors + 1;
633
+ }
634
+ }
635
+
636
+ if (globalPageIds.length > 0) {
637
+ const result = await handleRequest(callbackGlobalPages, responseGlobalPageActions, [])(dispatch);
638
+ if (!result) {
639
+ errors = errors + 1;
640
+ }
641
+ }
629
642
 
630
- return resultPages || resultGlobalPages;
643
+ return errors > 0 ? false : true;
631
644
  } catch (e) {
632
645
  console.log(e);
633
646
  return false;