1
1
import { Link } from "@remix-run/react" ;
2
-
3
2
import type { ActionFunctionArgs , LoaderFunctionArgs } from "@remix-run/node" ;
4
3
import { json , redirect } from "@remix-run/node" ;
5
4
import {
@@ -8,11 +7,13 @@ import {
8
7
useParams ,
9
8
useLoaderData ,
10
9
useRouteError ,
10
+ useNavigation ,
11
11
} from "@remix-run/react" ;
12
12
import invariant from "tiny-invariant" ;
13
13
14
- import { deleteNote , getNote } from "~/models/note.server" ;
14
+ import { deleteNote , getNote , updateNote } from "~/models/note.server" ;
15
15
import { requireUserId } from "~/session.server" ;
16
+ import { useState } from "react" ;
16
17
17
18
export const loader = async ( { params, request } : LoaderFunctionArgs ) => {
18
19
const userId = await requireUserId ( request ) ;
@@ -32,48 +33,127 @@ export const action = async ({ params, request }: ActionFunctionArgs) => {
32
33
const userId = await requireUserId ( request ) ;
33
34
invariant ( params . noteId , "noteId not found" ) ;
34
35
35
- console . log ( 'Action: Deleting note with id:' , params . noteId , 'for user:' , userId ) ;
36
+ const formData = await request . formData ( ) ;
37
+ const intent = formData . get ( "intent" ) ;
38
+
39
+ if ( intent === "delete" ) {
40
+ console . log ( 'Action: Deleting note with id:' , params . noteId , 'for user:' , userId ) ;
41
+ try {
42
+ await deleteNote ( { id : params . noteId , userId } ) ;
43
+ return redirect ( "/notes" ) ;
44
+ } catch ( error ) {
45
+ console . error ( 'Error deleting note:' , error ) ;
46
+ throw new Response ( "Failed to delete note" , { status : 500 } ) ;
47
+ }
48
+ } else if ( intent === "update" ) {
49
+ const title = formData . get ( "title" ) as string ;
50
+ const body = formData . get ( "body" ) as string ;
51
+
52
+ if ( ! title || title . length === 0 ) {
53
+ return json ( { errors : { title : "Title is required" } } , { status : 400 } ) ;
54
+ }
55
+ if ( ! body || body . length === 0 ) {
56
+ return json ( { errors : { body : "Body is required" } } , { status : 400 } ) ;
57
+ }
36
58
37
- try {
38
- await deleteNote ( { id : params . noteId , userId } ) ;
39
- return redirect ( "/notes" ) ;
40
- } catch ( error ) {
41
- console . error ( 'Error deleting note:' , error ) ;
42
- throw new Response ( "Failed to delete note" , { status : 500 } ) ;
59
+ console . log ( "Action: Updating note with id:" , params . noteId , "title:" , title , "body:" , body , "userId:" , userId ) ;
60
+
61
+ try {
62
+ await updateNote ( { id : params . noteId , title, body, userId } ) ;
63
+ return json ( { success : true } ) ;
64
+ } catch ( error ) {
65
+ console . error ( "Action Error: Failed to update note:" , error ) ;
66
+ return json (
67
+ { errors : { server : "Failed to update note. Please try again." } } ,
68
+ { status : 500 }
69
+ ) ;
70
+ }
43
71
}
72
+
73
+ return json ( { error : "Invalid intent" } , { status : 400 } ) ;
44
74
} ;
45
75
46
76
export default function NoteDetailsPage ( ) {
47
77
const params = useParams ( ) ;
48
78
const data = useLoaderData < typeof loader > ( ) ;
79
+ const navigation = useNavigation ( ) ;
80
+ const [ isEditing , setIsEditing ] = useState ( false ) ;
49
81
50
82
return (
51
83
< div className = "p-6" >
52
- < h3 className = "text-3xl font-bold mb-4" > { data . note . title } </ h3 >
53
- < p className = "py-6" > { data . note . body } </ p >
54
- < hr className = "my-4" />
55
- < div className = "space-y-4" >
56
- < Form method = "post" onSubmit = { ( e ) => {
57
- if ( ! confirm ( "Are you sure you want to delete this note?" ) ) {
58
- e . preventDefault ( ) ;
59
- }
60
- } } >
61
- < button
62
- type = "submit"
63
- className = "rounded bg-red-500 px-4 py-2 text-white hover:bg-red-600 focus:bg-red-400"
64
- >
65
- Delete
66
- </ button >
84
+ { isEditing ? (
85
+ < Form method = "post" className = "space-y-4" >
86
+ < input type = "hidden" name = "intent" value = "update" />
87
+ < div >
88
+ < label className = "block text-sm font-medium text-gray-700" >
89
+ Title:
90
+ < input
91
+ type = "text"
92
+ name = "title"
93
+ defaultValue = { data . note . title }
94
+ required
95
+ className = "mt-1 block w-full rounded-md border-gray-300 shadow-sm"
96
+ />
97
+ </ label >
98
+ </ div >
99
+ < div >
100
+ < label className = "block text-sm font-medium text-gray-700" >
101
+ Body:
102
+ < textarea
103
+ name = "body"
104
+ defaultValue = { data . note . body }
105
+ required
106
+ rows = { 4 }
107
+ className = "mt-1 block w-full rounded-md border-gray-300 shadow-sm"
108
+ />
109
+ </ label >
110
+ </ div >
111
+ < div className = "flex space-x-4" >
112
+ < button
113
+ type = "submit"
114
+ disabled = { navigation . state === "submitting" }
115
+ className = "rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400"
116
+ >
117
+ { navigation . state === "submitting" ? "Saving..." : "Save" }
118
+ </ button >
119
+ < button
120
+ type = "button"
121
+ onClick = { ( ) => setIsEditing ( false ) }
122
+ className = "rounded bg-gray-500 px-4 py-2 text-white hover:bg-gray-600 focus:bg-gray-400"
123
+ >
124
+ Cancel
125
+ </ button >
126
+ </ div >
67
127
</ Form >
68
- < Link to = { `/notes/${ params . noteId } /edit` } className = "inline-block" >
69
- < button
70
- type = "button"
71
- className = "rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400"
72
- >
73
- Edit
74
- </ button >
75
- </ Link >
76
- </ div >
128
+ ) : (
129
+ < >
130
+ < h3 className = "text-3xl font-bold mb-4" > { data . note . title } </ h3 >
131
+ < p className = "py-6" > { data . note . body } </ p >
132
+ < hr className = "my-4" />
133
+ < div className = "space-y-4" >
134
+ < Form method = "post" onSubmit = { ( e ) => {
135
+ if ( ! confirm ( "Are you sure you want to delete this note?" ) ) {
136
+ e . preventDefault ( ) ;
137
+ }
138
+ } } >
139
+ < input type = "hidden" name = "intent" value = "delete" />
140
+ < button
141
+ type = "submit"
142
+ className = "rounded bg-red-500 px-4 py-2 text-white hover:bg-red-600 focus:bg-red-400"
143
+ >
144
+ Delete
145
+ </ button >
146
+ </ Form >
147
+ < button
148
+ type = "button"
149
+ onClick = { ( ) => setIsEditing ( true ) }
150
+ className = "rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600 focus:bg-blue-400"
151
+ >
152
+ Edit
153
+ </ button >
154
+ </ div >
155
+ </ >
156
+ ) }
77
157
</ div >
78
158
) ;
79
159
}
0 commit comments