Skip to content

Commit

Permalink
✨ feat: 상품 상세 페이지 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
rak517 committed Dec 7, 2024
1 parent ae2ea4d commit bdf381d
Show file tree
Hide file tree
Showing 21 changed files with 694 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import "./App.css";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import ItemsPage from "./pages/ItemPage/ItemsPage";
import AddItemPage from "./pages/AddItemPage/AddItemPage";
import ItemDetailPage from "./pages/ItemDetailPage/ItemDetailPage";

function App() {
return (
<Router>
<Routes>
<Route path="/items" element={<ItemsPage />} />
<Route path="/items/:productId" element={<ItemDetailPage />} />
<Route path="/additem" element={<AddItemPage />} />
</Routes>
</Router>
Expand Down
52 changes: 52 additions & 0 deletions src/api/product.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,55 @@ export const fetchProducts = async (orderBy, pageSize) => {
}
}
};

export const fetchProductById = async (productId) => {
try {
const response = await fetch(`${BASE_URL}/${productId}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (!response.ok) {
handleResponseError(response);
}

const data = await response.json();
return data;
} catch (error) {
if (error instanceof HttpException) {
throw error;
} else {
console.error("네트워크 오류", error);
throw new Error("네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.");
}
}
};

export const fetchProductCommentById = async (productId, limit = 10) => {
const params = new URLSearchParams({ limit: limit });

try {
const response = await fetch(`${BASE_URL}/${productId}/comments?${params.toString()}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (!response.ok) {
handleResponseError(response);
}

const data = await response.json();
return data;
} catch (error) {
if (error instanceof HttpException) {
throw error;
} else {
console.error("네트워크 오류", error);
throw new Error("네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.");
}
}
};
4 changes: 4 additions & 0 deletions src/assets/icons/ic_back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/ic_kebab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/assets/images/Img_inquiry_empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions src/components/section/CommentList/CommentList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.comments-list {
display: flex;
flex-direction: column;
}

.comment-wrapper {
display: flex;
flex-direction: column;
padding-bottom: 12px;
border-bottom: 1px solid #e5e7eb;
}

.comment-author {
display: flex;
}

.comment-options {
width: 16px;
height: 16px;
cursor: pointer;
margin-left: auto;
}

.comment-content {
font-size: 14px;
color: #1f2937;
padding-top: 14px;
}

.comment-profile-image {
padding-right: 15px;
}

.comment-author-detail {
display: flex;
flex-direction: column;
gap: 4px;
}

.comment-nickname {
font-size: 12px;
color: #4b5563;
line-height: 18px;
}

.comment-date {
font-size: 12px;
line-height: 18px;
color: #9ca3af;
}

.comment-empty {
margin: 0 auto;
text-align: center;
}

.comment-empty-text {
color: #9ca3af;
}
41 changes: 41 additions & 0 deletions src/components/section/CommentList/CommentList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { formatRelativeTime } from "../../../utils/formatRelativeTime";
import "./CommentList.css";
import profile from "../../../assets/images/profile.svg";
import ic_kebab from "../../../assets/icons/ic_kebab.svg";
import inquiry_empty from "../../../assets/images/Img_inquiry_empty.svg";

function CommentList({ comments }) {
const getRelativeTime = (createdAt, updatedAt) => {
if (updatedAt && updatedAt !== createdAt) {
return formatRelativeTime(updatedAt);
}
return formatRelativeTime(createdAt);
};

return (
<div className="comments-list">
{comments?.length > 0 ? (
comments.map((comment) => (
<div key={comment.id} className="comment-wrapper">
<p className="comment-content">{comment.content}</p>
<img src={ic_kebab} alt="수정 삭제 버튼" className="comment-options" />
<div className="comment-author">
<img src={profile} alt={`${comment.writer.nickname} 프로필 이미지`} className="comment-profile-image" />
<div className="comment-author-detail">
<p className="comment-nickname">{comment.writer.nickname}</p>
<p className="comment-date">{getRelativeTime(comment.createdAt, comment.updatedAt)}</p>
</div>
</div>
</div>
))
) : (
<div className="comment-empty">
<img src={inquiry_empty} alt="댓글 없음" className="comment-empty-image" />
<p className="comment-empty-text">아직 문의가 없어요</p>
</div>
)}
</div>
);
}

export default CommentList;
29 changes: 29 additions & 0 deletions src/components/section/InquiryForm/InquiryForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.inquiry-form {
width: 100%;
max-width: 1200px;
margin: 0 auto;
position: relative;
padding: 30px 0;
}

.custom-inquiry-input {
height: 104px;
}

.inquiry-button {
padding: 12px 23px;
border-radius: 8px;
border: none;
background-color: #9ca3af;
color: #f3f4f6;
transition: background-color 0.3s ease;
}

.inquiry-button.active {
background-color: #3692ff;
}

.inquiry-button-wrapper {
display: flex;
justify-content: flex-end;
}
34 changes: 34 additions & 0 deletions src/components/section/InquiryForm/InquiryForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from "react";
import InputItem from "../../ui/Input/InputItem";
import "./InquiryForm.css";

const inquiryPlacholder =
"개인정보를 공유 및 요청하거나, 명예훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다.";

function InquiryForm() {
const [inputValue, setInputValue] = useState("");

const handleInputChange = (e) => {
setInputValue(e.target.value);
};

return (
<form className="inquiry-form">
<InputItem
isTextArea
id="inquiry"
title="문의하기"
placeholder={inquiryPlacholder}
className="custom-inquiry-input"
onChange={handleInputChange}
/>
<div className="inquiry-button-wrapper">
<button type="submit" className={`inquiry-button ${inputValue ? "active" : ""} `}>
등록
</button>
</div>
</form>
);
}

export default InquiryForm;
114 changes: 114 additions & 0 deletions src/components/section/ProductInfo/ProductInfo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
.item-detail-info {
display: flex;
width: 100%;
gap: 24px;
padding-bottom: 25px;
border-bottom: 1px solid #e5e7eb;
}

.item-detail-thumbnail {
width: 100%;
max-width: 486px;
height: auto;
object-fit: cover;
overflow: hidden;
aspect-ratio: 1;
border-radius: 16px;
margin-bottom: 16px;
}

.item-detail-options {
width: 3px;
height: 13px;
}

.item-detail-info-section {
width: 100%;
max-width: 690px;
display: flex;
flex-direction: column;
justify-content: space-around;
}

.item-detail-header {
display: flex;
justify-content: space-between;
padding-bottom: 10px;
border-bottom: 1px solid #e5e7eb;
width: 100%;
}

.item-detail-name {
font-size: 24px;
font-weight: 600;
color: #1f2937;
padding-bottom: 8px;
}

.item-detail-price {
font-size: 40px;
font-weight: 600;
line-height: 47px;
color: #1f2937;
}

.item-detail-description {
display: flex;
flex-direction: column;
padding: 14px 0;
gap: 20px;
}

.item-detail-description h3 {
font-size: 16px;
font-weight: 600;
color: #4b5563;
}

.item-detail-description p {
color: #4b5563;
}

.item-detail-tags {
display: flex;
flex-direction: column;
padding: 14px 0;
gap: 20px;
}

.item-detail-tags h3 {
font-size: 16px;
font-weight: 600;
color: #4b5563;
}

.item-detail-tags-wrapper {
display: flex;
list-style: none;
gap: 10px;
}

.item-detail-tag {
list-style: none;
padding: 6px 16px;
background-color: #f3f4f6;
border-radius: 26px;
color: #1f2937;
}

@media (max-width: 1199px) {
.item-detail-thumbnail {
width: 100%;
}
}

@media (max-width: 767px) {
.item-detail-info {
flex-direction: column;
}

.item-detail-thumbnail {
max-width: 100%;
width: 100%;
}
}
Loading

0 comments on commit bdf381d

Please sign in to comment.