useCsvFileDrop.ts71 lines · main
1import { type ImportDataFileAddedEvent } from 'common/telemetry-constants'
2import { useCallback, useState, type DragEvent } from 'react'
3
4import { flagInvalidFileImport } from '@/components/interfaces/TableGridEditor/SidePanelEditor/SpreadsheetImport/SpreadsheetImport.utils'
5
6interface UseCsvFileDropOptions {
7 enabled: boolean
8 onFileDropped: (file: File) => void
9 onTelemetryEvent?: (eventName: ImportDataFileAddedEvent['action']) => void
10}
11
12interface UseCsvFileDropReturn {
13 isDraggedOver: boolean
14 onDragOver: (event: DragEvent<HTMLDivElement>) => void
15 onFileDrop: (event: DragEvent<HTMLDivElement>) => void
16}
17
18export function useCsvFileDrop({
19 enabled,
20 onFileDropped,
21 onTelemetryEvent,
22}: UseCsvFileDropOptions): UseCsvFileDropReturn {
23 const [isDraggedOver, setIsDraggedOver] = useState(false)
24
25 const onDragOver = useCallback(
26 (event: DragEvent<HTMLDivElement>) => {
27 if (!enabled) return
28
29 const [item] = event.dataTransfer.items
30
31 // ignore non files drop, like column headers
32 if (item && item.kind !== 'file') return
33
34 if (event.type === 'dragover' && !isDraggedOver) {
35 setIsDraggedOver(true)
36 } else if (event.type === 'dragleave' || event.type === 'drop') {
37 setIsDraggedOver(false)
38 }
39 event.stopPropagation()
40 event.preventDefault()
41 },
42 [enabled, isDraggedOver]
43 )
44
45 const onFileDrop = useCallback(
46 (event: DragEvent<HTMLDivElement>) => {
47 if (!enabled) return
48
49 onDragOver(event)
50
51 const [file] = event.dataTransfer.files
52 const [item] = event.dataTransfer.items
53
54 // ignore non files drop, like column headers
55 if (item && item.kind !== 'file') return
56
57 if (flagInvalidFileImport(file)) return
58
59 onFileDropped(file)
60
61 onTelemetryEvent?.('import_data_dropzone_file_added')
62 },
63 [enabled, onDragOver, onFileDropped, onTelemetryEvent]
64 )
65
66 return {
67 isDraggedOver,
68 onDragOver,
69 onFileDrop,
70 }
71}