Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 1 addition & 2 deletions components/Footer.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
.footerBanner {
background-color: #111827;
width: 100%;
margin-top: 100px;
height: 160px;
padding: 32px 200px 32px 200px;
width: auto;
}

.footerBannerContent {
Expand Down
29 changes: 24 additions & 5 deletions components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@ import styles from "./Header.module.css";
import Link from "next/link";
import { useRouter } from "next/router";
import Image from "next/image";
import { useState, useEffect } from "react";

function Header() {
const router = useRouter();
const pathname = router;
const pathname = router.pathname;
const isItemPage = pathname === "/items";
const isFreePage = pathname === "/free";

const [accessToken, setAccessToken] = useState(null);

useEffect(() => {
// 클라이언트에서만 localStorage를 확인
const token = localStorage.getItem("accessToken");
setAccessToken(token);
}, []);

const handleLogout = () => {
if (accessToken) {
localStorage.removeItem("accessToken");
setAccessToken(null);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

로그아웃 할 때 accessToken은 삭제해주지만 refreshToken은 삭제하지 않은 이유가 있을까요? refreshToken만 있다면 유저는 로그인을 임의로 수행할 수도 있습니다. 로그아웃이란 유저의 세션을 모두 날리는 작업을 의미합니다. 때문에 특별한 의미가 없다면 refreshToken또한 삭제해주시는게 좋을 수 있습니다.

또한 로그인시에 로컬스토리지에 토큰을 넣는 동작을 수행하는데, 이렇게 로그인시에 토큰을 관리하는 로직을 별도의 훅으로 분리해서 동작시킬 수 있습니다. 그렇게 되면 로컬스토리지에 필요한 키값을 내부의 모듈안에서만 관리할 수 있고, 로그인에 필요한 동작들을 모듈화 할 수 있는 장점이 있습니다.

}
};

return (
<section className={styles.topNav}>
<div className={styles.navCon}>
Expand Down Expand Up @@ -38,10 +54,13 @@ function Header() {
</Link>
</div>

{/* 글씨 만이 아닌 여백을 클릭해도 링크 이동하기 위함 */}
<Link href="/login" className={styles.topNavLoginBt}>
로그인
</Link>
{accessToken ? (
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

accessToken이 있는지로 로그인이 확인되면 만로된 accessToken일때는 로그인이 되지않은 상태이지만, 여전히 로그인버튼은 노출되지 않을 수 있습니다.

<div onClick={handleLogout}>테스트</div>
) : (
<Link href="/login" className={styles.topNavLoginBt}>
로그인
</Link>
)}
</div>
</section>
);
Expand Down
2 changes: 1 addition & 1 deletion components/Header.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@
font-weight: bold;
text-decoration: none;
}
.navLinkBt.active {
.active {
color: #3692ff;
}
15 changes: 15 additions & 0 deletions components/LikeButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import styles from "./LikeButton.module.css";
import Image from "next/image";

export default function LikeButton({ favoriteCount }) {
return (
<button className={styles.likeBt}>
<div className={styles.btContents}>
<div className={styles.likeImgBox}>
<Image fill alt="heart" src="/imgs/ic_heart.png" />
</div>
<div className={styles.likeCount}>{favoriteCount}</div>
</div>
</button>
);
}
25 changes: 25 additions & 0 deletions components/LikeButton.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.likeBt {
height: 40px;
background-color: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 35px;
padding: 4px 12px 4px 12px;
}

.btContents {
display: flex;
gap: 4px;
align-items: center;
}

.likeImgBox {
position: relative;
width: 32px;
height: 32px;
}
.likeCount {
font-size: 16px;
line-height: 26px;
font-weight: 500;
color: #6b7280;
}
16 changes: 0 additions & 16 deletions components/NoComment.js

This file was deleted.

1 change: 0 additions & 1 deletion components/UpdateDropDown.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export default function UpdateDropDown() {
};
}, [isOpen]);

const handleClick = () => {};
return (
<div className={styles.dropdown} ref={dropdownRef}>
<button className={styles.articleChangeBt} onClick={toggleDropdown}>
Expand Down
2 changes: 1 addition & 1 deletion components/UpdateDropDown.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
border: 1px solid #e5e7eb;
border-radius: 12px;
background-color: white;
right: 220px;

width: 139px;
z-index: 1;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styles from "./ArticleDetail.module.css";
import Image from "next/image";
import UpdateDropDown from "./UpdateDropDown";
import UpdateDropDown from "../UpdateDropDown";

export default function ArticleDetail({ article }) {
return (
Expand Down Expand Up @@ -28,7 +28,7 @@ export default function ArticleDetail({ article }) {
<div className={styles.likeImgBox}>
<Image fill alt="heart" src="/imgs/ic_heart.png" />
</div>
<div>123</div>
<div className={styles.likeCount}>123</div>
</div>
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,10 @@
width: 32px;
height: 32px;
}

.likeCount {
font-size: 16px;
line-height: 26px;
font-weight: 500;
color: #6b7280;
}
25 changes: 17 additions & 8 deletions components/Comment.js → components/comment/Comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import InputComment from "./InputComment";
import CommentList from "./CommentList";
import NoComment from "./NoComment";
import { useState, useEffect } from "react";
import axios from "@/lib/axios";
// import axios from "@/lib/axios";
import codeitAxios from "@/lib/codeitAxios";

export default function Comment({ id }) {
export default function Comment({ id, isArticle }) {
const [value, setValue] = useState("");
const [comments, setComments] = useState([]);
const [isSubmitting, setIsSubmitting] = useState(false);

async function getComments() {
const response = await axios.get(`/article/${id}/comments`);
const comments = response.data ?? [];
const response = await codeitAxios.get(
isArticle
? `/articles/${id}/comments?limit=5`
: `/products/${id}/comments?limit=5`
);
const comments = response.data.list ?? [];
setComments(comments);
return response.data;
}
Expand All @@ -27,9 +32,12 @@ export default function Comment({ id }) {
async function createComment() {
try {
setIsSubmitting(true);
const response = await axios.post(`/article/${id}/comment`, {
content: value,
});
const response = await codeitAxios.post(
isArticle ? `/articles/${id}/comments` : `/products/${id}/comments`,
{
content: value,
}
);
return response.data;
} catch (err) {
console.log(err);
Expand All @@ -53,11 +61,12 @@ export default function Comment({ id }) {
setValue={setValue}
getComments={getComments}
isSubmitting={isSubmitting}
isArticle={isArticle}
/>
{comments.length > 0 ? (
<CommentList comments={comments} />
) : (
<NoComment />
<NoComment isArticle />
)}
</div>
);
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import styles from "./CommentLayout.module.css";
import Image from "next/image";
import UpdateDropDown from "./UpdateDropDown";
import UpdateDropDown from "../UpdateDropDown";
import formatUpdatedTime from "@/lib/formatDate";

export default function Comment({ comment }) {
const username = comment.writer.nickname;
const updatedAt = comment.updatedAt;

const updatedTime = formatUpdatedTime(updatedAt); // 하루 지나면 날짜 안지나면 ?시간 전 리턴

return (
<div className={styles.commentBox}>
<div className={styles.contents}>
Expand All @@ -12,8 +18,8 @@ export default function Comment({ comment }) {
<Image fill alt="userProfileImg" src="/imgs/userProfileImg.png" />
</div>
<div className={styles.nameAndDate}>
<div>똑똑한 판다</div>
<div>1시간 전</div>
<div>{username}</div>
<div>{updatedTime}</div>
</div>
</div>
</div>
Expand Down
File renamed without changes.
12 changes: 10 additions & 2 deletions components/InputComment.js → components/comment/InputComment.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { useRouter } from "next/router";
import styles from "./InputComment.module.css";

export default function InputComment({
handleClick,
value,
setValue,
isSubmitting,
isArticle,
}) {
const isBtDisabled = !value.trim();

return (
<div className={styles.container}>
<div className={styles.inputBox}>
<div className={styles.mediumText}>댓글달기</div>
<div className={styles.mediumText}>
{isArticle ? "댓글달기" : "문의하기"}
</div>
<textarea
className={styles.textArea}
placeholder="댓글 입력해주세요"
placeholder={
isArticle
? "댓글 입력해주세요"
: "개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
Expand Down
30 changes: 30 additions & 0 deletions components/comment/NoComment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Image from "next/image";
import styles from "./NoComment.module.css";

export default function NoComment({ isArticle }) {
return (
<div className={styles.noComment}>
<div className={styles.imgBox}>
<Image
fill
src={
isArticle
? "/imgs/img_reply_empty.png"
: "/imgs/img_inquiry_empty.png"
}
alt="emptyImg"
/>
</div>
<div className={styles.textCenter}>
{isArticle ? (
<>
<span> 아직 댓글이 없어요,</span>
<span> 지금 댓글을 달아보세요!</span>
</>
) : (
<span>아직 문의가 없어요</span>
)}
</div>
</div>
);
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function ArticleList({ articles }) {
{articles.map((article) => (
<Link
key={article.id}
href={`/article/${article.id}`}
href={`/articles/${article.id}`}
style={{ textDecoration: "none" }}
>
<Article article={article} />
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function BestArticleList({ bestArticles }) {
<div className={styles.bestArticleList}>
{bestArticles.map((article) => (
<Link
href={`/article/${article.id}`}
href={`/articles/${article.id}`}
style={{ textDecoration: "none" }}
key={article.id}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function Dropdown({ options, order, orderChange }) {
return (
<div className={styles.dropdown} ref={dropdownRef}>
<button className={styles.dropdownButton} onClick={toggleDropdown}>
{order}
{order.label}
<span className="arrow">▼</span>
</button>
{/* 열린 상태(isOpen = true)이면 보이게 */}
Expand All @@ -52,7 +52,7 @@ function Dropdown({ options, order, orderChange }) {
className={styles.dropdownItem}
onClick={() => handleSelect(option)}
>
{option}
{option.label}
</div>
))}
</div>
Expand Down
41 changes: 41 additions & 0 deletions components/itemDetail/ItemDescription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import styles from "./ItemDescription.module.css";

export default function ItemDescription({ description, tags }) {
return (
<div className={styles.itemDescriptionBox}>
{/* 상품 소개 */}
<div className={styles.itemDescription}>
<div className={`${styles.descriptionText} ${styles.middleWeight}`}>
상품 소개
</div>
<div className={`${styles.descriptionText} ${styles.smallWeight}`}>
{description}
{/* .split(".")
.filter((sentence) => sentence.trim() !== "") // 빈 문장 제거
.map((sentence, index) => (
<p key={index}>{sentence.trim()}.</p> // 문장을 p 태그로 감쌈
))} */}
</div>
</div>
{/* 상품 태그 */}
<div className={styles.itemTagBox}>
<div className={`${styles.descriptionText} ${styles.middleWeight}`}>
상품 태그
</div>
<div className={styles.itemTagList}>
{!tags ? (
<div className={styles.itemTag}> 로딩 중입니다 </div>
) : tags.length === 0 ? (
<div className={styles.itemTag}> 태그가 없습니다 </div>
) : (
tags.map((tag, index) => {
<div key={index} className={styles.itemTag}>
#{tag}
</div>;
})
)}
</div>
</div>
</div>
);
}
Loading