1"use client";
2
3import { useRouter } from "next/navigation";
4import { useState } from "react";
5
6export function NotesForm() {
7 const router = useRouter();
8 const [title, setTitle] = useState("");
9 const [error, setError] = useState<string | null>(null);
10
11 async function addNote() {
12 const trimmed = title.trim();
13 if (!trimmed) {
14 setError("Title is required.");
15 return;
16 }
17 setError(null);
18 try {
19 const created = await fetch("/api/notes", {
20 method: "POST",
21 headers: {
22 "content-type": "application/json",
23 },
24 body: JSON.stringify({ title: trimmed }),
25 });
26 if (!created.ok) {
27 throw new Error(`create failed: ${created.status}`);
28 }
29 setTitle("");
30 router.refresh();
31 } catch (err) {
32 setError(err instanceof Error ? err.message : String(err));
33 }
34 }
35
36 return (
37 <div className="space-y-2">
38 <form
39 className="flex gap-2"
40 onSubmit={(event) => {
41 event.preventDefault();
42 void addNote();
43 }}
44 >
45 <input
46 data-testid="note-title"
47 className="min-w-0 flex-1 rounded-md border border-slate-300 bg-white px-3 py-2 text-sm"
48 placeholder="Title"
49 value={title}
50 onChange={(event) => setTitle(event.target.value)}
51 />
52 <button
53 data-testid="note-save"
54 type="submit"
55 className="rounded-md bg-slate-900 px-3 py-2 text-sm font-medium text-white"
56 >
57 Add
58 </button>
59 </form>
60 {error ? (
61 <p data-testid="note-status" className="text-sm text-red-600">
62 {error}
63 </p>
64 ) : null}
65 </div>
66 );
67}
68
69export function NoteDelete({ id }: { id: string }) {
70 const router = useRouter();
71 const [error, setError] = useState<string | null>(null);
72
73 async function deleteNote() {
74 setError(null);
75 try {
76 const res = await fetch(`/api/notes/${encodeURIComponent(id)}`, {
77 method: "DELETE",
78 });
79 if (!res.ok) {
80 throw new Error(`delete failed: ${res.status}`);
81 }
82 router.refresh();
83 } catch (err) {
84 setError(err instanceof Error ? err.message : String(err));
85 }
86 }
87
88 return (
89 <span className="shrink-0 text-right">
90 <button
91 data-testid="note-delete"
92 type="button"
93 className="text-sm text-slate-500 underline"
94 onClick={() => void deleteNote()}
95 >
96 Delete
97 </button>
98 {error ? <p className="text-xs text-red-600">{error}</p> : null}
99 </span>
100 );
101}