Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 8 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sticky Notes App</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
</html>
33 changes: 17 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Binary file modified server/notes.db
Binary file not shown.
10 changes: 5 additions & 5 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -19,4 +19,4 @@ function App() {
);
}

export default App;
export default App;
109 changes: 104 additions & 5 deletions src/components/CreateNoteForm.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<h1>Create Note</h1>
{/* 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 */}
<div className="bg-white rounded-xl shadow-md p-6 md:p-8 max-w-4xl mx-auto">
<h2 className="text-2xl font-bold text-gray-800 mb-6">
Create a New Note
</h2>

{submitError && (
<div className="bg-red-50 border border-red-200 text-red-800 rounded-md p-4 mb-6 flex items-start">
<AlertCircle className="h-5 w-5 mr-2 mt-0.5 flex-shrink-0" />
<div>
<p className="font-medium">Submission failed</p>
<p className="text-sm">{submitError}</p>
</div>
</div>
)}

<form onSubmit={handleSubmit(sendToTheServer)} className="space-y-6">
<div className="flex flex-col align-middle justify-center">
<div className="flex flex-col align-middle justify-center gap-3">
<label htmlFor="Title" className="form-label">
Title
</label>
<input
id="Title"
type="text"
placeholder="Note Title"
className={`w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.name ? "border-red-500" : ""
}`}
{...register("title")}
/>
{errors.title && (
<p className="error-message text-red-500">
{errors.title.message}
</p>
)}
</div>
<div className="flex flex-col align-middle justify-center gap-4 mt-6">
<label htmlFor="content" className="form-label">
Content
</label>
<textarea
id="experience"
rows={6}
className="w-full rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Write your content here..."
{...register("content")}
/>
{errors.content && (
<p className="error-message text-red-500">
{errors.content.message}
</p>
)}
</div>
</div>
<div className="flex justify-center">
<button
type="submit"
className="flex flex-row items-center justify-center gap-x-2 w-full rounded-md border bg-yellow-500 px-3 py-2 text-white font-medium"
>
<Save /> save note
</button>
</div>
</form>
</div>
</>
);
};
Expand Down
36 changes: 19 additions & 17 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import { Sticker as Sticky, Plus, List } from 'lucide-react';
import { Link, useLocation } from 'react-router-dom';
import { Sticker as Sticky, Plus, List } from "lucide-react";
import { Link, useLocation } from "react-router-dom";

const Header = () => {
const { pathname } = useLocation();

return (
<header className="bg-white shadow-sm">
<div className="container mx-auto px-4 py-4">
<nav className="flex items-center justify-between">
<Link to="/" className="flex items-center gap-2 text-yellow-600 font-bold text-xl">
<Link
to="/"
className="flex items-center gap-2 text-yellow-600 font-bold text-xl"
>
<Sticky size={24} />
<span>Sticky Notes</span>
</Link>

<div className="flex gap-4">
<Link
to="/"
<Link
to="/"
className={`flex items-center gap-1 px-3 py-2 rounded-md transition-colors ${
pathname === '/'
? 'bg-yellow-100 text-yellow-700'
: 'hover:bg-gray-100 text-gray-700'
pathname === "/"
? "bg-yellow-100 text-yellow-700"
: "hover:bg-gray-100 text-gray-700"
}`}
>
<Plus size={18} />
<span>Create</span>
</Link>
<Link
to="/notes"

<Link
to="/notes"
className={`flex items-center gap-1 px-3 py-2 rounded-md transition-colors ${
pathname === '/notes'
? 'bg-yellow-100 text-yellow-700'
: 'hover:bg-gray-100 text-gray-700'
pathname === "/notes"
? "bg-yellow-100 text-yellow-700"
: "hover:bg-gray-100 text-gray-700"
}`}
>
<List size={18} />
Expand All @@ -44,4 +46,4 @@ const Header = () => {
);
};

export default Header;
export default Header;
13 changes: 10 additions & 3 deletions src/schema/notes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { z } from "zod";

export const noteSchema = z.object({
//TODO: create the title and content schema,
//TODO: create the title and content schema,
// Make sure the title is required and the content is required
// Make sure the title is max 50 characters and the content is max 500 characters

});
title: z
.string()
.min(1, "Title is required")
.max(50, "Title must be at most 50 characters"),
content: z
.string()
.min(1, "Content is required")
.max(500, "Content must be at most 500 characters"),
});
Loading