Skip to content

Commit

Permalink
Merge pull request #200 from woowacourse-teams/feature/#188
Browse files Browse the repository at this point in the history
홈(모임 목록) 비즈니스 로직 및 API 연동 작업
  • Loading branch information
cys4585 authored Aug 5, 2024
2 parents 2dbabed + 5a225fa commit aa79f96
Show file tree
Hide file tree
Showing 19 changed files with 240 additions and 43 deletions.
20 changes: 19 additions & 1 deletion frontend/src/apis/gets.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// ./src/apis/gets.ts
import { MoimInfo, Participation } from '@_types/index';
import ApiClient from './apiClient';
import {
Expand All @@ -9,6 +8,7 @@ import {
GetZzimMine,
} from './responseTypes';
import { checkStatus } from './apiconfig';
import { Filter } from '@_components/MyMoimListFilters/MyMoimListFilters';

export const getMoims = async (): Promise<MoimInfo[]> => {
const response = await ApiClient.getWithAuth('moim');
Expand All @@ -18,6 +18,24 @@ export const getMoims = async (): Promise<MoimInfo[]> => {
return json.data.moims;
};

export const getMyMoims = async (
filter: Filter['api'],
): Promise<MoimInfo[]> => {
const response = await ApiClient.getWithAuth(`moim/mine?filter=${filter}`);
checkStatus(response);

const json: GetMoims = await response.json();
return json.data.moims;
};

export const getMyZzimMoims = async (): Promise<MoimInfo[]> => {
const response = await ApiClient.getWithAuth('moim/zzim');
checkStatus(response);

const json: GetMoims = await response.json();
return json.data.moims;
};

export const getMoim = async (moimId: number): Promise<MoimInfo> => {
const response = await ApiClient.getWithAuth(`moim/${moimId}`);
checkStatus(response);
Expand Down
22 changes: 22 additions & 0 deletions frontend/src/components/HomeMainContent/HomeMainContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import MoimList from '@_components/MoimList/MoimList';
import { MainPageTab } from '@_components/MoimTabBar/MoimTabBar';
import MyMoimList from '@_components/MyMoim/MyMoim';
import MyZzimMoimList from '@_components/MyZzimMoimList/MyZzimMoimList';

interface MoimMainContentProps {
currentTab: MainPageTab;
}

export default function HomeMainContent(props: MoimMainContentProps) {
const { currentTab } = props;

if (currentTab === '모임목록') {
return <MoimList />;
}
if (currentTab === '나의모임') {
return <MyMoimList />;
}
if (currentTab === '찜한모임') {
return <MyZzimMoimList />;
}
}
8 changes: 6 additions & 2 deletions frontend/src/components/MoimCard/MoimCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ export const Default: Story = {
place: '서울 마포구 독막로 96 1층',
maxPeople: 5,
currentPeople: 3,
zzim: true,
isZzimed: true,
moimId: 1,
authorNickname: '김코딩',
participants: ['김코딩', '이코딩', '박코딩'],
participants: [
{ nickname: '김코딩', profile: 'profile', role: 'moimer' },
],
description: '코딩하면서 놀아요',
status: 'MOIMING',
comments: [],
},
},
render: (args) => <MoimCard {...args} />,
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/components/MoimCard/MoimCard.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export const cardTitle = (props: { theme: Theme }) => {
`;
};

export const heartButton = css`
padding: 0;
background: none;
border: 0;
`;

export const subjectBox = css`
display: flex;
gap: 0.8rem;
Expand Down
24 changes: 22 additions & 2 deletions frontend/src/components/MoimCard/MoimCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,44 @@ import { formatHhmmToKorean, formatYyyymmddToKorean } from '@_utils/formatters';
import { MoimInfo } from '@_types/index';
import { useTheme } from '@emotion/react';
import HeartIcon from '@_components/Icons/HeartIcon';
import useChangeZzim from '@_hooks/mutaions/useChangeZzim';

interface MoimCardProps extends HTMLProps<HTMLDivElement> {
moimInfo: MoimInfo;
}

export default function MoimCard(props: MoimCardProps) {
const {
moimInfo: { title, date, time, place, maxPeople, currentPeople, zzim },
moimInfo: {
moimId,
title,
date,
time,
place,
maxPeople,
currentPeople,
isZzimed,
},
...args
} = props;

const theme = useTheme();

const { mutate: changeZzim } = useChangeZzim();

const handleHeartButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
console.log(1);
changeZzim(moimId);
};

return (
<div css={S.cardBox} {...args}>
<div css={S.titleBox}>
<h2 css={S.cardTitle({ theme })}>{title}</h2>
<HeartIcon isFilled={zzim} />
<button css={S.heartButton} onClick={handleHeartButtonClick}>
<HeartIcon isFilled={isZzimed} />
</button>
</div>

<div css={S.subjectBox}>
Expand Down
24 changes: 18 additions & 6 deletions frontend/src/components/MoimCardList/MoimCardList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ export const Default: Story = {
place: '서울 마포구 독막로 96 1층',
maxPeople: 5,
currentPeople: 3,
zzim: true,
isZzimed: true,
moimId: 1,
authorNickname: '김코딩',
participants: ['김코딩', '이코딩', '박코딩'],
participants: [
{ nickname: '김코딩', profile: 'profile', role: 'moimer' },
],
description: '코딩하면서 놀아요',
status: 'MOIMING',
comments: [],
},
{
title: '볼 함 차보까?',
Expand All @@ -41,11 +45,15 @@ export const Default: Story = {
place: '서울 마포구 독막로 96 1층',
maxPeople: 5,
currentPeople: 3,
zzim: false,
isZzimed: false,
moimId: 1,
authorNickname: '김코딩',
participants: ['김코딩', '이코딩', '박코딩'],
participants: [
{ nickname: '김코딩', profile: 'profile', role: 'moimer' },
],
description: '코딩하면서 놀아요',
status: 'MOIMING',
comments: [],
},
{
title: '볼 함 차보까?',
Expand All @@ -54,11 +62,15 @@ export const Default: Story = {
place: '서울 마포구 독막로 96 1층',
maxPeople: 5,
currentPeople: 3,
zzim: true,
isZzimed: true,
moimId: 1,
authorNickname: '김코딩',
participants: ['김코딩', '이코딩', '박코딩'],
participants: [
{ nickname: '김코딩', profile: 'profile', role: 'moimer' },
],
description: '코딩하면서 놀아요',
status: 'MOIMING',
comments: [],
},
],
},
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/components/MoimList/MoimList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import MoimCardList from '@_components/MoimCardList/MoimCardList';
import useMoims from '@_hooks/queries/useMoims';

export default function MoimList() {
const { moims, isLoading } = useMoims();

if (isLoading) {
return <div>로딩중...</div>;
}

return moims && <MoimCardList moimInfos={moims} />;
}
3 changes: 1 addition & 2 deletions frontend/src/components/MoimTabBar/MoimTabBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
tabs: ['Tab1', 'Tab2', 'Tab3'],
currentTab: 'Tab1',
currentTab: '모임목록',
onTabClick: (tab: string) => console.log(tab),
},
render: (args) => <MoimTabBar {...args} />,
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/components/MoimTabBar/MoimTabBar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { useTheme } from '@emotion/react';
import * as S from './MoimTabBar.style';

export type MainPageTab = '모임목록' | '나의모임' | '찜한모임';

const tabs: MainPageTab[] = ['모임목록', '나의모임', '찜한모임'];

interface MoimTabBarProps {
tabs: string[];
currentTab: string;
onTabClick: (tab: string) => void;
currentTab: MainPageTab;
onTabClick: (tab: MainPageTab) => void;
}

export default function MoimTabBar(props: MoimTabBarProps) {
const { tabs, currentTab, onTabClick } = props;
const { currentTab, onTabClick } = props;

const theme = useTheme();

Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/MyMoim/MyMoim.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import MoimCardList from '@_components/MoimCardList/MoimCardList';
import MyMoimListFilters, {
Filter,
} from '@_components/MyMoimListFilters/MyMoimListFilters';
import useMyMoims from '@_hooks/queries/useMyMoims';
import { Fragment, useState } from 'react';

export default function MyMoimList() {
const [selectedFilter, setSelectedFilter] = useState<Filter['api']>('all');

const { myMoims, isLoading } = useMyMoims(selectedFilter);

const handleFilterSelect = (filter: Filter['api']) => {
setSelectedFilter(filter);
};

if (isLoading) {
return <div>로딩중...</div>;
}

return (
<Fragment>
<MyMoimListFilters
selectedFilter={selectedFilter}
handleFilterSelect={handleFilterSelect}
/>
{myMoims && <MoimCardList moimInfos={myMoims} />}
</Fragment>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
selectedFilter: 'all',
handleFilterSelect: () => {},
},
render: (args) => <MyMoimListFilters {...args} />,
};
40 changes: 31 additions & 9 deletions frontend/src/components/MyMoimListFilters/MyMoimListFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
import MyMoimListFilterTag from '@_components/MyMoimListFilterTag/MyMoimListFilterTag';
import { useState } from 'react';
import * as S from './MyMoimListFilters.style';

const filters = ['모든 모임', '다가오는 모임', '지난 모임'];
export type Filter =
| {
ui: '모든 모임';
api: 'all';
}
| {
ui: '다가오는 모임';
api: 'upcoming';
}
| {
ui: '지난 모임';
api: 'past';
};

export default function MyMoimListFilters() {
const [selectedFilter, setSelectedFilter] = useState(filters[0]);
const filters: Filter[] = [
{ ui: '모든 모임', api: 'all' },
{ ui: '다가오는 모임', api: 'upcoming' },
{ ui: '지난 모임', api: 'past' },
];

interface MyMoimListFiltersProps {
selectedFilter: Filter['api'];
handleFilterSelect: (filter: Filter['api']) => void;
}

export default function MyMoimListFilters(props: MyMoimListFiltersProps) {
const { selectedFilter, handleFilterSelect } = props;

return (
<div css={S.container}>
{filters.map((filter) => (
{filters.map(({ ui, api }) => (
<MyMoimListFilterTag
key={filter}
label={filter}
isSelected={selectedFilter === filter}
onClick={() => setSelectedFilter(filter)}
key={ui}
label={ui}
isSelected={selectedFilter === api}
onClick={() => handleFilterSelect(api)}
/>
))}
</div>
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/components/MyZzimMoimList/MyZzimMoimList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import MoimCardList from '@_components/MoimCardList/MoimCardList';
import useMyZzimMoims from '@_hooks/queries/useMyZzimMoim';

export default function MyZzimMoimList() {
const { myZzimMoims, isLoading } = useMyZzimMoims();

if (isLoading) {
return <div>로딩중...</div>;
}

return myZzimMoims && <MoimCardList moimInfos={myZzimMoims} />;
}
2 changes: 2 additions & 0 deletions frontend/src/constants/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const QUERY_KEYS = {
moims: 'moims',
myMoims: 'myMoims',
myZzimMoims: 'myZzimMoims',
moim: 'moim',
userKey: 'userKey',
chamyoMine: 'chamyoMine',
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/hooks/mutaions/useChangeZzim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ export default function useChangeZzim() {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.ZzimMine, moimId],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.moims],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.myMoims],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.myZzimMoims],
});
},
});
}
13 changes: 13 additions & 0 deletions frontend/src/hooks/queries/useMyMoims.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getMyMoims } from '@_apis/gets';
import { Filter } from '@_components/MyMoimListFilters/MyMoimListFilters';
import QUERY_KEYS from '@_constants/queryKeys';
import { useQuery } from '@tanstack/react-query';

export default function useMyMoims(selectedFilter: Filter['api']) {
const { data: myMoims, isLoading } = useQuery({
queryKey: [QUERY_KEYS.myMoims, selectedFilter],
queryFn: () => getMyMoims(selectedFilter),
});

return { myMoims, isLoading };
}
12 changes: 12 additions & 0 deletions frontend/src/hooks/queries/useMyZzimMoim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getMyZzimMoims } from '@_apis/gets';
import QUERY_KEYS from '@_constants/queryKeys';
import { useQuery } from '@tanstack/react-query';

export default function useMyZzimMoims() {
const { data: myZzimMoims, isLoading } = useQuery({
queryKey: [QUERY_KEYS.myZzimMoims],
queryFn: getMyZzimMoims,
});

return { myZzimMoims, isLoading };
}
Loading

0 comments on commit aa79f96

Please sign in to comment.