diff --git a/__mocks__/apis/handlers/comment.ts b/__mocks__/apis/handlers/comment.ts index f69cf75..82fce72 100644 --- a/__mocks__/apis/handlers/comment.ts +++ b/__mocks__/apis/handlers/comment.ts @@ -1,9 +1,11 @@ import { ResponseComposition, RestContext, RestRequest, rest } from 'msw'; import { COMMENTS } from '@mocks/data/comment'; +import { MEMBER } from '@mocks/data/member'; -import { Comment, GetCommentsResponseData, PostCommentResponsData } from '@src/apis'; +import { GetCommentsResponse, PostCommentRequest, PostCommentResponse } from '@src/apis'; import { BASE_URL } from '@src/configs/axios'; +import Comment from '@src/types/Comment'; const comments = COMMENTS; @@ -20,7 +22,7 @@ const getComments = (req: RestRequest, res: ResponseComposition, ctx: RestContex return res( ctx.status(200), - ctx.json({ + ctx.json({ code: 'SUCCESS', message: '성공', data: responseData, @@ -30,19 +32,13 @@ const getComments = (req: RestRequest, res: ResponseComposition, ctx: RestContex ); }; -const createComment = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => { - const commentContent = req.body; +const createComment = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => { + const contents = req.body; - const comment = { + const comment: Comment = { commentId: Math.floor(Math.random() * 100), - member: { - id: 3, - name: 'MemberC', - profileImage: null, - jobCategory: 'product_manager', - workingYears: 1, - }, - commentContent, + member: MEMBER, + contents, likeAmount: 0, liked: false, }; @@ -51,7 +47,7 @@ const createComment = (req: RestRequest, res: Respons return res( ctx.status(201), - ctx.json({ + ctx.json({ code: 'SUCCESS', message: '성공', data: comment, diff --git a/__mocks__/apis/handlers/topic.ts b/__mocks__/apis/handlers/topic.ts index b4d5fa6..d54670e 100644 --- a/__mocks__/apis/handlers/topic.ts +++ b/__mocks__/apis/handlers/topic.ts @@ -2,8 +2,9 @@ import { ResponseComposition, RestContext, RestRequest, rest } from 'msw'; import { TOPIC } from '@mocks/data/topic'; -import { BaseResponse, Topic } from '@src/apis/'; +import { BaseResponse } from '@src/apis/'; import { BASE_URL } from '@src/configs/axios'; +import Topic from '@src/types/Topic'; const getTopic = (req: RestRequest, res: ResponseComposition, ctx: RestContext) => { return res( diff --git a/__mocks__/data/comment.ts b/__mocks__/data/comment.ts index 688dac2..ab4b0f0 100644 --- a/__mocks__/data/comment.ts +++ b/__mocks__/data/comment.ts @@ -1,134 +1,79 @@ -import { Comment } from '@src/apis'; +import { MEMBER, MEMBER_DESIGNER, MEMBER_PM } from '@mocks/data/member'; + +import Comment from '@src/types/Comment'; + +export const COMMENT: Comment = { + commentId: 30, + member: MEMBER, + contents: 'Comment 10', + likeAmount: 30, + liked: false, +}; + +export const COMMENT_LIKED: Comment = { + commentId: 30, + member: MEMBER, + contents: 'Comment 10', + likeAmount: 30, + liked: true, +}; export const COMMENTS: Comment[] = [ + COMMENT, { - commentId: 30, - member: { - id: 3, - name: 'MemberC', - profileImage: null, - jobCategory: 'product_manager', - workingYears: 1, - }, - commentContent: 'Comment 10', - likeAmount: 30, - liked: false, - }, - { + ...COMMENT, commentId: 29, - member: { - id: 2, - name: 'MemberB', - profileImage: null, - jobCategory: 'Designer', - workingYears: 5, - }, - commentContent: 'Comment 10', + member: MEMBER_DESIGNER, + contents: 'Comment 10', likeAmount: 29, - liked: false, }, { + ...COMMENT, commentId: 28, - member: { - id: 1, - name: 'MemberA', - profileImage: null, - jobCategory: 'developer', - workingYears: 3, - }, - commentContent: 'Comment 10', + member: MEMBER_PM, + contents: 'Comment 10', likeAmount: 28, - liked: false, }, { + ...COMMENT, commentId: 27, - member: { - id: 3, - name: 'MemberC', - profileImage: null, - jobCategory: 'product_manager', - workingYears: 1, - }, - commentContent: 'Comment 9', + contents: 'Comment 9', likeAmount: 27, - liked: false, }, { + ...COMMENT, commentId: 26, - member: { - id: 2, - name: 'MemberB', - profileImage: null, - jobCategory: 'Designer', - workingYears: 5, - }, - commentContent: 'Comment 9', + contents: 'Comment 9', likeAmount: 26, - liked: false, }, { + ...COMMENT, commentId: 25, - member: { - id: 1, - name: 'MemberA', - profileImage: null, - jobCategory: 'developer', - workingYears: 3, - }, - commentContent: 'Comment 9', + contents: 'Comment 9', likeAmount: 25, - liked: false, }, { + ...COMMENT, commentId: 24, - member: { - id: 3, - name: 'MemberC', - profileImage: null, - jobCategory: 'product_manager', - workingYears: 1, - }, - commentContent: 'Comment 8', + contents: 'Comment 8', likeAmount: 24, - liked: false, }, { + ...COMMENT, commentId: 23, - member: { - id: 2, - name: 'MemberB', - profileImage: null, - jobCategory: 'Designer', - workingYears: 5, - }, - commentContent: 'Comment 8', + contents: 'Comment 8', likeAmount: 23, - liked: false, }, { + ...COMMENT, commentId: 22, - member: { - id: 1, - name: 'MemberA', - profileImage: null, - jobCategory: 'developer', - workingYears: 3, - }, - commentContent: 'Comment 8', + contents: 'Comment 8', likeAmount: 22, - liked: false, }, { + ...COMMENT, commentId: 21, - member: { - id: 3, - name: 'MemberC', - profileImage: null, - jobCategory: 'product_manager', - workingYears: 1, - }, - commentContent: 'Comment 7', + contents: 'Comment 7', likeAmount: 21, - liked: false, }, ]; diff --git a/__mocks__/data/member.ts b/__mocks__/data/member.ts index daecb43..d1fd3e9 100644 --- a/__mocks__/data/member.ts +++ b/__mocks__/data/member.ts @@ -1,9 +1,25 @@ -import { Member } from '@src/apis'; +import Member from '@src/types/Member'; export const MEMBER: Member = { - id: 4, - name: 'MemberA', + memberId: 4, + nickname: 'Developer', profileImage: null, jobCategory: 'developer', workingYears: 3, }; + +export const MEMBER_DESIGNER: Member = { + memberId: 2, + nickname: 'Designer', + profileImage: null, + jobCategory: 'designer', + workingYears: 5, +}; + +export const MEMBER_PM: Member = { + memberId: 2, + nickname: 'PM', + profileImage: null, + jobCategory: 'product_manager', + workingYears: 5, +}; diff --git a/__mocks__/data/topic.ts b/__mocks__/data/topic.ts index e3bda5c..38ee64b 100644 --- a/__mocks__/data/topic.ts +++ b/__mocks__/data/topic.ts @@ -1,37 +1,27 @@ -import { Topic } from '@src/apis'; +import { MEMBER } from '@mocks/data/member'; +import { VOTE_OPTIONS } from '@mocks/data/voteOption'; + +import Topic from '@src/types/Topic'; export const TOPIC: Topic = { topicId: 1, title: 'Vote1', contents: 'Content1', - member: { - id: 4, - name: 'MemberA', - profileImage: null, - jobCategory: 'developer', - workingYears: 3, - }, + member: MEMBER, commentAmount: 2, voteAmount: 0, liked: false, - likedAmount: 0, + likeAmount: 0, tags: [], - voteOptions: [ - { - id: 1, - text: 'Content1 OptionA', - voteOptionImageFilename: null, - codeBlock: null, - voted: false, - votedAmount: 1, - }, - { - id: 2, - text: 'Content1 OptionB', - voteOptionImageFilename: null, - codeBlock: null, - voted: false, - votedAmount: 1, - }, - ], + voteOptions: VOTE_OPTIONS, }; + +export const TOPICS: Topic[] = [ + { ...TOPIC }, + { ...TOPIC, topicId: 1, title: '두번째' }, + { ...TOPIC, topicId: 2, title: '세번째' }, + { ...TOPIC, topicId: 3, title: '네번째' }, + { ...TOPIC, topicId: 4, title: '다섯번째' }, + { ...TOPIC, topicId: 5, title: '여섯번째' }, + { ...TOPIC, topicId: 6, title: '일곱번째' }, +]; diff --git a/__mocks__/data/topics.ts b/__mocks__/data/topics.ts deleted file mode 100644 index 87cd9ef..0000000 --- a/__mocks__/data/topics.ts +++ /dev/null @@ -1,27 +0,0 @@ -import Topic from '@src/types/Topic'; - -export const TOPIC: Topic = { - id: 0, - title: '개발자 취업 밸런스 게임 하나 하겠습니다.', - contents: '아래의 두가지 예시중 누가 더 개발자 채용시장에서 환영을 받을 까요?', - options: [ - { id: 0, text: '골고루 다 할 수 있는 풀스택 개발자', voters: 24 }, - { id: 1, text: '한 언어를 제대로 마스터한 개발자', voters: 45 }, - ], - member: { - jobCategory: '개발자', - nickname: '개발자', - profileImage: 'https://avatars.githubusercontent.com/u/45786387?v=4', - }, - comments: 0, -}; - -export const TOPICS: Topic[] = [ - { ...TOPIC }, - { ...TOPIC, id: 1, title: '두번째' }, - { ...TOPIC, id: 2, title: '세번째' }, - { ...TOPIC, id: 3, title: '네번째' }, - { ...TOPIC, id: 4, title: '다섯번째' }, - { ...TOPIC, id: 5, title: '여섯번째' }, - { ...TOPIC, id: 6, title: '일곱번째' }, -]; diff --git a/__mocks__/data/voteOption.ts b/__mocks__/data/voteOption.ts new file mode 100644 index 0000000..aca1aed --- /dev/null +++ b/__mocks__/data/voteOption.ts @@ -0,0 +1,18 @@ +import VoteOption from '@src/types/VoteOption'; + +export const VOTE_OPTION: VoteOption = { + voteOptionId: 1, + text: 'Content1 OptionA', + image: null, + codeBlock: null, + voted: false, + voteAmount: 1, +}; + +export const VOTE_OPTION2: VoteOption = { + ...VOTE_OPTION, + voteOptionId: 2, + text: 'Content1 OptionB', +}; + +export const VOTE_OPTIONS: VoteOption[] = [VOTE_OPTION, VOTE_OPTION2]; diff --git a/src/apis/comment.ts b/src/apis/comment.ts index 7c4299b..3abc9e4 100644 --- a/src/apis/comment.ts +++ b/src/apis/comment.ts @@ -1,22 +1,17 @@ import axios from 'axios'; -import { BasePaginationResponse, BaseResponse, Member } from './'; +import Comment from '@src/types/Comment'; -export interface Comment { - commentId: number; - member: Member; - commentContent: string; - likeAmount: number; - liked: boolean; -} +import { BasePaginationResponse, BaseResponse } from './'; /** * topic 별 댓글 조회 */ -export type GetCommentsResponseData = BasePaginationResponse; +export type GetCommentsResponse = BasePaginationResponse; + export const getComments = async (topicId: number, offsetId?: number) => { const url = `/comment/${topicId}/latest${offsetId ? `?lastOffset=${offsetId}` : ''}`; - const res = await axios.get(url); + const res = await axios.get(url); return res.data; }; @@ -24,9 +19,12 @@ export const getComments = async (topicId: number, offsetId?: number) => { /** * 댓글 생성 */ -export type PostCommentResponsData = BaseResponse; -export const createComment = async (topicId: number, data: Comment['commentContent']) => { - const res = await axios.post(`/comment/${topicId}`, data); +export type PostCommentRequest = Comment['contents']; + +export type PostCommentResponse = BaseResponse; + +export const createComment = async (topicId: number, data: PostCommentRequest) => { + const res = await axios.post(`/comment/${topicId}`, data); return res.data.data; }; diff --git a/src/apis/topic.ts b/src/apis/topic.ts index e39d5af..b1d81d2 100644 --- a/src/apis/topic.ts +++ b/src/apis/topic.ts @@ -1,43 +1,16 @@ import axios from 'axios'; -import { BaseResponse } from './'; - -type VoteOption = { - id: number; - text: string; - voteOptionImageFilename: string | null; - codeBlock: string | null; - voted: boolean; - votedAmount: number; -}; - -export type Member = { - id: number; - name: string; - profileImage: string | null; - jobCategory: string; - workingYears: number; -}; +import Topic from '@src/types/Topic'; -export type Topic = { - topicId: number; - title: string; - contents: string; - member: Member; - commentAmount: number; - voteAmount: number; - liked: boolean; - likedAmount: number; - tags: string[]; - voteOptions: VoteOption[]; -}; +import { BaseResponse } from './'; /** * 토픽 상세 조회 */ -export type GetTopicDetailResponseData = BaseResponse; +export type GetTopicDetailResponse = BaseResponse; + export const getTopicDetail = async (topicId: number) => { - const res = await axios.get(`/topic/${topicId}`); + const res = await axios.get(`/topic/${topicId}`); return res.data.data; }; diff --git a/src/components/common/TopicCard/SelectOption/SelectOption.tsx b/src/components/common/TopicCard/SelectOption/SelectOption.tsx index 5c707f3..e121c92 100644 --- a/src/components/common/TopicCard/SelectOption/SelectOption.tsx +++ b/src/components/common/TopicCard/SelectOption/SelectOption.tsx @@ -1,11 +1,11 @@ import React, { MouseEvent } from 'react'; import Icon from '@src/components/common/Icon'; -import { TopicOption } from '@src/types/Topic'; +import VoteOption from '@src/types/VoteOption'; import * as S from './SelectOption.style'; -interface SelectOptionProps extends TopicOption { +interface SelectOptionProps extends VoteOption { rate?: number; result?: boolean; selected?: boolean; @@ -13,12 +13,12 @@ interface SelectOptionProps extends TopicOption { } const SelectOption = (props: SelectOptionProps) => { - const { id, text, rate = 0, result = false, selected = false, onClick } = props; + const { voteOptionId, text, rate = 0, result = false, selected = false, onClick } = props; const handleClick = (e: MouseEvent) => { e.stopPropagation(); e.nativeEvent.preventDefault(); - onClick(id, selected); + onClick(voteOptionId, selected); }; return ( diff --git a/src/components/common/TopicCard/TopicCard.stories.tsx b/src/components/common/TopicCard/TopicCard.stories.tsx index f472f2e..d09c02f 100644 --- a/src/components/common/TopicCard/TopicCard.stories.tsx +++ b/src/components/common/TopicCard/TopicCard.stories.tsx @@ -1,6 +1,9 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; +import { MEMBER } from '@mocks/data/member'; +import { VOTE_OPTION, VOTE_OPTION2, VOTE_OPTIONS } from '@mocks/data/voteOption'; + import TopicCard from '.'; export default { @@ -14,35 +17,28 @@ export const Default = Template.bind({}); Default.args = { title: 'Title', contents: 'contents', - options: [ - { id: 0, text: 'text', voters: 0 }, - { id: 1, text: 'text', voters: 0 }, - ], - member: { - jobCategory: '개발자', - nickname: '닉네임', - profileImage: 'https://avatars.githubusercontent.com/u/45786387?v=4', - }, - comments: 0, + voteOptions: VOTE_OPTIONS, + member: MEMBER, + commentAmount: 0, type: 'feed', }; export const 글자수_많음_2개 = Template.bind({}); 글자수_많음_2개.args = { ...Default.args, - options: [ - { id: 0, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voters: 10 }, - { id: 1, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voters: 20 }, + voteOptions: [ + { ...VOTE_OPTION, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voteAmount: 20 }, + { ...VOTE_OPTION2, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voteAmount: 10 }, ], }; export const 글자수_많음_3개 = Template.bind({}); 글자수_많음_3개.args = { ...Default.args, - options: [ - { id: 0, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voters: 10 }, - { id: 1, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voters: 10 }, - { id: 2, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voters: 30 }, + voteOptions: [ + { ...VOTE_OPTION, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voteAmount: 20 }, + { ...VOTE_OPTION2, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voteAmount: 10 }, + { ...VOTE_OPTION2, voteOptionId: 3, text: '일이삼사오육칠팔구십일이삼사오육칠팔구십', voteAmount: 30 }, ], }; @@ -61,20 +57,17 @@ Detail.args = { export const ThreeOptions = Template.bind({}); ThreeOptions.args = { ...Default.args, - options: [ - { id: 0, text: 'text', voters: 10 }, - { id: 1, text: 'text', voters: 20 }, - { id: 2, text: 'text', voters: 4 }, + voteOptions: [ + ...VOTE_OPTIONS, + { + ...VOTE_OPTION, + voteOptionId: 3, + }, ], }; export const FourOptions = Template.bind({}); FourOptions.args = { ...Default.args, - options: [ - { id: 0, text: 'text', voters: 10 }, - { id: 1, text: 'text', voters: 2 }, - { id: 2, text: 'text', voters: 34 }, - { id: 3, text: 'text', voters: 3 }, - ], + voteOptions: [...VOTE_OPTIONS, { ...VOTE_OPTION, voteOptionId: 3 }, { ...VOTE_OPTION, voteOptionId: 4 }], }; diff --git a/src/components/common/TopicCard/TopicCard.tsx b/src/components/common/TopicCard/TopicCard.tsx index e02a2f8..3e3d230 100644 --- a/src/components/common/TopicCard/TopicCard.tsx +++ b/src/components/common/TopicCard/TopicCard.tsx @@ -1,7 +1,9 @@ import React, { useState } from 'react'; +import USER_DEFAULT from '@src/assets/user-default.png'; import ShareIcon from '@src/components/common/ShareIcon'; -import Topic, { TopicOption } from '@src/types/Topic'; +import Topic from '@src/types/Topic'; +import VoteOption from '@src/types/VoteOption'; import Icon from '../Icon'; import SelectOption from './SelectOption'; @@ -9,28 +11,29 @@ import * as S from './TopicCard.style'; export type TopicCardType = 'feed' | 'detail'; -interface TopicCardProps extends Topic { +interface TopicCardProps extends Omit { badge?: string; // TODO: Icon등의 형태 논의 필요 type: TopicCardType; onClick?: () => void; } const TopicCard = (props: TopicCardProps, ref: React.ForwardedRef) => { - const { id, title, contents, options: defaultOptions, member, comments, badge, type, onClick } = props; - const [options, setOptions] = useState(defaultOptions); - const [selectedOptionId, setSelectedOptionId] = useState(null); // TODO: 초기 선택 여부 확인해야함 + const { topicId, title, contents, voteOptions: defaultOptions, member, commentAmount, badge, type, onClick } = props; + const [options, setOptions] = useState(defaultOptions); + const selectedOption = options.find((option) => option.voted); + const [selectedOptionId, setSelectedOptionId] = useState(selectedOption?.voteOptionId || null); + const votedAmount = options.reduce((prev, option) => prev + option.voteAmount, 0); - const participant = options.reduce((prev, option) => prev + option.voters, 0); const isFeed = type === 'feed'; const handleClickOption = (id: number) => { const changed = options.map((option) => { - if (option.id === selectedOptionId) { - option.voters -= 1; + if (option.voteOptionId === selectedOptionId) { + option.voteAmount -= 1; return option; } - if (option.id === id) { - option.voters += 1; + if (option.voteOptionId === id) { + option.voteAmount += 1; } return option; }); @@ -57,17 +60,17 @@ const TopicCard = (props: TopicCardProps, ref: React.ForwardedRef{title} - {isFeed && } + {isFeed && } {contents} {options.map((option) => ( ))} @@ -76,7 +79,7 @@ const TopicCard = (props: TopicCardProps, ref: React.ForwardedRef {isFeed ? ( - + {member.nickname} ) : ( @@ -88,12 +91,12 @@ const TopicCard = (props: TopicCardProps, ref: React.ForwardedRef - {('00' + participant).slice(-3)}명 참여 + {('00' + votedAmount).slice(-3)}명 참여 · - {('00' + comments).slice(-3)}개 댓글 + {('00' + commentAmount).slice(-3)}개 댓글 diff --git a/src/components/main/Main/Main.stories.tsx b/src/components/main/Main/Main.stories.tsx index a3ae955..ea6f9a8 100644 --- a/src/components/main/Main/Main.stories.tsx +++ b/src/components/main/Main/Main.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { TOPICS } from '@mocks/data/topics'; +import { TOPICS } from '@mocks/data/topic'; import Main from '.'; diff --git a/src/components/main/MainTopicList/MainTopicList.stories.tsx b/src/components/main/MainTopicList/MainTopicList.stories.tsx index e328cb6..a6ad2b2 100644 --- a/src/components/main/MainTopicList/MainTopicList.stories.tsx +++ b/src/components/main/MainTopicList/MainTopicList.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { TOPICS } from '@mocks/data/topics'; +import { TOPICS } from '@mocks/data/topic'; import MainTopicList from '.'; diff --git a/src/components/main/MainTopicList/MainTopicList.tsx b/src/components/main/MainTopicList/MainTopicList.tsx index 1a2bb05..2cc6eb9 100644 --- a/src/components/main/MainTopicList/MainTopicList.tsx +++ b/src/components/main/MainTopicList/MainTopicList.tsx @@ -18,7 +18,7 @@ const MainTopicList: React.FC = (props) => { return ( {topics.map((topic) => ( - + ))} diff --git a/src/components/main/TopicCarousel/TopicCarousel.stories.tsx b/src/components/main/TopicCarousel/TopicCarousel.stories.tsx index bc91d4e..536f040 100644 --- a/src/components/main/TopicCarousel/TopicCarousel.stories.tsx +++ b/src/components/main/TopicCarousel/TopicCarousel.stories.tsx @@ -2,7 +2,7 @@ import { ComponentStory } from '@storybook/react'; import React from 'react'; import { MEMBER } from '@mocks/data/member'; -import { TOPICS } from '@mocks/data/topics'; +import { TOPICS } from '@mocks/data/topic'; import TopicCarousel from '.'; diff --git a/src/components/main/TopicCarousel/TopicCarousel.tsx b/src/components/main/TopicCarousel/TopicCarousel.tsx index 4a13856..a213dfd 100644 --- a/src/components/main/TopicCarousel/TopicCarousel.tsx +++ b/src/components/main/TopicCarousel/TopicCarousel.tsx @@ -82,10 +82,10 @@ const TopicCarousel: React.FC = (props: TopicCarouselProps) {carouselTopics.map((topic) => ( - - + + {/* TODO: badge 정책 필요 */} - + ))} diff --git a/src/components/topic/CommentList/CommentList.stories.tsx b/src/components/topic/CommentList/CommentList.stories.tsx index 7b90366..7daa9f5 100644 --- a/src/components/topic/CommentList/CommentList.stories.tsx +++ b/src/components/topic/CommentList/CommentList.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { commentArr } from '@mocks/data/comment'; +import { COMMENTS } from '@mocks/data/comment'; import CommentList from '.'; @@ -14,7 +14,7 @@ const Template: ComponentStory = ({ ...args }) => { const [order, setOrder] = useState('latest'); - const { fetchNextPage, data: comments, isLoading, hasNextPage } = useGetComments(Number(router.query.id)); + const { fetchNextPage, data: comments = [], isLoading, hasNextPage } = useGetComments(Number(router.query.id)); const { ref } = useInView({ onChange: (inView) => { if (inView && hasNextPage) { @@ -33,6 +33,7 @@ const CommentList: FC = () => { const commentList = getCommentByOrder(comments, order); const subTitle = `댓글과 좋아요는 Thumbs UP과 Finger님들에게\n 큰 힘이 됩니다.`; + return ( diff --git a/src/components/topic/CommentList/CommentListItem/CommentListItem.stories.tsx b/src/components/topic/CommentList/CommentListItem/CommentListItem.stories.tsx index 3cc2471..f8a478d 100644 --- a/src/components/topic/CommentList/CommentListItem/CommentListItem.stories.tsx +++ b/src/components/topic/CommentList/CommentListItem/CommentListItem.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { commentArr } from '@mocks/data/comment'; +import { COMMENT, COMMENT_LIKED } from '@mocks/data/comment'; import CommentListItem from '.'; @@ -14,10 +14,10 @@ const Template: ComponentStory = ({ ...args }) => = (props) => { const { comment } = props; + const { contents, likeAmount, liked, member } = comment; - const { commentContent, likeAmount, liked, member } = comment; return ( - {member.name} + {member.nickname} {member.jobCategory}·{member.workingYears}연차 - {commentContent} + {contents} {likeAmount} diff --git a/src/components/topic/TopicDetailMain/TopicDetailMain.tsx b/src/components/topic/TopicDetailMain/TopicDetailMain.tsx index d894127..e06cd32 100644 --- a/src/components/topic/TopicDetailMain/TopicDetailMain.tsx +++ b/src/components/topic/TopicDetailMain/TopicDetailMain.tsx @@ -1,17 +1,18 @@ import { FC } from 'react'; -import { Topic } from '@src/apis'; import ShareIcon from '@src/components/common/ShareIcon'; import TopicCard from '@src/components/common/TopicCard'; import CommentForm from '@src/components/topic/CommentForm'; import CommentList from '@src/components/topic/CommentList'; import { useCreateComments } from '@src/queires/useCreateComment'; +import Topic from '@src/types/Topic'; import * as S from './TopicDetailMain.styles'; interface Props { topic: Topic; } + const TopicDetailMain: FC = (props) => { const { topic } = props; @@ -21,14 +22,13 @@ const TopicDetailMain: FC = (props) => { mutateComment.mutate(commentValue); }; - const { title, contents, commentAmount, voteOptions } = topic; return ( - + diff --git a/src/components/topic/TopicUserInfo/TopicUserInfo.stories.tsx b/src/components/topic/TopicUserInfo/TopicUserInfo.stories.tsx index 38e9be9..7a28b4c 100644 --- a/src/components/topic/TopicUserInfo/TopicUserInfo.stories.tsx +++ b/src/components/topic/TopicUserInfo/TopicUserInfo.stories.tsx @@ -1,5 +1,7 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { MEMBER } from '@mocks/data/member'; + import TopicUserInfo from '.'; export default { @@ -12,6 +14,6 @@ const Template: ComponentStory = ({ ...args }) => = (props) => { const { member, tags } = props; - const { name, profileImage, jobCategory, workingYears } = member; + const { nickname, profileImage, jobCategory, workingYears } = member; return ( - + - {name} + {nickname} {jobCategory}·{workingYears}연차 diff --git a/src/pages/index.tsx b/src/pages/index.tsx index f118aa6..b71942a 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,7 +1,7 @@ import type { NextPage } from 'next'; import { MEMBER } from '@mocks/data/member'; -import { TOPICS } from '@mocks/data/topics'; +import { TOPICS } from '@mocks/data/topic'; import DefaultLayout from '@src/components/common/DefaultLayout'; import Main from '@src/components/main/Main'; diff --git a/src/pages/topic/[id].tsx b/src/pages/topic/[id].tsx index 874da71..3b4d2d7 100644 --- a/src/pages/topic/[id].tsx +++ b/src/pages/topic/[id].tsx @@ -1,13 +1,15 @@ import type { GetServerSideProps, NextPage } from 'next'; -import { Topic, getTopicDetail } from '@src/apis'; +import { getTopicDetail } from '@src/apis'; import DefaultLayout from '@src/components/common/DefaultLayout'; import TopicDetailMain from '@src/components/topic/TopicDetailMain'; import TopicUserInfo from '@src/components/topic/TopicUserInfo'; +import Topic from '@src/types/Topic'; interface Props { topicDetail: Topic; } + const TopicDetail: NextPage = ({ topicDetail }) => { const { member, tags } = topicDetail; diff --git a/src/queires/useCreateComment.ts b/src/queires/useCreateComment.ts index 33ae07a..b2a69bc 100644 --- a/src/queires/useCreateComment.ts +++ b/src/queires/useCreateComment.ts @@ -1,6 +1,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { Comment, createComment } from '@src/apis'; +import { PostCommentRequest, createComment } from '@src/apis'; import { queryKeys } from './constant'; @@ -8,12 +8,9 @@ export const useCreateComments = (topicId: number) => { const queryClient = useQueryClient(); // TODO-GYU: 성공시, 실패시 등 낙관적업데이트 관련 로직 추가 - const mutateComment = useMutation( - (commentContent: Comment['commentContent']) => createComment(topicId, commentContent), - { - onSuccess: () => queryClient.invalidateQueries([queryKeys.comment, topicId]), - }, - ); + const mutateComment = useMutation((commentContent: PostCommentRequest) => createComment(topicId, commentContent), { + onSuccess: () => queryClient.invalidateQueries([queryKeys.comment, topicId]), + }); return { mutateComment }; }; diff --git a/src/queires/useGetComments.ts b/src/queires/useGetComments.ts index 4cda1ba..bb96e4f 100644 --- a/src/queires/useGetComments.ts +++ b/src/queires/useGetComments.ts @@ -1,11 +1,11 @@ import { useInfiniteQuery } from '@tanstack/react-query'; -import { Comment, IGetCommentsResponseData, getComments } from '@src/apis'; +import { GetCommentsResponse, getComments } from '@src/apis'; import { queryKeys } from './constant'; export const useGetComments = (topicId: number) => { - const result = useInfiniteQuery( + const result = useInfiniteQuery( [queryKeys.comment, topicId], ({ pageParam }) => getComments(topicId, pageParam), { @@ -18,7 +18,7 @@ export const useGetComments = (topicId: number) => { const comments = data ? data.pages .map((page) => page.data) - .reduce((mergedContents: Comment[], currentContents) => [...mergedContents, ...(currentContents || [])], []) + .reduce((mergedContents, currentContents) => [...(mergedContents || []), ...(currentContents || [])], []) : []; return { diff --git a/src/types/Comment.ts b/src/types/Comment.ts index 19be1a5..c7ecfd8 100644 --- a/src/types/Comment.ts +++ b/src/types/Comment.ts @@ -1,11 +1,9 @@ -export interface IComment { +import Member from '@src/types/Member'; + +export default interface Comment { commentId: number; - createdMemberId: number; - createdMemberName: string; - createdMemberProfileImage: string | null; - createdMemberJobCategory: string; - createdMemberWorkingYears: number; - commentContent: string; + contents: string; likeAmount: number; liked: boolean; + member: Member; } diff --git a/src/types/Member.ts b/src/types/Member.ts index 4939f23..cc79e44 100644 --- a/src/types/Member.ts +++ b/src/types/Member.ts @@ -1,6 +1,7 @@ export default interface Member { - id?: number; - jobCategory: string; + memberId: number; nickname: string; - profileImage: string; + profileImage?: string | null; + jobCategory: string; + workingYears: number; } diff --git a/src/types/Topic.ts b/src/types/Topic.ts index be7fe07..b47df7e 100644 --- a/src/types/Topic.ts +++ b/src/types/Topic.ts @@ -1,16 +1,16 @@ +import VoteOption from '@src/types/VoteOption'; + import Member from './Member'; export default interface Topic { - id?: number; + topicId: number; title: string; contents: string; - options: TopicOption[]; + commentAmount: number; + liked: boolean; + likeAmount: number; + tags: string[]; + voteAmount: number; + voteOptions: VoteOption[]; member: Member; - comments: number; -} - -export interface TopicOption { - id: number; - text: string; - voters: number; } diff --git a/src/types/VoteOption.ts b/src/types/VoteOption.ts new file mode 100644 index 0000000..54e3fab --- /dev/null +++ b/src/types/VoteOption.ts @@ -0,0 +1,11 @@ +export default interface VoteOption { + voteOptionId: number; + text: string; + image?: string | null; + codeBlock?: { + language: string; + contents: string; + } | null; + voted: boolean; + voteAmount: number; +}