import React, { useEffect, useState } from "react";
import axios from "axios";
import styled from "@emotion/styled";
import CardList from "./CardList";
const Monsters = () => {
const [monsters, setMonsters] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const [copy, setCopy] = useState([]);
useEffect(() => {
const fetch = async () => {
const { data } = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
data.map(
(e) =>
(e.image = `https://robohash.org/${e.id}?set=set2&size=180x180`)
); // 불러온 API 파일에 따로 이미지 src가 없어서, data에 추가 저장함
setMonsters(data);
setCopy(data);
};
fetch();
}, []);
const handleInputChange = (e) => {
setSearchTerm(e.target.value);
};
useEffect(() => {
setMonsters(
copy.filter(
(e) =>
e.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
e.phone.includes(searchTerm) ||
e.email.toLowerCase().includes(searchTerm.toLowerCase())
)
);
}, [searchTerm, copy]);
return (
<Container>
<FixedWrap>
<Title>연락처</Title>
<Search
placeholder="이름, 연락처, 이메일 검색"
onChange={handleInputChange}
/>
</FixedWrap>
<CardList item={monsters} />
</Container>
);
};
export default Monsters;
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
background-color: aliceblue;
height: 1600px;
text-align: center;
padding: 10px;
`;
const FixedWrap = styled.div`
position: fixed;
background-color: aliceblue;
top: 0;
width: 100%;
`;
const Title = styled.h1`
color: navy;
`;
const Search = styled.input`
all: unset;
background-color: white;
width: 90%;
height: 50px;
font-size: 25px;
margin-bottom: 40px;
border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,
rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
::placeholder {
font-size: 16px;
}
`;
(사실 4번이 가장 어려웠다)
// CardList.js
import styled from "@emotion/styled";
import React, { useState } from "react";
import Card from "./Card";
import Detail from "./Detail";
const CardList = ({ item }) => {
const [clicked, setClicked] = useState();
const handleCardClick = (id) => {
setClicked(item.find((el) => el.id === id));
};
return (
<CardListContainer>
{item.map((monster) => (
<Card
name={monster.name}
id={monster.id}
phone={monster.phone}
email={monster.email}
key={monster.id}
image={monster.image}
onClick={() => handleCardClick(monster.id)}
clicked={clicked}
setClicked={setClicked}
/>
))}
{clicked && <Detail clicked={clicked} setClicked={setClicked} />}
</CardListContainer>
);
};
export default CardList;
const CardListContainer = styled.div`
display: flex;
flex-direction: column;
margin-top: 160px;
gap: 10px;
width: 100%;
`;
// Detail.js
import React from "react";
import styled from "@emotion/styled";
import Overlay from "./Overlay";
const Detail = ({ clicked, setClicked }) => {
return (
<>
<Overlay onClick={() => setClicked()} />
<Container>
<h2>연락처 정보</h2>
<img src={clicked.image} alt="프로필사진" />
<Info>
<InfoLeft> Name : </InfoLeft>
<InfoRight>{clicked.name}</InfoRight>
</Info>
<Info>
<InfoLeft> Phone : </InfoLeft>
<InfoRight>{clicked.phone}</InfoRight>
</Info>
<Info>
<InfoLeft> Company : </InfoLeft>
<InfoRight>{clicked.company.name}</InfoRight>
</Info>
<Info>
<InfoLeft> Email : </InfoLeft>
<InfoRight>{clicked.email}</InfoRight>
</Info>
</Container>
</>
);
};
export default Detail;
const Container = styled.div`
position: fixed;
margin: 0 auto;
left: 0;
right: 0;
z-index: 500;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 70%;
background-color: white;
border-radius: 20px;
padding-bottom: 30px;
img {
width: 300px;
margin-bottom: 20px;
}
`;
const Info = styled.div``;
const InfoLeft = styled.span`
font-weight: 600;
font-size: 18px;
`;
const InfoRight = styled.span``;
// Card.js
import React from "react";
import styled from "@emotion/styled";
const Card = ({ name, email, phone, image, onClick }) => {
return (
<CardContainer onClick={onClick}>
<img src={image} alt="프로필 사진 오류" />
<UserInfo>
<Name>{name}</Name>
<Info>▶︎ PHONE : {phone}</Info>
<Info>▶︎ EMAIL : {email}</Info>
</UserInfo>
</CardContainer>
);
};
export default Card;
const CardContainer = styled.div`
display: flex;
padding: 10px;
background-color: rgba(255, 255, 255, 0.7);
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
img {
width: 60px;
}
`;
const UserInfo = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
margin-left: 20px;
`;
const Name = styled.span`
font-size: 20px;
font-weight: 600;
`;
const Info = styled.span`
font-size: 14px;
`;
// Overlay.js
import styled from "@emotion/styled";
const Overlay = () => {
return <Container></Container>;
};
export default Overlay;
const Container = styled.div`
position: fixed;
z-index: 1000;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 1001;
`;