diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d29575 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/src/Component/Body.js b/src/Component/Body.js index d519657..5e573de 100644 --- a/src/Component/Body.js +++ b/src/Component/Body.js @@ -1,16 +1,23 @@ import React, { useState, useEffect } from 'react'; import { api_url } from '../env'; -import "/Users/dml-veerjot/Documents/development/html/blog_app/src/styleing/body.css"; +import "../styleing/body.css"; +import Pagination from './Pagination'; + + +import AddPostForm from './addPost'; function Body() { const [data, setData] = useState([]); const [error, setError] = useState(null); - + const [filteredData, setFilteredData] = useState([]); + const [currentPage,setCurrentPage] = useState(1); + const postsPerPage = 6; const fetchData = async () => { try { const res = await fetch(api_url); - const d = await res.json(); + const d = await res?.json(); setData(d); + setFilteredData(d) } catch (e) { setError(e); } @@ -20,6 +27,23 @@ function Body() { fetchData(); }, []); + const handleAddPost = (newPost) => { + const postWithId = { ...newPost, id: Date.now() }; + const updatedData = [postWithId,...data]; + setData(updatedData); + setFilteredData(updatedData); + }; + const handleDeletePost = (id) => { + const updatedData = data?.filter((post) => post?.id !== id); + setData(updatedData); + setFilteredData(updatedData); + }; + + const indexOfLastPost = currentPage * postsPerPage; + const indexOfFirstPost = indexOfLastPost-postsPerPage; + const currentPosts = filteredData.slice(indexOfFirstPost,indexOfLastPost); + const totalPages = Math.ceil(filteredData?.length/postsPerPage); + if (error) { return
Error: {error.message}
; } @@ -27,14 +51,21 @@ function Body() { return (
+ + setCurrentPage(page)}>
); } diff --git a/src/Component/DarkMode.js b/src/Component/DarkMode.js new file mode 100644 index 0000000..75dd917 --- /dev/null +++ b/src/Component/DarkMode.js @@ -0,0 +1,21 @@ +import React,{useState} from "react"; +function DarkMode(){ + const [theme,setTheme] = useState("light"); + const toggleTheme = ()=>{ + setTheme(theme === "light" ? "dark" : "light"); + }; + return ( +
+

{theme.charAt(0).toUpperCase()+theme.slice(1)}Mode

+ +
+ ); +} +export default DarkMode; \ No newline at end of file diff --git a/src/Component/Layout.js b/src/Component/Layout.js index 04ed71e..4927d2b 100644 --- a/src/Component/Layout.js +++ b/src/Component/Layout.js @@ -1,22 +1,60 @@ -import React from "react"; -import Body from "./Body"; -import "/Users/dml-veerjot/Documents/development/html/blog_app/src/styleing/layout.css"; +import React, { useState, useEffect } from "react"; +import Body from "./Body"; +import SearchBar from "./SearchBar"; +import "../styleing/layout.css"; +import { api_url } from "../env"; +import DarkMode from "./DarkMode"; const Layout = () => { + const [data, setData] = useState([]); + const [filteredData, setFilteredData] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + + + const fetchData = async () => { + try { + const res = await fetch(api_url); + const fetchedData = await res?.json(); + setData(fetchedData); + setFilteredData(fetchedData); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + + const handleSearch = (searchTerm) => { + if(!searchTerm){ + setFilteredData(data); + } + else{ + const filtered = data.filter( + (post) => + post?.title.toLowerCase().includes(searchTerm?.toLowerCase()) || + post?.body.toLowerCase().includes(searchTerm?.toLowerCase()) + ); + setFilteredData(filtered); + setCurrentPage(1); + } + }; + + useEffect(() => { + fetchData(); + }, []); + return (
+ {/* */}
-

Latest Blogs

- +

Latest Blogs

+
+
- + +
+
); }; diff --git a/src/Component/Pagination.js b/src/Component/Pagination.js new file mode 100644 index 0000000..d0d4c68 --- /dev/null +++ b/src/Component/Pagination.js @@ -0,0 +1,21 @@ +import React from 'react'; +import "../styleing/pagination.css" +const Pagination = ({ currentPage, totalPages, onPageChange }) => { + const handlePageChange = (page) => { + onPageChange(page); + }; + + return ( +
+ + Page {currentPage} of {totalPages} + +
+ ); +}; + +export default Pagination; diff --git a/src/Component/SearchBar.js b/src/Component/SearchBar.js index e69de29..dd08fe0 100644 --- a/src/Component/SearchBar.js +++ b/src/Component/SearchBar.js @@ -0,0 +1,27 @@ + +import React, { useState } from 'react'; +import '../styleing/SearchBar.css'; + +const SearchBar = ({ onSearch }) => { + const [searchTerm, setSearchTerm] = useState(''); + + const handleInputChange = (event) => { + const value = event.target.value; + setSearchTerm(value); + onSearch(value); + }; + + return ( +
+ +
+ ); +}; + +export default SearchBar; diff --git a/src/Component/addPost.js b/src/Component/addPost.js index e69de29..04d0aef 100644 --- a/src/Component/addPost.js +++ b/src/Component/addPost.js @@ -0,0 +1,35 @@ + +import React, { useState } from 'react'; +import "../styleing/addPost.css" +const AddPostForm = ({ onAddPost }) => { + const [newPost, setNewPost] = useState({ title: '', body: '' }); + + const handleSubmit = (e) => { + e.preventDefault(); + if (newPost.title && newPost.body) { + onAddPost(newPost); + setNewPost({ title: '', body: '' }); + } else { + alert('Title and Body are required!'); + } + }; + + return ( +
+ setNewPost({ ...newPost, title: e.target.value })} + /> +