Skip to content

Commit 48cfdc8

Browse files
김수영KimSuyoung
andauthored
[김수영] sprint9 (#118)
* feat: 폴더구조 수정, header 추가 * feat:베스트게시글 ui * feat: 게시물리스트 ui * feat:전체게시물 불러오기 * feat:게시물 검색 * style:반응형 * fix:github branch-config --------- Co-authored-by: KimSuyoung <kimsuyoung@KimSuyoungui-MacBookAir.local>
1 parent 8d163dd commit 48cfdc8

37 files changed

+1918
-500
lines changed

.babelrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["next/babel"],
3+
"plugins": ["babel-plugin-styled-components"]
4+
}

.bash_profile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
parse_git_branch() {
2+
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
3+
}
4+
export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "

.github/workflows/delete-merged-branch-config.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ jobs:
88
delete-branch:
99
runs-on: ubuntu-latest
1010
steps:
11-
- name: delete branch
11+
- name: Checkout repository
12+
uses: actions/checkout@v3
13+
14+
- name: Check if branch exists
15+
id: check_branch
16+
run: |
17+
if git show-ref --verify --quiet refs/heads/${{ github.head_ref }}; then
18+
echo "branch_exists=true" >> $GITHUB_ENV
19+
else
20+
echo "branch_exists=false" >> $GITHUB_ENV
21+
fi
22+
23+
- name: Delete branch
24+
if: env.branch_exists == 'true'
1225
uses: SvanBoxel/delete-merged-branch@main
1326
env:
14-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

components/_styled/boardStyled.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import styled from "styled-components";
2+
3+
export const BoardPage = styled.div`
4+
width:100%;
5+
display:flex;
6+
flex-direction:column;
7+
align-items:center;
8+
justify-content:center;
9+
`;
10+
export const BoardPageContainer = styled.div`
11+
max-width:1200px;
12+
width:100%;
13+
margin-top:24px;
14+
display:flex;
15+
gap:40px;
16+
flex-direction:column;
17+
18+
@media(max-width:1199px){
19+
max-width:696px;
20+
}
21+
@media(max-width:767px){
22+
max-width:343px;
23+
}
24+
`;

components/_styled/mainStyled.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import styled from "styled-components";
2+
3+
export const MainWrapper = styled.div`
4+
width: 100%;
5+
height: 100%;
6+
display: flex;
7+
align-items: center;
8+
`;
9+
export const MainContainer = styled.div`
10+
width: 100%;
11+
`;

components/boards/BestPost.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { useState, useEffect, useCallback} from 'react';
2+
import * as BS from './Styled';
3+
import BestPostCard from './BestPostCard';
4+
import { Item, ItemList } from './PostList';
5+
import { getArticles } from '@/pages/api/api';
6+
7+
interface ItemCardProps {
8+
item: Item;
9+
}
10+
11+
interface ItemListProps {
12+
itemList : ItemList;
13+
}
14+
15+
export default function BestPost() {
16+
const [itemList, setItemList] = useState<ItemList>({ totalCount: 0, list: [] });
17+
const [pageSize, setPageSize] = useState(4);
18+
const [order, setOrder] = useState('like');
19+
const fetchSortedData = useCallback(async () => {
20+
try {
21+
const articles = await getArticles({ orderBy: order, pageSize });
22+
setItemList(articles);
23+
console.log(articles);
24+
} catch (error) {
25+
console.error('Error fetching articles:', error);
26+
}
27+
}, [order, pageSize]);
28+
29+
useEffect(() => {
30+
fetchSortedData();
31+
}, [fetchSortedData]);
32+
33+
useEffect(() => {
34+
const handleResize = () => {
35+
const width = window.innerWidth;
36+
if (width < 767) {
37+
setPageSize(1);
38+
} else if (width < 1280) {
39+
setPageSize(2);
40+
} else {
41+
setPageSize(4);
42+
}
43+
};
44+
45+
window.addEventListener('resize', handleResize);
46+
handleResize();
47+
48+
return () => {
49+
window.removeEventListener('resize', handleResize);
50+
};
51+
}, []);
52+
53+
return (
54+
<BS.BestPostConainer>
55+
<BS.Title>베스트 게시글</BS.Title>
56+
<BS.BestCardListContainer>
57+
{itemList.list.map((item) => (
58+
<BestPostCard key={item.id} item={item} />
59+
))}
60+
</BS.BestCardListContainer>
61+
</BS.BestPostConainer>
62+
);
63+
}

components/boards/BestPostCard.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import * as BS from './Styled';
3+
import MedalIcon from '../common/images/ic_medal.png';
4+
import LikeIcon from '../common/images/ic_heart.png';
5+
import DefaultImg from '../common/images/default.png';
6+
import { Item } from './PostList';
7+
import formatDate from '../common/function/formatDate';
8+
9+
interface ItemCardProps {
10+
item:Item;
11+
}
12+
13+
14+
const BestPostCard:React.FC<ItemCardProps> = ({ item }) => {
15+
return (
16+
<BS.BestCardContainer>
17+
<BS.BestBadgeContainer>
18+
<BS.MedalIcon src={MedalIcon} alt="메달아이콘" />
19+
<BS.BestText>Best</BS.BestText>
20+
</BS.BestBadgeContainer>
21+
<BS.BestPostContentContainer>
22+
<BS.BestPostContentText>{item.title}</BS.BestPostContentText>
23+
<BS.BestPostImg
24+
src={item.image ? item.image : DefaultImg}
25+
width={72}
26+
height={72}
27+
alt="게시물 이미지" >
28+
</BS.BestPostImg>
29+
</BS.BestPostContentContainer>
30+
<BS.SubContainer>
31+
<BS.InfoContainer>
32+
<BS.Writer>{item.writer.nickname}</BS.Writer>
33+
<BS.LikeIcon src={LikeIcon} alt="좋아요 아이콘"></BS.LikeIcon>
34+
<BS.LikeCount>{item.likeCount}</BS.LikeCount>
35+
</BS.InfoContainer>
36+
<BS.PostDate>{formatDate(item.createdAt)}</BS.PostDate>
37+
</BS.SubContainer>
38+
</BS.BestCardContainer>
39+
);
40+
}
41+
export default BestPostCard;

