@griddo/ax 10.2.25 → 10.3.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.
- package/package.json +2 -2
- package/public/img/icons/excel.png +0 -0
- package/public/img/icons/pdf.png +0 -0
- package/public/img/icons/word.png +0 -0
- package/public/img/icons/zip.png +0 -0
- package/src/GlobalStore.tsx +3 -0
- package/src/__mocks__/store/GenericStore.ts +3 -0
- package/src/__tests__/components/Fields/FileField/FileField.test.tsx +34 -8
- package/src/__tests__/components/Gallery/GalleryPanel/GalleryDragAndDrop/GalleryDragAndDrop.test.tsx +1 -1
- package/src/api/files.tsx +171 -1
- package/src/api/users.tsx +5 -2
- package/src/components/ActionMenu/index.tsx +5 -13
- package/src/components/BackFolder/index.tsx +28 -0
- package/src/components/BackFolder/style.tsx +33 -0
- package/src/components/BulkSelectionOptions/index.tsx +4 -8
- package/src/components/Button/index.tsx +8 -3
- package/src/components/Button/style.tsx +5 -3
- package/src/components/ElementsTooltip/index.tsx +22 -7
- package/src/components/ElementsTooltip/style.tsx +2 -2
- package/src/components/Fields/FileField/index.tsx +7 -7
- package/src/components/Fields/TextField/index.tsx +3 -0
- package/src/components/FileGallery/FolderItem/index.tsx +39 -0
- package/src/components/FileGallery/FolderItem/style.tsx +31 -0
- package/src/components/FileGallery/GalleryPanel/DetailPanel/index.tsx +164 -0
- package/src/components/FileGallery/GalleryPanel/DetailPanel/style.tsx +113 -0
- package/src/components/FileGallery/GalleryPanel/index.tsx +42 -0
- package/src/components/FileGallery/GalleryPanel/style.tsx +7 -0
- package/src/components/FileGallery/GridItem/index.tsx +47 -0
- package/src/components/FileGallery/GridItem/style.tsx +51 -0
- package/src/components/FileGallery/index.tsx +304 -0
- package/src/components/FileGallery/style.tsx +173 -0
- package/src/components/FileGallery/utils.tsx +19 -0
- package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/index.tsx +4 -6
- package/src/components/Icon/components/Back.js +10 -0
- package/src/components/Icon/components/ClosePanel.js +12 -0
- package/src/components/Icon/components/NewFolder.js +10 -0
- package/src/components/Icon/components/OpenPanel.js +12 -0
- package/src/components/Icon/svgs/Back.svg +3 -0
- package/src/components/Icon/svgs/Close_panel.svg +3 -0
- package/src/components/Icon/svgs/New-folder.svg +3 -0
- package/src/components/Icon/svgs/Open_panel.svg +3 -0
- package/src/components/Modal/index.tsx +7 -5
- package/src/components/Modal/style.tsx +6 -6
- package/src/components/ProgressBar/index.tsx +3 -2
- package/src/components/ProgressBar/style.tsx +5 -3
- package/src/components/TableList/index.tsx +3 -2
- package/src/components/TableList/style.tsx +4 -0
- package/src/components/Toast/style.tsx +2 -2
- package/src/components/index.tsx +4 -0
- package/src/containers/FileDrive/actions.tsx +386 -0
- package/src/containers/FileDrive/constants.tsx +24 -0
- package/src/containers/FileDrive/index.tsx +7 -0
- package/src/containers/FileDrive/interfaces.tsx +59 -0
- package/src/containers/FileDrive/reducer.tsx +57 -0
- package/src/containers/FileDrive/utils.tsx +37 -0
- package/src/containers/Gallery/actions.tsx +1 -1
- package/src/containers/Gallery/interfaces.tsx +1 -1
- package/src/helpers/index.tsx +2 -0
- package/src/helpers/objects.tsx +6 -0
- package/src/modules/FileDrive/Breadcrumb/index.tsx +42 -0
- package/src/modules/FileDrive/Breadcrumb/style.tsx +18 -0
- package/src/modules/FileDrive/BulkGridHeader/GridHeader/index.tsx +37 -0
- package/src/modules/FileDrive/BulkGridHeader/GridHeader/style.tsx +19 -0
- package/src/modules/FileDrive/BulkGridHeader/index.tsx +35 -0
- package/src/modules/FileDrive/BulkGridHeader/style.tsx +17 -0
- package/src/modules/FileDrive/BulkListHeader/TableHeader/index.tsx +42 -0
- package/src/modules/FileDrive/BulkListHeader/TableHeader/style.tsx +53 -0
- package/src/modules/FileDrive/BulkListHeader/index.tsx +35 -0
- package/src/modules/FileDrive/BulkListHeader/style.tsx +17 -0
- package/src/modules/FileDrive/FileDragAndDrop/index.tsx +249 -0
- package/src/{components/Fields/FileField → modules/FileDrive}/FileDragAndDrop/style.tsx +50 -9
- package/src/modules/FileDrive/FileModal/DetailPanel/index.tsx +170 -0
- package/src/modules/FileDrive/FileModal/DetailPanel/style.tsx +81 -0
- package/src/modules/FileDrive/FileModal/index.tsx +129 -0
- package/src/modules/FileDrive/FileModal/style.tsx +112 -0
- package/src/modules/FileDrive/FolderItem/index.tsx +180 -0
- package/src/modules/FileDrive/FolderItem/style.tsx +39 -0
- package/src/modules/FileDrive/FolderTree/index.tsx +108 -0
- package/src/modules/FileDrive/FolderTree/style.tsx +69 -0
- package/src/modules/FileDrive/FolderTree/utils.tsx +91 -0
- package/src/modules/FileDrive/GridItem/index.tsx +167 -0
- package/src/modules/FileDrive/GridItem/style.tsx +76 -0
- package/src/modules/FileDrive/ListItem/index.tsx +180 -0
- package/src/modules/FileDrive/ListItem/style.tsx +88 -0
- package/src/modules/FileDrive/atoms.tsx +173 -0
- package/src/modules/FileDrive/helpers.tsx +19 -0
- package/src/modules/FileDrive/index.tsx +670 -0
- package/src/modules/FileDrive/style.tsx +145 -0
- package/src/modules/Sites/SitesList/index.tsx +0 -3
- package/src/routes/multisite.tsx +9 -0
- package/src/routes/site.tsx +9 -0
- package/src/types/index.tsx +63 -0
- package/src/components/Fields/FileField/FileDragAndDrop/index.tsx +0 -188
- package/src/components/Fields/FileField/store.tsx +0 -61
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
import { FieldsBehavior } from "@ax/components";
|
|
3
|
+
|
|
4
|
+
const Wrapper = styled.div`
|
|
5
|
+
display: flex;
|
|
6
|
+
border-top: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
7
|
+
height: 100%;
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
const FolderPanel = styled.div<{ isOpen: boolean }>`
|
|
11
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
12
|
+
border-right: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
13
|
+
width: ${(p) => (p.isOpen ? "240px" : "0")};
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
transition: width 0.8s ease-out;
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const FolderPanelContent = styled.div`
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
overflow: auto;
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const ContentWrapper = styled.div`
|
|
29
|
+
width: 100%;
|
|
30
|
+
overflow: auto;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const SectionWrapper = styled.div`
|
|
34
|
+
width: 100%;
|
|
35
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const SectionHeader = styled.div`
|
|
39
|
+
display: flex;
|
|
40
|
+
margin-bottom: ${(p) => p.theme.spacing.s};
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: flex-end;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const SectionTitle = styled.div`
|
|
46
|
+
${(p) => p.theme.textStyle.headingM};
|
|
47
|
+
display: flex;
|
|
48
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
49
|
+
margin-right: auto;
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const ButtonWrapper = styled.div`
|
|
53
|
+
margin-left: ${(p) => p.theme.spacing.m};
|
|
54
|
+
flex-shrink: 0;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const EmptyStateWrapper = styled.div`
|
|
58
|
+
width: 100%;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const DocumentsWrapper = styled.div`
|
|
62
|
+
display: flex;
|
|
63
|
+
width: 100%;
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
const GridWrapper = styled.div`
|
|
67
|
+
display: grid;
|
|
68
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
69
|
+
grid-template-rows: repeat(auto-fit, minmax(154px, 154px));
|
|
70
|
+
gap: ${(p) => p.theme.spacing.s};
|
|
71
|
+
width: 100%;
|
|
72
|
+
justify-content: start;
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
const FiltersBar = styled.div<{isSite: boolean}>`
|
|
76
|
+
display: flex;
|
|
77
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
78
|
+
padding: ${(p) => p.isSite ? `${p.theme.spacing.s} ${p.theme.spacing.m} 0 ${p.theme.spacing.m}` : `${p.theme.spacing.s} ${p.theme.spacing.m}`};
|
|
79
|
+
border-bottom: ${(p) => `1px solid ${p.theme.color.uiLine}`};
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const DisplayModeWrapper = styled.div`
|
|
83
|
+
margin-left: auto;
|
|
84
|
+
button:last-child {
|
|
85
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
const FoldersWrapper = styled.div`
|
|
90
|
+
width: 100%;
|
|
91
|
+
display: flex;
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
const FoldersGrid = styled.div`
|
|
95
|
+
width: 100%;
|
|
96
|
+
display: grid;
|
|
97
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
98
|
+
grid-template-rows: repeat(auto-fit, minmax(64px, 64px));
|
|
99
|
+
gap: ${(p) => p.theme.spacing.s};
|
|
100
|
+
justify-content: start;
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
const FoldersIconWrapper = styled.div`
|
|
104
|
+
width: 24px;
|
|
105
|
+
height: 24px;
|
|
106
|
+
margin-left: ${(p) => p.theme.spacing.xs};
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
`;
|
|
109
|
+
|
|
110
|
+
const ModalContent = styled.div`
|
|
111
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
112
|
+
p {
|
|
113
|
+
margin-bottom: ${(p) => p.theme.spacing.m};
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const NoMarginFieldsBehavior = styled(FieldsBehavior)`
|
|
118
|
+
margin-bottom: 0;
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
const TabsWrapper = styled.div`
|
|
122
|
+
width: ${p => `calc(${p.theme.spacing.xl} * 3)`};
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
Wrapper,
|
|
127
|
+
FolderPanel,
|
|
128
|
+
FolderPanelContent,
|
|
129
|
+
ContentWrapper,
|
|
130
|
+
SectionWrapper,
|
|
131
|
+
SectionHeader,
|
|
132
|
+
SectionTitle,
|
|
133
|
+
ButtonWrapper,
|
|
134
|
+
DocumentsWrapper,
|
|
135
|
+
EmptyStateWrapper,
|
|
136
|
+
GridWrapper,
|
|
137
|
+
FiltersBar,
|
|
138
|
+
DisplayModeWrapper,
|
|
139
|
+
FoldersWrapper,
|
|
140
|
+
FoldersGrid,
|
|
141
|
+
FoldersIconWrapper,
|
|
142
|
+
ModalContent,
|
|
143
|
+
NoMarginFieldsBehavior,
|
|
144
|
+
TabsWrapper,
|
|
145
|
+
};
|
|
@@ -36,7 +36,6 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
|
|
|
36
36
|
setListConfig,
|
|
37
37
|
hasAnimation,
|
|
38
38
|
setHasAnimation,
|
|
39
|
-
isLoading,
|
|
40
39
|
} = props;
|
|
41
40
|
|
|
42
41
|
const isMount = useIsMount();
|
|
@@ -370,7 +369,6 @@ interface ISitesProps {
|
|
|
370
369
|
error: IError;
|
|
371
370
|
config: ISiteListConfig;
|
|
372
371
|
hasAnimation: boolean;
|
|
373
|
-
isLoading: boolean;
|
|
374
372
|
}
|
|
375
373
|
|
|
376
374
|
const mapStateToProps = (state: IRootState) => ({
|
|
@@ -381,7 +379,6 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
381
379
|
error: state.app.error,
|
|
382
380
|
config: state.sites.config,
|
|
383
381
|
hasAnimation: state.app.hasAnimation,
|
|
384
|
-
isLoading: state.app.isLoading,
|
|
385
382
|
});
|
|
386
383
|
|
|
387
384
|
interface IDispatchProps {
|
package/src/routes/multisite.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import Editor from "./../modules/GlobalEditor";
|
|
|
10
10
|
import GlobalSettings from "./../modules/GlobalSettings";
|
|
11
11
|
import AnalyticsSettings from "../modules/Analytics";
|
|
12
12
|
import FramePreview from "../modules/FramePreview";
|
|
13
|
+
import FileDrive from "../modules/FileDrive";
|
|
13
14
|
|
|
14
15
|
export default [
|
|
15
16
|
{
|
|
@@ -43,6 +44,14 @@ export default [
|
|
|
43
44
|
icon: "Category",
|
|
44
45
|
permission: "global.globalData.accessToTaxonomies",
|
|
45
46
|
},
|
|
47
|
+
{
|
|
48
|
+
path: "/files",
|
|
49
|
+
component: FileDrive,
|
|
50
|
+
name: "File Drive Manager",
|
|
51
|
+
showInNav: true,
|
|
52
|
+
icon: "Photo-library",
|
|
53
|
+
permission: "global.mediaGallery.accessToGlobalFileDrive",
|
|
54
|
+
},
|
|
46
55
|
{
|
|
47
56
|
path: "/users",
|
|
48
57
|
component: Users,
|
package/src/routes/site.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import UserEdit from "./../modules/Users/UserEdit";
|
|
|
15
15
|
import Profile from "./../modules/Users/Profile";
|
|
16
16
|
import Integrations from "./../modules/Settings/Integrations";
|
|
17
17
|
import IntegrationForm from "./../modules/Settings/Integrations/IntegrationForm";
|
|
18
|
+
import FileDrive from "./../modules/FileDrive";
|
|
18
19
|
|
|
19
20
|
const BASE_PATH = "/sites";
|
|
20
21
|
|
|
@@ -87,6 +88,14 @@ export default [
|
|
|
87
88
|
},
|
|
88
89
|
],
|
|
89
90
|
},
|
|
91
|
+
{
|
|
92
|
+
path: `${BASE_PATH}/files`,
|
|
93
|
+
component: FileDrive,
|
|
94
|
+
name: "File Drive Manager",
|
|
95
|
+
showInNav: true,
|
|
96
|
+
icon: "Photo-library",
|
|
97
|
+
permission: "mediaGallery.accessToSiteFileDrive",
|
|
98
|
+
},
|
|
90
99
|
{
|
|
91
100
|
path: `${BASE_PATH}/users`,
|
|
92
101
|
component: Users,
|
package/src/types/index.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { IDomainsState } from "@ax/containers/Domains/reducer";
|
|
|
12
12
|
import { IRedirectsState } from "@ax/containers/Redirects/reducer";
|
|
13
13
|
import { IAnalyticsState } from "@ax/containers/Analytics/reducer";
|
|
14
14
|
import { IIntegrationsState } from "@ax/containers/Integrations/reducer";
|
|
15
|
+
import { IFileDriveState } from "@ax/containers/FileDrive/reducer";
|
|
15
16
|
|
|
16
17
|
export interface IBreadcrumbItem {
|
|
17
18
|
editorID: number;
|
|
@@ -226,6 +227,7 @@ export interface IRootState {
|
|
|
226
227
|
redirects: IRedirectsState;
|
|
227
228
|
analytics: IAnalyticsState;
|
|
228
229
|
integrations: IIntegrationsState;
|
|
230
|
+
fileDrive: IFileDriveState;
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
export interface IStyledProps {
|
|
@@ -698,6 +700,7 @@ export interface IModal {
|
|
|
698
700
|
toggleModal: () => void;
|
|
699
701
|
mainModalAction?: { title: string; onClick: () => void };
|
|
700
702
|
secondaryModalAction?: { title: string; onClick: () => void };
|
|
703
|
+
isChild?: boolean;
|
|
701
704
|
}
|
|
702
705
|
|
|
703
706
|
export interface IUserEditing {
|
|
@@ -889,6 +892,66 @@ export interface IUpdateNavigationParam {
|
|
|
889
892
|
navigations: { navigationId: number | null; type: "header" | "footer"; pageId: number }[];
|
|
890
893
|
}
|
|
891
894
|
|
|
895
|
+
export interface IFilesFolder {
|
|
896
|
+
files: {
|
|
897
|
+
totalItems: number;
|
|
898
|
+
items: IFile[];
|
|
899
|
+
};
|
|
900
|
+
folders: IFolder[];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
export interface IFile {
|
|
904
|
+
id: number;
|
|
905
|
+
fileName: string;
|
|
906
|
+
sizeBytes: number;
|
|
907
|
+
uploadDate: Date;
|
|
908
|
+
fileType: string;
|
|
909
|
+
tags: string[];
|
|
910
|
+
url: string;
|
|
911
|
+
alt: string;
|
|
912
|
+
title: string;
|
|
913
|
+
site: number | null;
|
|
914
|
+
folder: number | null;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
export interface IFolder {
|
|
918
|
+
id: number;
|
|
919
|
+
folderName: string;
|
|
920
|
+
parentId: number;
|
|
921
|
+
site: number;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
export interface IFolderTree {
|
|
925
|
+
id: number;
|
|
926
|
+
name: string;
|
|
927
|
+
children: IFolderTree[];
|
|
928
|
+
isExpanded?: boolean;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
export interface IGetFolderParams {
|
|
932
|
+
siteID: number | "global";
|
|
933
|
+
folderID: number | null;
|
|
934
|
+
loading?: boolean;
|
|
935
|
+
search?: string;
|
|
936
|
+
filter?: string;
|
|
937
|
+
order?: string;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
export interface IActionMenuOption {
|
|
941
|
+
label: string;
|
|
942
|
+
action: () => void;
|
|
943
|
+
icon: string;
|
|
944
|
+
disabled?: boolean;
|
|
945
|
+
helpText?: string | null;
|
|
946
|
+
color?: boolean;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
export interface IBulkAction {
|
|
950
|
+
icon?: string;
|
|
951
|
+
text: string;
|
|
952
|
+
action: () => void;
|
|
953
|
+
}
|
|
954
|
+
|
|
892
955
|
export type Field =
|
|
893
956
|
| "AsyncCheckGroup"
|
|
894
957
|
| "AsyncSelect"
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import React, { memo, useEffect, useReducer, useRef } from "react";
|
|
2
|
-
|
|
3
|
-
import { files } from "@ax/api";
|
|
4
|
-
import { isReqOk } from "@ax/helpers";
|
|
5
|
-
import { Icon, DragAndDrop } from "@ax/components";
|
|
6
|
-
import {
|
|
7
|
-
reducer,
|
|
8
|
-
initialState,
|
|
9
|
-
setDropDepth,
|
|
10
|
-
setInDropZone,
|
|
11
|
-
setIsUploading,
|
|
12
|
-
setUploadSuccess,
|
|
13
|
-
setUploadError,
|
|
14
|
-
MAX_SIZE,
|
|
15
|
-
} from "./../store";
|
|
16
|
-
|
|
17
|
-
import * as S from "./style";
|
|
18
|
-
|
|
19
|
-
const FileDragAndDrop = (props: IProps) => {
|
|
20
|
-
const { validFormats, addFile } = props;
|
|
21
|
-
|
|
22
|
-
const validExtensions = validFormats.map((format) => `.${format}`).join(",");
|
|
23
|
-
|
|
24
|
-
const filesInputRef = useRef<any>(null);
|
|
25
|
-
const filesButtonRef = useRef<any>(null);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (filesInputRef.current) {
|
|
29
|
-
filesInputRef.current.addEventListener("change", handleFilesUpload, false);
|
|
30
|
-
}
|
|
31
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
32
|
-
}, [filesInputRef]);
|
|
33
|
-
|
|
34
|
-
const [state, dispatch] = useReducer(reducer, initialState);
|
|
35
|
-
|
|
36
|
-
const handleDragEnter = () => {
|
|
37
|
-
dispatch(setDropDepth(state.dropDepth + 1));
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const handleDragLeave = () => {
|
|
41
|
-
dispatch(setDropDepth(state.dropDepth - 1));
|
|
42
|
-
if (state.dropDepth > 1) return;
|
|
43
|
-
dispatch(setInDropZone(false));
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
|
47
|
-
e.dataTransfer.dropEffect = "copy";
|
|
48
|
-
dispatch(setInDropZone(true));
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const checkType = (type: string) => {
|
|
52
|
-
for (const i in validFormats) {
|
|
53
|
-
if (type.includes(validFormats[i])) return true;
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
|
|
59
|
-
const files = Array.from(e.dataTransfer.files);
|
|
60
|
-
e.dataTransfer.clearData();
|
|
61
|
-
await handleUploadFile(files);
|
|
62
|
-
dispatch(setDropDepth(0));
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const handleFilesUpload = (e: any) => {
|
|
66
|
-
const files = Array.from(e.currentTarget.files);
|
|
67
|
-
handleUploadFile(files);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const handleUploadFile = async (filesArr: Array<any>) => {
|
|
71
|
-
if (filesArr[0]) {
|
|
72
|
-
dispatch(setIsUploading());
|
|
73
|
-
const fileSize = filesArr[0].size / (1024 * 1024);
|
|
74
|
-
|
|
75
|
-
if (!checkType(filesArr[0].type)) {
|
|
76
|
-
dispatch(setUploadError("Invalid format"));
|
|
77
|
-
} else if (fileSize > MAX_SIZE) {
|
|
78
|
-
dispatch(setUploadError("File is too big"));
|
|
79
|
-
} else {
|
|
80
|
-
try {
|
|
81
|
-
const form = new FormData();
|
|
82
|
-
form.append("file", filesArr[0]);
|
|
83
|
-
const result = await files.uploadFile(form);
|
|
84
|
-
if (isReqOk(result.status)) {
|
|
85
|
-
dispatch(setUploadSuccess());
|
|
86
|
-
setTimeout(function () {
|
|
87
|
-
addFile(result.data);
|
|
88
|
-
dispatch(setInDropZone(false));
|
|
89
|
-
}, 800);
|
|
90
|
-
}
|
|
91
|
-
} catch (e) {
|
|
92
|
-
dispatch(setUploadError("Error uploading file"));
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const handleTryAgain = () => {
|
|
99
|
-
dispatch(setInDropZone(false));
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const handleFileClick = () => {
|
|
103
|
-
if (filesInputRef) {
|
|
104
|
-
filesInputRef.current.click();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const errorWrapper = state.errorMsg ? <S.ErrorMsg>{state.errorMsg}</S.ErrorMsg> : null;
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<S.Wrapper data-testid="file-drag-and-drop-wrapper">
|
|
112
|
-
<S.DragAndDropWrapper
|
|
113
|
-
inDropZone={state.inDropZone}
|
|
114
|
-
uploading={state.isUploading}
|
|
115
|
-
success={state.isSuccess}
|
|
116
|
-
error={state.isError}
|
|
117
|
-
>
|
|
118
|
-
<DragAndDrop
|
|
119
|
-
onDrop={handleDrop}
|
|
120
|
-
onDragOver={handleDragOver}
|
|
121
|
-
onDragEnter={handleDragEnter}
|
|
122
|
-
onDragLeave={handleDragLeave}
|
|
123
|
-
validFormats={validFormats}
|
|
124
|
-
>
|
|
125
|
-
<S.StatusWrapper>
|
|
126
|
-
<S.DragStatus>
|
|
127
|
-
<S.DragIcon>
|
|
128
|
-
<Icon name="uploadFile" size="48" />
|
|
129
|
-
</S.DragIcon>
|
|
130
|
-
<S.DragTitle>Drag your file here</S.DragTitle>
|
|
131
|
-
<S.DragSubtitle>or</S.DragSubtitle>
|
|
132
|
-
<S.FilesInput type="file" ref={filesInputRef} multiple accept={validExtensions} />
|
|
133
|
-
<S.FilesButton ref={filesButtonRef} type="button" buttonStyle="line" onClick={handleFileClick}>
|
|
134
|
-
Select files
|
|
135
|
-
</S.FilesButton>
|
|
136
|
-
<S.DragSubtitle>Valid formats: {validFormats.join(", ")}. Max. size: {MAX_SIZE}MB</S.DragSubtitle>
|
|
137
|
-
</S.DragStatus>
|
|
138
|
-
<S.DragOverStatus>
|
|
139
|
-
<S.DragIcon>
|
|
140
|
-
<Icon name="success" size="48" />
|
|
141
|
-
</S.DragIcon>
|
|
142
|
-
<S.DragTitle>Drop your file</S.DragTitle>
|
|
143
|
-
<S.DragSubtitle>Valid formats: {validFormats.join(", ")}. Max. size: {MAX_SIZE}MB</S.DragSubtitle>
|
|
144
|
-
</S.DragOverStatus>
|
|
145
|
-
</S.StatusWrapper>
|
|
146
|
-
</DragAndDrop>
|
|
147
|
-
</S.DragAndDropWrapper>
|
|
148
|
-
<S.UploadingWrapper
|
|
149
|
-
inDropZone={state.inDropZone}
|
|
150
|
-
uploading={state.isUploading}
|
|
151
|
-
success={state.isSuccess}
|
|
152
|
-
error={state.isError}
|
|
153
|
-
>
|
|
154
|
-
<S.StatusWrapper>
|
|
155
|
-
<S.UploadingStatus>
|
|
156
|
-
<S.DragIcon>
|
|
157
|
-
<Icon name="uploadFile" size="48" />
|
|
158
|
-
</S.DragIcon>
|
|
159
|
-
<S.DragTitle>Uploading...</S.DragTitle>
|
|
160
|
-
</S.UploadingStatus>
|
|
161
|
-
<S.SuccessStatus>
|
|
162
|
-
<S.DragIcon>
|
|
163
|
-
<Icon name="success" size="48" />
|
|
164
|
-
</S.DragIcon>
|
|
165
|
-
<S.DragTitle>File loaded!</S.DragTitle>
|
|
166
|
-
</S.SuccessStatus>
|
|
167
|
-
<S.ErrorStatus>
|
|
168
|
-
<S.DragIcon>
|
|
169
|
-
<Icon name="alert" size="48" />
|
|
170
|
-
</S.DragIcon>
|
|
171
|
-
<S.DragTitle>Error uploading file</S.DragTitle>
|
|
172
|
-
{errorWrapper}
|
|
173
|
-
<S.StyledButton type="button" buttonStyle="text" onClick={handleTryAgain}>
|
|
174
|
-
TRY AGAIN
|
|
175
|
-
</S.StyledButton>
|
|
176
|
-
</S.ErrorStatus>
|
|
177
|
-
</S.StatusWrapper>
|
|
178
|
-
</S.UploadingWrapper>
|
|
179
|
-
</S.Wrapper>
|
|
180
|
-
);
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
interface IProps {
|
|
184
|
-
validFormats: string[];
|
|
185
|
-
addFile: (file: any) => void;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export default memo(FileDragAndDrop);
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
const SET_DROP_DEPTH = "SET_DROP_DEPTH";
|
|
2
|
-
const SET_IN_DROP_ZONE = "SET_IN_DROP_ZONE";
|
|
3
|
-
const SET_IS_UPLOADING = "SET_IS_UPLOADING";
|
|
4
|
-
const SET_UPLOAD_SUCCESS = "SET_UPLOAD_SUCCESS";
|
|
5
|
-
const SET_UPLOAD_ERROR = "SET_UPLOAD_ERROR";
|
|
6
|
-
export const MAX_SIZE = 50; // MB
|
|
7
|
-
|
|
8
|
-
export const reducer = (prevState: IGalleryStore, action: any): IGalleryStore => {
|
|
9
|
-
switch (action.type) {
|
|
10
|
-
case SET_DROP_DEPTH:
|
|
11
|
-
return { ...prevState, dropDepth: action.payload.dropDepth };
|
|
12
|
-
case SET_IN_DROP_ZONE:
|
|
13
|
-
return { ...prevState, inDropZone: action.payload.inDropZone, isUploading: false, isError: false, isSuccess: false, errorMsg: "" };
|
|
14
|
-
case SET_IS_UPLOADING:
|
|
15
|
-
return { ...prevState, inDropZone: false, isUploading: true };
|
|
16
|
-
case SET_UPLOAD_SUCCESS:
|
|
17
|
-
return { ...prevState, isUploading: false, isSuccess: true };
|
|
18
|
-
case SET_UPLOAD_ERROR:
|
|
19
|
-
return { ...prevState, inDropZone: false, isUploading: false, isError: true, errorMsg: action.payload.msg };
|
|
20
|
-
default:
|
|
21
|
-
return prevState;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export function setDropDepth(dropDepth: number) {
|
|
26
|
-
return { type: SET_DROP_DEPTH, payload: { dropDepth } };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function setInDropZone(inDropZone: boolean) {
|
|
30
|
-
return { type: SET_IN_DROP_ZONE, payload: { inDropZone } };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function setIsUploading() {
|
|
34
|
-
return { type: SET_IS_UPLOADING };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function setUploadSuccess() {
|
|
38
|
-
return { type: SET_UPLOAD_SUCCESS };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function setUploadError(errorMsg: string = "") {
|
|
42
|
-
return { type: SET_UPLOAD_ERROR, payload: { errorMsg } };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const initialState: IGalleryStore = {
|
|
46
|
-
dropDepth: 0,
|
|
47
|
-
inDropZone: false,
|
|
48
|
-
isUploading: false,
|
|
49
|
-
isSuccess: false,
|
|
50
|
-
isError: false,
|
|
51
|
-
errorMsg: "",
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
interface IGalleryStore {
|
|
55
|
-
dropDepth: number;
|
|
56
|
-
inDropZone: boolean;
|
|
57
|
-
isUploading: boolean;
|
|
58
|
-
isSuccess: boolean;
|
|
59
|
-
isError: boolean;
|
|
60
|
-
errorMsg: string;
|
|
61
|
-
}
|