From df7bbef8bf60edbc30b5f6875411f4c0be0ec318 Mon Sep 17 00:00:00 2001 From: Tran Vo Date: Wed, 25 Jun 2025 13:57:27 -0400 Subject: [PATCH 01/11] added basic form to add book and basic states --- src/components/AddBook.jsx | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/components/AddBook.jsx b/src/components/AddBook.jsx index 9f115e7..b793db5 100644 --- a/src/components/AddBook.jsx +++ b/src/components/AddBook.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState} from "react"; /** * A book should have the following fields: @@ -13,8 +13,38 @@ import React from "react"; * - isFavorite (boolean, default false) */ -const AddBook = () => { - return
AddBook
; +const AddBook = () => { //states + const [title, setTitle] = useState(""); + const [author, setAuthor] = useState(""); + + const handleSubmit = (e) => { + e.preventDefault(); + const newBook = { + title: title, + author: author, + ratings: [], + "release date": "" + }; + handleAddBook(newBook); + }; + + return ( +
+

Add a Book

+ +
+ + setTitle(e.target.value)} /> +
+ +
+ + setAuthor(e.target.value)} /> +
+ + +
+ ); }; export default AddBook; From 67278dd19aa847b9d76c4887d863f802227474c4 Mon Sep 17 00:00:00 2001 From: Tran Vo Date: Wed, 25 Jun 2025 14:34:40 -0400 Subject: [PATCH 02/11] added ratings and release date fields and update newBook object --- src/components/AddBook.jsx | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/AddBook.jsx b/src/components/AddBook.jsx index b793db5..1bee5ac 100644 --- a/src/components/AddBook.jsx +++ b/src/components/AddBook.jsx @@ -16,14 +16,17 @@ import React, { useState} from "react"; const AddBook = () => { //states const [title, setTitle] = useState(""); const [author, setAuthor] = useState(""); + const [rating, setRating] = useState(""); + const [releaseDate, setReleaseDate] = useState(""); const handleSubmit = (e) => { e.preventDefault(); + const newBook = { title: title, author: author, - ratings: [], - "release date": "" + ratings: [parseFloat(rating)], + "release date": releaseDate }; handleAddBook(newBook); }; @@ -41,6 +44,25 @@ const AddBook = () => { //states setAuthor(e.target.value)} /> +
+ + setRating(e.target.value)} + type="number" + step="0.1" + /> +
+
+ + setReleaseDate(e.target.value)} + type="text" + placeholder="YYYY-MM-DD" + /> +
+ From e5d3670d411502f676dfe2c5224919d7cdda12a9 Mon Sep 17 00:00:00 2001 From: Jocsan Rodriguez Date: Wed, 25 Jun 2025 15:28:20 -0400 Subject: [PATCH 03/11] bookList --- src/App.jsx | 28 +++++++++++++++++++++++++-- src/components/BookList.jsx | 38 ++++++++++++++++++++++++++++++++++--- src/style.css | 6 +++++- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index c5c0b50..05b85be 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,15 +1,39 @@ -import React from "react"; +// Book Object: { +// title: string, +// author: string, +// ratings: Array of floats, +// release date: "string" +// } + +import React, {useState} from "react"; import { createRoot } from "react-dom/client"; import "./style.css"; import AddBook from "./components/AddBook"; import BookList from "./components/BookList"; const App = () => { + const [books, setBooks] = useState([{ +title: "Book1", +author: "author1", +ratings: [2.5, 5, 3, 3], +releaseDate: "December 2025", +}, +{ +title: "Book2", +author: "author2", +ratings: [3.5, 4, 3.5, 3], +releaseDate: "November 2025", +}, +]); + return (

React Forms! 📝