components/boards/PostCard.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import * as PS from './Styled';
3+
import DefaultImg from '../common/images/default.png';
4+
import LikeIcon from '../common/images/ic_heart.png';
5+
import ProfileImg from '../common/images/profile.png';
6+
import { Item } from './PostList';
7+
import formatDate from '../common/function/formatDate';
8+
9+
interface ItemCardProps {
10+
item: Item;
11+
}
12+
13+
const PostCard: React.FC<ItemCardProps> = ({ item }) => {
14+
return (
15+
<PS.PostCardContainer>
16+
<PS.PostContentContainer>
17+
<PS.BestPostContentText>{item.title}</PS.BestPostContentText>
18+
<PS.BestPostImg
19+
src={item.image ? item.image : DefaultImg}
20+
width={72}
21+
height={72}
22+
alt="게시물 이미지"
23+
/>
24+
</PS.PostContentContainer>
25+
<PS.SubContainer>
26+
<PS.InfoContainer>
27+
<PS.ProfileImg
28+
src={ProfileImg}
29+
30+
alt="프로필 이미지"
31+
/>
32+
<PS.Writer>{item.writer.nickname}</PS.Writer>
33+
<PS.PostDate>{formatDate(item.createdAt)}</PS.PostDate>
34+
</PS.InfoContainer>
35+
<PS.InfoContainer>
36+
<PS.LikeIcon
37+
src={LikeIcon}
38+
alt="좋아요 아이콘"
39+
/>
40+
<PS.LikeCount>{item.likeCount}</PS.LikeCount>
41+
</PS.InfoContainer>
42+
</PS.SubContainer>
43+
</PS.PostCardContainer>
44+
);
45+
}
46+
47+
export default PostCard;

components/boards/PostList.tsx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import React, { useState, useEffect, useCallback } from 'react';
2+
import { useRouter } from 'next/router';
3+
import * as BS from './Styled';
4+
import PostCard from './PostCard';
5+
import { getArticles } from '@/pages/api/api';
6+
7+
export interface Item {
8+
id: number;
9+
title: string;
10+
content: string;
11+
image: string;
12+
writer: Writer;
13+
likeCount: number;
14+
updatedAt: string;
15+
createdAt: string;
16+
}
17+
18+
interface Writer {
19+
nickname: string;
20+
id: number;
21+
}
22+
23+
export interface ItemList {
24+
totalCount: number;
25+
list: Item[];
26+
}
27+
28+
export default function PostList() {
29+
const [itemList, setItemList] = useState<ItemList>({ totalCount: 0, list: [] });
30+
const [pageSize, setPageSize] = useState(4);
31+
const [order, setOrder] = useState('recent');
32+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
33+
const [search, setSearch] = useState('');
34+
35+
const router = useRouter();
36+
const{ q } = router.query;
37+
38+
const toggleDropdown = () => {
39+
setIsDropdownOpen(!isDropdownOpen);
40+
};
41+
42+
const handleNewestClick = () => {
43+
setOrder('recent');
44+
setIsDropdownOpen(false);
45+
};
46+
47+
const handleLikeClick = () => {
48+
setOrder('like');
49+
setIsDropdownOpen(false);
50+
};
51+
52+
const handleChange = (e:React.ChangeEvent<HTMLInputElement>) => setSearch(e.target.value);
53+
const fetchSortedData = useCallback(async () => {
54+
try {
55+
const articles = await getArticles({ orderBy: order, pageSize: 1, keyword:search});
56+
const totalCount = articles.totalCount;
57+
const allArticles = await getArticles({ orderBy: order, pageSize: totalCount, keyword:search});
58+
setItemList(allArticles);
59+
console.log(allArticles);
60+
} catch (error) {
61+
console.error('Error fetching articles:', error);
62+
}
63+
}, [order, search]);
64+
65+
useEffect(() => {
66+
fetchSortedData();
67+
}, [fetchSortedData]);
68+
69+
return (
70+
<BS.PostListContainer>
71+
<BS.PostListHeader>
72+
<BS.Title>게시물</BS.Title>
73+
<BS.PostButton>글쓰기</BS.PostButton>
74+
</BS.PostListHeader>
75+
<BS.SearchContainer>
76+
<BS.SearchBox
77+
type='text'
78+
placeholder='검색할 상품을 입력해주세요'
79+
onChange={handleChange}
80+
value={search}
81+
>
82+
</BS.SearchBox>
83+
<BS.DropdownButtonContainer>
84+
<BS.DropdownButton onClick={toggleDropdown}>
85+
{order === 'recent' ? '최신순' : '좋아요순'} <BS.DropdownArrow></BS.DropdownArrow>
86+
</BS.DropdownButton>
87+
<BS.DropdownMenu $isOpen={isDropdownOpen}>
88+
<BS.DropdownOption onClick={handleNewestClick}>최신순</BS.DropdownOption>
89+
<BS.DropdownOption onClick={handleLikeClick}>좋아요순</BS.DropdownOption>
90+
</BS.DropdownMenu>
91+
</BS.DropdownButtonContainer>
92+
</BS.SearchContainer>
93+
{itemList.list.map((item) => (
94+
<PostCard key={item.id} item={item} />
95+
))}
96+
</BS.PostListContainer>
97+
);
98+
}

0 commit comments

Comments
 (0)