a tool for shared writing and social publishing
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};