Skip to content

Commit

Permalink
[김수영] sprint9 (#118)
Browse files Browse the repository at this point in the history
* feat: 폴더구조 수정, header 추가

* feat:베스트게시글 ui

* feat: 게시물리스트 ui

* feat:전체게시물 불러오기

* feat:게시물 검색

* style:반응형

* fix:github branch-config

---------

Co-authored-by: KimSuyoung <[email protected]>
  • Loading branch information
swim-kim and KimSuyoung authored Oct 29, 2024
1 parent 8d163dd commit 48cfdc8
Show file tree
Hide file tree
Showing 37 changed files with 1,918 additions and 500 deletions.
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["next/babel"],
"plugins": ["babel-plugin-styled-components"]
}
4 changes: 4 additions & 0 deletions .bash_profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "
17 changes: 15 additions & 2 deletions .github/workflows/delete-merged-branch-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@ jobs:
delete-branch:
runs-on: ubuntu-latest
steps:
- name: delete branch
- name: Checkout repository
uses: actions/checkout@v3

- name: Check if branch exists
id: check_branch
run: |
if git show-ref --verify --quiet refs/heads/${{ github.head_ref }}; then
echo "branch_exists=true" >> $GITHUB_ENV
else
echo "branch_exists=false" >> $GITHUB_ENV
fi
- name: Delete branch
if: env.branch_exists == 'true'
uses: SvanBoxel/delete-merged-branch@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 changes: 24 additions & 0 deletions components/_styled/boardStyled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styled from "styled-components";

export const BoardPage = styled.div`
width:100%;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
`;
export const BoardPageContainer = styled.div`
max-width:1200px;
width:100%;
margin-top:24px;
display:flex;
gap:40px;
flex-direction:column;
@media(max-width:1199px){
max-width:696px;
}
@media(max-width:767px){
max-width:343px;
}
`;
11 changes: 11 additions & 0 deletions components/_styled/mainStyled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from "styled-components";

