11import { useState , useEffect } from 'react' ;
22import {
3- Stack ,
43 Text ,
54 Button ,
65 Group ,
@@ -9,70 +8,25 @@ import {
98 Box ,
109 TextInput
1110} from '@mantine/core' ;
12- import { notifications } from '@mantine/notifications' ;
13- import { IconTrash , IconChevronLeft , IconPaperclip , IconDownload } from '@tabler/icons-react' ;
11+ import { IconTrash , IconChevronLeft } from '@tabler/icons-react' ;
1412import { WebStorageService } from '../services/webStorage' ;
1513import { Note } from '../types/sync' ;
1614import { MarkdownEditor } from './MarkdownEditor' ;
1715
18- interface AttachmentsListProps {
19- note : Note ;
20- onRemove : ( attachmentId : string ) => void ;
21- onDownload : ( attachmentId : string ) => void ;
22- isSyncing : boolean ;
23- }
24-
25- function AttachmentsList ( { note, onRemove, onDownload, isSyncing } : AttachmentsListProps ) {
26- if ( ! note . attachments ?. length ) return null ;
27-
28- return (
29- < Stack gap = "xs" mt = "md" >
30- < Text fw = { 500 } size = "sm" > Attachments</ Text >
31- { note . attachments . map ( attachment => (
32- < Group key = { attachment . id } justify = "space-between" >
33- < Text size = "sm" > { attachment . name } </ Text >
34- < Group gap = "xs" >
35- < ActionIcon
36- variant = "subtle"
37- size = "sm"
38- onClick = { ( ) => onDownload ( attachment . id ) }
39- disabled = { isSyncing }
40- >
41- < IconDownload size = { 16 } />
42- </ ActionIcon >
43- < ActionIcon
44- color = "red"
45- variant = "subtle"
46- size = "sm"
47- onClick = { ( ) => onRemove ( attachment . id ) }
48- disabled = { isSyncing }
49- >
50- < IconTrash size = { 16 } />
51- </ ActionIcon >
52- </ Group >
53- </ Group >
54- ) ) }
55- </ Stack >
56- ) ;
57- }
58-
59- interface NoteEditorProps {
16+ export interface NoteEditorProps {
6017 note : Note ;
6118 isMobile ?: boolean ;
6219 isKeyboardVisible ?: boolean ;
6320 onBack ?: ( ) => void ;
64- loadNotes : ( ) => void ;
21+ loadNotes : ( ) => Promise < void > ;
6522}
6623
6724export function NoteEditor ( { note, isMobile = false , isKeyboardVisible = false , onBack, loadNotes } : NoteEditorProps ) {
68- const [ currentNote , setCurrentNote ] = useState ( note ) ;
6925 const [ title , setTitle ] = useState ( note . title || 'Untitled' ) ;
7026 const [ content , setContent ] = useState ( note . content || '' ) ;
7127 const [ saveStatus , setSaveStatus ] = useState < 'saved' | 'saving' | null > ( 'saved' ) ;
72- const [ isSyncing , setIsSyncing ] = useState ( false ) ;
7328
7429 useEffect ( ( ) => {
75- setCurrentNote ( note ) ;
7630 setTitle ( note . title || 'Untitled' ) ;
7731 setContent ( note . content || '' ) ;
7832 } , [ note ] ) ;
@@ -109,88 +63,14 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
10963 }
11064 } , [ isMobile ] ) ;
11165
112- const handleFileUpload = async ( event : React . ChangeEvent < HTMLInputElement > ) => {
113- const file = event . target . files ?. [ 0 ] ;
114- if ( ! file || ! currentNote ?. id ) return ;
115-
116- try {
117- setIsSyncing ( true ) ;
118-
119- if ( file . size > 10 * 1024 * 1024 ) {
120- throw new Error ( 'File size exceeds 10MB limit' ) ;
121- }
122-
123- const updatedNote = await WebStorageService . addAttachment ( currentNote . id , file ) ;
124- setCurrentNote ( updatedNote ) ;
125- await loadNotes ( ) ;
126-
127- notifications . show ( {
128- title : 'Success' ,
129- message : 'File attached successfully' ,
130- color : 'green' ,
131- } ) ;
132- } catch ( error ) {
133- console . error ( 'Failed to attach file:' , error ) ;
134- notifications . show ( {
135- title : 'Error' ,
136- message : error instanceof Error ? error . message : 'Failed to attach file' ,
137- color : 'red' ,
138- } ) ;
139- } finally {
140- setIsSyncing ( false ) ;
141- }
142- } ;
143-
144- const handleDownload = async ( attachmentId : string ) => {
145- try {
146- setIsSyncing ( true ) ;
147- await WebStorageService . downloadAttachment ( note . id ! , attachmentId ) ;
148- } catch ( error ) {
149- console . error ( 'Failed to download file:' , error ) ;
150- notifications . show ( {
151- title : 'Error' ,
152- message : error instanceof Error ? error . message : 'Failed to download file' ,
153- color : 'red' ,
154- } ) ;
155- } finally {
156- setIsSyncing ( false ) ;
157- }
158- } ;
159-
160- const handleRemoveAttachment = async ( attachmentId : string ) => {
161- if ( ! confirm ( 'Are you sure you want to remove this attachment?' ) ) return ;
162-
163- try {
164- setIsSyncing ( true ) ;
165- await WebStorageService . removeAttachment ( note . id ! , attachmentId ) ;
166-
167- // Get the updated note after attachment removal
168- const notes = await WebStorageService . getNotes ( ) ;
169- const updated = notes . find ( n => n . id === note . id ) ;
170- if ( updated ) {
171- setCurrentNote ( updated ) ;
172- }
173-
174- await loadNotes ( ) ;
175- } catch ( error ) {
176- console . error ( 'Failed to remove attachment:' , error ) ;
177- notifications . show ( {
178- title : 'Error' ,
179- message : error instanceof Error ? error . message : 'Failed to remove attachment' ,
180- color : 'red' ,
181- } ) ;
182- } finally {
183- setIsSyncing ( false ) ;
184- }
185- } ;
186-
18766 const saveNote = async ( ) => {
18867 setSaveStatus ( 'saving' ) ;
18968 const updatedNote = {
19069 ...note ,
19170 title,
19271 content,
193- updated_at : Date . now ( )
72+ updated_at : Date . now ( ) ,
73+ pending_sync : true
19474 } ;
19575
19676 await WebStorageService . saveNote ( updatedNote ) ;
@@ -250,18 +130,6 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
250130 size = "md"
251131 onBlur = { saveNote }
252132 />
253- < label htmlFor = "file-upload" >
254- < ActionIcon component = "span" variant = "subtle" radius = "xl" >
255- < IconPaperclip size = { 20 } />
256- </ ActionIcon >
257- </ label >
258- < input
259- id = "file-upload"
260- type = "file"
261- onChange = { handleFileUpload }
262- style = { { display : 'none' } }
263- disabled = { isSyncing }
264- />
265133 </ Group >
266134 </ Paper >
267135
@@ -282,17 +150,6 @@ export function NoteEditor({ note, isMobile = false, isKeyboardVisible = false,
282150 />
283151 </ Box >
284152
285- { currentNote . attachments && currentNote . attachments . length > 0 && (
286- < Paper p = "md" mb = "md" withBorder >
287- < AttachmentsList
288- note = { currentNote }
289- onRemove = { handleRemoveAttachment }
290- onDownload = { handleDownload }
291- isSyncing = { isSyncing }
292- />
293- </ Paper >
294- ) }
295-
296153 < Paper className = "mobile-fixed-bottom" style = { {
297154 position : 'fixed' ,
298155 bottom : 0 ,
0 commit comments