@@ -14,7 +14,7 @@ const FileUploadComponent = ({ onFileUpload }) => {
14
14
const [ selectedFiles , setSelectedFiles ] = useState ( [ ] ) ;
15
15
const [ previewFile , setPreviewFile ] = useState ( null ) ;
16
16
const fileInputRef = useRef ( null ) ;
17
- const { captureScreenshot, isCapturing } = useScreenshotCapture ( ) ;
17
+ const { captureScreenshot, isCapturing, isScreenCaptureAvailable } = useScreenshotCapture ( ) ;
18
18
19
19
// Helper function to announce messages to screen readers
20
20
const announceToScreenReader = ( message ) => {
@@ -28,7 +28,21 @@ const FileUploadComponent = ({ onFileUpload }) => {
28
28
} ;
29
29
30
30
const handleFiles = ( files ) => {
31
- const newFileArray = Array . from ( files ) ;
31
+ // Defensive check: ensure files is valid and iterable
32
+ if ( ! files || ! files . length || files . length === 0 ) {
33
+ console . warn ( 'FileUploadComponent: No valid files provided to handleFiles' ) ;
34
+ return ;
35
+ }
36
+
37
+ let newFileArray ;
38
+ try {
39
+ newFileArray = Array . from ( files ) ;
40
+ } catch ( error ) {
41
+ console . error ( 'FileUploadComponent: Error converting files to array:' , error ) ;
42
+ announceToScreenReader ( 'Error processing selected files. Please try again.' ) ;
43
+ return ;
44
+ }
45
+
32
46
const updatedFiles = [ ...selectedFiles , ...newFileArray ] ;
33
47
setSelectedFiles ( updatedFiles ) ;
34
48
@@ -66,19 +80,36 @@ const FileUploadComponent = ({ onFileUpload }) => {
66
80
e . stopPropagation ( ) ;
67
81
setDragActive ( false ) ;
68
82
69
- if ( e . dataTransfer . files && e . dataTransfer . files . length > 0 ) {
70
- handleFiles ( e . dataTransfer . files ) ;
83
+ try {
84
+ if ( e . dataTransfer && e . dataTransfer . files && e . dataTransfer . files . length > 0 ) {
85
+ handleFiles ( e . dataTransfer . files ) ;
86
+ }
87
+ } catch ( error ) {
88
+ console . error ( 'FileUploadComponent: Error in handleDrop:' , error ) ;
89
+ announceToScreenReader ( 'Error processing dropped files. Please try again.' ) ;
71
90
}
72
91
} ;
73
92
74
93
const handleFileSelect = ( e ) => {
75
- if ( e . target . files && e . target . files . length > 0 ) {
76
- handleFiles ( e . target . files ) ;
94
+ try {
95
+ if ( e . target && e . target . files && e . target . files . length > 0 ) {
96
+ handleFiles ( e . target . files ) ;
97
+ }
98
+ } catch ( error ) {
99
+ console . error ( 'FileUploadComponent: Error in handleFileSelect:' , error ) ;
100
+ announceToScreenReader ( 'Error processing selected files. Please try again.' ) ;
77
101
}
78
102
} ;
79
103
80
104
const handleButtonClick = ( ) => {
81
- fileInputRef . current . click ( ) ;
105
+ try {
106
+ if ( fileInputRef . current ) {
107
+ fileInputRef . current . click ( ) ;
108
+ }
109
+ } catch ( error ) {
110
+ console . error ( 'FileUploadComponent: Error in handleButtonClick:' , error ) ;
111
+ announceToScreenReader ( 'Error opening file selection dialog. Please try again.' ) ;
112
+ }
82
113
} ;
83
114
84
115
const handleRemoveFile = ( indexToRemove ) => {
@@ -202,50 +233,52 @@ const FileUploadComponent = ({ onFileUpload }) => {
202
233
203
234
return (
204
235
< div className = "file-upload-container" style = { { padding : '16px' , margin : '8px 0' } } >
205
- < div style = { { display : 'flex' , justifyContent : 'center' , marginBottom : '10px' } } >
206
- < button
207
- onClick = { ( e ) => {
208
- e . preventDefault ( ) ;
209
- handleScreenshotCapture ( ) ;
210
- } }
211
- disabled = { isCapturing }
212
- aria-describedby = "screenshot-help"
213
- aria-label = { isCapturing ? 'Taking screenshot, please wait' : 'Take a screenshot to attach' }
214
- style = { {
215
- display : 'flex' ,
216
- alignItems : 'center' ,
217
- gap : '8px' ,
218
- backgroundColor : '#107180' ,
219
- color : 'white' ,
220
- border : 'none' ,
221
- borderRadius : '5px' ,
222
- padding : '8px 12px' ,
223
- cursor : isCapturing ? 'not-allowed' : 'pointer' ,
224
- fontSize : '14px' ,
225
- fontWeight : '500' ,
226
- boxShadow : '0 1px 3px rgba(0,0,0,0.2)' ,
227
- } }
228
- >
229
- < svg
230
- xmlns = "http://www.w3.org/2000/svg"
231
- width = "16"
232
- height = "16"
233
- viewBox = "0 0 24 24"
234
- fill = "none"
235
- stroke = "currentColor"
236
- strokeWidth = "2"
237
- strokeLinecap = "round"
238
- strokeLinejoin = "round"
236
+ { isScreenCaptureAvailable && (
237
+ < div style = { { display : 'flex' , justifyContent : 'center' , marginBottom : '10px' } } >
238
+ < button
239
+ onClick = { ( e ) => {
240
+ e . preventDefault ( ) ;
241
+ handleScreenshotCapture ( ) ;
242
+ } }
243
+ disabled = { isCapturing }
244
+ aria-describedby = "screenshot-help"
245
+ aria-label = { isCapturing ? 'Taking screenshot, please wait' : 'Take a screenshot to attach' }
246
+ style = { {
247
+ display : 'flex' ,
248
+ alignItems : 'center' ,
249
+ gap : '8px' ,
250
+ backgroundColor : '#107180' ,
251
+ color : 'white' ,
252
+ border : 'none' ,
253
+ borderRadius : '5px' ,
254
+ padding : '8px 12px' ,
255
+ cursor : isCapturing ? 'not-allowed' : 'pointer' ,
256
+ fontSize : '14px' ,
257
+ fontWeight : '500' ,
258
+ boxShadow : '0 1px 3px rgba(0,0,0,0.2)' ,
259
+ } }
239
260
>
240
- < path d = "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" > </ path >
241
- < circle cx = "12" cy = "13" r = "4" > </ circle >
242
- </ svg >
243
- { isCapturing ? 'Taking screenshot...' : 'Take screenshot...' }
244
- </ button >
245
- < span id = "screenshot-help" className = "sr-only" >
246
- Captures the current screen and adds it as an attachment
247
- </ span >
248
- </ div >
261
+ < svg
262
+ xmlns = "http://www.w3.org/2000/svg"
263
+ width = "16"
264
+ height = "16"
265
+ viewBox = "0 0 24 24"
266
+ fill = "none"
267
+ stroke = "currentColor"
268
+ strokeWidth = "2"
269
+ strokeLinecap = "round"
270
+ strokeLinejoin = "round"
271
+ >
272
+ < path d = "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" > </ path >
273
+ < circle cx = "12" cy = "13" r = "4" > </ circle >
274
+ </ svg >
275
+ { isCapturing ? 'Taking screenshot...' : 'Take screenshot...' }
276
+ </ button >
277
+ < span id = "screenshot-help" className = "sr-only" >
278
+ Captures the current screen and adds it as an attachment
279
+ </ span >
280
+ </ div >
281
+ ) }
249
282
250
283
< div
251
284
className = { `file-upload-dropzone ${ dragActive ? "active" : "" } ` }
0 commit comments