-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #247 from myong39/Next-서미영-sprint9
[서미영] Sprint9
- Loading branch information
Showing
63 changed files
with
1,774 additions
and
473 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { getLinkStyle } from "@/utils/Utils"; | ||
import Link from "next/link"; | ||
import { useRouter } from "next/router"; | ||
import { CSSProperties } from "react"; | ||
|
||
interface NavLinkProps { | ||
href: string; | ||
children: React.ReactNode; | ||
style?: CSSProperties; | ||
} | ||
|
||
const NavLink: React.FC<NavLinkProps> = ({ href, children }) => { | ||
const router = useRouter(); | ||
const isActive = router.pathname === href; | ||
const style: CSSProperties = isActive ? getLinkStyle({ isActive: true }) : {}; | ||
|
||
return ( | ||
<Link href={href} style={style}> | ||
{children} | ||
</Link> | ||
); | ||
}; | ||
|
||
export default NavLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { ArticleProp } from "@/types/articleTypes"; | ||
import styles from "./Freeboard.module.scss"; | ||
import favoriteImg from "@/public/images/icons/ic_heart.svg"; | ||
import { getFormatTime } from "@/utils/Utils"; | ||
|
||
export default function AllArticleItem({ | ||
article: { createdAt, image, likeCount, title, writer }, | ||
}: ArticleProp) { | ||
return ( | ||
<div className={styles["all-card"]}> | ||
<div className={styles["content-wrapper"]}> | ||
<div className={styles["title-wrapper"]}> | ||
<h2 className={styles["card-title"]}>{title}</h2> | ||
{image && ( | ||
<div className={styles["item-box"]}> | ||
<img className={styles.item} src={image} alt="대표 이미지" /> | ||
</div> | ||
)} | ||
</div> | ||
<div className={styles["writer-wrapper"]}> | ||
<div className={styles["nickname-wrapper"]}> | ||
<span className={styles["nickname"]}>{writer.nickname}</span> | ||
<span className={styles["date"]}> | ||
{getFormatTime(createdAt, false)} | ||
</span> | ||
</div> | ||
<div className={styles["favorite-wrapper"]}> | ||
<img | ||
className={styles["favorite"]} | ||
src={favoriteImg.src} | ||
alt="즐겨찾기" | ||
/> | ||
<span className={styles["favorite-count"]}>{likeCount}</span> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { useEffect, useState } from "react"; | ||
import styles from "./Freeboard.module.scss"; | ||
import AllArticleItem from "./AllArticleItem"; | ||
import { Article, ArticleApiData } from "@/types/articleTypes"; | ||
import SearchInput from "@/components/layout/SearchInput"; | ||
import Button from "@/components/layout/Button"; | ||
import Dropdown from "@/components/layout/Dropdown"; | ||
import Link from "next/link"; | ||
import { getArticle } from "@/lib/articleApi"; | ||
import { useRouter } from "next/router"; | ||
|
||
export default function AllArticleList({ | ||
initialArticles, | ||
}: { | ||
initialArticles: Article[]; | ||
}) { | ||
const [articles, setArticles] = useState(initialArticles); | ||
const [orderBy, setOrderBy] = useState<ArticleApiData["orderBy"]>("recent"); | ||
|
||
const router = useRouter(); | ||
const keyword = router.query.q; | ||
|
||
const handleOrderChange = (option: string) => { | ||
if (option === "recent" || option === "like") setOrderBy(option); | ||
}; | ||
|
||
const fetchData = async ({ orderBy, pageSize, keyword }: ArticleApiData) => { | ||
try { | ||
const searchKeyword = Array.isArray(keyword) ? keyword[0] : keyword; | ||
const result = await getArticle({ | ||
orderBy, | ||
pageSize, | ||
keyword: searchKeyword, | ||
}); | ||
|
||
setArticles(() => result.list); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
}; | ||
|
||
const handleSortBySearch = (value: string) => { | ||
const searchValue = value.trim(); | ||
|
||
if (!searchValue) { | ||
router.push("/boards"); | ||
return; | ||
} | ||
|
||
router.push(`/boards?q=${searchValue}`); | ||
}; | ||
|
||
useEffect(() => { | ||
fetchData({ orderBy: orderBy, keyword: keyword }); | ||
}, [orderBy, keyword]); | ||
|
||
return ( | ||
<section className={styles["all-article"]}> | ||
<div className={styles["all-title-wrapper"]}> | ||
<h1 className={styles.title}>게시글</h1> | ||
<Button>글쓰기</Button> | ||
</div> | ||
<div className={styles["search-wrapper"]}> | ||
<SearchInput onSortBySearch={handleSortBySearch} /> | ||
<Dropdown onOrderChange={handleOrderChange} /> | ||
</div> | ||
{articles.length | ||
? articles.map((article) => ( | ||
<Link href={`/board/${article.id}`} key={article.id}> | ||
<AllArticleItem article={article} /> | ||
</Link> | ||
)) | ||
: keyword && <div>{`'${keyword}'(으)로 검색된 결과가 없습니다.`}</div>} | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import styles from "./Freeboard.module.scss"; | ||
import badgeImg from "@/public/images/icons/img_badge.svg"; | ||
import favoriteImg from "@/public/images/icons/ic_heart.svg"; | ||
import { ArticleProp } from "@/types/articleTypes"; | ||
import { getFormatTime } from "@/utils/Utils"; | ||
|
||
export default function BestArticleItem({ | ||
article: { createdAt, image, likeCount, title, writer }, | ||
}: ArticleProp) { | ||
return ( | ||
<div className={styles["best-card"]}> | ||
<img className={styles.badge} src={badgeImg.src} alt="Best 뱃지" /> | ||
<div className={styles["content-wrapper"]}> | ||
<div className={styles["title-wrapper"]}> | ||
<h2 className={styles["card-title"]}>{title}</h2> | ||
{image && ( | ||
<div className={styles["item-box"]}> | ||
<img className={styles.item} src={image} alt="대표 이미지" /> | ||
</div> | ||
)} | ||
</div> | ||
<div className={styles["writer-wrapper"]}> | ||
<div className={styles["nickname-wrapper"]}> | ||
<span className={styles["nickname"]}>{writer.nickname}</span> | ||
<div className={styles["favorite-wrapper"]}> | ||
<img | ||
className={styles["favorite"]} | ||
src={favoriteImg.src} | ||
alt="즐겨찾기" | ||
/> | ||
<span className={styles["favorite-count"]}>{likeCount}</span> | ||
</div> | ||
</div> | ||
<span className={styles["date"]}> | ||
{getFormatTime(createdAt, false)} | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { useEffect, useState } from "react"; | ||
import styles from "./Freeboard.module.scss"; | ||
import BestArticleItem from "./BestArticleItem"; | ||
import { getArticle } from "@/lib/articleApi"; | ||
import { Article, ArticleApiData } from "@/types/articleTypes"; | ||
import Link from "next/link"; | ||
import useDeviceType from "@/hooks/useDeviceType"; | ||
import { DeviceTypePageSize } from "@/types/articleTypes"; | ||
|
||
const ORDERBY = "like"; | ||
|
||
export default function BestArticleList() { | ||
const [articles, setArticles] = useState<Article[]>([]); | ||
const { isMobile, isTablet } = useDeviceType(); | ||
const { MOBILE_PAGE_SIZE, TABLET_PAGE_SIZE, DESKTOP_PAGE_SIZE } = | ||
DeviceTypePageSize; | ||
|
||
const pageSize = isTablet | ||
? TABLET_PAGE_SIZE | ||
: isMobile | ||
? MOBILE_PAGE_SIZE | ||
: DESKTOP_PAGE_SIZE; | ||
|
||
const fetchData = async ({ orderBy, pageSize }: ArticleApiData) => { | ||
try { | ||
const result = await getArticle({ orderBy, pageSize }); | ||
|
||
setArticles(() => result.list); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
fetchData({ orderBy: ORDERBY, pageSize: pageSize }); | ||
}, [pageSize]); | ||
|
||
return ( | ||
<section className={styles["best-article"]}> | ||
<h1 className={styles.title}>베스트 게시글</h1> | ||
<div className={styles["card-container"]}> | ||
{articles.map((article) => ( | ||
<Link href={`/board/${article.id}`} key={article.id}> | ||
<BestArticleItem article={article} /> | ||
</Link> | ||
))} | ||
</div> | ||
</section> | ||
); | ||
} |
Oops, something went wrong.