a tool for shared writing and social publishing
at main 2.0 kB view raw
1import { useCallback } from "react"; 2import { useReplicache } from "src/replicache"; 3import { generateKeyBetween } from "fractional-indexing"; 4import { addImage } from "src/utils/addImage"; 5import { useEntitySetContext } from "components/EntitySetProvider"; 6import { v7 } from "uuid"; 7 8export const useHandleDrop = (params: { 9 parent: string; 10 position: string | null; 11 nextPosition: string | null; 12}) => { 13 let { rep } = useReplicache(); 14 let entity_set = useEntitySetContext(); 15 16 return useCallback( 17 async (e: React.DragEvent) => { 18 e.preventDefault(); 19 e.stopPropagation(); 20 21 if (!rep) return; 22 23 const files = e.dataTransfer.files; 24 if (!files || files.length === 0) return; 25 26 // Filter for image files only 27 const imageFiles = Array.from(files).filter((file) => 28 file.type.startsWith("image/"), 29 ); 30 31 if (imageFiles.length === 0) return; 32 33 let currentPosition = params.position; 34 35 // Calculate positions for all images first 36 const imageBlocks = imageFiles.map((file) => { 37 const entity = v7(); 38 const position = generateKeyBetween( 39 currentPosition, 40 params.nextPosition, 41 ); 42 currentPosition = position; 43 return { file, entity, position }; 44 }); 45 46 // Create all blocks in parallel 47 await Promise.all( 48 imageBlocks.map((block) => 49 rep.mutate.addBlock({ 50 parent: params.parent, 51 factID: v7(), 52 permission_set: entity_set.set, 53 type: "image", 54 position: block.position, 55 newEntityID: block.entity, 56 }), 57 ), 58 ); 59 60 // Upload all images in parallel 61 await Promise.all( 62 imageBlocks.map((block) => 63 addImage(block.file, rep, { 64 entityID: block.entity, 65 attribute: "block/image", 66 }), 67 ), 68 ); 69 70 return true; 71 }, 72 [rep, params.position, params.nextPosition, params.parent, entity_set.set], 73 ); 74};