From 67a52f38a2ef933f7388cc8a6c4656b1181ee8c0 Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Tue, 20 Jun 2023 15:13:14 +0300 Subject: [PATCH] Upload 5.5, 5.6, and 5.7 --- part5/bloglist-frontend/src/App.js | 85 +++++-------------- .../bloglist-frontend/src/components/Blog.js | 31 +++++-- .../src/components/BlogForm.js | 59 +++++++++++++ .../src/components/Togglable.js | 30 +++++++ 4 files changed, 133 insertions(+), 72 deletions(-) create mode 100644 part5/bloglist-frontend/src/components/BlogForm.js create mode 100644 part5/bloglist-frontend/src/components/Togglable.js diff --git a/part5/bloglist-frontend/src/App.js b/part5/bloglist-frontend/src/App.js index 49ae691..de682e6 100644 --- a/part5/bloglist-frontend/src/App.js +++ b/part5/bloglist-frontend/src/App.js @@ -1,26 +1,22 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import Blog from "./components/Blog"; +import { BlogForm } from "./components/BlogForm"; import Notification from "./components/Notification"; import blogService from "./services/blogs"; import loginService from "./services/login"; +import Togglable from "./components/Togglable"; const App = () => { const [blogs, setBlogs] = useState([]); const [user, setUser] = useState(null); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); - const [title, setTitle] = useState(""); - const [author, setAuthor] = useState(""); - const [urlAddress, setUrlAddress] = useState(""); const [errorMessage, setErrorMessage] = useState(null); const [successMessage, setSuccessMessage] = useState(null); const resetInputFields = () => { setUsername(""); setPassword(""); - setTitle(""); - setAuthor(""); - setUrlAddress(""); }; const setNotification = (message, type) => { @@ -75,22 +71,16 @@ const App = () => { setNotification("Logout failed", "error"); } }; - - const handleNewBlog = async (event) => { - event.preventDefault(); - const newBlog = { - title: title, - author: author, - url: urlAddress, - }; - + const newBlogRef = useRef(); + const handleNewBlog = async (newBlog) => { + newBlogRef.current.toggleVisibility(); blogService .create(newBlog) .then((returnedBlog) => { setBlogs(blogs.concat(returnedBlog)); resetInputFields(); setNotification( - `A new blog ${title} by ${author} at ${urlAddress} added`, + `A new blog ${returnedBlog.title} by ${returnedBlog.author} at ${returnedBlog.url} added`, "success" ); }) @@ -123,52 +113,21 @@ const App = () => { ); - const blogForm = () => ( -
-

Create new blog

-
-
- Title: - setTitle(target.value)} - /> -
-
- Author: - setAuthor(target.value)} - /> -
-
- URL: - setUrlAddress(target.value)} - /> -
- -
-

All blogs

- - - - - - + const blogForm = () => { + return ( +
+

{user.name} logged in

+ + + + +

All blogs

{blogs.map((blog) => ( ))} -
TitleAuthorURL
-
- ); + + ); + }; return (
@@ -183,11 +142,7 @@ const App = () => { {loginForm()}
) : ( -
-

{user.name} logged in

- - {blogForm()} -
+
{blogForm()}
)} ); diff --git a/part5/bloglist-frontend/src/components/Blog.js b/part5/bloglist-frontend/src/components/Blog.js index 1b61a44..a539016 100644 --- a/part5/bloglist-frontend/src/components/Blog.js +++ b/part5/bloglist-frontend/src/components/Blog.js @@ -1,9 +1,26 @@ -const Blog = ({ blog }) => ( - - {blog.title} - {blog.author} - {blog.url} - -); +import Togglable from "./Togglable"; + +const Blog = ({ blog }) => { + const blogStyle = { + paddingTop: 10, + paddingLeft: 2, + border: "solid", + borderWidth: 1, + marginBottom: 5, + }; + return ( +
+
+ {blog.title} + +
    +
  • {blog.author}
  • +
  • {blog.url}
  • +
+
+
+
+ ); +}; export default Blog; diff --git a/part5/bloglist-frontend/src/components/BlogForm.js b/part5/bloglist-frontend/src/components/BlogForm.js new file mode 100644 index 0000000..7cb6621 --- /dev/null +++ b/part5/bloglist-frontend/src/components/BlogForm.js @@ -0,0 +1,59 @@ +import { useState } from "react"; + +export const BlogForm = ({ createBlog }) => { + const [title, setTitle] = useState(""); + const [author, setAuthor] = useState(""); + const [urlAddress, setUrlAddress] = useState(""); + + const resetInputFields = () => { + setTitle(""); + setAuthor(""); + setUrlAddress(""); + }; + + const addBlog = async (event) => { + event.preventDefault(); + createBlog({ + title: title, + author: author, + url: urlAddress, + }); + resetInputFields(); + }; + + return ( +
+

Create new blog

+
+
+ Title: + setTitle(event.target.value)} + /> +
+
+ Author: + setAuthor(event.target.value)} + /> +
+
+ URL: + setUrlAddress(event.target.value)} + /> +
+ +
+
+ ); +}; diff --git a/part5/bloglist-frontend/src/components/Togglable.js b/part5/bloglist-frontend/src/components/Togglable.js new file mode 100644 index 0000000..84c0e0a --- /dev/null +++ b/part5/bloglist-frontend/src/components/Togglable.js @@ -0,0 +1,30 @@ +import { useState, forwardRef, useImperativeHandle } from "react"; + +const Togglable = forwardRef((props, refs) => { + const [visible, setVisible] = useState(false); + + const hideWhenVisible = { display: visible ? "none" : "" }; + const showWhenVisible = { display: visible ? "" : "none" }; + + const toggleVisibility = () => { + setVisible(!visible); + }; + + useImperativeHandle(refs, () => { + return { toggleVisibility }; + }); + + return ( +
+
+ +
+
+ {props.children} + +
+
+ ); +}); + +export default Togglable;