-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
모임상세, 모임 참여 API 연결 로직 구현 #79
Changes from all commits
a76ca7e
4faf1d2
71c018f
b0ae104
ac1d56b
e344d61
0af623f
a1ce49a
7c53588
835451b
fcff584
91ab84c
92cf203
7bdbfcb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export const defaultHeaders = { | ||
'Content-Type': 'application/json', | ||
}; | ||
|
||
export const defaultOptions = { | ||
headers: defaultHeaders, | ||
}; | ||
|
||
export const checkStatus = async (response: Response) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 공통 API 에러처리 분리 |
||
const statusHead = Math.floor(response.status / 100); | ||
if (statusHead === 4 || statusHead === 5) { | ||
const json = await response.json(); | ||
throw new Error(json.message); | ||
} | ||
return response; | ||
}; | ||
Comment on lines
+9
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. checkStatus 함수 분리, 네이밍 아주 좋네요~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네이밍도 한번 고민해보아야 겠네요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다만 header라는 것이 api통신을 위한 환경설정이라는 의미로 붙인 것이긴 합니다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,29 @@ | ||
import ENDPOINTS from '@_apis/endPoints'; | ||
import { GetMoim } from '@_apis/responseTypes'; | ||
import { GetMoim, GetMoims } from '@_apis/responseTypes'; | ||
import { MoimInfo } from '@_types/index'; | ||
import { checkStatus, defaultOptions } from './apiconfig'; | ||
|
||
const defaultGetOptions = { | ||
method: 'GET', | ||
...defaultOptions, | ||
}; | ||
export const getMoims = async (): Promise<MoimInfo[]> => { | ||
const url = ENDPOINTS.moims; | ||
|
||
const options = { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}; | ||
const response = await fetch(url, defaultGetOptions); | ||
|
||
checkStatus(response); | ||
const json = (await response.json()) as GetMoims; | ||
return json.data.moims; | ||
}; | ||
|
||
export const getMoim = async (moimId: number): Promise<MoimInfo> => { | ||
const url = `${ENDPOINTS.moim}/${moimId}`; | ||
|
||
const response = await fetch(url, options); | ||
const response = await fetch(url, defaultGetOptions); | ||
|
||
const statusHead = Math.floor(response.status / 100); | ||
if (statusHead === 4 || statusHead === 5) { | ||
throw new Error('모임을 받아오지 못했습니다.'); | ||
} | ||
checkStatus(response); | ||
|
||
const json = (await response.json()) as GetMoim; | ||
return json.data.moims; | ||
return json.data; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,37 @@ | ||
import ENDPOINTS from '@_apis/endPoints'; | ||
import { MoimInfo } from '@_types/index'; | ||
import { MoimInputInfo } from '@_types/index'; | ||
import { PostMoim } from '@_apis/responseTypes'; | ||
import { checkStatus, defaultOptions } from './apiconfig'; | ||
|
||
export const postMoim = async (moim: MoimInfo): Promise<number> => { | ||
const defaultPostOptions = { | ||
method: 'POST', | ||
...defaultOptions, | ||
}; | ||
export const postMoim = async (moim: MoimInputInfo): Promise<number> => { | ||
const url = ENDPOINTS.moim; | ||
|
||
const options = { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
...defaultPostOptions, | ||
body: JSON.stringify(moim), | ||
}; | ||
|
||
const response = await fetch(url, options); | ||
|
||
const statusHead = Math.floor(response.status / 100); | ||
if (statusHead === 4 || statusHead === 5) | ||
throw new Error('모임을 업데이트하지 못했습니다.'); | ||
checkStatus(response); | ||
|
||
const json = (await response.json()) as PostMoim; | ||
return json.id; | ||
return json.data; | ||
}; | ||
|
||
export const postJoinMoim = async (moimId: number) => { | ||
const url = `${ENDPOINTS.moims}/join`; | ||
|
||
const options = { | ||
...defaultPostOptions, | ||
body: JSON.stringify({ moimId }), | ||
}; | ||
|
||
const response = await fetch(url, options); | ||
|
||
await checkStatus(response); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
import { MoimInfo } from '../types'; | ||
|
||
export interface GetMoim { | ||
export interface GetMoims { | ||
data: { moims: MoimInfo[] }; | ||
} | ||
|
||
export interface GetMoim { | ||
data: MoimInfo; | ||
} | ||
|
||
export interface PostMoim { | ||
id: number; | ||
data: number; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,18 +6,20 @@ import { | |
} from '../../utils/formatters'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 작업 공간이 겹치는 파일이 있을 때(ex:api가 component를 건드는 경우) 어떻게 하면 좋을지 생각해봐야 할 것 같아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아마 merge하는 사람이 충돌을 해결해야 할 것 같은데 추후에 다시 의견을 나누어 보죠 |
||
|
||
import { MoimInfo } from '../../types'; | ||
import { HTMLProps } from 'react'; | ||
|
||
interface MoimCardProps { | ||
interface MoimCardProps extends HTMLProps<HTMLDivElement> { | ||
moimInfo: MoimInfo; | ||
} | ||
|
||
export default function MoimCard(props: MoimCardProps) { | ||
const { | ||
moimInfo: { title, date, time, place, maxPeople }, | ||
moimInfo: { title, date, time, place, maxPeople, currentPeople }, | ||
...args | ||
} = props; | ||
|
||
return ( | ||
<div css={S.cardBox}> | ||
<div css={S.cardBox} {...args}> | ||
<h2 css={S.cardTitle}>{title}</h2> | ||
<div css={S.subjectBox}> | ||
<span css={S.subjectTag}>날짜 및 시간</span> | ||
|
@@ -30,8 +32,10 @@ export default function MoimCard(props: MoimCardProps) { | |
<span css={S.subjectInfo}>{place}</span> | ||
</div> | ||
<div css={S.subjectBox}> | ||
<span css={S.subjectTag}>최대인원수</span> | ||
<span css={S.subjectInfo}>{maxPeople}명</span> | ||
<span css={S.subjectTag}>인원수</span> | ||
<span css={S.subjectInfo}> | ||
최대{maxPeople}명 / 현재 {currentPeople}명 | ||
</span> | ||
</div> | ||
</div> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
const QUERY_KEYS = { moims: 'moims' }; | ||
const QUERY_KEYS = { moims: 'moims', moim: 'moim' }; | ||
|
||
export default QUERY_KEYS; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
const ROUTES = { | ||
main: '/', | ||
addMoim: '/add-moim', | ||
detail: '/moim/:moimId', | ||
}; | ||
|
||
export default ROUTES; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
|
||
import QUERY_KEYS from '@_constants/queryKeys'; | ||
import { postJoinMoim } from '@_apis/posts'; | ||
|
||
export default function useJoinMoim(onSuccess: () => void) { | ||
const queryClient = useQueryClient(); | ||
|
||
return useMutation({ | ||
mutationFn: postJoinMoim, | ||
onSuccess: () => { | ||
queryClient.invalidateQueries({ | ||
queryKey: [QUERY_KEYS.moim], | ||
}); | ||
onSuccess(); | ||
}, | ||
Comment on lines
+11
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 참여 신청이 성공했을 때, QUERY_KEYS.moim을 refetching 해야하는 이유가 있을까요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 페이지에서 현재 참여 인원수를 반영하기 위해 refetching 하고 있습니다. |
||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import QUERY_KEYS from '@_constants/queryKeys'; | ||
import { getMoim } from '@_apis/gets'; | ||
import { useQuery } from '@tanstack/react-query'; | ||
|
||
export default function useMoim(moimId: number) { | ||
const { data: moim, isLoading } = useQuery({ | ||
queryKey: [QUERY_KEYS.moim, moimId], | ||
queryFn: () => getMoim(moimId), | ||
}); | ||
Comment on lines
+6
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. queryKey를 두 개를 두면 nesting이 되는 걸까요?? 꿀팁 ㄱㅅㄱㅅ~ |
||
|
||
return { moim, isLoading }; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,15 +2,16 @@ import Button from '@_components/Button/Button'; | |
import FormLayout from '@_layouts/FormLayout/FormLayout'; | ||
import LabeledInput from '@_components/Input/MoimInput'; | ||
import MOIM_INPUT_INFOS from './MoimCreationPage.constant'; | ||
import ROUTES from '@_constants/routes'; | ||
import useAddMoim from '@_hooks/mutaions/useAddMoim'; | ||
import useMoimInfoInput from './MoimCreatePage.hook'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { useState } from 'react'; | ||
|
||
export default function MoimCreationPage() { | ||
const navigate = useNavigate(); | ||
const { mutate } = useAddMoim(() => navigate(ROUTES.main)); | ||
const { mutate } = useAddMoim((moimId: number) => { | ||
navigate(`/${moimId}`); | ||
}); | ||
const [isSubmitted, setIsSubmitted] = useState(false); | ||
|
||
const { inputData, handleChange, isValidMoimInfoInput } = useMoimInfoInput(); | ||
|
@@ -26,7 +27,7 @@ export default function MoimCreationPage() { | |
|
||
return ( | ||
<FormLayout> | ||
<FormLayout.Header onBackArrowClick={() => navigate(ROUTES.main)}> | ||
<FormLayout.Header onBackArrowClick={() => navigate(-1)}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
모임등록하기 | ||
</FormLayout.Header> | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import useJoinMoim from '@_hooks/mutaions/useJoinMoim'; | ||
import useMoim from '@_hooks/queries/useMoim'; | ||
import { useParams } from 'react-router-dom'; | ||
|
||
export default function TempDetailPage() { | ||
const params = useParams(); | ||
const moimId = Number(params.moimId); | ||
|
||
const { moim, isLoading } = useMoim(moimId); | ||
const { mutate } = useJoinMoim(() => { | ||
alert('참여했습니다.'); | ||
}); | ||
|
||
if (isLoading) { | ||
return <div>Loading...</div>; | ||
} | ||
if (!moim) { | ||
return <div>No data found</div>; | ||
} | ||
|
||
// moim 데이터를 출력합니다. | ||
return ( | ||
<div> | ||
<h1>{moim.title}</h1> | ||
<p>{moim.description}</p> | ||
<p>Place: {moim.place}</p> | ||
<p>Date: {moim.date}</p> | ||
<p>Time: {moim.time}</p> | ||
<p>Max People: {moim.maxPeople}</p> | ||
<p>currentPeople: {moim.currentPeople}</p> | ||
<p>Author: {moim.authorNickname}</p> | ||
|
||
<button onClick={() => mutate(moimId)}>참여하기</button> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,10 +6,14 @@ const createQueryClient = () => { | |
queries: { | ||
networkMode: 'always', | ||
}, | ||
mutations: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. queryClient 에러 처리 추가 |
||
onError: (error) => alert(error.message), | ||
networkMode: 'always', | ||
}, | ||
}, | ||
queryCache: new QueryCache({ | ||
onError: (error) => { | ||
alert(error); | ||
alert(error instanceof Error ? error.message : 'An error occurred'); | ||
}, | ||
}), | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import MainPage from '@_pages/MainPage/MainPage'; | |
import MoimCreationPage from '@_pages/MoimCreationPage/MoimCreationPage'; | ||
import ROUTES from '@_constants/routes'; | ||
import { createBrowserRouter } from 'react-router-dom'; | ||
import TempDetailPage from '@_pages/TempDetail/TempDetailPage'; | ||
|
||
const router = createBrowserRouter([ | ||
{ | ||
|
@@ -12,6 +13,10 @@ const router = createBrowserRouter([ | |
path: ROUTES.addMoim, | ||
element: <MoimCreationPage />, | ||
}, | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분에 대한 커밋이 안올라온 것 같아요ㅜㅜ 다시 올려주시면 좋을 것 같아요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 올렸습니다. 구현 자체랑 상관없어서 올리지 않았는데 올리는 것이 이해하는데 더 좋았겠네요 |
||
path: ROUTES.detail, | ||
element: <TempDetailPage />, | ||
}, | ||
]); | ||
|
||
export default router; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
export interface MoimInfo { | ||
moimId: number; | ||
title: string; | ||
date: string; | ||
time: string; | ||
place: string; | ||
maxPeople: number; | ||
currentPeople: number; | ||
authorNickname: string; | ||
description?: string; | ||
} | ||
|
||
export type MoimInputInfo = Omit<MoimInfo, 'moimId' | 'currentPeople'>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Omit 굿굿~~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultHeader에 대해서 같이 조금 더 생각을 해봐야 할 것 같아요
저는 json이 아닌 다른 요청들도 필요할 수 있다고 생각이 들어요.(제가 잘 몰라서 그럼)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 같은 의견입니다. 다만 현재는 header의 형태가 하나여서 이렇게 네이밍한것일 뿐 언제나 수정 가능합니다. 좋은 의견이네요