fixed filtering and moved refersh button into header, added css modules for components
This commit is contained in:
parent
d3f26083de
commit
12e5665a1c
50
src/App.css
50
src/App.css
@ -5,61 +5,11 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block{
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
width: 100%;
|
|
||||||
padding: 15px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh-btn{
|
|
||||||
padding: 5px;
|
|
||||||
background-color: #0000ff;
|
|
||||||
color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh-btn:hover{
|
|
||||||
opacity: 0.7;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post{
|
|
||||||
display: flex;
|
|
||||||
border-bottom: 1px solid #b3b3b3;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-id{
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-body{
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post:hover{
|
|
||||||
background-color: #b3b3b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-title{
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh-and-search{
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh-and-search input{
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
44
src/App.tsx
44
src/App.tsx
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import Header from './components/Header'
|
import Header from './components/Header'
|
||||||
import PostList from './components/PostList'
|
import PostList from './components/PostList'
|
||||||
@ -7,7 +7,7 @@ import axios from 'axios'
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
const [allPosts, setAllPosts] = useState<Post[]>([]);
|
|
||||||
const [posts, setPosts] = useState<Post[]>([]);
|
const [posts, setPosts] = useState<Post[]>([]);
|
||||||
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
@ -16,7 +16,7 @@ function App() {
|
|||||||
const fetchPosts = async () => {
|
const fetchPosts = async () => {
|
||||||
const response = await axios.get<Post[]>("https://jsonplaceholder.typicode.com/posts");
|
const response = await axios.get<Post[]>("https://jsonplaceholder.typicode.com/posts");
|
||||||
|
|
||||||
setAllPosts(response.data);
|
|
||||||
setPosts(response.data);
|
setPosts(response.data);
|
||||||
|
|
||||||
console.log("Posts fetched:", response.data);
|
console.log("Posts fetched:", response.data);
|
||||||
@ -29,20 +29,34 @@ function App() {
|
|||||||
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
const normalize = (str: string) => str.replace(/\s+/g, " ").toLowerCase();
|
|
||||||
|
|
||||||
|
|
||||||
if (searchTerm) {
|
const normalize = (str: string) => str.replace(/\s+/g, " ").toLowerCase();
|
||||||
const filteredPosts = allPosts.filter(post =>
|
|
||||||
normalize(post.body).includes(searchTerm.toLowerCase()) || post.title.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
);
|
const filteredPosts = useMemo(() => {
|
||||||
setPosts(filteredPosts);
|
return posts.filter(post => {
|
||||||
} else {
|
if (searchTerm == "") {
|
||||||
setPosts(allPosts);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalize(post.body).includes(searchTerm.toLowerCase()) || post.title.toLowerCase().includes(searchTerm.toLowerCase())) {
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [searchTerm, allPosts]);
|
|
||||||
|
);
|
||||||
|
},[posts, searchTerm]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +65,7 @@ function App() {
|
|||||||
|
|
||||||
<Header setRefresh={fetchPosts} searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
|
<Header setRefresh={fetchPosts} searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
|
||||||
|
|
||||||
<PostList posts={posts} />
|
<PostList posts={filteredPosts} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
||||||
|
|||||||
8
src/components/Block.module.css
Normal file
8
src/components/Block.module.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.block {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import type { BlockProps } from "./types";
|
import type { BlockProps } from "./types";
|
||||||
|
import styles from "./Block.module.css";
|
||||||
|
|
||||||
function Block({title, children}:BlockProps) {
|
function Block({title, children}:BlockProps) {
|
||||||
return (
|
return (
|
||||||
<div className="block">
|
<div className={styles.block}>
|
||||||
<h1 className="title">{title}</h1>
|
<h1>{title}</h1>
|
||||||
<div className="block-children">
|
<div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
22
src/components/Header.module.css
Normal file
22
src/components/Header.module.css
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.refreshBtn {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #0000ff;
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refreshBtn:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refreshAndSearch {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refreshAndSearch input {
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
import Block from "./Block";
|
import Block from "./Block";
|
||||||
import RefreshButton from "./RefreshButton";
|
|
||||||
import type { HeaderProps } from "./types";
|
import type { HeaderProps } from "./types";
|
||||||
|
import styles from "./Header.module.css";
|
||||||
|
|
||||||
function Header({setRefresh, searchTerm, setSearchTerm}:HeaderProps) {
|
function Header({setRefresh, searchTerm, setSearchTerm}:HeaderProps) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Block title='Header'>
|
<Block title="Header">
|
||||||
<hr></hr>
|
<hr></hr>
|
||||||
<div className="refresh-and-search">
|
<div className={styles.refreshAndSearch}>
|
||||||
<RefreshButton setRefresh={setRefresh}/>
|
<button className={styles.refreshBtn} onClick={() => setRefresh()}>Refresh</button>
|
||||||
<input type="text" name="search" id="search" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="search..."/>
|
<input type="text" name="search" id="search" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="search..."/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
25
src/components/PostItem.module.css
Normal file
25
src/components/PostItem.module.css
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.post {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #b3b3b3;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postId {
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postBody {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post:hover {
|
||||||
|
background-color: #b3b3b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postTitle {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
|
|
||||||
import type { postItemProps } from "./types";
|
import type { postItemProps } from "./types";
|
||||||
|
import styles from "./PostItem.module.css";
|
||||||
|
|
||||||
function PostItem({post}:postItemProps){
|
function PostItem({post}:postItemProps){
|
||||||
return (
|
return (
|
||||||
<div className="post">
|
<div className={styles.post}>
|
||||||
<div className="post-id">{post.id}</div> <div className="post-body" onClick={() => alert("clicked on post: " + post.title)}> <span className="post-title">{post.title}</span> <br /> <br />{post.body} </div>
|
<div className={styles.postId}>{post.id}</div> <div className={styles.postBody} onClick={() => alert("clicked on post: " + post.title)}> <span className={styles.postTitle}>{post.title}</span> <br /> <br />{post.body} </div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import type { RefreshButtonProps } from "./types";
|
|
||||||
|
|
||||||
function RefreshButton({setRefresh}: RefreshButtonProps) {
|
|
||||||
return (
|
|
||||||
<button className="refresh-btn" onClick={() => setRefresh()}>Refresh</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RefreshButton;
|
|
||||||
@ -18,3 +18,5 @@ body {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user