From 20fa6743931d77685e4b8ad3923302e2a662621f Mon Sep 17 00:00:00 2001 From: Samuel Shuert Date: Thu, 20 Nov 2025 18:54:26 +0000 Subject: [PATCH] feat: Add Post Creation --- react/src/App.tsx | 15 ++- react/src/components/BlogPostDetail.tsx | 16 ++- react/src/components/BlogPostForm.tsx | 158 ++++++++++++++++++++++++ react/src/components/BlogPostList.tsx | 2 +- react/src/lib/post.ts | 64 +++++----- react/src/main.tsx | 2 + 6 files changed, 223 insertions(+), 34 deletions(-) create mode 100644 react/src/components/BlogPostForm.tsx diff --git a/react/src/App.tsx b/react/src/App.tsx index b03050c..069e62e 100644 --- a/react/src/App.tsx +++ b/react/src/App.tsx @@ -1,11 +1,24 @@ import { posts } from "./lib/post"; import { BlogPostList } from "./components/BlogPostList"; +import { Link } from "react-router"; export function App() { return ( <> + Posts
-

Posts

+
+

+ Posts +

+
+ +
+ New Post +
+ +
+
diff --git a/react/src/components/BlogPostDetail.tsx b/react/src/components/BlogPostDetail.tsx index c882ce5..c90e419 100644 --- a/react/src/components/BlogPostDetail.tsx +++ b/react/src/components/BlogPostDetail.tsx @@ -4,7 +4,11 @@ import { Link } from "react-router"; export function BlogPostDetail() { const { postId } = useParams(); - const post = posts[parseInt(postId!)]; + const post = posts.find((post) => post.id === parseInt(postId!)); + + if (!post) { + return
Post not found
; + } const formattedDate = new Date(post.datePosted).toLocaleDateString("en-US", { month: "long", @@ -13,6 +17,7 @@ export function BlogPostDetail() { }); return ( <> + {post.title}
Home -

+

{post.title}

+
+ +
+ Edit Post +
+ +

diff --git a/react/src/components/BlogPostForm.tsx b/react/src/components/BlogPostForm.tsx new file mode 100644 index 0000000..ac687f5 --- /dev/null +++ b/react/src/components/BlogPostForm.tsx @@ -0,0 +1,158 @@ +import { posts, type BlogPost } from "../lib/post"; +import { useState } from "react"; +import { useNavigate } from "react-router"; +import { useSearchParams } from "react-router"; + +export function BlogPostForm({ + post, + onSubmit, +}: { + post: BlogPost | null; + onSubmit: (post: BlogPost) => void; +}) { + const [postState, setPostState] = useState( + post ?? { + id: posts.length, + title: "", + summary: "", + content: "", + author: "", + datePosted: new Date().toISOString().split("T")[0], + }, + ); + const [missing, setMissing] = useState([]); + + const navigate = useNavigate(); + + const handleChange = ( + event: React.ChangeEvent, + ) => { + const { name, value } = event.target; + setPostState((prevState) => ({ ...prevState, [name]: value })); + }; + + const handleMissing = () => { + const missingFields = Object.entries(postState) + .map(([key, value]) => (value === "" ? key : null)) + .filter((key) => key !== null); + setMissing(missingFields); + }; + + const handleSubmit = (event: React.MouseEvent) => { + event.preventDefault(); + + if ( + !postState.title || + !postState.summary || + !postState.content || + !postState.author + ) { + handleMissing(); + return; + } + + onSubmit(postState); + navigate("/"); + }; + + return ( +

+ + {missing.includes("title") && ( +

Title is required

+ )} +