@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.
@@ -0,0 +1,3 @@
1
+ export default UploadFilesModal;
2
+ declare const UploadFilesModal: React.ForwardRefExoticComponent<React.RefAttributes<any>>;
3
+ import React from 'react';
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,7 @@
1
+ ;
2
+ ;
3
+
4
+ export const compositions = [];
5
+ export const overview = [];
6
+
7
+ export const compositions_metadata = {"compositions":[]};
@@ -0,0 +1,4 @@
1
+ export default useUploadFiles;
2
+ declare function useUploadFiles(api: any, accessToken: any): {
3
+ uploadFiles: (event: any, onProgress: any) => Promise<void>;
4
+ };
@@ -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
+ }
@@ -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
+ }
@@ -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;