Skip to content

Commit 3c3be8a

Browse files
committed
refact: ticket api 리팩토링
1 parent 8f0575f commit 3c3be8a

File tree

9 files changed

+114
-116
lines changed

9 files changed

+114
-116
lines changed

src/features/ticket/api/ticket.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import { axiosClient } from "../../../shared/types/api/http-client";
2-
import { CreateTicketRequest } from "../model/ticketCreation";
2+
import { CreateTicketRequest, ReadTicketResponse } from "../model/ticketInformation";
33

44
export const createTicket = async (data: CreateTicketRequest) => {
55
const response = await axiosClient.post('/tickets', data);
66
return response.data;
77
}
88

9-
export const readTicket = {
10-
getAll: async (eventId: number) => {
11-
const response = await axiosClient.get("/tickets", {
12-
params: { eventId },
13-
});
14-
return response.data;
15-
},
9+
export const readTicket = async (eventId: number): Promise<{ isSuccess: boolean; result: ReadTicketResponse[] }> => {
10+
const response = await axiosClient.get("/tickets", {
11+
params: { eventId },
12+
});
13+
return response.data;
1614
}
1715

18-
export const deleteTicket = {
19-
remove: async (ticketId: number) => {
20-
const response = await axiosClient.delete(`/tickets/${ticketId}`);
21-
return response.data;
22-
},
16+
export const deleteTicket = async (ticketId: number) => {
17+
const response = await axiosClient.delete(`/tickets/${ticketId}`);
18+
return response.data;
2319
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useMutation, useQuery } from "@tanstack/react-query";
2+
import { createTicket, deleteTicket, readTicket } from "../api/ticket";
3+
import { CreateTicketRequest, ReadTicketResponse, TicketResponse } from "../model/ticketInformation";
4+
5+
export const useTickets = (eventId: number) => {
6+
return useQuery<{ isSuccess: boolean; result: ReadTicketResponse[] }>({
7+
queryKey: ['tickets', eventId],
8+
queryFn: () => readTicket(eventId),
9+
enabled: !!eventId,
10+
});
11+
};
12+
13+
export const useCreateTicket = () => {
14+
return useMutation<TicketResponse, Error, CreateTicketRequest>({
15+
mutationFn: createTicket,
16+
onSuccess: () => {
17+
alert('티켓이 성공적으로 저장되었습니다.');
18+
window.location.reload();
19+
},
20+
onError: () => {
21+
alert('티켓 저장에 실패했습니다. 다시 시도해주세요.');
22+
},
23+
});
24+
};
25+
26+
export const useDeleteTicket = () => {
27+
return useMutation<TicketResponse, Error, number>({
28+
mutationFn: deleteTicket,
29+
onSuccess: () => {
30+
alert("티켓이 삭제되었습니다.");
31+
window.location.reload();
32+
},
33+
onError: () => {
34+
alert('티켓 삭제 중 오류가 발생했습니다.');
35+
}
36+
});
37+
};

src/features/ticket/model/TicketContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createContext, ReactNode, useContext, useState } from 'react';
2-
import { CreateTicketRequest } from './ticketCreation';
2+
import { CreateTicketRequest } from './ticketInformation';
33

44
export interface TicketState {
55
ticketState: CreateTicketRequest;

src/features/ticket/model/ticketCreation.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export interface CreateTicketRequest {
2+
eventId: number;
3+
ticketType: string;
4+
ticketName: string;
5+
ticketDescription: string;
6+
ticketPrice: number;
7+
availableQuantity: number;
8+
startDate: string;
9+
endDate: string;
10+
startTime: string;
11+
endTime: string;
12+
}
13+
14+
export interface TicketResponse {
15+
isSuccess: boolean;
16+
code: string;
17+
message: string;
18+
result: string; // "ticketId: 2"
19+
}
20+
21+
export interface ReadTicketResponse {
22+
ticketId: number;
23+
ticketName: string;
24+
ticketDescription: string;
25+
ticketPrice: number;
26+
availableQuantity: number;
27+
}

src/pages/dashboard/ui/ticket/TicketCreatePage.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ import ChoiceChip from '../../../../../design-system/ui/ChoiceChip';
55
import DefaultTextField from '../../../../../design-system/ui/textFields/DefaultTextField';
66
import Button from '../../../../../design-system/ui/Button';
77
import TicketDatePicker from '../../../../features/ticket/model/TicketDatePicker';
8-
import { createTicket } from '../../../../features/ticket/api/ticket';
9-
import { CreateTicketRequest } from '../../../../features/ticket/model/ticketCreation';
8+
import { CreateTicketRequest } from '../../../../features/ticket/model/ticketInformation';
9+
import { useCreateTicket } from '../../../../features/ticket/hooks/useTicketHook';
10+
import { useNavigate, useParams } from 'react-router-dom';
1011

1112
const TicketCreatePage = () => {
13+
const navigate = useNavigate();
14+
const { mutate: createTicket } = useCreateTicket();
15+
const { id } = useParams();
16+
const eventId = Number(id);
17+
1218
const [ticketData, setTicketData] = useState<CreateTicketRequest>({
13-
eventId: 1,
19+
eventId: eventId,
1420
ticketType: 'FIRST_COME',
1521
ticketName: '',
1622
ticketDescription: '',
@@ -76,14 +82,8 @@ const TicketCreatePage = () => {
7682
alert('모든 필수 입력 항목을 작성해주세요.');
7783
return;
7884
}
79-
try {
80-
const response = await createTicket(ticketData);
81-
console.log('티켓 저장 성공:', response);
82-
alert('티켓이 성공적으로 저장되었습니다.');
83-
} catch (err) {
84-
console.error('티켓 저장에 실패했습니다.', err);
85-
alert('티켓 저장에 실패했습니다. 다시 시도해주세요.');
86-
}
85+
createTicket(ticketData);
86+
navigate(`/dashboard/${id}/ticket`);
8787
};
8888

8989
return (

src/pages/dashboard/ui/ticket/TicketListPage.tsx

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,24 @@
11
import DashboardLayout from '../../../../shared/ui/backgrounds/DashboardLayout';
22
import Ticket from '../../../../../public/assets/dashboard/ticket/Ticket(horizon).svg';
33
import TicketItem from '../../../../widgets/dashboard/ui/TicketItem';
4-
import { useNavigate } from 'react-router-dom';
5-
import { DASHBOARD_ROUTES } from '../../../../app/routes/routes';
4+
import { useNavigate, useParams } from 'react-router-dom';
65
import HorizontalCardButton from '../../../../../design-system/ui/buttons/HorizontalCardButton';
76
import AddButton from '../../../../../public/assets/dashboard/ticket/AddButton.svg';
8-
import { useEffect, useState } from 'react';
9-
import { readTicket } from '../../../../features/ticket/api/ticket';
10-
11-
export interface ReadTicket {
12-
ticketId: number;
13-
ticketName: string;
14-
ticketDescription: string;
15-
ticketPrice: number;
16-
availableQuantity: number;
17-
}
7+
import { useTickets } from '../../../../features/ticket/hooks/useTicketHook';
188

199
const TicketListPage = () => {
2010
const navigate = useNavigate();
2111

2212
const navigateToTicketCreate = () => {
23-
navigate(DASHBOARD_ROUTES.ticketCreate);
13+
navigate(`/dashboard/${id}/ticket/create`);
2414
};
15+
const { id } = useParams();
16+
const eventId = id ? parseInt(id) : 1;
17+
const { data, isLoading, isError } = useTickets(eventId);
2518

26-
const [tickets, setTickets] = useState<ReadTicket[]>([]);
27-
const eventId = 1; //수정 필요
19+
if (isLoading) return <div>로딩 중...</div>;
20+
if (isError) return <div>티켓 정보를 불러오는 중 오류가 발생했습니다.</div>;
2821

29-
useEffect(() => {
30-
const fetchTickets = async () => {
31-
try {
32-
const data = await readTicket.getAll(eventId);
33-
if (data.isSuccess && Array.isArray(data.result)) {
34-
setTickets(data.result);
35-
} else {
36-
setTickets([]);
37-
}
38-
} catch (error) {
39-
console.error("티켓 데이터를 불러오는 중 오류 발생:", error);
40-
setTickets([]);
41-
}
42-
};
43-
fetchTickets();
44-
}, [eventId]);
45-
4622
return (
4723
<DashboardLayout centerContent="WOOACON 2024">
4824
<div className="mt-8 px-7">
@@ -69,8 +45,8 @@ const TicketListPage = () => {
6945
<img src={Ticket} />
7046
<p className="font-bold text-base md:text-lg">티켓</p>
7147
</div>
72-
{tickets.length > 0 ? (
73-
tickets.map(value => <TicketItem key={value.ticketId} ticket={value}/>)
48+
{data?.isSuccess && data?.result.length > 0 ? (
49+
data.result.map(value => <TicketItem key={value.ticketId} ticket={value} />)
7450
) : (
7551
<div className="text-gray5 font-thin">현재 등록된 티켓이 없습니다.</div>
7652
)}

src/widgets/dashboard/ui/TicketItem.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
import AvailableTicket from '../../../../public/assets/dashboard/ticket/Ticket(gray).svg';
22
import PersonIcon from '../../../../public/assets/dashboard/ticket/PersonIcon.svg';
3-
import { ReadTicket } from '../../../pages/dashboard/ui/ticket/TicketListPage';
43
import { motion } from "framer-motion";
54
import { useState } from 'react';
6-
import { deleteTicket } from '../../../features/ticket/api/ticket';
5+
import { ReadTicketResponse } from '../../../features/ticket/model/ticketInformation';
6+
import { useDeleteTicket } from '../../../features/ticket/hooks/useTicketHook';
77

8-
const TicketItem = ({ ticket }: { ticket: ReadTicket }) => {
8+
const TicketItem = ({ ticket }: { ticket: ReadTicketResponse }) => {
99
const [isDragging, setIsDragging] = useState(false);
10-
const handleDelete = async () => {
11-
const isConfirmed = window.confirm("티켓을 삭제하시겠습니까?");
12-
if (!isConfirmed) return;
13-
try {
14-
await deleteTicket.remove(ticket.ticketId);
15-
alert("티켓이 삭제되었습니다.");
16-
window.location.reload();
17-
} catch (error) {
18-
console.error("티켓 삭제 중 오류 발생:", error);
19-
}
20-
};
10+
const { mutate: handleDelete} = useDeleteTicket();
2111
return (
2212
<div className="relative overflow-hidden w-full mb-4">
2313
<motion.div
@@ -54,7 +44,7 @@ const TicketItem = ({ ticket }: { ticket: ReadTicket }) => {
5444
initial={{ x: '100%' }}
5545
animate={{ x: isDragging ? 0 : 'calc(100% + 1px)' }}
5646
transition={{ duration: 0 }}
57-
onClick={handleDelete}
47+
onClick={() => handleDelete(ticket.ticketId)}
5848
>
5949
삭제
6050
</motion.button>

src/widgets/event/ui/TicketInfo.tsx

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,26 @@
11
import { useEffect, useState } from 'react';
22
import TertiaryButton from '../../../../design-system/ui/buttons/TertiaryButton';
33
import TextButton from '../../../../design-system/ui/buttons/TextButton';
4-
import { readTicket } from '../../../features/ticket/api/ticket';
5-
import { ReadTicket } from '../../../pages/dashboard/ui/ticket/TicketListPage';
64
import { OrderTicketRequest } from '../../../features/ticket/model/OrderCreation';
75
import { orderTickets } from '../../../features/ticket/api/order';
86
import { useNavigate } from 'react-router-dom';
7+
import { useTickets } from '../../../features/ticket/hooks/useTicketHook';
98

109
const TicketInfo = ({ eventId }: { eventId: number }) => {
1110
const limitNum = 4;
12-
const [tickets, setTickets] = useState<ReadTicket[]>([]);
11+
const { data, isError, isLoading } = useTickets(eventId);
1312
const [quantity, setQuantity] = useState<{ [key: number]: number }>({});
1413
const navigate = useNavigate();
15-
16-
useEffect(() => {
17-
const fetchTickets = async () => {
18-
try {
19-
const data = await readTicket.getAll(eventId);
20-
if (data.isSuccess && Array.isArray(data.result)) {
21-
setTickets(data.result);
22-
} else {
23-
setTickets([]);
24-
}
25-
} catch (error) {
26-
console.error("티켓 데이터를 불러오는 중 오류 발생:", error);
27-
setTickets([]);
28-
}
29-
};
30-
fetchTickets();
31-
}, [eventId]);
3214
useEffect(() => {
33-
if (tickets.length > 0) {
15+
if (data && data.isSuccess) {
3416
const initialQuantity: { [key: number]: number } = {};
35-
tickets.forEach(ticket => {
17+
data.result.forEach(ticket => {
3618
initialQuantity[ticket.ticketId] = 1;
3719
});
3820
setQuantity(initialQuantity);
3921
}
40-
}, [tickets]);
22+
}, [data]);
23+
4124
const handleIncrement = (ticketId: number) => {
4225
setQuantity(prev => ({
4326
...prev,
@@ -60,28 +43,29 @@ const TicketInfo = ({ eventId }: { eventId: number }) => {
6043
eventId,
6144
ticketCnt,
6245
};
63-
46+
6447
const response = await orderTickets(requestData);
65-
48+
6649
console.log("API 응답:", response);
67-
50+
6851
if (response.isSuccess && Array.isArray(response.result)) {
6952
const orderIds = response.result;
70-
53+
7154
navigate('/payment/ticket-confirm', { state: { orderIds, ticketId, eventId } });
7255
} else {
7356
alert("주문 정보를 불러올 수 없습니다.");
7457
}
75-
58+
7659
} catch (error) {
7760
alert("티켓 구매 중 오류가 발생했습니다.");
7861
}
7962
};
80-
63+
if (isLoading) return <div>Loading...</div>;
64+
if (isError || !data || !data.isSuccess) return <div>티켓 정보를 불러올 수 없습니다.</div>;
8165

8266
return (
8367
<div className="w-full h-full">
84-
{tickets.map(ticket => (
68+
{data.result.map(ticket => (
8569
<div key={ticket.ticketId} className="bg-gray1 px-3 py-3 md:px-6 md:py-4 rounded-[10px] mb-3">
8670
<div className="flex justify-between items-center">
8771
<div className="flex flex-col gap-2">

0 commit comments

Comments
 (0)