@onehat/ui 0.3.183 → 0.3.186

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.183",
3
+ "version": "0.3.186",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -49,7 +49,8 @@
49
49
  "react-draggable": "^4.4.5",
50
50
  "react-native": "*",
51
51
  "react-native-draggable": "^3.3.0",
52
- "react-native-svg": "*"
52
+ "react-native-svg": "*",
53
+ "use-file-picker": "^2.1.1"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@babel/core": "^7.22.1",
@@ -297,6 +297,10 @@ export default function withFilters(WrappedComponent) {
297
297
  elementProps.autoSubmit = true;
298
298
  }
299
299
  }
300
+ if (!Element) {
301
+ debugger;
302
+ return; // to protect against errors
303
+ }
300
304
  if (field === 'q') {
301
305
  elementProps.flex = 1;
302
306
  elementProps.minWidth = 100;
@@ -1,4 +1,7 @@
1
1
  import React, { useState, useEffect, } from 'react';
2
+ import {
3
+ Modal,
4
+ } from 'native-base';
2
5
  import Clipboard from '../Icons/Clipboard.js';
3
6
  import Duplicate from '../Icons/Duplicate.js';
4
7
  import Edit from '../Icons/Edit.js';
@@ -6,7 +9,9 @@ import Eye from '../Icons/Eye.js';
6
9
  import Trash from '../Icons/Trash.js';
7
10
  import Plus from '../Icons/Plus.js';
8
11
  import Print from '../Icons/Print.js';
12
+ import UploadDownload from '../Icons/UploadDownload.js';
9
13
  import inArray from '../../Functions/inArray.js';
14
+ import UploadsDownloadsWindow from '../Window/UploadsDownloadsWindow.js';
10
15
  import _ from 'lodash';
11
16
 
12
17
  // Note: A 'present button' will create both a context menu item
@@ -20,6 +25,7 @@ const presetButtons = [
20
25
  'copy',
21
26
  'duplicate',
22
27
  // 'print',
28
+ 'uploadDownload',
23
29
  ];
24
30
 
25
31
  export default function withPresetButtons(WrappedComponent, isGrid = false) {
@@ -34,6 +40,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
34
40
  // extract and pass
35
41
  contextMenuItems = [],
36
42
  additionalToolbarButtons = [],
43
+ useUploadDownload = false,
37
44
  onChangeColumnsConfig,
38
45
  verifyCanEdit,
39
46
  verifyCanDelete,
@@ -60,6 +67,9 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
60
67
  // withComponent
61
68
  self,
62
69
 
70
+ // withData
71
+ Repository,
72
+
63
73
  // withEditor
64
74
  userCanEdit = true,
65
75
  userCanView = true,
@@ -77,6 +87,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
77
87
  selectorSelected,
78
88
  } = props,
79
89
  [isReady, setIsReady] = useState(false),
90
+ [isModalShown, setIsModalShown] = useState(false),
80
91
  [localContextMenuItems, setLocalContextMenuItems] = useState([]),
81
92
  [localAdditionalToolbarButtons, setLocalAdditionalToolbarButtons] = useState([]),
82
93
  [localColumnsConfig, setLocalColumnsConfig] = useState([]),
@@ -124,6 +135,11 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
124
135
  isDisabled = true;
125
136
  }
126
137
  break;
138
+ case 'uploadDownload':
139
+ if (!useUploadDownload) {
140
+ isDisabled = true;
141
+ }
142
+ break;
127
143
  default:
128
144
  }
129
145
  return isDisabled;
@@ -224,6 +240,12 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
224
240
  // handler = onPrint;
225
241
  // icon = <Print />;
226
242
  // break;
243
+ case 'uploadDownload':
244
+ key = 'uploadDownloadBtn';
245
+ text = 'Upload/Download';
246
+ handler = onUploadDownload;
247
+ icon = <UploadDownload />;
248
+ break;
227
249
  default:
228
250
  }
229
251
  return {
@@ -282,7 +304,9 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
282
304
  if (showInfo) {
283
305
  showInfo('Copied to clipboard!');
284
306
  }
285
- };
307
+ },
308
+ onUploadDownload = () => setIsModalShown(true),
309
+ onModalClose = () => setIsModalShown(false);
286
310
  // onPrint = () => {
287
311
  // debugger;
288
312
  // };
@@ -298,18 +322,32 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
298
322
  return null;
299
323
  }
300
324
 
301
- return <WrappedComponent
302
- {...propsToPass}
303
- disablePresetButtons={false}
304
- contextMenuItems={[
305
- ...contextMenuItems,
306
- ...localContextMenuItems,
307
- ]}
308
- additionalToolbarButtons={[
309
- ...additionalToolbarButtons,
310
- ...localAdditionalToolbarButtons,
311
- ]}
312
- onChangeColumnsConfig={onChangeColumnsConfigDecorator}
313
- />;
325
+ return <>
326
+ <WrappedComponent
327
+ {...propsToPass}
328
+ disablePresetButtons={false}
329
+ contextMenuItems={[
330
+ ...contextMenuItems,
331
+ ...localContextMenuItems,
332
+ ]}
333
+ additionalToolbarButtons={[
334
+ ...additionalToolbarButtons,
335
+ ...localAdditionalToolbarButtons,
336
+ ]}
337
+ onChangeColumnsConfig={onChangeColumnsConfigDecorator}
338
+ />
339
+ {isModalShown &&
340
+ <Modal
341
+ isOpen={true}
342
+ onClose={onModalClose}
343
+ >
344
+ <UploadsDownloadsWindow
345
+ reference="uploadsDownloads"
346
+ onClose={onModalClose}
347
+ Repository={Repository}
348
+ columnsConfig={props.columnsConfig}
349
+ />
350
+ </Modal>}
351
+ </>;
314
352
  };
315
353
  }
@@ -13,6 +13,7 @@ import Inflector from 'inflector-js';
13
13
  import Header from './Header.js';
14
14
  import Mask from './Mask.js';
15
15
  import withCollapsible from '../Hoc/withCollapsible.js';
16
+ import withComponent from '../Hoc/withComponent.js';
16
17
  import emptyFn from '../../Functions/emptyFn.js';
17
18
  import UiGlobals from '../../UiGlobals.js';
18
19
  import _ from 'lodash';
@@ -169,4 +170,4 @@ function Panel(props) {
169
170
 
170
171
  }
171
172
 
