Skip to content

Commit

Permalink
Merge pull request #139 from softeerbootcamp4th/feat/#137-admin-api
Browse files Browse the repository at this point in the history
[Feat] 어드민 - API 연동
  • Loading branch information
jhj2713 authored Aug 13, 2024
2 parents 2305645 + c44c0dd commit 00aceac
Show file tree
Hide file tree
Showing 29 changed files with 724 additions and 451 deletions.
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

0 comments on commit 00aceac

Please sign in to comment.