├── Home Page.png ├── Settings.png ├── one_post.png ├── color scheme.png ├── launch_page.png ├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── logo512.png ├── manifest.json └── index.html ├── src ├── assets │ ├── cat_logo.png │ ├── cat_logo_lines.png │ └── cat_logo_transparent.png ├── context │ ├── PostsContext.js │ ├── UserContext.js │ └── CommentContext.js ├── setupTests.js ├── App.test.js ├── pages │ ├── HomePage.css │ ├── PostPage.js │ ├── MainPage.css │ ├── HomePage.js │ ├── MainPage.js │ ├── SettingPage.css │ └── SettingPage.js ├── components │ ├── RandomCatPic.css │ ├── NewCommentForm.css │ ├── NewPostForm.css │ ├── PostList.js │ ├── SignInUp.css │ ├── NavBar.css │ ├── CommentsList.js │ ├── RandomCatPic.js │ ├── NavBar.js │ ├── PostDetail.js │ ├── NewCommentForm.js │ ├── NewPostForm.js │ ├── Comment.js │ ├── Post.js │ └── SignInUp.js ├── reportWebVitals.js ├── index.js ├── App.js ├── index.css ├── App.css └── logo.svg ├── .gitignore ├── package.json └── README.md /Home Page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/Home Page.png -------------------------------------------------------------------------------- /Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/Settings.png -------------------------------------------------------------------------------- /one_post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/one_post.png -------------------------------------------------------------------------------- /color scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/color scheme.png -------------------------------------------------------------------------------- /launch_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/launch_page.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/assets/cat_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/src/assets/cat_logo.png -------------------------------------------------------------------------------- /src/assets/cat_logo_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/src/assets/cat_logo_lines.png -------------------------------------------------------------------------------- /src/context/PostsContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const PostsContext = createContext(null); 4 | -------------------------------------------------------------------------------- /src/context/UserContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const UserContext = createContext(null); 4 | -------------------------------------------------------------------------------- /src/context/CommentContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const CommentContext = createContext(null); 4 | -------------------------------------------------------------------------------- /src/assets/cat_logo_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindy-d-tran/blog-app-frontend/HEAD/src/assets/cat_logo_transparent.png -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/pages/HomePage.css: -------------------------------------------------------------------------------- 1 | .home-page-container{ 2 | margin: 3.5em 0; 3 | display: flex; 4 | background-color: var(--cream); 5 | border: 5px solid var(--main-color); 6 | border-top: 2.5em solid var(--main-color); 7 | border-radius: 2em; 8 | overflow: hidden; 9 | box-shadow: #e9d6d2 3px -3px 10px 2px; 10 | } -------------------------------------------------------------------------------- /src/components/RandomCatPic.css: -------------------------------------------------------------------------------- 1 | .random-cat-pic { 2 | width: 30vw; 3 | height: fit-content; 4 | padding: 1em; 5 | background-color: var(--cream); 6 | border-bottom: 5px solid var(--main-color); 7 | } 8 | .random-cat-pic img { 9 | width: 100%; 10 | height: 75%; 11 | object-fit: contain; 12 | background-color: var(--cream); 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/PostPage.js: -------------------------------------------------------------------------------- 1 | import PostDetail from "../components/PostDetail"; 2 | import { useParams } from "react-router-dom"; 3 | 4 | function PostPage() { 5 | const param = useParams(); 6 | // console.log(param.id); 7 | return ( 8 | <> 9 | 10 | 11 | ); 12 | } 13 | 14 | export default PostPage; 15 | -------------------------------------------------------------------------------- /src/components/NewCommentForm.css: -------------------------------------------------------------------------------- 1 | .comment-list .create-container { 2 | margin-top: 1em; 3 | } 4 | .new-comment-form { 5 | display: flex; 6 | flex-direction: column; 7 | flex-grow: 1; 8 | } 9 | .new-comment-form button { 10 | margin-top: 1em; 11 | padding: 0.25em 1em; 12 | align-self: end; 13 | } 14 | 15 | #newComment { 16 | height: 75px; 17 | padding: 0.25em; 18 | resize: none; 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/pages/MainPage.css: -------------------------------------------------------------------------------- 1 | .launch-page{ 2 | display: flex; 3 | height: 90vh; 4 | justify-content: space-around; 5 | align-items: center; 6 | } 7 | .logo-big{ 8 | width: 400px; 9 | } 10 | 11 | .hero-area{ 12 | margin-right: 4cm; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | } 17 | 18 | .hero-area h1 { 19 | color: var(--main-color); 20 | font-size: 45px; 21 | } -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/components/NewPostForm.css: -------------------------------------------------------------------------------- 1 | .create-container { 2 | padding-bottom: 1em; 3 | display: flex; 4 | border-bottom: 2px solid var(--main-color); 5 | } 6 | .new-post-form { 7 | display: flex; 8 | flex-direction: column; 9 | flex-grow: 1; 10 | } 11 | .new-post-form button { 12 | margin-top: 1em; 13 | padding: 0.25em 1em; 14 | align-self: end; 15 | } 16 | 17 | #new-post-content { 18 | height: 75px; 19 | padding: 0.25em; 20 | resize: none; 21 | } 22 | #new-post-title { 23 | padding: 0.25em; 24 | margin-bottom: 5px; 25 | } 26 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/PostList.js: -------------------------------------------------------------------------------- 1 | import Post from "./Post"; 2 | import { PostsContext } from "../context/PostsContext"; 3 | import { useContext } from "react"; 4 | import NewPostForm from "./NewPostForm"; 5 | 6 | function PostList() { 7 | const postsCtx = useContext(PostsContext); 8 | const { posts } = postsCtx; 9 | 10 | return ( 11 |
12 | 13 | {posts.length>0 ? ( 14 | posts.map((post) => ) 15 | ) : ( 16 |

loading

17 | )} 18 |
19 | ); 20 | } 21 | 22 | export default PostList; 23 | -------------------------------------------------------------------------------- /src/components/SignInUp.css: -------------------------------------------------------------------------------- 1 | .sign-in-up-form{ 2 | margin-bottom: 0.75em; 3 | display: flex; 4 | flex-direction: column; 5 | padding: 1em; 6 | background-color: var(--accent-color); 7 | border-radius: 1em; 8 | } 9 | .sign-in-up-form input{ 10 | padding: 0.25em; 11 | margin: 0.25em 0 0.5em ; 12 | } 13 | .sign-in-up-form h3{ 14 | font-weight: 600; 15 | font-size: 23px; 16 | } 17 | .sign-in-up-form button { 18 | margin: 0.5em 0; 19 | background-color: var(--main-color); 20 | color: var(--text-color); 21 | } 22 | .link{ 23 | color: var(--dark-color); 24 | border-bottom: 1px solid var(--dark-color); 25 | cursor: pointer; 26 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | import { BrowserRouter } from "react-router-dom"; 7 | 8 | const root = ReactDOM.createRoot(document.getElementById("root")); 9 | root.render( 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | 17 | // If you want to start measuring performance in your app, pass a function 18 | // to log results (for example: reportWebVitals(console.log)) 19 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 20 | reportWebVitals(); 21 | -------------------------------------------------------------------------------- /src/components/NavBar.css: -------------------------------------------------------------------------------- 1 | nav { 2 | display: flex; 3 | } 4 | a { 5 | text-decoration: none; 6 | color: var(--text-color); 7 | } 8 | 9 | /*start of nav style*/ 10 | nav > ul { 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | background-color: var(--main-color); 15 | list-style-type: none; 16 | width: 100vw; 17 | } 18 | li { 19 | padding: 1em; 20 | } 21 | li a:hover:not(.active) { 22 | border-bottom: 3px solid var(--accent-color); 23 | 24 | } 25 | 26 | .active { 27 | border-bottom: 2px solid var(--dark-color); 28 | } 29 | .active > a { 30 | color: white; 31 | } 32 | 33 | /* li:first-child { 34 | padding: 9px 0.5em 5px; 35 | } */ 36 | #menu-logo { 37 | width: 37px; 38 | } 39 | /*end of nav style*/ 40 | -------------------------------------------------------------------------------- /src/components/CommentsList.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | 3 | // importing components 4 | import Comment from "./Comment"; 5 | import NewCommentForm from "./NewCommentForm"; 6 | 7 | // importing context 8 | import { CommentContext } from "../context/CommentContext"; 9 | 10 | function CommentsList({ postID }) { 11 | const commentsCtx = useContext(CommentContext); 12 | const { comments } = commentsCtx; 13 | 14 | return ( 15 |
16 | 17 | {comments ? ( 18 | comments.map((c) => ) 19 | ) : ( 20 |

loading

21 | )} 22 |
23 | ); 24 | } 25 | 26 | export default CommentsList; 27 | -------------------------------------------------------------------------------- /src/pages/HomePage.js: -------------------------------------------------------------------------------- 1 | import PostList from "../components/PostList"; 2 | 3 | import { useState, useEffect } from "react"; 4 | import axios from "axios"; 5 | import RandomCatPic from "../components/RandomCatPic"; 6 | 7 | import { PostsContext } from "../context/PostsContext"; 8 | 9 | import "./HomePage.css"; 10 | 11 | function HomePage() { 12 | const [posts, setPosts] = useState([]); 13 | 14 | useEffect(() => { 15 | const fetchData = async () => { 16 | const res = await axios.get("https://blog-app-0no1.onrender.com/api/posts"); 17 | setPosts(res.data); 18 | // console.log(res.data); 19 | }; 20 | fetchData(); 21 | }, []); 22 | return ( 23 |
24 | 25 | 26 | 27 | 28 |
29 | ); 30 | } 31 | 32 | export default HomePage; 33 | -------------------------------------------------------------------------------- /src/pages/MainPage.js: -------------------------------------------------------------------------------- 1 | import SignInUp from "../components/SignInUp"; 2 | import Logo from "../assets/cat_logo.png"; 3 | 4 | import { UserContext } from "../context/UserContext"; 5 | import { useContext } from "react"; 6 | 7 | import "./MainPage.css"; 8 | import HomePage from "./HomePage"; 9 | 10 | function MainPage() { 11 | const userCtx = useContext(UserContext); 12 | const { user } = userCtx; 13 | 14 | return ( 15 | <> 16 | {user ? ( 17 | <> 18 | 19 | 20 | ) : ( 21 | <> 22 |
23 |
24 | logo big 25 |

Blog App

26 |
27 | 28 |
29 | 30 | )} 31 | 32 | ); 33 | } 34 | 35 | export default MainPage; 36 | -------------------------------------------------------------------------------- /src/components/RandomCatPic.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { useEffect, useState } from "react"; 3 | import './RandomCatPic.css'; 4 | 5 | function RandomCatPic() { 6 | const [catImg, setCatImg] = useState(null); 7 | 8 | useEffect(() => { 9 | try { 10 | const createPost = async () => { 11 | const res = await axios.get( 12 | `https://api.thecatapi.com/v1/images/search` 13 | ); 14 | setCatImg(res.data); 15 | // console.log(res.data.url); 16 | }; 17 | createPost(); 18 | } catch (error) { 19 | console.log(error); 20 | } 21 | }, []); 22 | 23 | return ( 24 |
25 | {catImg ? ( 26 | <> 27 | cat 28 |

random cat pic

29 | 30 | ) : ( 31 |

loading

32 | )} 33 |
34 | ); 35 | } 36 | 37 | export default RandomCatPic; 38 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | // importing hooks 2 | import { Route, Routes } from "react-router-dom"; 3 | import { useState } from "react"; 4 | 5 | // importing style 6 | import "./App.css"; 7 | 8 | // importing context 9 | import { UserContext } from "./context/UserContext"; 10 | 11 | // importing pages 12 | import MainPage from "./pages/MainPage"; 13 | import SettingPage from "./pages/SettingPage"; 14 | 15 | //importing components 16 | import NavBar from "./components/NavBar"; 17 | import PostPage from "./pages/PostPage"; 18 | 19 | function App() { 20 | // creeating state for user 21 | const [user, setUser] = useState(null); 22 | 23 | return ( 24 | 25 |
26 | 27 | 28 | } /> 29 | } /> 30 | } /> 31 | 32 |
33 |
34 | ); 35 | } 36 | 37 | export default App; 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^6.5.1", 7 | "@fortawesome/free-regular-svg-icons": "^6.5.1", 8 | "@fortawesome/free-solid-svg-icons": "^6.5.1", 9 | "@fortawesome/react-fontawesome": "^0.2.0", 10 | "@testing-library/jest-dom": "^5.17.0", 11 | "@testing-library/react": "^13.4.0", 12 | "@testing-library/user-event": "^13.5.0", 13 | "axios": "^1.6.7", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "react-router-dom": "^6.22.0", 17 | "react-scripts": "5.0.1", 18 | "web-vitals": "^2.1.4" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "react-app", 29 | "react-app/jest" 30 | ] 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Indie+Flower&family=Klee+One:wght@400;600&display=swap"); 2 | 3 | :root { 4 | --cream: #fff9ef; 5 | --main-color: #f8bdbd; 6 | --dark-color: #8f4761; 7 | --accent-color: #ffebc4; 8 | --text-color: rgb(46, 33, 38); 9 | } 10 | * { 11 | box-sizing: border-box; 12 | padding: 0; 13 | margin: 0; 14 | scrollbar-color: var(--main-color) var(--cream); 15 | } 16 | body { 17 | margin: 0; 18 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 19 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 20 | sans-serif; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | background-color: var(--cream); 24 | color: var(--text-color); 25 | } 26 | 27 | .klee-one-regular { 28 | font-family: "Klee One", cursive; 29 | font-weight: 400; 30 | font-style: normal; 31 | } 32 | 33 | .klee-one-semibold { 34 | font-family: "Klee One", cursive; 35 | font-weight: 600; 36 | font-style: normal; 37 | } 38 | 39 | h1, 40 | h2, 41 | h3, 42 | h4, 43 | h5, 44 | h6 { 45 | font-family: "Klee One", cursive; 46 | } 47 | 48 | code { 49 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 50 | monospace; 51 | } 52 | 53 | button { 54 | background-color: var(--dark-color); 55 | color: var(--cream); 56 | padding: 0.25em 0.5em; 57 | border: none; 58 | border-radius: 0.75em; 59 | cursor: pointer; 60 | } 61 | -------------------------------------------------------------------------------- /src/pages/SettingPage.css: -------------------------------------------------------------------------------- 1 | .settings { 2 | width: 75vw; 3 | margin: 3.5em 0; 4 | padding: 1em; 5 | background-color: var(--cream); 6 | border: 5px solid var(--main-color); 7 | border-top: 2.5em solid var(--main-color); 8 | border-radius: 2em; 9 | overflow: hidden; 10 | box-shadow: #e9d6d2 3px -3px 10px 2px; 11 | } 12 | .settings h2{ 13 | font-size: 30px; 14 | } 15 | .settings form { 16 | /* margin: 1em; */ 17 | display: flex; 18 | flex-direction: column; 19 | } 20 | 21 | .userDisplay { 22 | display: flex; 23 | align-items: center; 24 | } 25 | .username{ 26 | font-size: 30px; 27 | } 28 | .settings svg { 29 | cursor: pointer; 30 | margin-left: auto; 31 | margin-right: 1em; 32 | } 33 | #edit-username { 34 | flex-direction: row; 35 | } 36 | #edit-username button { 37 | margin-top: 0.25em; 38 | margin-left: 0.5em; 39 | } 40 | .userDisplay img { 41 | width: 100px; 42 | height: 100px; 43 | margin-right: 1em; 44 | object-fit: cover; 45 | border-radius: 50%; 46 | border: 5px solid var(--main-color); 47 | background-color: var(--dark-color); 48 | } 49 | 50 | .settings label { 51 | border-bottom: 2px solid var(--main-color); 52 | margin-top: 1em; 53 | margin-bottom: 0.5em; 54 | font-size: 22px; 55 | } 56 | 57 | .settings form:last-child label { 58 | align-self: flex-start; 59 | } 60 | .settings input { 61 | margin: 0.25em 0; 62 | } 63 | .settings button { 64 | margin-top: 0.5em; 65 | } 66 | 67 | .edit-email { 68 | display: flex; 69 | } 70 | -------------------------------------------------------------------------------- /src/components/NavBar.js: -------------------------------------------------------------------------------- 1 | import "./NavBar.css"; 2 | import { Link } from "react-router-dom"; 3 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 4 | import { faRightFromBracket } from "@fortawesome/free-solid-svg-icons"; 5 | import { redirect } from "react-router-dom"; 6 | import { useContext } from "react"; 7 | import { UserContext } from "../context/UserContext"; 8 | function NavBar() { 9 | const userCtx = useContext(UserContext); 10 | const { user, setUser } = userCtx; 11 | const navBarItems = [ 12 | { text: "Home", href: "/" }, 13 | { text: "Settings", href: "/settings" }, 14 | ]; 15 | 16 | return ( 17 | 47 | ); 48 | } 49 | 50 | export default NavBar; 51 | -------------------------------------------------------------------------------- /src/components/PostDetail.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import axios from "axios"; 3 | 4 | // importing context 5 | import { CommentContext } from "../context/CommentContext"; 6 | 7 | // importing components 8 | import CommentsList from "./CommentsList"; 9 | import Post from "./Post"; 10 | 11 | function PostDetail({ id }) { 12 | const [post, setPost] = useState(null); 13 | const [comments, setComments] = useState(null); 14 | 15 | useEffect(() => { 16 | try { 17 | const fetchPosts = async () => { 18 | const res = await axios.get(`https://blog-app-0no1.onrender.com/api/posts/${id}/`); 19 | console.log(res.data); 20 | setPost(res.data); 21 | }; 22 | fetchPosts(); 23 | const fetchComments = async () => { 24 | const res = await axios.get( 25 | `https://blog-app-0no1.onrender.com/api/comments/post/${id}/` 26 | ); 27 | console.log(res.data); 28 | setComments(res.data); 29 | }; 30 | fetchComments(); 31 | } catch (error) { 32 | console.log(error); 33 | } 34 | }, []); 35 | 36 | return ( 37 | <> 38 | {post ? ( 39 |
40 | {" "} 41 | 42 | {" "} 43 | 44 |
45 | ) : ( 46 |

loading

47 | )} 48 | 49 | ); 50 | } 51 | 52 | export default PostDetail; 53 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | overflow-x: hidden; 7 | } 8 | 9 | .App-link { 10 | color: #61dafb; 11 | } 12 | 13 | svg { 14 | color: var(--dark-color); 15 | } 16 | 17 | .post-list { 18 | /* margin: 1em; */ 19 | width: 40vw; 20 | padding: 1em; 21 | background-color: var(--cream); 22 | border-right: 5px solid var(--main-color); 23 | 24 | } 25 | .post-body, .comment{ 26 | margin: 1em 0; 27 | padding: 1em 0; 28 | background-color: var(--cream); 29 | 30 | border-bottom: 2px solid var(--main-color); 31 | } 32 | .post-comment { 33 | width: 60vw; 34 | margin: 3.5em 0; 35 | padding: 1em 2em; 36 | background-color: var(--cream); 37 | border: 5px solid var(--main-color); 38 | border-top: 2.5em solid var(--main-color); 39 | border-radius: 2em; 40 | overflow: hidden; 41 | box-shadow: #e9d6d2 3px -3px 10px 2px; 42 | } 43 | .post-comment > .post-body { 44 | margin: 0; 45 | padding: 0; 46 | } 47 | .post-img-gallery img { 48 | width: 100%; 49 | height: 100%; 50 | object-fit: cover; 51 | } 52 | 53 | .postbuttons{ 54 | display: flex; 55 | justify-content: space-between; 56 | } 57 | .postbuttons svg:last-child{ 58 | cursor: pointer; 59 | } 60 | .userDisplay-small { 61 | display: flex; 62 | align-items: flex-start; 63 | } 64 | .userDisplay-small img { 65 | width: 50px; 66 | height: 50px; 67 | margin-right: 0.5em; 68 | object-fit: cover; 69 | border-radius: 50%; 70 | border: 4px solid var(--main-color); 71 | background-color: var(--dark-color); 72 | } 73 | input, textarea{ 74 | padding: 0.25em; 75 | outline-color: var(--dark-color); 76 | border-color: var(--main-color); 77 | border-style: solid; 78 | } -------------------------------------------------------------------------------- /src/components/NewCommentForm.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { useState, useContext } from "react"; 3 | 4 | import { UserContext } from "../context/UserContext"; 5 | import { CommentContext } from "../context/CommentContext"; 6 | 7 | import ProfilePic from "../assets/cat_logo_transparent.png"; 8 | import './NewCommentForm.css' 9 | 10 | function NewCommentForm({ postID }) { 11 | const userCtx = useContext(UserContext); 12 | const { user } = userCtx; 13 | const commentsCtx = useContext(CommentContext); 14 | 15 | const { setComments } = commentsCtx; 16 | const [newComment, setNewComment] = useState(""); 17 | 18 | const handleOnSubmit = async (e) => { 19 | e.preventDefault(); 20 | try { 21 | console.log(newComment); 22 | const res = await axios.post(`https://blog-app-0no1.onrender.com/api/comments`, { 23 | user_id: user._id, 24 | post_id: postID, 25 | comment_content: newComment, 26 | }); 27 | console.log(res.data); 28 | const resComments = await axios.get( 29 | `https://blog-app-0no1.onrender.com/api/comments/post/${postID}` 30 | ); 31 | setComments(resComments.data); 32 | } catch (error) { 33 | console.log(error); 34 | } 35 | }; 36 | 37 | return ( 38 |
39 |
40 | user icon 41 |
42 |
43 |