11import { useCallback } from 'react'
2- import { UpdateDocRequestBody } from '../../../api/teams/docs'
2+ import {
3+ createDoc ,
4+ CreateDocRequestBody ,
5+ UpdateDocRequestBody ,
6+ } from '../../../api/teams/docs'
37import { UpdateFolderRequestBody } from '../../../api/teams/folders'
48import { moveResource } from '../../../api/teams/resources'
59import {
@@ -20,23 +24,107 @@ import {
2024} from '../../utils/patterns'
2125import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder'
2226import { SerializedDocWithSupplemental } from '../../../interfaces/db/doc'
27+ import { SerializedTeam } from '../../../interfaces/db/team'
2328import { SidebarDragState } from '../../../../design/lib/dnd'
2429import { useToast } from '../../../../design/lib/stores/toast'
2530import { getMapFromEntityArray } from '../../../../design/lib/utils/array'
2631
32+ const textFileExtensions = new Set ( [ '.md' , '.txt' , '.html' , '.htm' ] )
33+
34+ function getDroppedFiles ( event : any ) {
35+ return Array . from < File > ( event . dataTransfer ?. files || [ ] ) . filter ( ( file ) => {
36+ const lowerCaseName = file . name . toLowerCase ( )
37+ return Array . from ( textFileExtensions ) . some ( ( extension ) =>
38+ lowerCaseName . endsWith ( extension )
39+ )
40+ } )
41+ }
42+
43+ function getDocTitleFromFileName ( fileName : string ) {
44+ const matchingExtension = Array . from ( textFileExtensions ) . find ( ( extension ) =>
45+ fileName . toLowerCase ( ) . endsWith ( extension )
46+ )
47+
48+ if ( matchingExtension == null ) {
49+ return fileName
50+ }
51+
52+ return fileName . slice ( 0 , - matchingExtension . length ) || fileName
53+ }
54+
55+ function readTextFile ( file : File ) {
56+ return new Promise < string > ( ( resolve , reject ) => {
57+ const reader = new FileReader ( )
58+ reader . onload = ( ) => resolve ( String ( reader . result || '' ) )
59+ reader . onerror = ( ) => reject ( reader . error )
60+ reader . readAsText ( file )
61+ } )
62+ }
63+
2764export function useCloudDnd ( ) {
2865 const {
2966 updateFoldersMap,
3067 updateDocsMap,
3168 updateWorkspacesMap,
69+ updateParentFolderOfDoc,
70+ updateParentWorkspaceOfDoc,
3271 setCurrentPath,
3372 } = useNav ( )
3473 const { pageDoc, pageFolder } = usePage ( )
3574 const { pushApiErrorMessage } = useToast ( )
3675
76+ const dropFilesAsDocs = useCallback (
77+ async (
78+ event : any ,
79+ team : SerializedTeam ,
80+ destination : Pick < CreateDocRequestBody , 'workspaceId' | 'parentFolderId' >
81+ ) => {
82+ const files = getDroppedFiles ( event )
83+ if ( files . length === 0 ) {
84+ return false
85+ }
86+
87+ event . preventDefault ( )
88+ event . stopPropagation ( )
89+
90+ try {
91+ for ( const file of files ) {
92+ const content = await readTextFile ( file )
93+ const { doc } = await createDoc (
94+ { id : team . id } ,
95+ {
96+ ...destination ,
97+ title : getDocTitleFromFileName ( file . name ) ,
98+ content,
99+ }
100+ )
101+
102+ updateDocsMap ( [ doc . id , doc ] )
103+
104+ if ( doc . parentFolder != null ) {
105+ updateParentFolderOfDoc ( doc )
106+ } else if ( doc . workspace != null ) {
107+ updateParentWorkspaceOfDoc ( doc )
108+ }
109+ }
110+ } catch ( error ) {
111+ pushApiErrorMessage ( error )
112+ }
113+
114+ return true
115+ } ,
116+ [
117+ pushApiErrorMessage ,
118+ updateDocsMap ,
119+ updateParentFolderOfDoc ,
120+ updateParentWorkspaceOfDoc ,
121+ ]
122+ )
123+
37124 const dropInWorkspace = useCallback (
38125 async (
39126 event : any ,
127+ team : SerializedTeam ,
40128 workspaceId : string ,
41129 updateFolder : (
42130 folder : FolderDataTransferItem ,
@@ -47,6 +135,11 @@ export function useCloudDnd() {
47135 body : UpdateDocRequestBody
48136 ) => Promise < void >
49137 ) => {
138+ const droppedFiles = await dropFilesAsDocs ( event , team , { workspaceId } )
139+ if ( droppedFiles ) {
140+ return
141+ }
142+
50143 const draggedResource = getDraggedResource ( event )
51144 if ( draggedResource === null ) {
52145 return
@@ -69,7 +162,7 @@ export function useCloudDnd() {
69162 } )
70163 }
71164 } ,
72- [ ]
165+ [ dropFilesAsDocs ]
73166 )
74167
75168 const dropInDocOrFolder = useCallback (
@@ -171,6 +264,7 @@ export function useCloudDnd() {
171264 } , [ ] )
172265
173266 return {
267+ dropFilesAsDocs,
174268 dropInWorkspace,
175269 dropInDocOrFolder,
176270 saveFolderTransferData,
0 commit comments