Skip to content

Commit

Permalink
SKRR-12 feat: 클럽 게시물 상세조회 구현 (#245)
Browse files Browse the repository at this point in the history
* feat: 클럽 게시글 단건 조회 api 구현

* feat: 클럽 게시글 단건 조회 hook 구현

* design: 게시글 상세 페이지 디자인

* feat: 게시물 상세 조회 구현
  • Loading branch information
colorkite10 authored Jan 5, 2024
1 parent 81088f8 commit 61ae73e
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 3 deletions.
4 changes: 1 addition & 3 deletions src/apis/club/getClub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { GetClubRequest, GetClubResponse } from '@/types/api/getClub';
import { axiosClientWithAuth } from '../axiosClient';

const getClub = async ({ clubId }: GetClubRequest) => {
const { data } = await axiosClientWithAuth.get<GetClubResponse>(
`${END_POINTS.GET_CLUB({ clubId })}`,
);
const { data } = await axiosClientWithAuth.get<GetClubResponse>(END_POINTS.GET_CLUB({ clubId }));

return data;
};
Expand Down
14 changes: 14 additions & 0 deletions src/apis/club/getClubPost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { END_POINTS } from '@/constants/api';
import { GetClubPostRequest, GetClubPostResponse } from '@/types/api/getClubPost';

import { axiosClientWithAuth } from '../axiosClient';

const getClubPost = async ({ clubId, postId }: GetClubPostRequest) => {
const { data } = await axiosClientWithAuth.get<GetClubPostResponse>(
END_POINTS.CLUB_POST(clubId, postId),
);

return data;
};

export default getClubPost;
53 changes: 53 additions & 0 deletions src/components/ClubPostDetail/ClubPostDetail.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Theme from '@/styles/Theme';
import styled from '@emotion/styled';

const ClubPostDetailContainer = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
width: 100%;
`;

const PostAuthorWrapper = styled.div`
display: flex;
justify-content: start;
gap: 0.3rem;
width: 100%;
`;

const PostTitleStyled = styled.h1`
font-size: ${Theme.fontSize.smallTitle};
font-weight: 600;
`;

const PostContentStyled = styled.p`
font-size: ${Theme.fontSize.largeContent};
word-break: break-all;
`;

const PostedDateStyled = styled.div`
font-size: ${Theme.fontSize.largeContent};
color: ${Theme.color.textGrey};
`;

const PostSeparatorStyled = styled.div`
width: 100%;
border: 1px solid ${Theme.color.tSeparator};
`;

const ButtonWrapper = styled.div`
display: flex;
justify-content: end;
gap: 0.3rem;
width: 100%;
`;

export {
ClubPostDetailContainer,
PostAuthorWrapper,
PostTitleStyled,
PostContentStyled,
PostedDateStyled,
PostSeparatorStyled,
ButtonWrapper,
};
61 changes: 61 additions & 0 deletions src/components/ClubPostDetail/ClubPostDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import useGetClubPostDetail from '@/hooks/query/club/useGetClubPostDetail';
import { getStorage } from '@/utils/localStorage';

import Avatar from '../common/Avatar/Avatar';
import Button from '../common/Button/Button';
import {
ButtonWrapper,
ClubPostDetailContainer,
PostAuthorWrapper,
PostContentStyled,
PostTitleStyled,
PostedDateStyled,
} from './ClubPostDetail.style';

interface ClubPostDetailProps {
clubId: string;
postId: string;
}

const ClubPostDetail = ({ clubId, postId }: ClubPostDetailProps) => {
const { clubPostDetail } = useGetClubPostDetail({ clubId, postId });

if (!clubPostDetail) {
return null;
}

const {
title,
content,
authorId,
author,
authorImageUrl,
postImageUrl,
createDate,
lastModifiedDate,
} = clubPostDetail;

const isAuthor = authorId === getStorage('userId');

return (
<ClubPostDetailContainer>
{isAuthor && (
<ButtonWrapper>
<Button buttonText="수정" outline />
<Button buttonText="삭제" />
</ButtonWrapper>
)}
<PostAuthorWrapper>
<Avatar avatarSize="small" profileImageSrc={authorImageUrl} />
{author}
</PostAuthorWrapper>
<PostTitleStyled>{title}</PostTitleStyled>
{postImageUrl && <img src={postImageUrl} />}
<PostContentStyled>{content}</PostContentStyled>
{lastModifiedDate && <div>편집됨</div>}
<PostedDateStyled>{createDate}</PostedDateStyled>
</ClubPostDetailContainer>
);
};

export default ClubPostDetail;
1 change: 1 addition & 0 deletions src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const END_POINTS = {
CLUB_SCHEDULES: ({ clubId }: { clubId: string }) => `/clubs/${clubId}/events?page=0&sort=id,desc`,
CLUB_POSTS: (clubId: string, pageNumber: number) =>
`/boards/${clubId}?page=${pageNumber}&size=20&sort=id,desc`,
CLUB_POST: (clubId: string, postId: string) => `/boards/posts/${clubId}/${postId}`,

PATCH_MEMBER_ROLE: ({ clubId, memberId }: { clubId: string; memberId: string }) =>
`/clubs/${clubId}/members/${memberId}`,
Expand Down
17 changes: 17 additions & 0 deletions src/hooks/query/club/useGetClubPostDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import getClubPost from '@/apis/club/getClubPost';
import { GetClubPostRequest } from '@/types/api/getClubPost';

import { useQuery } from '@tanstack/react-query';

export const QUERY_KEY = { GET_CLUB_POST_DETAIL: 'GET_CLUB_POST_DETAIL' };

const useGetClubPostDetail = ({ clubId, postId }: GetClubPostRequest) => {
const { data } = useQuery({
queryKey: [QUERY_KEY, clubId, postId],
queryFn: () => getClubPost({ clubId, postId }),
});

return { clubPostDetail: data };
};

export default useGetClubPostDetail;
2 changes: 2 additions & 0 deletions src/pages/club/ClubBoardPage/ClubBoardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PATH } from '@/constants/path';

import { useNavigate, useParams } from 'react-router-dom';

import ClubPostDetailPage from '../ClubPostDetailPage/ClubPostDetailPage';
import {
ButtonWrapper,
ClubBoardContentWrapper,
Expand Down Expand Up @@ -41,6 +42,7 @@ const ClubBoardPage = () => {
<ClubPosts clubId={clubId} />
</ClubBoardContentWrapper>
</ClubBoardPageContainer>
<ClubPostDetailPage />
</>
);
};
Expand Down
19 changes: 19 additions & 0 deletions src/pages/club/ClubPostDetailPage/ClubPostDetailPage.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import styled from '@emotion/styled';

import { ClubHomePageContainer, ClubHomeTopWrapper } from '../ClubHomePage/ClubHomePage.style';

const ClubPostDetailPageContainer = styled(ClubHomePageContainer)``;

const ClubPostDetailTopWrapper = styled(ClubHomeTopWrapper)``;

const ClubPostWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
padding: 1rem;
`;

export { ClubPostDetailPageContainer, ClubPostDetailTopWrapper, ClubPostWrapper };
35 changes: 35 additions & 0 deletions src/pages/club/ClubPostDetailPage/ClubPostDetailPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import ClubHeader from '@/components/ClubHeader/ClubHeader';
import ClubPostDetail from '@/components/ClubPostDetail/ClubPostDetail';
import ClubBanner from '@/components/common/ClubBanner/ClubBanner';

import { useParams } from 'react-router-dom';

import {
ClubPostDetailPageContainer,
ClubPostDetailTopWrapper,
ClubPostWrapper,
} from './ClubPostDetailPage.style';

const ClubPostDetailPage = () => {
const { clubId, postId } = useParams();
if (!clubId) {
throw new Error('클럽 ID를 찾을 수 없습니다');
} else if (!postId) {
return null; //#TODO: 게시물 찾을 수 없다는 모달창 띄우고 전 페이지로 이동
}

return (
<>
<ClubHeader clubId={clubId} />
<ClubPostDetailPageContainer>
<ClubPostDetailTopWrapper>
<ClubBanner withdrawClubButton clubId={clubId} bannerSize="small" />
</ClubPostDetailTopWrapper>
<ClubPostWrapper>
<ClubPostDetail clubId={clubId} postId={postId} />
</ClubPostWrapper>
</ClubPostDetailPageContainer>
</>
);
};
export default ClubPostDetailPage;
2 changes: 2 additions & 0 deletions src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ClubBoardPage from '@/pages/club/ClubBoardPage/ClubBoardPage';
import ClubEventPage from '@/pages/club/ClubEventPage/ClubEventPage';
import ClubHomePage from '@/pages/club/ClubHomePage/ClubHomePage';
import ClubManagePage from '@/pages/club/ClubManagePage/ClubManagePage';
import ClubPostDetailPage from '@/pages/club/ClubPostDetailPage/ClubPostDetailPage';
import ClubPostWritePage from '@/pages/club/ClubPostWritePage/ClubPostWritePage';
import CreateClubPage from '@/pages/club/CreateClubPage/CreateClubPage';
import InvitePage from '@/pages/club/InvitePage/InvitePage';
Expand Down Expand Up @@ -60,6 +61,7 @@ const router = createBrowserRouter([
{ path: PATH.CLUB.EVENT(':clubId'), element: <ClubEventPage /> },
{ path: PATH.CLUB.BOARD(':clubId'), element: <ClubBoardPage /> },
{ path: PATH.CLUB.WRITE_POST(':clubId'), element: <ClubPostWritePage /> },
{ path: PATH.CLUB.POST(':clubId', ':postId'), element: <ClubPostDetailPage /> },
{
element: <PrivateManager />,
children: [
Expand Down
18 changes: 18 additions & 0 deletions src/types/api/getClubPost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
interface GetClubPostRequest {
clubId: string;
postId: string;
}

interface GetClubPostResponse {
postId: string;
title: string;
content: string;
authorId: string;
author: string;
authorImageUrl?: string;
postImageUrl?: string;
createDate: string;
lastModifiedDate?: string;
}

export { GetClubPostRequest, GetClubPostResponse };

0 comments on commit 61ae73e

Please sign in to comment.