Skip to content
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

[Feat] 어드민 - API 연동 #139

Merged
merged 20 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions admin/src/apis/lotteryAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
GetLotteryWinnerParams,
GetLotteryWinnerResponse,
PostLotteryWinnerResponse,
PutLotteryParams,
PutLotteryResponse,
} from "@/types/lotteryApi";
import { fetchWithTimeout } from "@/utils/fetchWithTimeout";

Expand All @@ -20,13 +22,13 @@ export const LotteryAPI = {
return new Promise((resolve) =>
resolve([
{
lotteryEventId: 1,
startDate: "2024-07-26",
startTime: "00:00",
startTime: "00:00:00",
endDate: "2024-08-25",
endTime: "23:59",
endTime: "23:59:00",
appliedCount: 1000000,
winnerCount: 363,
status: "BEFORE",
},
])
);
Expand All @@ -40,6 +42,28 @@ export const LotteryAPI = {
throw error;
}
},
async putLottery(body: PutLotteryParams): Promise<PutLotteryResponse> {
try {
return new Promise((resolve) =>
resolve({
startDate: "2024-08-26",
startTime: "00:00:00",
endDate: "2024-09-25 23:59",
endTime: "00:00:00",
winnerCount: 363,
})
);
const response = await fetchWithTimeout(`${baseURL}`, {
method: "PUT",
headers: headers,
body: JSON.stringify(body),
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async postLotteryWinner(): Promise<PostLotteryWinnerResponse> {
try {
return new Promise((resolve) => resolve({ message: "요청에 성공하였습니다." }));
Expand All @@ -54,15 +78,14 @@ export const LotteryAPI = {
}
},
async getLotteryParticipant({
id,
size,
page,
phoneNumber,
}: GetLotteryWinnerParams): Promise<GetLotteryParticipantResponse> {
try {
return new Promise((resolve) =>
resolve({
data: [
participants: [
{
id: 1,
phoneNumber: "010-1111-2222",
Expand Down Expand Up @@ -96,7 +119,7 @@ export const LotteryAPI = {
})
);
const response = await fetchWithTimeout(
`${baseURL}/${id}/participants?size=${size}&page=${page}&number=${phoneNumber}`,
`${baseURL}/participants?size=${size}&page=${page}&number=${phoneNumber}`,
{
method: "GET",
headers: headers,
Expand All @@ -109,15 +132,14 @@ export const LotteryAPI = {
}
},
async getLotteryWinner({
id,
size,
page,
phoneNumber,
}: GetLotteryWinnerParams): Promise<GetLotteryWinnerResponse> {
try {
return new Promise((resolve) =>
resolve({
data: [
participants: [
{
id: 1,
phoneNumber: "010-1111-2222",
Expand Down Expand Up @@ -145,7 +167,7 @@ export const LotteryAPI = {
})
);
const response = await fetchWithTimeout(
`${baseURL}/${id}/winner?size=${size}&page=${page}&number=${phoneNumber}`,
`${baseURL}/winner?size=${size}&page=${page}&number=${phoneNumber}`,
{
method: "GET",
headers: headers,
Expand All @@ -158,7 +180,6 @@ export const LotteryAPI = {
}
},
async getLotteryExpectations({
lotteryId,
participantId,
}: GetLotteryExpectationsParams): Promise<GetLotteryExpectationsResponse> {
try {
Expand All @@ -179,7 +200,7 @@ export const LotteryAPI = {
])
);
const response = await fetchWithTimeout(
`${baseURL}/${lotteryId}/participants/${participantId}/expectations`,
`${baseURL}/participants/${participantId}/expectations`,
{
method: "GET",
headers: headers,
Expand Down
123 changes: 119 additions & 4 deletions admin/src/apis/rushAPI.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
GetRushEventResponse,
GetRushOptionsParams,
GetRushOptionsResponse,
GetRushParticipantListParams,
GetRushParticipantListResponse,
GetRushWinnerListParams,
PutRushEventResponse,
} from "@/types/rushApi";
import { fetchWithTimeout } from "@/utils/fetchWithTimeout";

Expand All @@ -13,6 +15,119 @@ const headers = {
};

export const RushAPI = {
async getRush(): Promise<GetRushEventResponse> {
try {
return new Promise((resolve) =>
resolve([
{
rushEventId: 1,
eventDate: "2024-07-25",
openTime: "20:00:00",
closeTime: "20:10:00",
winnerCount: 315,
prizeImageUrl: "prize1.png",
prizeDescription: "스타벅스 1만원 기프트카드",
status: "BEFORE",
leftOption: {
rushOptionId: 1,
mainText: "첫 차로 저렴한 차 사기",
subText: "첫 차는 가성비가 짱이지!",
resultMainText: "누구보다 가성비 갑인 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/660/660026.png",
},
rightOption: {
rushOptionId: 2,
mainText: "첫 차로 성능 좋은 차 사기",
subText: "차는 당연히 성능이지!",
resultMainText: "필요한 건 다 갖춘 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/846/846551.png",
},
},
{
rushEventId: 2,
eventDate: "2024-07-26",
openTime: "20:00:00",
closeTime: "20:10:00",
winnerCount: 315,
prizeImageUrl: "prize2.png",
prizeDescription: "올리브영 1만원 기프트카드",
status: "DURING",
leftOption: {
rushOptionId: 1,
mainText: "첫 차로 저렴한 차 사기",
subText: "첫 차는 가성비가 짱이지!",
resultMainText: "누구보다 가성비 갑인 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/660/660026.png",
},
rightOption: {
rushOptionId: 2,
mainText: "첫 차로 성능 좋은 차 사기",
subText: "차는 당연히 성능이지!",
resultMainText: "필요한 건 다 갖춘 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/846/846551.png",
},
},
{
rushEventId: 3,
eventDate: "2024-07-27",
openTime: "20:00:00",
closeTime: "20:10:00",
winnerCount: 315,
prizeImageUrl: "prize3.png",
prizeDescription: "배달의 민족 1만원 기프트카드",
status: "AFTER",
leftOption: {
rushOptionId: 1,
mainText: "첫 차로 저렴한 차 사기",
subText: "첫 차는 가성비가 짱이지!",
resultMainText: "누구보다 가성비 갑인 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/660/660026.png",
},
rightOption: {
rushOptionId: 2,
mainText: "첫 차로 성능 좋은 차 사기",
subText: "차는 당연히 성능이지!",
resultMainText: "필요한 건 다 갖춘 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "https://cdn-icons-png.flaticon.com/512/846/846551.png",
},
},
])
);
const response = await fetchWithTimeout(`${baseURL}`, {
method: "GET",
headers: headers,
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async putRush(body: FormData[]): Promise<PutRushEventResponse> {
try {
body.forEach((b) => {
for (let pair of b.entries()) {
console.log(pair[0] + ": " + pair[1]);
}
});
return new Promise((resolve) => resolve([]));
const response = await fetchWithTimeout(`${baseURL}`, {
method: "PUT",
headers: { "Content-Type": "multipart/form-data" },
body: JSON.stringify(body),
});
return response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
},
async getRushParticipantList({
id,
phoneNumber,
Expand All @@ -23,7 +138,7 @@ export const RushAPI = {
try {
return new Promise((resolve) =>
resolve({
data: [
participants: [
{
id: 1,
phoneNumber: "010-1111-2222",
Expand Down Expand Up @@ -72,7 +187,7 @@ export const RushAPI = {
try {
return new Promise((resolve) =>
resolve({
data: [
participants: [
{
id: 1,
phoneNumber: "010-3843-6999",
Expand Down Expand Up @@ -122,15 +237,15 @@ export const RushAPI = {
subText: " 첫 차는 가성비가 짱이지!",
resultMainText: "누구보다 가성비 갑인 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씬 저렴한 캐스퍼 일렉트릭!",
imageUrl: "left_image.png",
imageUrl: "https://cdn-icons-png.flaticon.com/512/660/660026.png",
},
{
rushOptionId: 2,
mainText: "첫 차로 성능 좋은 차 사기",
subText: " 차는 당연히 성능이지!",
resultMainText: "필요한 건 다 갖춘 캐스퍼 일렉트릭",
resultSubText: "전기차 평균보다 훨씨니 저렴한 캐스퍼 일렉트릭!",
imageUrl: "left_image.png",
imageUrl: "https://cdn-icons-png.flaticon.com/512/660/660026.png",
},
])
);
Expand Down
4 changes: 3 additions & 1 deletion admin/src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { ChangeEvent } from "react";

interface DatePickerProps {
date: string;
disabled?: boolean;
onChangeDate: (date: string) => void;
}

export default function DatePicker({ date, onChangeDate }: DatePickerProps) {
export default function DatePicker({ date, disabled = false, onChangeDate }: DatePickerProps) {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
onChangeDate(e.target.value);
};
Expand All @@ -17,6 +18,7 @@ export default function DatePicker({ date, onChangeDate }: DatePickerProps) {
</div>
<input
type="date"
disabled={disabled}
value={date}
onChange={handleChange}
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full ps-10 p-2.5"
Expand Down
42 changes: 42 additions & 0 deletions admin/src/components/FileInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useEffect, useState } from "react";

interface FileInputProps {
selectedFile: File | string | null;
setSelectedFile: (file: File) => void;
}

export default function FileInput({ selectedFile, setSelectedFile }: FileInputProps) {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);

useEffect(() => {
if (!selectedFile) {
setPreviewUrl(null);
return;
}
if (typeof selectedFile === "string") {
setPreviewUrl(selectedFile);
return;
}

const objectUrl = URL.createObjectURL(selectedFile);
setPreviewUrl(objectUrl);

return () => URL.revokeObjectURL(objectUrl);
}, [selectedFile]);

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
setSelectedFile(file);
}
};

return (
<div>
{previewUrl && (
<img src={previewUrl} alt="Preview" style={{ width: "auto", maxHeight: "100px" }} />
)}
<input type="file" accept="image/*" onChange={handleFileChange} />
</div>
);
}
4 changes: 3 additions & 1 deletion admin/src/components/TimePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { ChangeEvent } from "react";

interface TimePickerProps {
time: string;
disabled?: boolean;
onChangeTime: (time: string) => void;
}

export default function TimePicker({ time, onChangeTime }: TimePickerProps) {
export default function TimePicker({ time, disabled = false, onChangeTime }: TimePickerProps) {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
/**
* 시간-분 까지만 선택 가능
Expand Down Expand Up @@ -36,6 +37,7 @@ export default function TimePicker({ time, onChangeTime }: TimePickerProps) {
<input
type="time"
id="time"
disabled={disabled}
className="bg-gray-50 border leading-none border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
min="09:00"
max="18:00"
Expand Down
16 changes: 16 additions & 0 deletions admin/src/components/Toast/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
interface ToastProps {
message: string;
isVisible: boolean;
}

export default function Toast({ message, isVisible }: ToastProps) {
return (
<div
className={`fixed top-[88px] left-[50%] translate-x-[-50%] h-heading-4-bold bg-neutral-400 text-white px-6 py-4 rounded-lg transition-opacity ${
isVisible ? "opacity-100" : "opacity-0"
}`}
>
{message}
</div>
);
}
Loading
Loading