172
- export default withCollapsible(Panel);
173
+ export default withComponent(withCollapsible(Panel));
@@ -0,0 +1,189 @@
1
+ /**
2
+ * COPYRIGHT NOTICE
3
+ * This file is categorized as "Custom Source Code"
4
+ * and is subject to the terms and conditions defined in the
5
+ * "LICENSE.txt" file, which is part of this source code package.
6
+ */
7
+ import { useState, } from 'react';
8
+ import {
9
+ Icon,
10
+ } from 'native-base';
11
+ import Excel from '../Icons/Excel';
12
+ import Panel from '../Panel/Panel.js';
13
+ import Form from '../Form/Form.js';
14
+ import useAdjustedWindowSize from '../../Hooks/useAdjustedWindowSize.js';
15
+ import downloadWithFetch from '../../Functions/downloadWithFetch.js';
16
+ import withAlert from '../Hoc/withAlert.js';
17
+ import withComponent from '../Hoc/withComponent.js';
18
+ import Cookies from 'js-cookie';
19
+ import _ from 'lodash';
20
+
21
+ function UploadsDownloadsWindow(props) {
22
+ const
23
+ {
24
+ Repository,
25
+ columnsConfig = [],
26
+
27
+ // withComponent
28
+ self,
29
+
30
+ // withAlert
31
+ alert,
32
+ showInfo,
33
+ } = props,
34
+ [importFile, setImportFile] = useState(null),
35
+ [width, height] = useAdjustedWindowSize(400, 400),
36
+ onDownload = (isTemplate = false) => {
37
+ const
38
+ baseURL = Repository.api.baseURL,
39
+ filters = Repository.filters.reduce((result, current) => {
40
+ result[current.name] = current.value;
41
+ return result;
42
+ }, {}),
43
+ columns = columnsConfig.map((column) => {
44
+ return column.fieldName;
45
+ }),
46
+ order = Repository.getSortField() + ' ' + Repository.getSortDirection(),
47
+ model = Repository.name,
48
+ url = baseURL + 'Reports/getReport',
49
+ download_token = 'dl' + (new Date()).getTime(),
50
+ options = {
51
+ // method: 'GET',
52
+ method: 'POST',
53
+ body: JSON.stringify({
54
+ download_token,
55
+ report_id: 1,
56
+ filters,
57
+ columns,
58
+ order,
59
+ model,
60
+ isTemplate,
61
+ }),
62
+ headers: _.merge({ 'Content-Type': 'application/json' }, Repository.headers),
63
+ },
64
+ fetchWindow = downloadWithFetch(url, options),
65
+ interval = setInterval(function() {
66
+ const cookie = Cookies.get(download_token);
67
+ if (fetchWindow.window && cookie) {
68
+ clearInterval(interval);
69
+ Cookies.remove(download_token);
70
+ fetchWindow.window.close();
71
+ }
72
+ }, 1000);
73
+ },
74
+ onDownloadTemplate = () => {
75
+ onDownload(true);
76
+ },
77
+ onUpload = async () => {
78
+ const
79
+ url = Repository.api.baseURL + Repository.name + '/uploadBatch',
80
+ result = await Repository._send('POST', url, { importFile })
81
+ .catch(error => {
82
+ if (Repository.debugMode) {
83
+ console.log(url + ' error', error);
84
+ console.log('response:', error.response);
85
+ }
86
+ });
87
+ if (Repository.debugMode) {
88
+ console.log('Result ' + url, result);
89
+ }
90
+ const
91
+ parsed = JSON.parse(result.data),
92
+ {
93
+ data,
94
+ success,
95
+ message,
96
+ } = parsed;
97
+ if (!success) {
98
+ const msgElements = ['Could not upload.'];
99
+ if (message === 'Errors') {
100
+ // assemble the errors from the upload
101
+ _.each(data, (obj) => {
102
+ // {
103
+ // "2": "ID does not exist."
104
+ // }
105
+ const line = Object.entries(obj)
106
+ .map(([key, value]) => `Line ${key}: ${value}`)
107
+ .join("\n");
108
+ msgElements.push(line);
109
+ });
110
+ }
111
+ alert(msgElements.join("\n"));
112
+ } else {
113
+ setImportFile(null);
114
+ self.formSetValue('file', null);
115
+ showInfo("Upload successful.\n");
116
+ }
117
+ };
118
+
119
+ return <Panel
120
+ {...props}
121
+ parent={self}
122
+ reference="UploadsDownloadsWindow"
123
+ isCollapsible={false}
124
+ title="Uploads & Downloads"
125
+ bg="#fff"
126
+ w={width}
127
+ h={height}
128
+ flex={null}
129
+ >
130
+ <Form
131
+ {...props}
132
+ parent={self}
133
+ reference="form"
134
+ items={[
135
+ {
136
+ "type": "Column",
137
+ "flex": 1,
138
+ "defaults": {},
139
+ "items": [
140
+ {
141
+ type: 'DisplayField',
142
+ text: 'Download an Excel file of the current grid contents.',
143
+ },
144
+ {
145
+ type: 'Button',
146
+ text: 'Download',
147
+ isEditable: false,
148
+ leftIcon: <Icon as={Excel} />,
149
+ onPress: () => onDownload(),
150
+ },
151
+ {
152
+ type: 'DisplayField',
153
+ text: 'Upload an Excel file to the current grid.',
154
+ mt: 10,
155
+ },
156
+ {
157
+ type: 'File',
158
+ name: 'file',
159
+ onChangeValue: setImportFile,
160
+ accept: '.xlsx',
161
+ },
162
+ {
163
+ type: 'Button',
164
+ text: 'Upload',
165
+ isEditable: false,
166
+ leftIcon: <Icon as={Excel} />,
167
+ isDisabled: !importFile,
168
+ onPress: onUpload,
169
+ },
170
+ {
171
+ type: 'Button',
172
+ text: 'Get Template',
173
+ isEditable: false,
174
+ onPress: onDownloadTemplate,
175
+ variant: 'ghost',
176
+ },
177
+ ]
178
+ },
179
+ ]}
180
+ // record={selection}
181
+ // onCancel={onCancel}
182
+ // onSave={onSave}
183
+ // onClose={onClose}
184
+ // onDelete={onDelete}
185
+ />
186
+ </Panel>;
187
+ }
188
+
189
+ export default withComponent(withAlert(UploadsDownloadsWindow));
@@ -1,13 +1,16 @@
1
1
  const downloadWithFetch = (url, options = {}) => {
2
+ let obj = {};
2
3
  fetch(url, options)
3
4
  .then( res => res.blob() )
4
5
  .then( blob => {
5
6
  const
6
7
  winName = 'ReportWindow',
7
8
  opts = 'resizable=yes,height=600,width=800,location=0,menubar=0,scrollbars=1',
8
- externalWindow = window.open('', winName, opts),
9
- file = externalWindow.URL.createObjectURL(blob);
10
- externalWindow.location.assign(file);
9
+ win = window.open('', winName, opts),
10
+ file = win.URL.createObjectURL(blob);
11
+ obj.window = win;
12
+ win.location.assign(file);
11
13
  });
14
+ return obj;
12
15
  };