- + +
+ +
); }; diff --git a/src/components/BookList.jsx b/src/components/BookList.jsx index 0a87a3f..d991a29 100644 --- a/src/components/BookList.jsx +++ b/src/components/BookList.jsx @@ -1,7 +1,39 @@ -import React from "react"; +import React, { useState } from "react"; -const BookList = () => { - return
BookList
; +const BookList = ({books}) => { +const [searchedBook, setSearchedBook] = useState([]); + console.log(searchedBook); + const handleSubmit = (event) => { + event.preventDefault(); + const titleInput = event.target[0].value; + console.log("title:", titleInput); + + for(let i = 0; i < books.length; i++){ + if(books[i].title.toLowerCase().includes(titleInput.toLowerCase())){ + setSearchedBook([...searchedBook, books[i]]); + } + } + + } + + // const clearBar = () => { + // setTitleInput(""); + // } + + return ( + <> +
Book List
+
+ + +
+ + ); }; export default BookList; diff --git a/src/style.css b/src/style.css index e1b4f2c..2f4bcc5 100644 --- a/src/style.css +++ b/src/style.css @@ -25,7 +25,7 @@ body { min-height: 100vh; } -.app * { +.app { color: #ffffff; } @@ -40,3 +40,7 @@ body { .gif-card img { width: 100%; } + +.buttom{ + color: black; +} From 63728d4180cadb4f684ee7eabd1b72a5edfe58dd Mon Sep 17 00:00:00 2001 From: Tran Vo Date: Wed, 25 Jun 2025 15:31:13 -0400 Subject: [PATCH 04/11] added validation/reset form/minor css tweak --- src/components/AddBook.jsx | 23 ++++++++++++++++++++++- src/style.css | 5 +++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/components/AddBook.jsx b/src/components/AddBook.jsx index 1bee5ac..ea09836 100644 --- a/src/components/AddBook.jsx +++ b/src/components/AddBook.jsx @@ -13,14 +13,28 @@ import React, { useState} from "react"; * - isFavorite (boolean, default false) */ -const AddBook = () => { //states +const AddBook = ( { handleAddBook}) => { //states const [title, setTitle] = useState(""); const [author, setAuthor] = useState(""); const [rating, setRating] = useState(""); const [releaseDate, setReleaseDate] = useState(""); + const [error, setError] = useState(""); const handleSubmit = (e) => { e.preventDefault(); + //add validation + + if (!title.trim() || !author.trim() || !rating.trim()) { + setError("Title, author, and rating are required."); + return; +} + +const numericRating = parseFloat(rating); +if (isNaN(numericRating) || numericRating < 1 || numericRating > 5) { + setError("Rating must be a number between 1 and 5."); + return; +} + const newBook = { title: title, @@ -29,7 +43,13 @@ const AddBook = () => { //states "release date": releaseDate }; handleAddBook(newBook); + setTitle(""); + setAuthor(""); + setRating(""); + setReleaseDate(""); + setError(""); }; + return (
@@ -63,6 +83,7 @@ const AddBook = () => { //states /> + {error &&

{error}

}
diff --git a/src/style.css b/src/style.css index e1b4f2c..b1ab1ea 100644 --- a/src/style.css +++ b/src/style.css @@ -7,6 +7,7 @@ body { background-color: #160f29; + color: #160f29; } .title { @@ -40,3 +41,7 @@ body { .gif-card img { width: 100%; } +input { + color: black !important; +} + From 0ef6cb3e9d1c2d4f3e8d054d077b4b3bc3e42184 Mon Sep 17 00:00:00 2001 From: EmmanuelR21 Date: Wed, 25 Jun 2025 15:31:26 -0400 Subject: [PATCH 05/11] Add BookCard component with styling and book details --- src/components/BookCard.jsx | 51 +++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/components/BookCard.jsx b/src/components/BookCard.jsx index b3bbda7..20300c3 100644 --- a/src/components/BookCard.jsx +++ b/src/components/BookCard.jsx @@ -1,7 +1,54 @@ import React from "react"; -const BookCard = () => { - return
BookCard
; +const cardStyling = { + position: "relative", + padding: "10px", + display: "flex", + flexDirection: "column", + alignItems: "center", + backgroundColor: "white", + border: "1px solid red", + margin: "10px", +}; +const imgStyling = { + width: "180px", +}; +const textStyling = { + color: "black", + alignSelf: "flex-start", +}; +const releaseDateStyling = { + position: "absolute", + fontSize: "10px", + fontStyle: "italic", + color: "darkgray", + bottom: 0, + right: 0, +}; +const ratingStyling = { + color: "black", +}; + +const BookCard = ({ title, author, ratings, releaseDate }) => { + const ratingsAverage = Math.round( + ratings.reduce((acc, rating) => acc + rating, 0) / ratings.length, + ); + return ( +
+ {/* Not sure about adding an image, this would then need to also be included in state + + Adding dummy image for now*/} + Image of Book +

{title}

+

{author}

+

Ratings: {ratingsAverage}

+

Release: {releaseDate}

+
+ ); }; export default BookCard; From fbea8fdec677a2253fccd8929b02e661fadd87fe Mon Sep 17 00:00:00 2001 From: Tran Vo Date: Wed, 25 Jun 2025 15:40:17 -0400 Subject: [PATCH 06/11] css for add book submit button/color change --- src/components/AddBook.jsx | 2 +- src/style.css | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/AddBook.jsx b/src/components/AddBook.jsx index ea09836..4061c8f 100644 --- a/src/components/AddBook.jsx +++ b/src/components/AddBook.jsx @@ -85,7 +85,7 @@ if (isNaN(numericRating) || numericRating < 1 || numericRating > 5) { {error &&

{error}

} - + ); }; diff --git a/src/style.css b/src/style.css index b1ab1ea..75a4605 100644 --- a/src/style.css +++ b/src/style.css @@ -44,4 +44,6 @@ body { input { color: black !important; } - +.black-text { + color: black; +} From 2c3ba76a0d573b175d43cbb0b7dffa84f78399d1 Mon Sep 17 00:00:00 2001 From: Tran Vo Date: Wed, 25 Jun 2025 15:45:48 -0400 Subject: [PATCH 07/11] add state and pass props to addbook --- src/App.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index c5c0b50..6ef21db 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,15 +1,21 @@ -import React from "react"; +import React, { useState} from "react"; import { createRoot } from "react-dom/client"; import "./style.css"; import AddBook from "./components/AddBook"; import BookList from "./components/BookList"; const App = () => { + const [books, setBooks] = useState([]); + + const handleAddBook = (newBook) => { + setBooks([...books, newBook]); + }; + return (

React Forms! 📝

- - + +
); }; From 18b79b5db0019665a81241bfbcbc0720aeee1a33 Mon Sep 17 00:00:00 2001 From: EmmanuelR21 Date: Wed, 25 Jun 2025 15:47:22 -0400 Subject: [PATCH 08/11] Format and clean up code in App and BookList components --- src/App.jsx | 41 ++++++++++-------------- src/components/BookList.jsx | 62 +++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 05b85be..8f00989 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,39 +1,30 @@ -// Book Object: { -// title: string, -// author: string, -// ratings: Array of floats, -// release date: "string" -// } - -import React, {useState} from "react"; +import React, { useState } from "react"; import { createRoot } from "react-dom/client"; import "./style.css"; import AddBook from "./components/AddBook"; import BookList from "./components/BookList"; const App = () => { - const [books, setBooks] = useState([{ -title: "Book1", -author: "author1", -ratings: [2.5, 5, 3, 3], -releaseDate: "December 2025", -}, -{ -title: "Book2", -author: "author2", -ratings: [3.5, 4, 3.5, 3], -releaseDate: "November 2025", -}, -]); + const [books, setBooks] = useState([ + { + title: "Book1", + author: "author1", + ratings: [2.5, 5, 3, 3], + releaseDate: "December 2025", + }, + { + title: "Book2", + author: "author2", + ratings: [3.5, 4, 3.5, 3], + releaseDate: "November 2025", + }, + ]); return (

React Forms! 📝

- -
- -
+
); }; diff --git a/src/components/BookList.jsx b/src/components/BookList.jsx index d991a29..d8badb1 100644 --- a/src/components/BookList.jsx +++ b/src/components/BookList.jsx @@ -1,37 +1,51 @@ import React, { useState } from "react"; +import BookCard from "./BookCard"; -const BookList = ({books}) => { -const [searchedBook, setSearchedBook] = useState([]); - console.log(searchedBook); - const handleSubmit = (event) => { +const BookList = ({ books }) => { + const [searchedBook, setSearchedBook] = useState([]); + console.log(searchedBook); + const handleSubmit = (event) => { event.preventDefault(); const titleInput = event.target[0].value; console.log("title:", titleInput); - for(let i = 0; i < books.length; i++){ - if(books[i].title.toLowerCase().includes(titleInput.toLowerCase())){ - setSearchedBook([...searchedBook, books[i]]); + for (let i = 0; i < books.length; i++) { + if (books[i].title.toLowerCase().includes(titleInput.toLowerCase())) { + setSearchedBook([...searchedBook, books[i]]); } - } - - } - - // const clearBar = () => { - // setTitleInput(""); - // } + } + }; return ( <> -
Book List
-
- - -
+
Book List
+
+ + +
+ {searchedBook.length !== 0 + ? searchedBook.map((book) => { + return ( + + ); + }) + : books.map((book) => { + return ( + + ); + })} ); }; From 973bdea1d419e7e5b980bf9edc8159ba3d617df5 Mon Sep 17 00:00:00 2001 From: EmmanuelR21 Date: Wed, 25 Jun 2025 16:07:17 -0400 Subject: [PATCH 09/11] Fix book search to accumulate filtered results correctly --- src/components/BookList.jsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/BookList.jsx b/src/components/BookList.jsx index d8badb1..5c5be8c 100644 --- a/src/components/BookList.jsx +++ b/src/components/BookList.jsx @@ -3,17 +3,18 @@ import BookCard from "./BookCard"; const BookList = ({ books }) => { const [searchedBook, setSearchedBook] = useState([]); - console.log(searchedBook); + const handleSubmit = (event) => { event.preventDefault(); const titleInput = event.target[0].value; - console.log("title:", titleInput); + const filteredBooks = []; for (let i = 0; i < books.length; i++) { if (books[i].title.toLowerCase().includes(titleInput.toLowerCase())) { - setSearchedBook([...searchedBook, books[i]]); + filteredBooks.push(books[i]); } } + setSearchedBook(filteredBooks); }; return ( From 40eb8b0e34abfb83f12d070016c4013bb03f797e Mon Sep 17 00:00:00 2001 From: EmmanuelR21 Date: Wed, 25 Jun 2025 15:31:26 -0400 Subject: [PATCH 10/11] Add BookCard component with styling and book details --- src/components/BookCard.jsx | 51 +++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/components/BookCard.jsx b/src/components/BookCard.jsx index b3bbda7..20300c3 100644 --- a/src/components/BookCard.jsx +++ b/src/components/BookCard.jsx @@ -1,7 +1,54 @@ import React from "react"; -const BookCard = () => { - return
BookCard
; +const cardStyling = { + position: "relative", + padding: "10px", + display: "flex", + flexDirection: "column", + alignItems: "center", + backgroundColor: "white", + border: "1px solid red", + margin: "10px", +}; +const imgStyling = { + width: "180px", +}; +const textStyling = { + color: "black", + alignSelf: "flex-start", +}; +const releaseDateStyling = { + position: "absolute", + fontSize: "10px", + fontStyle: "italic", + color: "darkgray", + bottom: 0, + right: 0, +}; +const ratingStyling = { + color: "black", +}; + +const BookCard = ({ title, author, ratings, releaseDate }) => { + const ratingsAverage = Math.round( + ratings.reduce((acc, rating) => acc + rating, 0) / ratings.length, + ); + return ( +
+ {/* Not sure about adding an image, this would then need to also be included in state + + Adding dummy image for now*/} + Image of Book +

{title}

+

{author}

+

Ratings: {ratingsAverage}

+

Release: {releaseDate}

+
+ ); }; export default BookCard; From 6be0095bc65ee6e31d8c108964a25ed6c3f7c43c Mon Sep 17 00:00:00 2001 From: EmmanuelR21 Date: Thu, 26 Jun 2025 09:54:18 -0400 Subject: [PATCH 11/11] Initialize book list with sample data and fix conflicts --- src/App.jsx | 52 ++++++++++++------------------------- src/components/AddBook.jsx | 33 +++++++++++------------ src/components/BookList.jsx | 37 ++++++++++++-------------- 3 files changed, 50 insertions(+), 72 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index a844220..26bc023 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,56 +1,36 @@ -<<<<<<< HEAD -import React, { useState} from "react"; -======= -// Book Object: { -// title: string, -// author: string, -// ratings: Array of floats, -// release date: "string" -// } - -import React, {useState} from "react"; ->>>>>>> main +import React, { useState } from "react"; import { createRoot } from "react-dom/client"; import "./style.css"; import AddBook from "./components/AddBook"; import BookList from "./components/BookList"; const App = () => { -<<<<<<< HEAD - const [books, setBooks] = useState([]); - + const [books, setBooks] = useState([ + { + title: "Book1", + author: "author1", + ratings: [2.5, 5, 3, 3], + releaseDate: "December 2025", + }, + { + title: "Book2", + author: "author2", + ratings: [3.5, 4, 3.5, 3], + releaseDate: "November 2025", + }, + ]); const handleAddBook = (newBook) => { setBooks([...books, newBook]); }; -======= - const [books, setBooks] = useState([{ -title: "Book1", -author: "author1", -ratings: [2.5, 5, 3, 3], -releaseDate: "December 2025", -}, -{ -title: "Book2", -author: "author2", -ratings: [3.5, 4, 3.5, 3], -releaseDate: "November 2025", -}, -]); ->>>>>>> main return (

React Forms! 📝

-<<<<<<< HEAD - -======= - - +
->>>>>>> main
); }; diff --git a/src/components/AddBook.jsx b/src/components/AddBook.jsx index 4061c8f..f413072 100644 --- a/src/components/AddBook.jsx +++ b/src/components/AddBook.jsx @@ -1,4 +1,4 @@ -import React, { useState} from "react"; +import React, { useState } from "react"; /** * A book should have the following fields: @@ -13,7 +13,8 @@ import React, { useState} from "react"; * - isFavorite (boolean, default false) */ -const AddBook = ( { handleAddBook}) => { //states +const AddBook = ({ handleAddBook }) => { + //states const [title, setTitle] = useState(""); const [author, setAuthor] = useState(""); const [rating, setRating] = useState(""); @@ -24,32 +25,30 @@ const AddBook = ( { handleAddBook}) => { //states e.preventDefault(); //add validation - if (!title.trim() || !author.trim() || !rating.trim()) { - setError("Title, author, and rating are required."); - return; -} - -const numericRating = parseFloat(rating); -if (isNaN(numericRating) || numericRating < 1 || numericRating > 5) { - setError("Rating must be a number between 1 and 5."); - return; -} + if (!title.trim() || !author.trim() || !rating.trim()) { + setError("Title, author, and rating are required."); + return; + } + const numericRating = parseFloat(rating); + if (isNaN(numericRating) || numericRating < 1 || numericRating > 5) { + setError("Rating must be a number between 1 and 5."); + return; + } const newBook = { title: title, author: author, ratings: [parseFloat(rating)], - "release date": releaseDate + releaseDate: releaseDate, }; handleAddBook(newBook); - setTitle(""); + setTitle(""); setAuthor(""); setRating(""); setReleaseDate(""); setError(""); }; - return (
@@ -85,7 +84,9 @@ if (isNaN(numericRating) || numericRating < 1 || numericRating > 5) { {error &&

{error}

} - +
); }; diff --git a/src/components/BookList.jsx b/src/components/BookList.jsx index d991a29..15c8f04 100644 --- a/src/components/BookList.jsx +++ b/src/components/BookList.jsx @@ -1,20 +1,19 @@ import React, { useState } from "react"; -const BookList = ({books}) => { -const [searchedBook, setSearchedBook] = useState([]); - console.log(searchedBook); - const handleSubmit = (event) => { +const BookList = ({ books }) => { + const [searchedBook, setSearchedBook] = useState([]); + console.log(searchedBook); + const handleSubmit = (event) => { event.preventDefault(); const titleInput = event.target[0].value; console.log("title:", titleInput); - for(let i = 0; i < books.length; i++){ - if(books[i].title.toLowerCase().includes(titleInput.toLowerCase())){ - setSearchedBook([...searchedBook, books[i]]); + for (let i = 0; i < books.length; i++) { + if (books[i].title.toLowerCase().includes(titleInput.toLowerCase())) { + setSearchedBook([...searchedBook, books[i]]); } - } - - } + } + }; // const clearBar = () => { // setTitleInput(""); @@ -22,16 +21,14 @@ const [searchedBook, setSearchedBook] = useState([]); return ( <> -
Book List
-
- - -
+
Book List
+
+ + +
); };