export const MainWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
align-items: center;
`;
export const MainContainer = styled.div`
width: 100%;
`;
63 changes: 63 additions & 0 deletions components/boards/BestPost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState, useEffect, useCallback} from 'react';
import * as BS from './Styled';
import BestPostCard from './BestPostCard';
import { Item, ItemList } from './PostList';
import { getArticles } from '@/pages/api/api';

interface ItemCardProps {
item: Item;
}

interface ItemListProps {
itemList : ItemList;
}

export default function BestPost() {
const [itemList, setItemList] = useState<ItemList>({ totalCount: 0, list: [] });
const [pageSize, setPageSize] = useState(4);
const [order, setOrder] = useState('like');
const fetchSortedData = useCallback(async () => {
try {
const articles = await getArticles({ orderBy: order, pageSize });
setItemList(articles);
console.log(articles);
} catch (error) {
console.error('Error fetching articles:', error);
}
}, [order, pageSize]);

useEffect(() => {
fetchSortedData();
}, [fetchSortedData]);

useEffect(() => {
const handleResize = () => {
const width = window.innerWidth;
if (width < 767) {
setPageSize(1);
} else if (width < 1280) {
setPageSize(2);
} else {
setPageSize(4);
}
};

window.addEventListener('resize', handleResize);
handleResize();

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return (
<BS.BestPostConainer>
<BS.Title>베스트 게시글</BS.Title>
<BS.BestCardListContainer>
{itemList.list.map((item) => (
<BestPostCard key={item.id} item={item} />
))}
</BS.BestCardListContainer>
</BS.BestPostConainer>
);
}
41 changes: 41 additions & 0 deletions components/boards/BestPostCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import * as BS from './Styled';
import MedalIcon from '../common/images/ic_medal.png';
import LikeIcon from '../common/images/ic_heart.png';
import DefaultImg from '../common/images/default.png';
import { Item } from './PostList';
import formatDate from '../common/function/formatDate';

interface ItemCardProps {
item:Item;
}


const BestPostCard:React.FC<ItemCardProps> = ({ item }) => {
return (
<BS.BestCardContainer>
<BS.BestBadgeContainer>
<BS.MedalIcon src={MedalIcon} alt="메달아이콘" />
<BS.BestText>Best</BS.BestText>
</BS.BestBadgeContainer>
<BS.BestPostContentContainer>
<BS.BestPostContentText>{item.title}</BS.BestPostContentText>
<BS.BestPostImg
src={item.image ? item.image : DefaultImg}
width={72}
height={72}
alt="게시물 이미지" >
</BS.BestPostImg>
</BS.BestPostContentContainer>
<BS.SubContainer>
<BS.InfoContainer>
<BS.Writer>{item.writer.nickname}</BS.Writer>
<BS.LikeIcon src={LikeIcon} alt="좋아요 아이콘"></BS.LikeIcon>
<BS.LikeCount>{item.likeCount}</BS.LikeCount>
</BS.InfoContainer>
<BS.PostDate>{formatDate(item.createdAt)}</BS.PostDate>
</BS.SubContainer>
</BS.BestCardContainer>
);
}
export default BestPostCard;
47 changes: 47 additions & 0 deletions components/boards/PostCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import * as PS from './Styled';
import DefaultImg from '../common/images/default.png';
import LikeIcon from '../common/images/ic_heart.png';
import ProfileImg from '../common/images/profile.png';
import { Item } from './PostList';
import formatDate from '../common/function/formatDate';

interface ItemCardProps {
item: Item;
}

const PostCard: React.FC<ItemCardProps> = ({ item }) => {
return (
<PS.PostCardContainer>
<PS.PostContentContainer>
<PS.BestPostContentText>{item.title}</PS.BestPostContentText>
<PS.BestPostImg
src={item.image ? item.image : DefaultImg}
width={72}
height={72}
alt="게시물 이미지"
/>
</PS.PostContentContainer>
<PS.SubContainer>
<PS.InfoContainer>
<PS.ProfileImg
src={ProfileImg}

alt="프로필 이미지"
/>
<PS.Writer>{item.writer.nickname}</PS.Writer>
<PS.PostDate>{formatDate(item.createdAt)}</PS.PostDate>
</PS.InfoContainer>
<PS.InfoContainer>
<PS.LikeIcon
src={LikeIcon}
alt="좋아요 아이콘"
/>
<PS.LikeCount>{item.likeCount}</PS.LikeCount>
</PS.InfoContainer>
</PS.SubContainer>
</PS.PostCardContainer>
);
}

export default PostCard;
98 changes: 98 additions & 0 deletions components/boards/PostList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useRouter } from 'next/router';
import * as BS from './Styled';
import PostCard from './PostCard';
import { getArticles } from '@/pages/api/api';

export interface Item {
id: number;
title: string;
content: string;
image: string;
writer: Writer;
likeCount: number;
updatedAt: string;
createdAt: string;
}

interface Writer {
nickname: string;
id: number;
}

export interface ItemList {
totalCount: number;
list: Item[];
}

export default function PostList() {
const [itemList, setItemList] = useState<ItemList>({ totalCount: 0, list: [] });
const [pageSize, setPageSize] = useState(4);
const [order, setOrder] = useState('recent');
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [search, setSearch] = useState('');

const router = useRouter();
const{ q } = router.query;

const toggleDropdown = () => {
setIsDropdownOpen(!isDropdownOpen);
};

const handleNewestClick = () => {
setOrder('recent');
setIsDropdownOpen(false);
};

const handleLikeClick = () => {
setOrder('like');
setIsDropdownOpen(false);
};

const handleChange = (e:React.ChangeEvent<HTMLInputElement>) => setSearch(e.target.value);
const fetchSortedData = useCallback(async () => {
try {
const articles = await getArticles({ orderBy: order, pageSize: 1, keyword:search});
const totalCount = articles.totalCount;
const allArticles = await getArticles({ orderBy: order, pageSize: totalCount, keyword:search});
setItemList(allArticles);
console.log(allArticles);
} catch (error) {
console.error('Error fetching articles:', error);
}
}, [order, search]);

useEffect(() => {
fetchSortedData();
}, [fetchSortedData]);

return (
<BS.PostListContainer>
<BS.PostListHeader>
<BS.Title>게시물</BS.Title>
<BS.PostButton>글쓰기</BS.PostButton>
</BS.PostListHeader>
<BS.SearchContainer>
<BS.SearchBox
type='text'
placeholder='검색할 상품을 입력해주세요'
onChange={handleChange}
value={search}
>
</BS.SearchBox>
<BS.DropdownButtonContainer>
<BS.DropdownButton onClick={toggleDropdown}>
{order === 'recent' ? '최신순' : '좋아요순'} <BS.DropdownArrow></BS.DropdownArrow>
</BS.DropdownButton>
<BS.DropdownMenu $isOpen={isDropdownOpen}>
<BS.DropdownOption onClick={handleNewestClick}>최신순</BS.DropdownOption>
<BS.DropdownOption onClick={handleLikeClick}>좋아요순</BS.DropdownOption>
</BS.DropdownMenu>
</BS.DropdownButtonContainer>
</BS.SearchContainer>
{itemList.list.map((item) => (
<PostCard key={item.id} item={item} />
))}
</BS.PostListContainer>
);
}
Loading

0 comments on commit 48cfdc8

Please sign in to comment.