Skip to content

Commit 039322b

Browse files
committed
Edit note
1 parent 1480256 commit 039322b

File tree

4 files changed

+350
-0
lines changed

4 files changed

+350
-0
lines changed

app/handlers/notes.handlers.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,76 @@ func handleNotesShow(logger *slog.Logger) http.HandlerFunc {
143143
}
144144
}
145145
}
146+
147+
func handleNotesEdit(logger *slog.Logger) http.HandlerFunc {
148+
return func(w http.ResponseWriter, r *http.Request) {
149+
note := rctx.GetNote(r.Context())
150+
form := forms.UpdateNote{
151+
Title: note.Title,
152+
Content: note.Content,
153+
}
154+
155+
err := pages.NotesEdit(&form, forms.EmptyErrors()).Render(r.Context(), w)
156+
if err != nil {
157+
logger.Error(
158+
"failed to render template",
159+
slog.Any("error", err),
160+
slog.String("template", "NotesEdit"),
161+
)
162+
http.Error(w, "internal server error", http.StatusInternalServerError)
163+
}
164+
}
165+
}
166+
167+
func handleNotesUpdate(logger *slog.Logger, queries *db.Queries) http.HandlerFunc {
168+
return func(w http.ResponseWriter, r *http.Request) {
169+
form, errors := forms.ParseUpdateNote(r)
170+
if errors != nil {
171+
w.WriteHeader(http.StatusUnprocessableEntity)
172+
err := pages.NotesEdit(&form, errors).Render(r.Context(), w)
173+
if err != nil {
174+
logger.Error(
175+
"failed to render template",
176+
slog.Any("error", err),
177+
slog.String("template", "NotesEdit"),
178+
)
179+
http.Error(w, "internal server error", http.StatusInternalServerError)
180+
}
181+
return
182+
}
183+
184+
now := time.Now().UTC()
185+
identity := rctx.GetIdentity(r.Context())
186+
note := rctx.GetNote(r.Context())
187+
_, err := queries.UpdateNote(
188+
r.Context(),
189+
db.UpdateNoteParams{
190+
UpdatedAt: now,
191+
UpdatedBy: sql.NullInt64{Int64: identity.Member.ID, Valid: true},
192+
Title: form.Title,
193+
Content: form.Content,
194+
NoteID: note.ID,
195+
},
196+
)
197+
if err != nil {
198+
logger.Error("error updating note in database", slog.Any("error", err))
199+
http.Error(w, "error updating note", http.StatusInternalServerError)
200+
return
201+
}
202+
203+
sess := rctx.GetSession(r.Context())
204+
sess.AddFlash(session.FlashMessage{
205+
Type: session.FlashType_Success,
206+
Content: "Changes saved successfully",
207+
})
208+
err = sess.Save(r, w)
209+
if err != nil {
210+
logger.Error("failed to save session", slog.Any("error", err))
211+
http.Error(w, "internal server error", http.StatusInternalServerError)
212+
return
213+
}
214+
215+
access := rctx.GetAccess(r.Context())
216+
http.Redirect(w, r, fmt.Sprintf("/s/%s/notes/%s", access.Token, note.PublicID), http.StatusSeeOther)
217+
}
218+
}

app/handlers/routes.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func RegisterRoutes(r chi.Router, cfg *config.Config, logger *slog.Logger, sqlDB
5252
r.Use(rctx.NoteCtxMiddleware(queries))
5353

5454
r.Get("/", handleNotesShow(logger))
55+
r.With(Authorize(access.Action_UpdateNote)).Group(func(r chi.Router) {
56+
r.Get("/edit", handleNotesEdit(logger))
57+
r.Post("/edit", handleNotesUpdate(logger, queries))
58+
})
5559
})
5660

5761
r.Get("/members", handleMembersList(logger, queries))
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package pages
2+
3+
import (
4+
"fmt"
5+
"github.com/nicolashery/simply-shared-notes/app/forms"
6+
"github.com/nicolashery/simply-shared-notes/app/rctx"
7+
"github.com/nicolashery/simply-shared-notes/app/views/layouts"
8+
)
9+
10+
templ NotesEdit(form *forms.UpdateNote, errors forms.Errors) {
11+
{{ access := rctx.GetAccess(ctx) }}
12+
{{ note := rctx.GetNote(ctx) }}
13+
@layouts.Space() {
14+
<div>
15+
<h1 class="text-2xl font-bold mb-4">Edit note</h1>
16+
<form
17+
method="POST"
18+
action={ templ.URL(fmt.Sprintf("/s/%s/notes/%s/edit", access.Token, note.PublicID)) }
19+
class="flex flex-col gap-4"
20+
>
21+
<fieldset class="flex flex-col gap-1.5">
22+
<label for="title" class="text-sm font-semibold">Title</label>
23+
<input
24+
type="text"
25+
name="title"
26+
id="title"
27+
value={ form.Title }
28+
class={ "input w-full", templ.KV("input-error", forms.HasError(errors, "title")) }
29+
/>
30+
for _, e := range forms.GetErrors(errors, "title") {
31+
<p class="text-sm text-error">
32+
{ e }
33+
</p>
34+
}
35+
</fieldset>
36+
<fieldset class="flex flex-col gap-1.5">
37+
<label for="content" class="text-sm font-semibold">Content</label>
38+
<p class="text-sm opacity-60">
39+
Uses <a class="link" target="_blank" href="https://www.markdownguide.org/cheat-sheet/">Markdown</a> syntax.
40+
</p>
41+
<textarea
42+
name="content"
43+
id="content"
44+
class={ "textarea w-full h-48", templ.KV("textarea-error", forms.HasError(errors, "content")) }
45+
>
46+
{ form.Content }
47+
</textarea>
48+
for _, e := range forms.GetErrors(errors, "content") {
49+
<p class="text-sm text-error">
50+
{ e }
51+
</p>
52+
}
53+
</fieldset>
54+
<div class="flex items-center gap-4 mt-4">
55+
<button type="submit" class="btn btn-primary">Save</button>
56+
<a
57+
href={ templ.URL(fmt.Sprintf("/s/%s/notes/%s", access.Token, note.PublicID)) }
58+
class="btn btn-soft"
59+
>Cancel</a>
60+
</div>
61+
</form>
62+
</div>
63+
}
64+
}

app/views/pages/notes_edit.page_templ.go

Lines changed: 209 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)