Skip to content

Commit

Permalink
카테고리 불러오기 api 연결 및 버그 수정 및 기타 등등_Feat/#238 (#247)
Browse files Browse the repository at this point in the history
* fix: (#238) 카테고리 api 속성이 달라 발생하는 오류 수정

- api 필드 isFavorite이 favorite으로 되어있었음

* fix: 카테고리 토글에 따른 즉시 렌더링 안되는 오류 수정

- 리액트 쿼리 키에서 favorite 삭제

* fix: 댓글 수정 시 발생하는 오류 해결

- 수정된 댓글 콘텐츠만 전달하여 발생한 id 못찾는 오류를 댓글 객체 전체를 전달하는 방식으로 수정하여 해결

* fix: 글 작성자는 투표 결과를 바로 볼 수 있고 투표 할 수 없도록 수정

* feat: 통계 api response 형식 수정에 따른 반영
  • Loading branch information
chsua authored and tjdtls690 committed Sep 12, 2023
1 parent e5794cf commit 49df3f8
Show file tree
Hide file tree
Showing 32 changed files with 246 additions and 153 deletions.
4 changes: 2 additions & 2 deletions frontend/__test__/api/categoryList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('카테고리에 대한 통신(카테고리 목록 조회, 즐겨찾기
});

test('회원이 카테고리 즐겨찾기를 할 수 있다.', async () => {
MOCK_CATEGORY_LIST[1].favorite = false;
MOCK_CATEGORY_LIST[1].isFavorite = false;

await addFavoriteCategory(MOCK_CATEGORY_LIST[1].id);

Expand All @@ -36,7 +36,7 @@ describe('카테고리에 대한 통신(카테고리 목록 조회, 즐겨찾기
});

test('회원이 카테고리 즐겨찾기를 해제할 수 있다.', async () => {
MOCK_CATEGORY_LIST[0].favorite = true;
MOCK_CATEGORY_LIST[0].isFavorite = true;

await removeFavoriteCategory(MOCK_CATEGORY_LIST[0].id);

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/categoryList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const transformCategoryListResponse = (categoryList: CategoryResponse[])
return categoryList.map(category => ({
id: category.id,
name: category.name,
isFavorite: category.favorite,
isFavorite: category.isFavorite,
}));
};

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/api/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export const editComment = async (
commentId: number,
updatedComment: CommentRequest
) => {
return await putFetch(`${BASE_URL}/posts/${postId}/comments/${commentId}`, updatedComment);
return await putFetch(`${BASE_URL}/posts/${postId}/comments/${commentId}`, {
content: updatedComment.content,
});
};

export const deleteComment = async (postId: number, commentId: number) => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const getCartList = async () => {
};

export const createCart = async () => {
return await postFetch<Cart, { id: number }>('api/cart', { id: 12, text: '생성' });
return await postFetch<Cart>('api/cart', { id: 12, text: '생성' });
};

export const editCart = async () => {
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/api/voteResult.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { VoteResult } from '@components/VoteStatistics/type';
import { VoteResultResponse } from '@components/VoteStatistics/type';

import { getFetch } from '@utils/fetch';

const BASE_URL = process.env.VOTOGETHER_BASE_URL;

export const getPostStatistics = async (postId: number): Promise<VoteResult> => {
return await getFetch<VoteResult>(`${BASE_URL}/posts/${postId}/options`);
export const getPostStatistics = async (postId: number): Promise<VoteResultResponse> => {
return await getFetch<VoteResultResponse>(`${BASE_URL}/posts/${postId}/options`);
};

export const getOptionStatistics = async ({
Expand All @@ -14,6 +14,6 @@ export const getOptionStatistics = async ({
}: {
postId: number;
optionId: number;
}): Promise<VoteResult> => {
return await getFetch<VoteResult>(`${BASE_URL}/posts/${postId}/options/${optionId}`);
}): Promise<VoteResultResponse> => {
return await getFetch<VoteResultResponse>(`${BASE_URL}/posts/${postId}/options/${optionId}`);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';

import { MOCK_VOTE_RESULT } from '@mocks/mockData/voteResult';
import { MOCK_DETAIL_VOTE_RESULT } from '@mocks/mockData/voteResult';

import OneLineGraph from '.';

Expand All @@ -12,13 +12,13 @@ export default meta;
type Story = StoryObj<typeof OneLineGraph>;

export const SizeSm: Story = {
render: () => <OneLineGraph size="sm" voteResult={MOCK_VOTE_RESULT} />,
render: () => <OneLineGraph size="sm" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};

export const SizeMd: Story = {
render: () => <OneLineGraph size="md" voteResult={MOCK_VOTE_RESULT} />,
render: () => <OneLineGraph size="md" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};

export const SizeLg: Story = {
render: () => <OneLineGraph size="lg" voteResult={MOCK_VOTE_RESULT} />,
render: () => <OneLineGraph size="lg" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};
19 changes: 8 additions & 11 deletions frontend/src/components/VoteStatistics/OneLineGraph/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import * as GS from '../GraphStyle';
import { AGE_OPTION, GraphProps } from '../type';
import { GraphProps } from '../type';

import * as S from './style';

export default function OneLineGraph({ voteResult, size }: GraphProps) {
const maxVoteAmount = Math.max(
...Object.values(voteResult.age).map(voteResult => voteResult.total)
);
export default function OneLineGraph({ ageGroup, size }: GraphProps) {
const maxVoteAmount = Math.max(...ageGroup.map(age => age.total));

return (
<GS.GraphContainer $size={size}>
<GS.Line $size={size} />
{AGE_OPTION.map(option => {
const voteResultFilteredByAge = voteResult.age[option];
const amount = Math.floor((voteResultFilteredByAge.total / maxVoteAmount) * 100);
{ageGroup.map(ageResult => {
const amount = Math.floor((ageResult.total / maxVoteAmount) * 100);

return (
<S.OptionContainer key={option} $size={size}>
<span aria-label="투표한 인원">{voteResultFilteredByAge.total}</span>
<S.OptionContainer key={ageResult.name} $size={size}>
<span aria-label="투표한 인원">{ageResult.total}</span>
<S.OptionLength $amount={amount} />
<span aria-label="투표한 나이대">{voteResultFilteredByAge.name}</span>
<span aria-label="투표한 나이대">{ageResult.name}</span>
</S.OptionContainer>
);
})}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';

import { MOCK_VOTE_RESULT } from '@mocks/mockData/voteResult';
import { MOCK_DETAIL_VOTE_RESULT } from '@mocks/mockData/voteResult';

import TwoLineGraph from '.';

Expand All @@ -12,13 +12,13 @@ export default meta;
type Story = StoryObj<typeof TwoLineGraph>;

export const SizeSm: Story = {
render: () => <TwoLineGraph size="sm" voteResult={MOCK_VOTE_RESULT} />,
render: () => <TwoLineGraph size="sm" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};

export const SizeMd: Story = {
render: () => <TwoLineGraph size="md" voteResult={MOCK_VOTE_RESULT} />,
render: () => <TwoLineGraph size="md" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};

export const SizeLg: Story = {
render: () => <TwoLineGraph size="lg" voteResult={MOCK_VOTE_RESULT} />,
render: () => <TwoLineGraph size="lg" ageGroup={MOCK_DETAIL_VOTE_RESULT} />,
};
25 changes: 10 additions & 15 deletions frontend/src/components/VoteStatistics/TwoLineGraph/index.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
import * as GS from '../GraphStyle';
import { AGE_OPTION, GraphProps } from '../type';
import { GraphProps } from '../type';

import * as S from './style';

export default function TwoLineGraph({ voteResult, size }: GraphProps) {
export default function TwoLineGraph({ ageGroup, size }: GraphProps) {
const maxVoteAmount = Math.max(
...Object.values(voteResult.age).map(voteResult => Math.max(voteResult.female, voteResult.male))
...ageGroup.map(voteResult => Math.max(voteResult.female, voteResult.male))
);

return (
<GS.GraphContainer $size={size}>
<GS.Line $size={size} />
{AGE_OPTION.map(option => {
const voteResultFilteredByAge = voteResult.age[option];

{ageGroup.map(ageResult => {
return (
<S.OptionContainer key={option} $size={size}>
<S.OptionContainer key={ageResult.name} $size={size}>
<S.DataWrapper>
<S.OptionLengthWrapper $gender="female">
<span aria-label="투표한 여자수">{voteResultFilteredByAge.female}</span>
<span aria-label="투표한 여자수">{ageResult.female}</span>
<S.OptionLength
$amount={(voteResultFilteredByAge.female / maxVoteAmount) * 100}
$amount={(ageResult.female / maxVoteAmount) * 100}
$gender="female"
/>
</S.OptionLengthWrapper>
<S.OptionLengthWrapper $gender="male">
<span aria-label="투표한 남자수">{voteResultFilteredByAge.male}</span>
<S.OptionLength
$amount={(voteResultFilteredByAge.male / maxVoteAmount) * 100}
$gender="male"
/>
<span aria-label="투표한 남자수">{ageResult.male}</span>
<S.OptionLength $amount={(ageResult.male / maxVoteAmount) * 100} $gender="male" />
</S.OptionLengthWrapper>
</S.DataWrapper>
<span aria-label="투표한 나이대">{voteResultFilteredByAge.name}</span>
<span aria-label="투표한 나이대">{ageResult.name}</span>
</S.OptionContainer>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ export default meta;
type Story = StoryObj<typeof VoteStatistics>;

export const SizeSm: Story = {
render: () => <VoteStatistics size="sm" voteResult={MOCK_VOTE_RESULT} />,
render: () => <VoteStatistics size="sm" voteResultResponse={MOCK_VOTE_RESULT} />,
};

export const SizeMd: Story = {
render: () => <VoteStatistics size="md" voteResult={MOCK_VOTE_RESULT} />,
render: () => <VoteStatistics size="md" voteResultResponse={MOCK_VOTE_RESULT} />,
};

export const SizeLg: Story = {
render: () => <VoteStatistics size="lg" voteResult={MOCK_VOTE_RESULT} />,
render: () => <VoteStatistics size="lg" voteResultResponse={MOCK_VOTE_RESULT} />,
};
18 changes: 14 additions & 4 deletions frontend/src/components/VoteStatistics/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import { MouseEvent, useState } from 'react';

import { Size } from '@type/style';

import OneLineGraph from './OneLineGraph';
import * as S from './style';
import TwoLineGraph from './TwoLineGraph';
import { GraphProps } from './type';
import { VoteResultResponse } from './type';
import { transVoteStatisticsFormat } from './util';

interface RadioMode {
all: string;
gender: string;
}

export interface VoteStatisticsProps {
voteResultResponse: VoteResultResponse;
size: Size;
}

const radioMode: RadioMode = {
all: '전체보기',
gender: '성별보기',
};

type RadioCategory = keyof RadioMode;

export default function VoteStatistics({ voteResult, size }: GraphProps) {
export default function VoteStatistics({ voteResultResponse, size }: VoteStatisticsProps) {
const [currentRadioMode, setCurrentRadioMode] = useState<RadioCategory>('all');

const radioModeKey = Object.keys(radioMode) as RadioCategory[];

const voteResult = transVoteStatisticsFormat(voteResultResponse);

const changeMode = (e: MouseEvent<HTMLInputElement>) => {
const target = e.target as HTMLInputElement;
const targetCategory = target.value as RadioCategory;
Expand All @@ -48,8 +58,8 @@ export default function VoteStatistics({ voteResult, size }: GraphProps) {
);
})}
</S.CategoryWrapper>
{currentRadioMode === 'all' && <OneLineGraph size={size} voteResult={voteResult} />}
{currentRadioMode === 'gender' && <TwoLineGraph size={size} voteResult={voteResult} />}
{currentRadioMode === 'all' && <OneLineGraph size={size} ageGroup={voteResult.ageGroup} />}
{currentRadioMode === 'gender' && <TwoLineGraph size={size} ageGroup={voteResult.ageGroup} />}
</S.Container>
);
}
50 changes: 32 additions & 18 deletions frontend/src/components/VoteStatistics/type.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
import { Size } from '@type/style';

export interface GraphProps {
voteResult: VoteResult;
ageGroup: VoteDetailResult[];
size: Size;
}

interface VoteDetailResult {
name: string;
total: number;
female: number;
male: number;
}

export const AGE_OPTION = [
'underTeenager',
'teenager',
'twenties',
'thirties',
'forties',
'fifties',
'aboveFifties',
'10대 미만',
'10대',
'20대',
'30대',
'40대',
'50대',
'60대 이상',
] as const;

export type AgeCategory = (typeof AGE_OPTION)[number];

export type VoteResultAge = Record<AgeCategory, VoteDetailResult>;
export interface VoteDetailResult {
name: AgeCategory;
total: number;
female: number;
male: number;
}

export interface VoteResult extends VoteDetailResult {
age: VoteResultAge;
export interface VoteResult {
ageGroup: VoteDetailResult[];
total: number;
female: number;
male: number;
}

export interface VoteDetailResultResponse {
ageGroup: AgeCategory;
voteCount: number;
femaleCount: number;
maleCount: number;
}
export interface VoteResultResponse {
ageGroup: VoteDetailResultResponse[];
totalVoteCount: number;
totalFemaleCount: number;
totalMaleCount: number;
}
22 changes: 22 additions & 0 deletions frontend/src/components/VoteStatistics/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { VoteResult, VoteResultResponse, VoteDetailResultResponse, VoteDetailResult } from './type';

const transDetailVoteStatisticsFormat = (
voteResult: VoteDetailResultResponse
): VoteDetailResult => {
const { ageGroup, femaleCount, maleCount, voteCount } = voteResult;

return { name: ageGroup, female: femaleCount, male: maleCount, total: voteCount };
};

export const transVoteStatisticsFormat = (voteResult: VoteResultResponse): VoteResult => {
const { ageGroup, totalFemaleCount, totalMaleCount, totalVoteCount } = voteResult;

const newAgeGroup = ageGroup.map(ageResult => transDetailVoteStatisticsFormat(ageResult));

return {
ageGroup: newAgeGroup,
female: totalFemaleCount,
male: totalMaleCount,
total: totalVoteCount,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function CommentItem({ comment, userType }: CommentItemProps) {
<S.TextFormWrapper>
<CommentTextForm
commentId={comment.id}
initialComment={content}
initialComment={comment}
handleCancelClick={handleCancelClick}
/>
</S.TextFormWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,26 @@ const meta: Meta<typeof CommentTextForm> = {
export default meta;
type Story = StoryObj<typeof CommentTextForm>;

const initialComment = {
id: -1,
member: {
id: -1,
nickname: '',
},
content: '',
createdAt: '',
isEdit: false,
};

export const InitForm: Story = {
render: () => <CommentTextForm commentId={-1} initialComment="" />,
render: () => <CommentTextForm commentId={-1} initialComment={initialComment} />,
};

export const EditForm: Story = {
render: () => (
<CommentTextForm
commentId={MOCK_TRANSFORMED_COMMENT_LIST[0].id}
initialComment={MOCK_TRANSFORMED_COMMENT_LIST[0].content}
initialComment={MOCK_TRANSFORMED_COMMENT_LIST[0]}
handleCancelClick={() => {}}
/>
),
Expand Down
Loading

0 comments on commit 49df3f8

Please sign in to comment.