diff --git a/README.md b/README.md index 71843a6..ebe3cec 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ ### Task 3: Stretch Goals - [ ] Add a rich text editor for note content -- [ ] Implement note categories/tags +- [ ] Implement note categories/tags ✅ - [ ] Add a search functionality for notes - [ ] Implement note editing and deletion - [ ] Add a dark mode toggle diff --git a/index.html b/index.html index 1d68caa..d98ade2 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,19 @@ - + Sticky Notes App - - - + + +
- \ No newline at end of file + diff --git a/package-lock.json b/package-lock.json index 70de9dc..526b0f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,13 @@ "version": "0.0.0", "dependencies": { "@hookform/resolvers": "^3.3.4", - "axios": "^1.9.0", + "axios": "^1.11.0", "lucide-react": "^0.344.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.50.1", + "react-hook-form": "^7.62.0", "react-router-dom": "^6.22.1", - "zod": "^3.22.4" + "zod": "^3.25.76" }, "devDependencies": { "@eslint/js": "^9.9.1", @@ -1844,13 +1844,13 @@ } }, "node_modules/axios": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", - "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -2662,14 +2662,15 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -3761,9 +3762,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.56.1", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.56.1.tgz", - "integrity": "sha512-qWAVokhSpshhcEuQDSANHx3jiAEFzu2HAaaQIzi/r9FNPm1ioAvuJSD4EuZzWd7Al7nTRKcKPnBKO7sRn+zavQ==", + "version": "7.62.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz", + "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -4585,9 +4586,9 @@ } }, "node_modules/zod": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", - "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index cfcfc8e..09c1e56 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,13 @@ }, "dependencies": { "@hookform/resolvers": "^3.3.4", - "axios": "^1.9.0", + "axios": "^1.11.0", "lucide-react": "^0.344.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.50.1", + "react-hook-form": "^7.62.0", "react-router-dom": "^6.22.1", - "zod": "^3.22.4" + "zod": "^3.25.76" }, "devDependencies": { "@eslint/js": "^9.9.1", diff --git a/server/notes.db b/server/notes.db index 9fb91df..e305901 100644 Binary files a/server/notes.db and b/server/notes.db differ diff --git a/src/App.jsx b/src/App.jsx index 0efe0cf..88f4f1c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ -import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; -import Header from './components/Header'; -import CreateNote from './pages/CreateNote'; -import ViewNotes from './pages/ViewNotes'; +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import Header from "./components/Header"; +import CreateNote from "./pages/CreateNote"; +import ViewNotes from "./pages/ViewNotes"; function App() { return ( @@ -19,4 +19,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/components/CreateNoteForm.jsx b/src/components/CreateNoteForm.jsx index ffb1252..d2b1d6a 100644 --- a/src/components/CreateNoteForm.jsx +++ b/src/components/CreateNoteForm.jsx @@ -1,24 +1,123 @@ // TODO: Import useForm, zodResolver, axios, useNavigate, useState, and noteSchema - - +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { noteSchema } from "../schema/notes"; +import { useNavigate } from "react-router-dom"; +import axios from "axios"; import { Save } from "lucide-react"; +import { useState } from "react"; const CreateNoteForm = () => { // TODO: Setup isSubmitting state with useState + const [isSubmitting, setSubmitting] = useState(false); + const [submitError, setSubmitError] = useState(""); // TODO: create navigate variable and set to useNavigate() - + const navigate = useNavigate(); // TODO: Set up the form with useForm from react-hook-form and zodResolver from @hookform/resolvers/zod + const { + register, + handleSubmit, + formState: { errors, isValid, isDirty }, + reset, + } = useForm({ + mode: "onChange", + resolver: zodResolver(noteSchema), + defaultValues: { + title: "", + content: "", + }, + }); const sendToTheServer = async (data) => { // TODO: Send the data to the server + setSubmitting(true); // TODO: Use axios to create a new note in the server using the endpoint http://localhost:3001/api/notes + try { + await axios.post("http://localhost:3001/api/notes", data, { + headers: { + "Content-Type": "application/json", + }, + }); + reset(); + navigate("/notes"); + } catch (error) { + setSubmitError( + "There was an error submitting your form. Please try again." + ); + console.error("Form submission error:", error); + } finally { + setSubmitting(false); + } }; return ( <> -

Create Note

- {/* TODO: Setup the form with TailwindCSS, create a form with the following fields: title, content, and submit button */} + {/* TODO: Setup the form with TailwindCSS, create a form with the following fields: title, content, and submit button */} +
+

+ Create a New Note +

+ + {submitError && ( +
+ +
+

Submission failed

+

{submitError}

+
+
+ )} + +
+
+
+ + + {errors.title && ( +

+ {errors.title.message} +

+ )} +
+
+ +