Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[배현지] Sprint7 #594

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import App from "./components/ui/App";
import UsedMarketPage from "./pages/UsedMarketPage";
import ProductRagistrationPage from "./pages/ProductRagistrationPage";
import FreeBoardPage from "./pages/FreeBoardPage";
import ProductDetailedPage from "./pages/ProductDetailedPage";

function Main() {
return (
Expand All @@ -12,6 +13,7 @@ function Main() {
<Route path="/free" element={<FreeBoardPage />} />
<Route path="/items" element={<UsedMarketPage />} />
<Route path="/additem" element={<ProductRagistrationPage />} />
<Route path="/items/:productId" element={<ProductDetailedPage />} />
</Routes>
</App>
</BrowserRouter>
Expand Down
57 changes: 57 additions & 0 deletions src/components/container/ProductDeatilsContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import ProductDetails from "../ui/ProductDetails";
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import { getProduct, getComment } from "../../api";
import CommentDetails from "../ui/CommentDetails";

function ProductDetailsContainer() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [comments, setComments] = useState([]);

useEffect(() => {
const detailedProduct = async () => {
try {
const productData = await getProduct(productId);
setProduct(productData);
} catch (e) {
if (e.response) {
console.log(e.response.status);
console.log(e.response.data);
} else {
console.log("리퀘스트가 실패했습니다.");
}
}
};

const detailedComment = async () => {
const params = { limit: 3 };
try {
const commentData = await getComment({ productId, params });
setComments(commentData.list);
} catch (e) {
if (e.response) {
console.log(e.response.status);
console.log(e.response.data);
} else {
console.log("리퀘스트가 실패했습니다.");
}
}
};
detailedComment();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[수정해주세요]

함수명은 동사를 사용해주세요!

detailedProduct();
}, [productId]);

if (!product) {
return <div>로딩중</div>;
}

return (
<>
<ProductDetails product={product} />
<CommentDetails comments={comments} />
</>
);
}

export default ProductDetailsContainer;
50 changes: 50 additions & 0 deletions src/components/ui/CommentDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import styles from "../ui/CommentDetails.module.css";
import backIcon from "../../assets/back-icon.png";
import { Link } from "react-router-dom";
import { elapsedTime } from "../../utils";

function CommentDetails({ comments }) {
return (
<div className={styles.commentWrapper}>
<div>
<h2>문의하기</h2>
<form>
<input
name="question"
type="text"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고,불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
required
autoComplete="off"
/>
<div className={styles.buttonWrapper}>
<button className={styles.disabledButton} type="submit">
등록
</button>
</div>
</form>
</div>
<div>
{comments.map((comment) => (
<div key={comment.id} className={styles.comment}>
<p className={styles.content}>{comment.content}</p>
<div className={styles.contentWrapper}>
<img src={comment.writer.image} alt="작성자 이미지" />
<div className={styles.commentContent}>
<p className={styles.nickname}>{comment.writer.nickname}</p>
<p className={styles.updatedAt}>
{elapsedTime(comment.updatedAt)}
</p>
</div>
</div>
</div>
))}
</div>
<Link to="/items" className={styles.goBackButton}>
<span>목록으로 돌아가기</span>
<img className={styles.backIcon} src={backIcon} alt="돌아가기 아이콘" />
</Link>
</div>
);
}

export default CommentDetails;
109 changes: 109 additions & 0 deletions src/components/ui/CommentDetails.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
.commentWrapper {
border-top: 1px solid #e5e7eb;
display: flex;
flex-direction: column;
}
.commentWrapper h2 {
font-weight: 600;
line-height: 19.09px;
margin-top: 24px;
margin-bottom: 16px;
}

.commentWrapper input {
border: none;
outline: none;
border-radius: 12px;
padding: 16px 24px 16px 24px;
width: 100%;
min-height: 104px;
background-color: #f3f4f6;
}

.buttonWrapper {
text-align: right;
margin-top: 16px;
margin-bottom: 24px;
}

.disabledButton {
background-color: #9ca3af;
color: #ffffff;
cursor: default;
padding: 12px 20px 12px 20px;
height: 42px;
width: 88px;
border-radius: 8px;
font-weight: 600;
line-height: 19.09px;
}

form:valid .disabledButton {
background-color: #3692ff;
cursor: pointer;
}

.content {
line-height: 22.4px;
margin-top: 24px;
margin-bottom: 24px;
}

.contentWrapper {
display: flex;
border-bottom: 1px solid #e5e7eb;
margin-bottom: 40px;
}

.comment img {
width: 40px;
height: 40px;
}

.commentContent {
margin-left: 8px;
margin-bottom: 5px;
}

.nickname {
margin: 0;
margin-bottom: 4px;
font-size: 14px;
line-height: 16.71px;
color: #4b5563;
}

.updatedAt {
font-size: 12px;
line-height: 14.32px;
margin: 0;
margin-bottom: 29px;
color: #9ca3af;
}

.goBackButton {
width: 240px;
height: 48px;
border-radius: 40px;
padding: 0;
background-color: #3692ff;
border: none;
cursor: pointer;
padding: 12px 71px 12px 71px;
margin: 0 auto 250px;
display: flex;
align-items: center;
justify-content: center;
text-wrap: nowrap;
}

.goBackButton span {
color: #ffffff;
font-weight: 600;
font-size: 18px;
line-height: 24px;
}

.backIcon {
margin-left: 10px;
}
28 changes: 28 additions & 0 deletions src/components/ui/ProductDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import styles from "../ui/ProductDetails.module.css";
import heartIcon from "../../assets/heart.png";

function ProductDetails({ product }) {
return (
<div className={styles.productWrapper}>
<img
className={styles.productImg}
src={product.images[0]}
alt={product.name}
/>
<div className={styles.productContent}>
<h2>{product.name}</h2>
<h1>{product.price}원</h1>
<p>상품 소개</p>
<h3>{product.description}</h3>
<p>상품 태그</p>
<h3>#{product.tags}</h3>
<button className={styles.favoriteTag}>
<img src={heartIcon} alt="하트 아이콘" />
{product.favoriteCount}
</button>
</div>
</div>
);
}

export default ProductDetails;
127 changes: 127 additions & 0 deletions src/components/ui/ProductDetails.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
.productImg {
width: 486px;
height: 486px;
margin-right: 24px;
border-radius: 20px;
}

.productWrapper {
max-width: 996px;
display: flex;
justify-content: space-between;
padding-top: 24px;
padding-bottom: 32px;
margin: 0 auto;
}

.productContent {
width: 486px;
height: 486px;
}

.productContent h2 {
font-weight: 600;
font-size: 24px;
line-height: 28.64px;
color: #1f2937;
margin: 0;
}

.productContent h1 {
font-weight: 600;
font-size: 40px;
line-height: 47.73px;
color: #1f2937;
margin: 0;
margin-top: 16px;
padding-bottom: 16px;
}

.productContent p {
font-weight: 500;
font-size: 14px;
line-height: 16.71px;
color: #4b5563;
margin-top: 16px;
margin-bottom: 8px;
}

.productContent h3 {
line-height: 22.4px;
color: #1f2937;
margin: 0;
}

.productContent h3 {
margin-bottom: 24px;
}

.favoriteTag {
width: 87px;
height: 40px;
border: 1px solid #e5e7eb;
border-radius: 35px;
padding: 4px 12px 4px 12px;
margin-top: 124px;
gap: 10px;
display: flex;
align-items: center;
color: #6b7280;
font-weight: 500;
line-height: 19.09px;
}

/* Tablet size*/
@media screen and (max-width: 1199px) {
.productContent h2 {
font-size: 20px;
line-height: 23.87px;
}

.productContent h1 {
font-size: 32px;
line-height: 38.19px;
}

.productContent p {
line-height: 19.6px;
}

.productImg {
width: 340px;
height: 340px;
}

.favoriteTag {
margin-top: 25px;
}
}
/*Mobile size*/
@media screen and (max-width: 767px) {
.productContent h2 {
font-size: 16px;
line-height: 19.09px;
}

.productContent h1 {
font-size: 24px;
line-height: 28.64px;
}

.productContent p {
line-height: 16.71px;
}

.favoriteTag img {
width: 24px;
}

.productImg {
width: 343px;
height: 343px;
}

.favoriteTag {
margin-top: 25px;
}
}
7 changes: 7 additions & 0 deletions src/pages/ProductDetailedPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ProductDetailsContainer from "../components/container/ProductDeatilsContainer";

function ProductDetailedPage() {
return <ProductDetailsContainer />;
}

export default ProductDetailedPage;
Loading