13
16
  export default downloadWithFetch;
@@ -1,11 +1,8 @@
1
- import { useState, useEffect, useRef, } from 'react';
1
+ import { useEffect, } from 'react';
2
2
  import {
3
- Box,
4
3
  Button,
5
4
  Column,
6
- Pressable,
7
5
  Row,
8
- Spinner,
9
6
  Text,
10
7
  } from 'native-base';
11
8
  import {
@@ -14,52 +11,22 @@ import {
14
11
  UI_MODE_REACT_NATIVE,
15
12
  } from '../../Constants/UiModes.js';
16
13
  import UiGlobals from '../../UiGlobals.js';
17
- import {
18
- FILE_MODE_IMAGE,
19
- FILE_MODE_FILE,
20
- } from '../../Constants/File.js';
21
- import { Avatar, Dropzone, FileMosaic, FileCard, FileInputButton, } from "@files-ui/react";
22
- import inArray from '../../Functions/inArray.js';
14
+ // import {
15
+ // FileAmountLimitValidator,
16
+ // FileTypeValidator,
17
+ // FileSizeValidator,
18
+ // ImageDimensionsValidator,
19
+ // } from 'use-file-picker/validators';
20
+ import { useFilePicker, useImperativeFilePicker } from 'use-file-picker'; // https://www.npmjs.com/package/use-file-picker
23
21
  import IconButton from '../../Components/Buttons/IconButton.js';
24
22
  import Xmark from '../../Components/Icons/Xmark.js'
25
23
  import withAlert from '../../Components/Hoc/withAlert.js';
26
24
  import withValue from '../../Components/Hoc/withValue.js';
27
- import downloadWithFetch from '../../Functions/downloadWithFetch.js';
25
+ import Loading from '../../Components/Messages/Loading.js';
28
26
  import _ from 'lodash';
29
27
 
30
- const
31
- EXPANDED_MAX = 100,
32
- COLLAPSED_MAX = 2;
33
-
34
- function FileCardCustom(props) {
35
- const
36
- {
37
- id,
38
- name: filename,
39
- type: mimetype,
40
- onDelete,
41
- downloadUrl,
42
- uploadStatus,
43
- } = props,
44
- isDownloading = uploadStatus && inArray(uploadStatus, ['preparing', 'uploading', 'success']);
45
- return <Pressable
46
- px={3}
47
- py={1}
48
- alignItems="center"
49
- flexDirection="row"
50
- borderRadius={5}
51
- borderWidth={1}
52
- borderColor="primary.700"
53
- onPress={() => {
54
- downloadWithFetch(downloadUrl);
55
- }}
56
- >
57
- {isDownloading && <Spinner mr={2} />}
58
- <Text>{filename}</Text>
59
- {onDelete && <IconButton ml={1} icon={Xmark} onPress={() => onDelete(id)} />}
60
- </Pressable>;
61
- }
62
28
 
29
+ // This component is used to present a single file upload button
63
30
 
64
31
  function FileComponent(props) {
65
32
 
@@ -68,186 +35,99 @@ function FileComponent(props) {
68
35
  }
69
36
 
70
37
  const {
71
- canCrud = true,
72
- _dropZone = {},
73
- _fileMosaic = {},
74
- useFileMosaic = true,
75
- accept, // 'image/*'
76
- maxFiles = null,
77
- disabled = false,
78
- clickable = true,
79
- confirmBeforeDelete = false,
80
-
81
- // parentContainer
82
- selectorSelected,
38
+ encodeAsBase64 = true,
39
+ readAs = 'BinaryString', // 'DataURL', 'Text', 'BinaryString', 'ArrayBuffer'
40
+ accept, // ['.png', '.txt'], 'image/*', '.txt'
41
+ multiple = false,
42
+ readFilesContent = true, // Ignores files content and omits reading process if set to false
43
+ validators, // [ new FileAmountLimitValidator({ max: 1 }), new FileTypeValidator(['jpg', 'png']), new FileSizeValidator({ maxFileSize: 50 * 1024 * 1024 /* 50 MB */ }), new ImageDimensionsValidator({maxHeight: 900,maxWidth: 1600,minHeight: 600,minWidth: 768,}),]
44
+ onFilesSelected, // always called, even if there are errors
45
+ onFilesRejected, // called when there were validation errors
46
+ onFilesSuccessfullySelected, // called when there were no validation errors
47
+ onFileRemoved, // called when a file is removed from the list of selected files
48
+ onClear, // called when the selection is cleared
83
49
 
84
50
  // withValue
85
51
  value,
86
52
  setValue,
87
-
88
- // withAlert
89
- alert,
90
- confirm,
91
-
92
53
  } = props,
93
54
  styles = UiGlobals.styles,
94
- model = _.isArray(selectorSelected) && selectorSelected[0] ? selectorSelected[0].repository?.name : selectorSelected?.repository?.name,
95
- modelidCalc = _.isArray(selectorSelected) ? _.map(selectorSelected, (entity) => entity.id) : selectorSelected?.id,
96
- modelid = useRef(modelidCalc),
97
- [isReady, setIsReady] = useState(false),
98
- [isUploading, setIsUploading] = useState(false),
99
- [showAll, setShowAll] = useState(false),
100
- [files, setFiles] = useState([]),
101
- // buildFiles = () => {
102
- // const files = _.map(Repository.entities, (entity) => {
103
- // return {
104
- // id: entity.id, // string | number The identifier of the file
105
- // // file: null, // File The file object obtained from client drop or selection
106
- // name: entity.attachments__filename, // string The name of the file
107
- // type: entity.attachments__mimetype, // string The file mime type.
108
- // size: entity.attachments__size, // number The size of the file in bytes.
109
- // // valid: null, // boolean If present, it will show a valid or rejected message ("valid", "denied"). By default valid is undefined.
110
- // // errors: null, // string[] The list of errors according to the validation criteria or the result of the given custom validation function.
111
- // // uploadStatus: null, // UPLOADSTATUS The current upload status. (e.g. "uploading").
112
- // // uploadMessage: null, // string A message that shows the result of the upload process.
113
- // imageUrl: entity.attachments__uri, // string A string representation or web url of the image that will be set to the "src" prop of an <img/> tag. If given, the component will use this image source instead of reading the image file.
114
- // downloadUrl: entity.attachments__uri, // string The url to be used to perform a GET request in order to download the file. If defined, the download icon will be shown.
115
- // // progress: null, // number The current percentage of upload progress. This value will have a higher priority over the upload progress value calculated inside the component.
116
- // // extraUploadData: null, // Record<string, any> The additional data that will be sent to the server when files are uploaded individually
117
- // // extraData: null, // Object Any kind of extra data that could be needed.
118
- // // serverResponse: null, // ServerResponse The upload response from server.
119
- // // xhr: null, // XMLHttpRequest A reference to the XHR object that allows the upload, progress and abort events.
120
- // };
121
- // });
122
- // setFiles(files);
123
- // },
124
- clearFiles = () => {
125
- setFiles([]);
126
- },
127
- toggleShowAll = () => {
128
- setShowAll(!showAll);
129
- },
130
- onDropzoneChange = (files) => {
131
- if (!files.length) {
132
- alert('No files accepted. Perhaps they were too large or the wrong file type?');
133
- return;
134
- }
135
- setFiles(files);
136
- },
137
- onUploadStart = (files) => {
138
- setIsUploading(true);
139
- },
140
- onUploadFinish = (files) => {
141
- let isDoneUploading = true,
142
- isError = false;
143
-
144
- _.each(files, (file) => {
145
- if (!file.xhr || file.xhr.status !== 200) {
146
- isDoneUploading = false;
147
- return false; // break
148
- }
149
- });
150
-
151
- if (isDoneUploading) {
152
- _.each(files, (file) => {
153
- if (file.uploadStatus === 'error') {
154
- isError = true;
155
- const msg = file.serverResponse?.payload || 'An error occurred';
156
- alert(msg);
157
- return false;
158
- }
159
- });
160
- if (!isError) {
161
- setIsUploading(false);
55
+ {
56
+ openFilePicker,
57
+ filesContent,
58
+ loading,
59
+ errors,
60
+ plainFiles,
61
+ clear,
62
+ } = useFilePicker({
63
+ readAs,
64
+ accept,
65
+ multiple,
66
+ readFilesContent,
67
+ validators,
68
+ onFilesSelected,
69
+ onFilesRejected,
70
+ onFilesSuccessfullySelected: ({ filesContent, plainFiles }) => {
71
+ let value = filesContent[0].content;
72
+ if (readAs === 'BinaryString' && encodeAsBase64) {
73
+ value = btoa(value); // convert to base64 encoded string
162
74
  }
163
- }
164
- },
165
- onFileDelete = (id) => {
166
- if (confirmBeforeDelete) {
167
- confirm('Are you sure you want to delete the file?', () => doDelete(id));
168
- } else {
169
- doDelete(id);
170
- }
171
- },
172
- doDelete = (id) => {
173
-
174
-
175
- };
176
-
177
- if (canCrud) {
178
- _fileMosaic.onDelete = onFileDelete;
75
+ setValue(value);
76
+ },
77
+ onFileRemoved,
78
+ onClear: () => setValue(null),
79
+ });
80
+
81
+ useEffect(() => {
82
+ if (errors.length) {
83
+ const
84
+ errorStack = errors.map(err => err.name + ': ' + err.reason),
85
+ msg = errorStack.join("\n");
86
+ alert(msg);
87
+ }
88
+ }, [errors.length]);
89
+
90
+ useEffect(() => {
91
+ if (!value && filesContent.length) {
92
+ clear();
93
+ }
94
+ }, [value, filesContent.length]);
95
+
96
+ if (loading) {
97
+ return <Loading />;
179
98
  }
180
- let content = <Column
181
- w="100%"
182
- p={2}
183
- background={styles.ATTACHMENTS_BG}
184
- >
185
- <Row flexWrap="wrap">
186
- {files.map((file) => {
187
- return <Box
188
- key={file.id}
189
- marginRight={4}
190
- >
191
- {useFileMosaic &&
192
- <FileMosaic
193
- {...file}
194
- backgroundBlurImage={false}
195
- {..._fileMosaic}
196
- />}
197
- {!useFileMosaic &&
198
- <FileCardCustom
199
- {...file}
200
- backgroundBlurImage={false}
201
- {..._fileMosaic}
202
- />}
203
- </Box>;
204
- })}
205
- </Row>
206
- {Repository.total <= COLLAPSED_MAX ? null :
207
- <Button
208
- onPress={toggleShowAll}
209
- mt={4}
210
- _text={{
211
- color: 'trueGray.600',
212
- fontStyle: 'italic',
213
- textAlign: 'left',
214
- width: '100%',
215
- }}
216
- variant="ghost"
217
- >{'Show ' + (showAll ? ' Less' : ' All ' + Repository.total)}</Button>}
218
- </Column>;
219
-
220
- if (canCrud) {
221
- content = <Dropzone
222
- value={files}
223
- onChange={onDropzoneChange}
224
- accept={accept}
225
- maxFiles={maxFiles}
226
- maxFileSize={styles.ATTACHMENTS_MAX_FILESIZE}
227
- autoClean={true}
228
- uploadConfig={{
229
- url: Repository.api.baseURL + Repository.name + '/uploadAttachment',
230
- method: 'POST',
231
- headers: Repository.headers,
232
- autoUpload: true,
233
- }}
234
- headerConfig={{
235
- deleteFiles: false,
236
- }}
237
- onUploadStart={onUploadStart}
238
- onUploadFinish={onUploadFinish}
239
- background={styles.ATTACHMENTS_BG}
240
- color={styles.ATTACHMENTS_COLOR}
241
- minHeight={150}
242
- footer={false}
243
- clickable={clickable}
244
- {..._dropZone}
245
- >
246
- {content}
247
- </Dropzone>;
248
99
 
100
+ let assembledComponents = null;
101
+ if (_.isEmpty(filesContent)) {
102
+ assembledComponents = <Button onPress={() => openFilePicker()}>Select File</Button>;
103
+ } else {
104
+ assembledComponents = <Row
105
+ px={3}
106
+ py={1}
107
+ alignItems="center"
108
+ borderRadius={5}
109
+ borderWidth={1}
110
+ borderColor="primary.700"
111
+ >
112
+ <IconButton
113
+ _icon={{
114
+ as: Xmark,
115
+ color: 'trueGray.600',
116
+ size: 'sm',
117
+ }}
118
+ onPress={() => clear()}
119
+ h="100%"
120
+ bg={styles.FORM_COMBO_TRIGGER_BG}
121
+ _hover={{
122
+ bg: styles.FORM_COMBO_TRIGGER_HOVER_BG,
123
+ }}
124
+ mr={1}
125
+ />
126
+ <Text>{plainFiles[0].name}</Text>
127
+ </Row>;
249
128
  }
250
- return content;
129
+
130
+ return assembledComponents;
251
131
  }
252
132
 
253
133
  export default withAlert(withValue(FileComponent));