-
Notifications
You must be signed in to change notification settings - Fork 0
refact: ticket api 리팩토링 #109
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
Changes from all commits
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 |
|---|---|---|
| @@ -1,23 +1,19 @@ | ||
| import { axiosClient } from "../../../shared/types/api/http-client"; | ||
| import { CreateTicketRequest } from "../model/ticketCreation"; | ||
| import { CreateTicketRequest, ReadTicketResponse } from "../model/ticketInformation"; | ||
|
|
||
| export const createTicket = async (data: CreateTicketRequest) => { | ||
| const response = await axiosClient.post('/tickets', data); | ||
| return response.data; | ||
| } | ||
|
|
||
| export const readTicket = { | ||
| getAll: async (eventId: number) => { | ||
| const response = await axiosClient.get("/tickets", { | ||
| params: { eventId }, | ||
| }); | ||
| return response.data; | ||
| }, | ||
| export const readTicket = async (eventId: number): Promise<{ isSuccess: boolean; result: ReadTicketResponse[] }> => { | ||
| const response = await axiosClient.get("/tickets", { | ||
| params: { eventId }, | ||
| }); | ||
| return response.data; | ||
| } | ||
|
|
||
| export const deleteTicket = { | ||
| remove: async (ticketId: number) => { | ||
| const response = await axiosClient.delete(`/tickets/${ticketId}`); | ||
| return response.data; | ||
| }, | ||
| export const deleteTicket = async (ticketId: number) => { | ||
| const response = await axiosClient.delete(`/tickets/${ticketId}`); | ||
| return response.data; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { useMutation, useQuery } from "@tanstack/react-query"; | ||
| import { createTicket, deleteTicket, readTicket } from "../api/ticket"; | ||
| import { CreateTicketRequest, ReadTicketResponse, TicketResponse } from "../model/ticketInformation"; | ||
|
|
||
| export const useTickets = (eventId: number) => { | ||
| return useQuery<{ isSuccess: boolean; result: ReadTicketResponse[] }>({ | ||
| queryKey: ['tickets', eventId], | ||
| queryFn: () => readTicket(eventId), | ||
| enabled: !!eventId, | ||
| }); | ||
| }; | ||
|
|
||
| export const useCreateTicket = () => { | ||
| return useMutation<TicketResponse, Error, CreateTicketRequest>({ | ||
| mutationFn: createTicket, | ||
| onSuccess: () => { | ||
| alert('티켓이 성공적으로 저장되었습니다.'); | ||
| window.location.reload(); | ||
| }, | ||
| onError: () => { | ||
| alert('티켓 저장에 실패했습니다. 다시 시도해주세요.'); | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| export const useDeleteTicket = () => { | ||
| return useMutation<TicketResponse, Error, number>({ | ||
| mutationFn: deleteTicket, | ||
| onSuccess: () => { | ||
| alert("티켓이 삭제되었습니다."); | ||
| window.location.reload(); | ||
| }, | ||
| onError: () => { | ||
| alert('티켓 삭제 중 오류가 발생했습니다.'); | ||
| } | ||
| }); | ||
| }; | ||
|
Comment on lines
+26
to
+37
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. 🛠️ Refactor suggestion useDeleteTicket 훅에도 동일한 개선이 필요합니다. 삭제 훅도 마찬가지로 페이지 리로드 대신 쿼리 무효화를 통한 데이터 갱신 방식으로 개선이 필요합니다. 다음과 같이 개선해보세요: export const useDeleteTicket = () => {
+ const queryClient = useQueryClient();
return useMutation<TicketResponse, Error, number>({
mutationFn: deleteTicket,
onSuccess: () => {
alert("티켓이 삭제되었습니다.");
- window.location.reload();
+ // 모든 티켓 쿼리 무효화
+ queryClient.invalidateQueries({ queryKey: ['tickets'] });
},
onError: () => {
alert('티켓 삭제 중 오류가 발생했습니다.');
}
});
};또한 삭제 함수에 이벤트 ID를 함께 전달하여 특정 이벤트의 티켓 쿼리만 무효화하는 방식으로도 구현할 수 있습니다: export const useDeleteTicket = () => {
const queryClient = useQueryClient();
return useMutation<TicketResponse, Error, { ticketId: number, eventId: number }>({
mutationFn: ({ ticketId }) => deleteTicket(ticketId),
onSuccess: (_, { eventId }) => {
alert("티켓이 삭제되었습니다.");
queryClient.invalidateQueries(['tickets', eventId]);
},
// ...
});
};이 방식을 사용하면 특정 이벤트의 티켓 목록만 갱신할 수 있어 더 효율적입니다. |
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| export interface CreateTicketRequest { | ||
| eventId: number; | ||
| ticketType: string; | ||
| ticketName: string; | ||
| ticketDescription: string; | ||
| ticketPrice: number; | ||
| availableQuantity: number; | ||
| startDate: string; | ||
| endDate: string; | ||
| startTime: string; | ||
| endTime: string; | ||
| } | ||
|
|
||
| export interface TicketResponse { | ||
| isSuccess: boolean; | ||
| code: string; | ||
| message: string; | ||
| result: string; // "ticketId: 2" | ||
| } | ||
|
|
||
| export interface ReadTicketResponse { | ||
| ticketId: number; | ||
| ticketName: string; | ||
| ticketDescription: string; | ||
| ticketPrice: number; | ||
| availableQuantity: number; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,12 +5,18 @@ import ChoiceChip from '../../../../../design-system/ui/ChoiceChip'; | |
| import DefaultTextField from '../../../../../design-system/ui/textFields/DefaultTextField'; | ||
| import Button from '../../../../../design-system/ui/Button'; | ||
| import TicketDatePicker from '../../../../features/ticket/model/TicketDatePicker'; | ||
| import { createTicket } from '../../../../features/ticket/api/ticket'; | ||
| import { CreateTicketRequest } from '../../../../features/ticket/model/ticketCreation'; | ||
| import { CreateTicketRequest } from '../../../../features/ticket/model/ticketInformation'; | ||
| import { useCreateTicket } from '../../../../features/ticket/hooks/useTicketHook'; | ||
| import { useNavigate, useParams } from 'react-router-dom'; | ||
|
|
||
| const TicketCreatePage = () => { | ||
| const navigate = useNavigate(); | ||
| const { mutate: createTicket } = useCreateTicket(); | ||
| const { id } = useParams(); | ||
| const eventId = Number(id); | ||
|
|
||
| const [ticketData, setTicketData] = useState<CreateTicketRequest>({ | ||
| eventId: 1, | ||
| eventId: eventId, | ||
| ticketType: 'FIRST_COME', | ||
| ticketName: '', | ||
| ticketDescription: '', | ||
|
|
@@ -76,14 +82,8 @@ const TicketCreatePage = () => { | |
| alert('모든 필수 입력 항목을 작성해주세요.'); | ||
| return; | ||
| } | ||
| try { | ||
| const response = await createTicket(ticketData); | ||
| console.log('티켓 저장 성공:', response); | ||
| alert('티켓이 성공적으로 저장되었습니다.'); | ||
| } catch (err) { | ||
| console.error('티켓 저장에 실패했습니다.', err); | ||
| alert('티켓 저장에 실패했습니다. 다시 시도해주세요.'); | ||
| } | ||
| createTicket(ticketData); | ||
| navigate(`/dashboard/${id}/ticket`); | ||
|
Comment on lines
+85
to
+86
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. 🛠️ Refactor suggestion 티켓 생성 로직이 React Query를 사용하여 개선되었습니다. 기존의 직접적인 API 호출 대신 React Query 기반 훅을 사용하여 코드가 간결해졌습니다. 하지만 다음 두 가지 개선점이 있습니다:
성공 여부를 확인한 후 페이지를 이동하는 방식이 더 안정적일 것입니다: - createTicket(ticketData);
- navigate(`/dashboard/${id}/ticket`);
+ createTicket(ticketData, {
+ onSuccess: () => {
+ navigate(`/dashboard/${id}/ticket`);
+ }
+ });이 변경을 위해서는 // useTicketHook.ts에서 수정 필요
export const useCreateTicket = () => {
return useMutation<TicketResponse, Error, CreateTicketRequest>({
mutationFn: createTicket,
onSuccess: () => {
alert('티켓이 성공적으로 저장되었습니다.');
// window.location.reload(); // 제거
},
onError: () => {
alert('티켓 저장에 실패했습니다. 다시 시도해주세요.');
},
});
}; |
||
| }; | ||
|
|
||
| return ( | ||
|
|
||
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.
🛠️ Refactor suggestion
useCreateTicket 훅에 개선이 필요합니다.
티켓 생성을 위한 훅이 잘 구현되었지만, 페이지 리로드 방식에 개선이 필요합니다.
현재 방식은
window.location.reload()를 사용하여 전체 페이지를 새로고침하고 있습니다. 이는 사용자 경험을 저하시키고, React Query의 장점을 충분히 활용하지 못합니다. 다음과 같이 개선해보세요:export const useCreateTicket = () => { return useMutation<TicketResponse, Error, CreateTicketRequest>({ mutationFn: createTicket, onSuccess: () => { alert('티켓이 성공적으로 저장되었습니다.'); - window.location.reload(); + // 쿼리 무효화를 통해 데이터 갱신 + // queryClient.invalidateQueries(['tickets']); }, onError: () => { alert('티켓 저장에 실패했습니다. 다시 시도해주세요.'); }, }); };이를 위해서는
QueryClient인스턴스에 대한 접근이 필요합니다. 다음과 같이 모듈 최상단에useQueryClient를 추가하고 훅 내부에서 사용할 수 있습니다: