Skip to content

Commit 1a212df

Browse files
Drag and drop blocks
1 parent 16880df commit 1a212df

4 files changed

Lines changed: 485 additions & 86 deletions

File tree

src/components/Document/DocumentBlockForm.tsx

Lines changed: 135 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
DELETE_DOCUMENT_BLOCK_BY_ID,
55
UPDATE_DOCUMENT_BLOCK_BY_ID,
66
} from '@/db/queries-qraphql'
7-
import { useState } from 'react'
7+
import { useState, useEffect } from 'react'
88
import { Button, Input, TextArea } from '@/components'
99
import classes from './document.module.css'
1010

@@ -21,14 +21,30 @@ type DocumentBlockFormProps = {
2121
documentId: string
2222
blockData: BlockData
2323
onDelete?: (id: string) => void
24+
onDragStart?: (e: React.DragEvent, blockId: string) => void
25+
onDragOver?: (e: React.DragEvent) => void
26+
onDragEnd?: () => void
27+
isCollapsed?: boolean
2428
}
2529
export const DocumentBlockForm = ({
2630
documentId,
2731
blockData,
2832
onDelete,
33+
onDragStart,
34+
onDragOver,
35+
onDragEnd,
36+
isCollapsed,
2937
}: DocumentBlockFormProps) => {
38+
if (blockData.id === '0fed5846-04f5-43ad-bd56-6d64d37a4f6e') {
39+
console.log('DocumentBlockForm blockData', blockData)
40+
}
3041
const [currentBlockData, setCurrentBlockData] = useState<BlockData>(blockData)
3142

43+
// Update local state when blockData prop changes
44+
useEffect(() => {
45+
setCurrentBlockData(blockData)
46+
}, [blockData])
47+
3248
const [deleteDocumentBlock] = useMutation(DELETE_DOCUMENT_BLOCK_BY_ID)
3349
const [updateDocumentBlock] = useMutation(UPDATE_DOCUMENT_BLOCK_BY_ID)
3450
const [createDocumentBlock] = useMutation(CREATE_DOCUMENT_BLOCK)
@@ -98,72 +114,125 @@ export const DocumentBlockForm = ({
98114
}
99115
}
100116

117+
const handleDragStart = (e: React.DragEvent) => {
118+
if (onDragStart) {
119+
onDragStart(e, currentBlockData.id || `temp-${currentBlockData.position}`)
120+
}
121+
}
122+
123+
const handleDragOver = (e: React.DragEvent) => {
124+
e.preventDefault()
125+
if (onDragOver) {
126+
onDragOver(e)
127+
}
128+
}
129+
130+
const handleDragEnd = () => {
131+
onDragEnd?.()
132+
}
133+
101134
return (
102-
<form
103-
className={classes.documentBlockForm}
104-
onSubmit={(e) => {
105-
e.preventDefault()
106-
handleSubmit()
107-
}}
135+
<div
136+
className={`${classes.container} ${isCollapsed ? classes.dragging : ''}`}
137+
draggable
138+
onDragStart={handleDragStart}
139+
onDragOver={handleDragOver}
140+
onDragEnd={handleDragEnd}
108141
>
109-
<p>Block {currentBlockData.position}</p>
110-
<fieldset>
111-
<label htmlFor="block_type">Type</label>
112-
<select
113-
name="type"
114-
onChange={handleTypeChange}
115-
value={currentBlockData.type}
116-
disabled={!!currentBlockData.id}
117-
>
118-
<option value="paragraph">Paragraph</option>
119-
<option value="heading2">Heading 2</option>
120-
<option value="heading3">Heading 3</option>
121-
<option value="list">List</option>
122-
<option value="youtube">Youtube</option>
123-
<option value="image">Image</option>
124-
<option value="quote">Quote</option>
125-
</select>
126-
</fieldset>
127-
{['heading2', 'heading3'].includes(currentBlockData.type) && (
128-
<Input
129-
label="Title"
130-
name="title"
131-
type="text"
132-
value={currentBlockData.title || ''}
133-
onChange={handleChange}
134-
required
135-
/>
136-
)}
137-
{['paragraph', 'list', 'quote'].includes(currentBlockData.type) && (
138-
<TextArea
139-
label="Content"
140-
name="content"
141-
rows={10}
142-
value={currentBlockData.content}
143-
onChange={(e) => {
144-
setCurrentBlockData({
145-
...currentBlockData,
146-
[e.target.name]: e.target.value,
147-
})
148-
}}
149-
/>
150-
)}
151-
{['youtube', 'image', 'quote'].includes(currentBlockData.type) && (
152-
<Input
153-
label="URL"
154-
name="url"
155-
type="url"
156-
value={currentBlockData.url || ''}
157-
onChange={handleChange}
158-
placeholder="https://example.com"
159-
/>
160-
)}
161-
<Button type="submit">
162-
{currentBlockData.id ? 'Update block' : 'Create block'}
163-
</Button>
164-
<Button type="button" variant="danger" onClick={handleDelete}>
165-
Delete block
166-
</Button>
167-
</form>
142+
<div className={classes.blockHeader}>
143+
<div>{currentBlockData.position}</div>
144+
{!!currentBlockData.id && <div>Type: {currentBlockData.type}</div>}
145+
</div>
146+
147+
<form
148+
className={classes.form}
149+
onSubmit={(e) => {
150+
e.preventDefault()
151+
handleSubmit()
152+
}}
153+
>
154+
{!isCollapsed && (
155+
<>
156+
{!currentBlockData.id && (
157+
<fieldset>
158+
<label htmlFor="block_type">Type</label>
159+
<select
160+
name="type"
161+
onChange={handleTypeChange}
162+
value={currentBlockData.type}
163+
>
164+
<option value="paragraph">Paragraph</option>
165+
<option value="heading2">Heading 2</option>
166+
<option value="heading3">Heading 3</option>
167+
<option value="list">List</option>
168+
<option value="youtube">Youtube</option>
169+
<option value="image">Image</option>
170+
<option value="quote">Quote</option>
171+
</select>
172+
</fieldset>
173+
)}
174+
{['heading2', 'heading3'].includes(currentBlockData.type) && (
175+
<Input
176+
id={`title_${currentBlockData.id}`}
177+
label="Title"
178+
name="title"
179+
type="text"
180+
value={currentBlockData.title || ''}
181+
onChange={handleChange}
182+
required
183+
/>
184+
)}
185+
{['paragraph', 'list', 'quote'].includes(currentBlockData.type) && (
186+
<TextArea
187+
id={`content_${currentBlockData.id}`}
188+
label="Content"
189+
name="content"
190+
rows={10}
191+
value={currentBlockData.content}
192+
onChange={(e) => {
193+
setCurrentBlockData({
194+
...currentBlockData,
195+
[e.target.name]: e.target.value,
196+
})
197+
}}
198+
/>
199+
)}
200+
{['youtube', 'image', 'quote'].includes(currentBlockData.type) && (
201+
<Input
202+
id={`url_${currentBlockData.id}`}
203+
label="URL"
204+
name="url"
205+
type="url"
206+
value={currentBlockData.url || ''}
207+
onChange={handleChange}
208+
placeholder="https://example.com"
209+
/>
210+
)}
211+
<div className={classes.blockActions}>
212+
<Button type="submit">
213+
{currentBlockData.id ? 'Update block' : 'Create block'}
214+
</Button>
215+
<Button type="button" variant="danger" onClick={handleDelete}>
216+
Delete block
217+
</Button>
218+
</div>
219+
</>
220+
)}
221+
222+
{isCollapsed && (
223+
<div className={classes.collapsedContent}>
224+
<div className={classes.blockType}>{currentBlockData.type}</div>
225+
{currentBlockData.title && (
226+
<div className={classes.blockTitle}>{currentBlockData.title}</div>
227+
)}
228+
{currentBlockData.content && (
229+
<div className={classes.blockPreview}>
230+
{currentBlockData.content}
231+
</div>
232+
)}
233+
</div>
234+
)}
235+
</form>
236+
</div>
168237
)
169238
}

0 commit comments

Comments
 (0)