@bit.rhplus/ui2.upload-files-modal 0.0.1
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/dist/index.d.ts +3 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/dist/preview-1763315539949.js +7 -0
- package/dist/useUploadFiles.d.ts +4 -0
- package/dist/useUploadFiles.js +95 -0
- package/dist/useUploadFiles.js.map +1 -0
- package/index.jsx +246 -0
- package/package.json +32 -0
- package/types/asset.d.ts +43 -0
- package/types/style.d.ts +42 -0
- package/useUploadFiles.js +103 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import DraggableModal from '@bit.rhplus/draggable-modal';
|
|
5
|
+
import { Card, Progress, List, Tag, Button, Typography, Empty } from 'antd';
|
|
6
|
+
import { CheckCircleOutlined, CloseCircleOutlined, SyncOutlined, FileTextOutlined, InboxOutlined, } from '@ant-design/icons';
|
|
7
|
+
import prettyBytes from 'pretty-bytes';
|
|
8
|
+
import useUploadFiles from './useUploadFiles';
|
|
9
|
+
const { Text } = Typography;
|
|
10
|
+
const UploadFilesModal = React.forwardRef((props, ref) => {
|
|
11
|
+
const { api, accessToken, getContainer = () => document.body, } = props;
|
|
12
|
+
const { uploadFiles } = useUploadFiles(api, accessToken);
|
|
13
|
+
const [opened, setOpened] = React.useState(false);
|
|
14
|
+
const [progressFiles, setProgressFiles] = React.useState({});
|
|
15
|
+
const { files: uploadedFiles = [], current = 0, total = 0 } = progressFiles || {};
|
|
16
|
+
const onProgress = (progress) => setProgressFiles(progress);
|
|
17
|
+
const handleFilesSelected = (selectedFiles) => {
|
|
18
|
+
setOpened(true);
|
|
19
|
+
uploadFiles(selectedFiles, onProgress);
|
|
20
|
+
};
|
|
21
|
+
React.useImperativeHandle(ref, () => ({
|
|
22
|
+
handleFilesSelected,
|
|
23
|
+
}));
|
|
24
|
+
// Výpočet celkového progressu
|
|
25
|
+
const overallProgress = React.useMemo(() => {
|
|
26
|
+
if (uploadedFiles.length === 0)
|
|
27
|
+
return 0;
|
|
28
|
+
const completed = uploadedFiles.filter((f) => f.state === 'success' || f.state === 'error').length;
|
|
29
|
+
return Math.round((completed / uploadedFiles.length) * 100);
|
|
30
|
+
}, [uploadedFiles]);
|
|
31
|
+
// Statistiky
|
|
32
|
+
const stats = React.useMemo(() => {
|
|
33
|
+
const success = uploadedFiles.filter((f) => f.state === 'success').length;
|
|
34
|
+
const error = uploadedFiles.filter((f) => f.state === 'error').length;
|
|
35
|
+
const loading = uploadedFiles.filter((f) => f.state === 'loading').length;
|
|
36
|
+
const waiting = uploadedFiles.filter((f) => f.state === 'waiting').length;
|
|
37
|
+
return { success, error, loading, waiting, total: uploadedFiles.length };
|
|
38
|
+
}, [uploadedFiles]);
|
|
39
|
+
// Ikona podle stavu
|
|
40
|
+
const getStatusIcon = (state) => {
|
|
41
|
+
switch (state) {
|
|
42
|
+
case 'success':
|
|
43
|
+
return _jsx(CheckCircleOutlined, { style: { color: '#52c41a', fontSize: 20 } });
|
|
44
|
+
case 'error':
|
|
45
|
+
return _jsx(CloseCircleOutlined, { style: { color: '#ff4d4f', fontSize: 20 } });
|
|
46
|
+
case 'loading':
|
|
47
|
+
return _jsx(SyncOutlined, { spin: true, style: { color: '#1890ff', fontSize: 20 } });
|
|
48
|
+
case 'waiting':
|
|
49
|
+
return _jsx(FileTextOutlined, { style: { color: '#d9d9d9', fontSize: 20 } });
|
|
50
|
+
default:
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// Tag podle stavu
|
|
55
|
+
const getStatusTag = (state) => {
|
|
56
|
+
switch (state) {
|
|
57
|
+
case 'success':
|
|
58
|
+
return (_jsx(Tag, { color: "success", icon: _jsx(CheckCircleOutlined, {}), children: "Nahr\u00E1no" }));
|
|
59
|
+
case 'error':
|
|
60
|
+
return (_jsx(Tag, { color: "error", icon: _jsx(CloseCircleOutlined, {}), children: "Chyba" }));
|
|
61
|
+
case 'loading':
|
|
62
|
+
return (_jsx(Tag, { color: "processing", icon: _jsx(SyncOutlined, { spin: true }), children: "Nahr\u00E1v\u00E1n\u00ED..." }));
|
|
63
|
+
case 'waiting':
|
|
64
|
+
return (_jsx(Tag, { color: "default", icon: _jsx(FileTextOutlined, {}), children: "\u010Cek\u00E1" }));
|
|
65
|
+
default:
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
return (_jsx(DraggableModal, { open: opened, onCancel: () => setOpened(false), getContainer: getContainer, width: "700px", title: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx(InboxOutlined, { style: { fontSize: 20, color: '#1890ff' } }), _jsx("span", { children: "Nahr\u00E1v\u00E1n\u00ED soubor\u016F" }), stats.total > 0 && (_jsxs("span", { style: { fontSize: 12, fontWeight: 'normal', color: '#999' }, children: ["(", stats.success + stats.error, "/", stats.total, ")"] }))] }), footer: () => (_jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }, children: _jsx(Button, { type: "primary", onClick: () => setOpened(false), children: "Zav\u0159\u00EDt" }) })), maskClosable: false, children: _jsxs("div", { style: { padding: '16px 0' }, children: [uploadedFiles.length > 0 && (_jsxs(Card, { size: "small", style: { marginBottom: 16 }, children: [_jsx("div", { style: { marginBottom: 8 }, children: _jsx(Text, { strong: true, children: "Celkov\u00FD pr\u016Fb\u011Bh" }) }), _jsx(Progress, { percent: overallProgress, strokeColor: {
|
|
70
|
+
'0%': '#108ee9',
|
|
71
|
+
'100%': '#87d068',
|
|
72
|
+
}, status: stats.error > 0 && stats.success === 0 ? 'exception' : undefined }), _jsxs("div", { style: {
|
|
73
|
+
marginTop: 12,
|
|
74
|
+
display: 'grid',
|
|
75
|
+
gridTemplateColumns: 'repeat(4, 1fr)',
|
|
76
|
+
gap: 8,
|
|
77
|
+
fontSize: 12,
|
|
78
|
+
}, children: [_jsxs("div", { children: [_jsx("div", { style: { color: '#999' }, children: "Celkem" }), _jsx("div", { style: { fontWeight: 'bold', fontSize: 16 }, children: stats.total })] }), _jsxs("div", { children: [_jsx("div", { style: { color: '#52c41a' }, children: "\u00DAsp\u011B\u0161n\u00E9" }), _jsx("div", { style: { fontWeight: 'bold', fontSize: 16, color: '#52c41a' }, children: stats.success })] }), _jsxs("div", { children: [_jsx("div", { style: { color: '#ff4d4f' }, children: "Chyby" }), _jsx("div", { style: { fontWeight: 'bold', fontSize: 16, color: '#ff4d4f' }, children: stats.error })] }), _jsxs("div", { children: [_jsx("div", { style: { color: '#1890ff' }, children: "Prob\u00EDh\u00E1" }), _jsx("div", { style: { fontWeight: 'bold', fontSize: 16, color: '#1890ff' }, children: stats.loading })] })] })] })), uploadedFiles.length > 0 ? (_jsx(List, { dataSource: uploadedFiles, renderItem: (file) => (_jsx(List.Item, { style: {
|
|
79
|
+
padding: '12px 16px',
|
|
80
|
+
background: file.state === 'error' ? '#fff2f0' : '#fafafa',
|
|
81
|
+
borderRadius: 4,
|
|
82
|
+
marginBottom: 8,
|
|
83
|
+
border: '1px solid',
|
|
84
|
+
borderColor: file.state === 'error' ? '#ffccc7' : '#d9d9d9',
|
|
85
|
+
}, children: _jsx(List.Item.Meta, { avatar: getStatusIcon(file.state), title: _jsxs("div", { style: {
|
|
86
|
+
display: 'flex',
|
|
87
|
+
justifyContent: 'space-between',
|
|
88
|
+
alignItems: 'center',
|
|
89
|
+
}, children: [_jsx("span", { style: {
|
|
90
|
+
fontWeight: 500,
|
|
91
|
+
color: file.state === 'error' ? '#ff4d4f' : '#262626',
|
|
92
|
+
}, children: file.name }), getStatusTag(file.state)] }), description: _jsxs("div", { style: { display: 'flex', gap: 16, fontSize: 12, flexWrap: 'wrap' }, children: [_jsxs("span", { children: ["Velikost: ", prettyBytes(file.size)] }), _jsxs("span", { children: ["Typ: ", file.type || 'neznámý'] }), file.error && (_jsxs("span", { style: { color: '#ff4d4f', fontWeight: 500 }, children: ["Chyba: ", file.error] }))] }) }) })) })) : (_jsx(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE, description: "\u017D\u00E1dn\u00E9 soubory k nahr\u00E1n\u00ED" }))] }) }));
|
|
93
|
+
});
|
|
94
|
+
UploadFilesModal.displayName = 'UploadFilesModal';
|
|
95
|
+
export default UploadFilesModal;
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.jsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import useData from '@bit.rhplus/data';
|
|
3
|
+
const StateEnum = {
|
|
4
|
+
Waiting: 'waiting',
|
|
5
|
+
Loading: 'loading',
|
|
6
|
+
Success: 'success',
|
|
7
|
+
Error: 'error',
|
|
8
|
+
};
|
|
9
|
+
const useUploadFiles = (api, accessToken) => {
|
|
10
|
+
const { fetchData } = useData();
|
|
11
|
+
const uploadFiles = async (event, onProgress) => {
|
|
12
|
+
// Podporuje jak File objekty (z drag&drop) tak FileList (z input)
|
|
13
|
+
let files;
|
|
14
|
+
if (event.target?.files) {
|
|
15
|
+
files = Array.from(event.target.files);
|
|
16
|
+
}
|
|
17
|
+
else if (Array.isArray(event)) {
|
|
18
|
+
files = event;
|
|
19
|
+
}
|
|
20
|
+
else if (event instanceof FileList) {
|
|
21
|
+
files = Array.from(event);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.error('Invalid files input', event);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (files.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
const total = files.length;
|
|
30
|
+
let progress = {
|
|
31
|
+
current: 0,
|
|
32
|
+
total,
|
|
33
|
+
files: files.map(({ name, size, type }) => ({
|
|
34
|
+
name,
|
|
35
|
+
size,
|
|
36
|
+
type,
|
|
37
|
+
state: StateEnum.Waiting,
|
|
38
|
+
error: null,
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
onProgress(progress);
|
|
42
|
+
const uploadFile = async (file, index) => {
|
|
43
|
+
// Set loading state
|
|
44
|
+
progress = {
|
|
45
|
+
...progress,
|
|
46
|
+
files: progress.files.map((f, i) => {
|
|
47
|
+
if (i === index)
|
|
48
|
+
return { ...f, state: StateEnum.Loading };
|
|
49
|
+
return f;
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
onProgress(progress);
|
|
53
|
+
try {
|
|
54
|
+
const formData = new FormData();
|
|
55
|
+
formData.append('Files', file);
|
|
56
|
+
const result = await fetchData(api, formData, accessToken);
|
|
57
|
+
// Set success state
|
|
58
|
+
progress = {
|
|
59
|
+
...progress,
|
|
60
|
+
current: progress.current + 1,
|
|
61
|
+
files: progress.files.map((f, i) => {
|
|
62
|
+
if (i === index)
|
|
63
|
+
return { ...f, state: StateEnum.Success };
|
|
64
|
+
return f;
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// Set error state with message
|
|
70
|
+
const errorMessage = error?.response?.data?.message ||
|
|
71
|
+
error?.message ||
|
|
72
|
+
'Neznámá chyba při nahrávání souboru';
|
|
73
|
+
progress = {
|
|
74
|
+
...progress,
|
|
75
|
+
current: progress.current + 1,
|
|
76
|
+
files: progress.files.map((f, i) => {
|
|
77
|
+
if (i === index)
|
|
78
|
+
return {
|
|
79
|
+
...f,
|
|
80
|
+
state: StateEnum.Error,
|
|
81
|
+
error: errorMessage,
|
|
82
|
+
};
|
|
83
|
+
return f;
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
onProgress(progress);
|
|
88
|
+
};
|
|
89
|
+
// Upload files in parallel
|
|
90
|
+
await Promise.all(files.map((file, index) => uploadFile(file, index)));
|
|
91
|
+
};
|
|
92
|
+
return { uploadFiles };
|
|
93
|
+
};
|
|
94
|
+
export default useUploadFiles;
|
|
95
|
+
//# sourceMappingURL=useUploadFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUploadFiles.js","sourceRoot":"","sources":["../useUploadFiles.js"],"names":[],"mappings":"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"}
|
package/index.jsx
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import DraggableModal from '@bit.rhplus/draggable-modal';
|
|
4
|
+
import { Card, Progress, List, Tag, Button, Typography, Empty } from 'antd';
|
|
5
|
+
import {
|
|
6
|
+
CheckCircleOutlined,
|
|
7
|
+
CloseCircleOutlined,
|
|
8
|
+
SyncOutlined,
|
|
9
|
+
FileTextOutlined,
|
|
10
|
+
InboxOutlined,
|
|
11
|
+
} from '@ant-design/icons';
|
|
12
|
+
import prettyBytes from 'pretty-bytes';
|
|
13
|
+
import useUploadFiles from './useUploadFiles';
|
|
14
|
+
|
|
15
|
+
const { Text } = Typography;
|
|
16
|
+
|
|
17
|
+
const UploadFilesModal = React.forwardRef((props, ref) => {
|
|
18
|
+
const {
|
|
19
|
+
api,
|
|
20
|
+
accessToken,
|
|
21
|
+
getContainer = () => document.body,
|
|
22
|
+
} = props;
|
|
23
|
+
|
|
24
|
+
const { uploadFiles } = useUploadFiles(api, accessToken);
|
|
25
|
+
const [opened, setOpened] = React.useState(false);
|
|
26
|
+
const [progressFiles, setProgressFiles] = React.useState({});
|
|
27
|
+
|
|
28
|
+
const { files: uploadedFiles = [], current = 0, total = 0 } = progressFiles || {};
|
|
29
|
+
|
|
30
|
+
const onProgress = (progress) => setProgressFiles(progress);
|
|
31
|
+
|
|
32
|
+
const handleFilesSelected = (selectedFiles) => {
|
|
33
|
+
setOpened(true);
|
|
34
|
+
uploadFiles(selectedFiles, onProgress);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
React.useImperativeHandle(ref, () => ({
|
|
38
|
+
handleFilesSelected,
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
// Výpočet celkového progressu
|
|
43
|
+
const overallProgress = React.useMemo(() => {
|
|
44
|
+
if (uploadedFiles.length === 0) return 0;
|
|
45
|
+
const completed = uploadedFiles.filter(
|
|
46
|
+
(f) => f.state === 'success' || f.state === 'error'
|
|
47
|
+
).length;
|
|
48
|
+
return Math.round((completed / uploadedFiles.length) * 100);
|
|
49
|
+
}, [uploadedFiles]);
|
|
50
|
+
|
|
51
|
+
// Statistiky
|
|
52
|
+
const stats = React.useMemo(() => {
|
|
53
|
+
const success = uploadedFiles.filter((f) => f.state === 'success').length;
|
|
54
|
+
const error = uploadedFiles.filter((f) => f.state === 'error').length;
|
|
55
|
+
const loading = uploadedFiles.filter((f) => f.state === 'loading').length;
|
|
56
|
+
const waiting = uploadedFiles.filter((f) => f.state === 'waiting').length;
|
|
57
|
+
|
|
58
|
+
return { success, error, loading, waiting, total: uploadedFiles.length };
|
|
59
|
+
}, [uploadedFiles]);
|
|
60
|
+
|
|
61
|
+
// Ikona podle stavu
|
|
62
|
+
const getStatusIcon = (state) => {
|
|
63
|
+
switch (state) {
|
|
64
|
+
case 'success':
|
|
65
|
+
return <CheckCircleOutlined style={{ color: '#52c41a', fontSize: 20 }} />;
|
|
66
|
+
case 'error':
|
|
67
|
+
return <CloseCircleOutlined style={{ color: '#ff4d4f', fontSize: 20 }} />;
|
|
68
|
+
case 'loading':
|
|
69
|
+
return <SyncOutlined spin style={{ color: '#1890ff', fontSize: 20 }} />;
|
|
70
|
+
case 'waiting':
|
|
71
|
+
return <FileTextOutlined style={{ color: '#d9d9d9', fontSize: 20 }} />;
|
|
72
|
+
default:
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Tag podle stavu
|
|
78
|
+
const getStatusTag = (state) => {
|
|
79
|
+
switch (state) {
|
|
80
|
+
case 'success':
|
|
81
|
+
return (
|
|
82
|
+
<Tag color="success" icon={<CheckCircleOutlined />}>
|
|
83
|
+
Nahráno
|
|
84
|
+
</Tag>
|
|
85
|
+
);
|
|
86
|
+
case 'error':
|
|
87
|
+
return (
|
|
88
|
+
<Tag color="error" icon={<CloseCircleOutlined />}>
|
|
89
|
+
Chyba
|
|
90
|
+
</Tag>
|
|
91
|
+
);
|
|
92
|
+
case 'loading':
|
|
93
|
+
return (
|
|
94
|
+
<Tag color="processing" icon={<SyncOutlined spin />}>
|
|
95
|
+
Nahrávání...
|
|
96
|
+
</Tag>
|
|
97
|
+
);
|
|
98
|
+
case 'waiting':
|
|
99
|
+
return (
|
|
100
|
+
<Tag color="default" icon={<FileTextOutlined />}>
|
|
101
|
+
Čeká
|
|
102
|
+
</Tag>
|
|
103
|
+
);
|
|
104
|
+
default:
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<DraggableModal
|
|
111
|
+
open={opened}
|
|
112
|
+
onCancel={() => setOpened(false)}
|
|
113
|
+
getContainer={getContainer}
|
|
114
|
+
width="700px"
|
|
115
|
+
title={
|
|
116
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
117
|
+
<InboxOutlined style={{ fontSize: 20, color: '#1890ff' }} />
|
|
118
|
+
<span>Nahrávání souborů</span>
|
|
119
|
+
{stats.total > 0 && (
|
|
120
|
+
<span style={{ fontSize: 12, fontWeight: 'normal', color: '#999' }}>
|
|
121
|
+
({stats.success + stats.error}/{stats.total})
|
|
122
|
+
</span>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
}
|
|
126
|
+
footer={() => (
|
|
127
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
|
|
128
|
+
<Button type="primary" onClick={() => setOpened(false)}>
|
|
129
|
+
Zavřít
|
|
130
|
+
</Button>
|
|
131
|
+
</div>
|
|
132
|
+
)}
|
|
133
|
+
maskClosable={false}
|
|
134
|
+
>
|
|
135
|
+
<div style={{ padding: '16px 0' }}>
|
|
136
|
+
{/* Overall Progress */}
|
|
137
|
+
{uploadedFiles.length > 0 && (
|
|
138
|
+
<Card size="small" style={{ marginBottom: 16 }}>
|
|
139
|
+
<div style={{ marginBottom: 8 }}>
|
|
140
|
+
<Text strong>Celkový průběh</Text>
|
|
141
|
+
</div>
|
|
142
|
+
<Progress
|
|
143
|
+
percent={overallProgress}
|
|
144
|
+
strokeColor={{
|
|
145
|
+
'0%': '#108ee9',
|
|
146
|
+
'100%': '#87d068',
|
|
147
|
+
}}
|
|
148
|
+
status={stats.error > 0 && stats.success === 0 ? 'exception' : undefined}
|
|
149
|
+
/>
|
|
150
|
+
<div
|
|
151
|
+
style={{
|
|
152
|
+
marginTop: 12,
|
|
153
|
+
display: 'grid',
|
|
154
|
+
gridTemplateColumns: 'repeat(4, 1fr)',
|
|
155
|
+
gap: 8,
|
|
156
|
+
fontSize: 12,
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<div>
|
|
160
|
+
<div style={{ color: '#999' }}>Celkem</div>
|
|
161
|
+
<div style={{ fontWeight: 'bold', fontSize: 16 }}>{stats.total}</div>
|
|
162
|
+
</div>
|
|
163
|
+
<div>
|
|
164
|
+
<div style={{ color: '#52c41a' }}>Úspěšné</div>
|
|
165
|
+
<div style={{ fontWeight: 'bold', fontSize: 16, color: '#52c41a' }}>
|
|
166
|
+
{stats.success}
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
<div>
|
|
170
|
+
<div style={{ color: '#ff4d4f' }}>Chyby</div>
|
|
171
|
+
<div style={{ fontWeight: 'bold', fontSize: 16, color: '#ff4d4f' }}>
|
|
172
|
+
{stats.error}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
<div>
|
|
176
|
+
<div style={{ color: '#1890ff' }}>Probíhá</div>
|
|
177
|
+
<div style={{ fontWeight: 'bold', fontSize: 16, color: '#1890ff' }}>
|
|
178
|
+
{stats.loading}
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</Card>
|
|
183
|
+
)}
|
|
184
|
+
|
|
185
|
+
{/* File List */}
|
|
186
|
+
{uploadedFiles.length > 0 ? (
|
|
187
|
+
<List
|
|
188
|
+
dataSource={uploadedFiles}
|
|
189
|
+
renderItem={(file) => (
|
|
190
|
+
<List.Item
|
|
191
|
+
style={{
|
|
192
|
+
padding: '12px 16px',
|
|
193
|
+
background: file.state === 'error' ? '#fff2f0' : '#fafafa',
|
|
194
|
+
borderRadius: 4,
|
|
195
|
+
marginBottom: 8,
|
|
196
|
+
border: '1px solid',
|
|
197
|
+
borderColor: file.state === 'error' ? '#ffccc7' : '#d9d9d9',
|
|
198
|
+
}}
|
|
199
|
+
>
|
|
200
|
+
<List.Item.Meta
|
|
201
|
+
avatar={getStatusIcon(file.state)}
|
|
202
|
+
title={
|
|
203
|
+
<div
|
|
204
|
+
style={{
|
|
205
|
+
display: 'flex',
|
|
206
|
+
justifyContent: 'space-between',
|
|
207
|
+
alignItems: 'center',
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
<span
|
|
211
|
+
style={{
|
|
212
|
+
fontWeight: 500,
|
|
213
|
+
color: file.state === 'error' ? '#ff4d4f' : '#262626',
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
{file.name}
|
|
217
|
+
</span>
|
|
218
|
+
{getStatusTag(file.state)}
|
|
219
|
+
</div>
|
|
220
|
+
}
|
|
221
|
+
description={
|
|
222
|
+
<div style={{ display: 'flex', gap: 16, fontSize: 12, flexWrap: 'wrap' }}>
|
|
223
|
+
<span>Velikost: {prettyBytes(file.size)}</span>
|
|
224
|
+
<span>Typ: {file.type || 'neznámý'}</span>
|
|
225
|
+
{file.error && (
|
|
226
|
+
<span style={{ color: '#ff4d4f', fontWeight: 500 }}>
|
|
227
|
+
Chyba: {file.error}
|
|
228
|
+
</span>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
}
|
|
232
|
+
/>
|
|
233
|
+
</List.Item>
|
|
234
|
+
)}
|
|
235
|
+
/>
|
|
236
|
+
) : (
|
|
237
|
+
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="Žádné soubory k nahrání" />
|
|
238
|
+
)}
|
|
239
|
+
</div>
|
|
240
|
+
</DraggableModal>
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
UploadFilesModal.displayName = 'UploadFilesModal';
|
|
245
|
+
|
|
246
|
+
export default UploadFilesModal;
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bit.rhplus/ui2.upload-files-modal",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"componentId": {
|
|
6
|
+
"name": "ui2/upload-files-modal",
|
|
7
|
+
"version": "0.0.1",
|
|
8
|
+
"scope": "remote-scope"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@ant-design/icons": "^5.4.0",
|
|
12
|
+
"antd": "^5.20.6",
|
|
13
|
+
"pretty-bytes": "^6.1.1",
|
|
14
|
+
"@bit.rhplus/draggable-modal": "0.0.12",
|
|
15
|
+
"@bit.rhplus/data": "0.0.57"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@bitdev/react.react-env": "4.0.14",
|
|
19
|
+
"@teambit/react.react-env": "1.0.132"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"react": "^17.0.0 || ^18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"license": "SEE LICENSE IN UNLICENSED",
|
|
25
|
+
"optionalDependencies": {},
|
|
26
|
+
"peerDependenciesMeta": {},
|
|
27
|
+
"private": false,
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"scope": "@bit.rhplus",
|
|
30
|
+
"registry": "https://registry.npmjs.org/"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/types/asset.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare module '*.png' {
|
|
2
|
+
const value: any;
|
|
3
|
+
export = value;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.svg' {
|
|
6
|
+
import type { FunctionComponent, SVGProps } from 'react';
|
|
7
|
+
|
|
8
|
+
export const ReactComponent: FunctionComponent<
|
|
9
|
+
SVGProps<SVGSVGElement> & { title?: string }
|
|
10
|
+
>;
|
|
11
|
+
const src: string;
|
|
12
|
+
export default src;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// @TODO Gilad
|
|
16
|
+
declare module '*.jpg' {
|
|
17
|
+
const value: any;
|
|
18
|
+
export = value;
|
|
19
|
+
}
|
|
20
|
+
declare module '*.jpeg' {
|
|
21
|
+
const value: any;
|
|
22
|
+
export = value;
|
|
23
|
+
}
|
|
24
|
+
declare module '*.gif' {
|
|
25
|
+
const value: any;
|
|
26
|
+
export = value;
|
|
27
|
+
}
|
|
28
|
+
declare module '*.bmp' {
|
|
29
|
+
const value: any;
|
|
30
|
+
export = value;
|
|
31
|
+
}
|
|
32
|
+
declare module '*.otf' {
|
|
33
|
+
const value: any;
|
|
34
|
+
export = value;
|
|
35
|
+
}
|
|
36
|
+
declare module '*.woff' {
|
|
37
|
+
const value: any;
|
|
38
|
+
export = value;
|
|
39
|
+
}
|
|
40
|
+
declare module '*.woff2' {
|
|
41
|
+
const value: any;
|
|
42
|
+
export = value;
|
|
43
|
+
}
|
package/types/style.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
declare module '*.module.css' {
|
|
2
|
+
const classes: { readonly [key: string]: string };
|
|
3
|
+
export default classes;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.module.scss' {
|
|
6
|
+
const classes: { readonly [key: string]: string };
|
|
7
|
+
export default classes;
|
|
8
|
+
}
|
|
9
|
+
declare module '*.module.sass' {
|
|
10
|
+
const classes: { readonly [key: string]: string };
|
|
11
|
+
export default classes;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module '*.module.less' {
|
|
15
|
+
const classes: { readonly [key: string]: string };
|
|
16
|
+
export default classes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module '*.less' {
|
|
20
|
+
const classes: { readonly [key: string]: string };
|
|
21
|
+
export default classes;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare module '*.css' {
|
|
25
|
+
const classes: { readonly [key: string]: string };
|
|
26
|
+
export default classes;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare module '*.sass' {
|
|
30
|
+
const classes: { readonly [key: string]: string };
|
|
31
|
+
export default classes;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '*.scss' {
|
|
35
|
+
const classes: { readonly [key: string]: string };
|
|
36
|
+
export default classes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare module '*.mdx' {
|
|
40
|
+
const component: any;
|
|
41
|
+
export default component;
|
|
42
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import useData from '@bit.rhplus/data';
|
|
3
|
+
|
|
4
|
+
const StateEnum = {
|
|
5
|
+
Waiting: 'waiting',
|
|
6
|
+
Loading: 'loading',
|
|
7
|
+
Success: 'success',
|
|
8
|
+
Error: 'error',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const useUploadFiles = (api, accessToken) => {
|
|
12
|
+
const { fetchData } = useData();
|
|
13
|
+
|
|
14
|
+
const uploadFiles = async (event, onProgress) => {
|
|
15
|
+
// Podporuje jak File objekty (z drag&drop) tak FileList (z input)
|
|
16
|
+
let files;
|
|
17
|
+
if (event.target?.files) {
|
|
18
|
+
files = Array.from(event.target.files);
|
|
19
|
+
} else if (Array.isArray(event)) {
|
|
20
|
+
files = event;
|
|
21
|
+
} else if (event instanceof FileList) {
|
|
22
|
+
files = Array.from(event);
|
|
23
|
+
} else {
|
|
24
|
+
console.error('Invalid files input', event);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (files.length === 0) return;
|
|
29
|
+
|
|
30
|
+
const total = files.length;
|
|
31
|
+
|
|
32
|
+
let progress = {
|
|
33
|
+
current: 0,
|
|
34
|
+
total,
|
|
35
|
+
files: files.map(({ name, size, type }) => ({
|
|
36
|
+
name,
|
|
37
|
+
size,
|
|
38
|
+
type,
|
|
39
|
+
state: StateEnum.Waiting,
|
|
40
|
+
error: null,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
onProgress(progress);
|
|
45
|
+
|
|
46
|
+
const uploadFile = async (file, index) => {
|
|
47
|
+
// Set loading state
|
|
48
|
+
progress = {
|
|
49
|
+
...progress,
|
|
50
|
+
files: progress.files.map((f, i) => {
|
|
51
|
+
if (i === index) return { ...f, state: StateEnum.Loading };
|
|
52
|
+
return f;
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
onProgress(progress);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const formData = new FormData();
|
|
59
|
+
formData.append('Files', file);
|
|
60
|
+
const result = await fetchData(api, formData, accessToken);
|
|
61
|
+
|
|
62
|
+
// Set success state
|
|
63
|
+
progress = {
|
|
64
|
+
...progress,
|
|
65
|
+
current: progress.current + 1,
|
|
66
|
+
files: progress.files.map((f, i) => {
|
|
67
|
+
if (i === index) return { ...f, state: StateEnum.Success };
|
|
68
|
+
return f;
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// Set error state with message
|
|
73
|
+
const errorMessage =
|
|
74
|
+
error?.response?.data?.message ||
|
|
75
|
+
error?.message ||
|
|
76
|
+
'Neznámá chyba při nahrávání souboru';
|
|
77
|
+
|
|
78
|
+
progress = {
|
|
79
|
+
...progress,
|
|
80
|
+
current: progress.current + 1,
|
|
81
|
+
files: progress.files.map((f, i) => {
|
|
82
|
+
if (i === index)
|
|
83
|
+
return {
|
|
84
|
+
...f,
|
|
85
|
+
state: StateEnum.Error,
|
|
86
|
+
error: errorMessage,
|
|
87
|
+
};
|
|
88
|
+
return f;
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onProgress(progress);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Upload files in parallel
|
|
97
|
+
await Promise.all(files.map((file, index) => uploadFile(file, index)));
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return { uploadFiles };
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default useUploadFiles;
|