diff --git a/admin/src/apis/lotteryAPI.ts b/admin/src/apis/lotteryAPI.ts
index e54eef5e..bc1e335b 100644
--- a/admin/src/apis/lotteryAPI.ts
+++ b/admin/src/apis/lotteryAPI.ts
@@ -1,4 +1,5 @@
import {
+ DeleteLotteryWinnerResponse,
GetLotteryExpectationsParams,
GetLotteryExpectationsResponse,
GetLotteryParticipantResponse,
@@ -55,6 +56,18 @@ export const LotteryAPI = {
throw error;
}
},
+ async deleteLotteryWinner(token: string): Promise {
+ try {
+ const response = await fetchWithTimeout(`${baseURL}/winner`, {
+ method: "DELETE",
+ headers: { ...headers, Authorization: `Bearer ${token}` },
+ });
+ return response.json();
+ } catch (error) {
+ console.error("Error:", error);
+ throw error;
+ }
+ },
async getLotteryParticipant(
{ size, page, phoneNumber }: GetLotteryWinnerParams,
token: string
diff --git a/admin/src/components/Suspense/index.tsx b/admin/src/components/Suspense/index.tsx
new file mode 100644
index 00000000..d5047d97
--- /dev/null
+++ b/admin/src/components/Suspense/index.tsx
@@ -0,0 +1,21 @@
+import { PropsWithChildren } from "react";
+
+interface SuspenseProps extends PropsWithChildren {
+ isLoading?: boolean;
+}
+
+export default function Suspense({ children, isLoading = false }: SuspenseProps) {
+ return (
+ <>
+ {isLoading ? (
+
+
+ 데이터를 불러오는 중입니다...
+
+
+ ) : (
+ children
+ )}
+ >
+ );
+}
diff --git a/admin/src/components/TimePicker/index.tsx b/admin/src/components/TimePicker/index.tsx
index e5f793ae..564e5cd1 100644
--- a/admin/src/components/TimePicker/index.tsx
+++ b/admin/src/components/TimePicker/index.tsx
@@ -12,7 +12,9 @@ export default function TimePicker({ time, disabled = false, onChangeTime }: Tim
* 시간-분 까지만 선택 가능
* 초는 0초를 디폴트로 넣는다
*/
- const time = `${e.target.value}:00`;
+ const value = e.target.value;
+ const isMinuteEnd = value.split(":").length === 2;
+ const time = `${e.target.value}${isMinuteEnd ? `:00` : ""}`;
onChangeTime(time);
};
diff --git a/admin/src/constants/common.ts b/admin/src/constants/common.ts
index 72066f83..7a6d140b 100644
--- a/admin/src/constants/common.ts
+++ b/admin/src/constants/common.ts
@@ -9,3 +9,8 @@ export const STATUS_MAP = {
[EVENT_STATUS.DURING]: "활성화",
[EVENT_STATUS.AFTER]: "종료",
};
+
+export const ERROR_MAP = {
+ CONFLICT: "409",
+ NOT_FOUND: "404",
+} as const;
diff --git a/admin/src/hooks/useFetch.ts b/admin/src/hooks/useFetch.ts
index fb9b92c4..f529013a 100644
--- a/admin/src/hooks/useFetch.ts
+++ b/admin/src/hooks/useFetch.ts
@@ -10,14 +10,18 @@ export default function useFetch(
const { showBoundary } = useErrorBoundary();
const [data, setData] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
+ const [errorStatus, setErrorStatus] = useState(null);
const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]);
const fetchData = async (params?: P) => {
setIsError(false);
setIsSuccess(false);
+ setIsLoading(true);
+ setErrorStatus(null);
try {
const data = await fetch(params as P, cookies[COOKIE_KEY.ACCESS_TOKEN]);
@@ -25,12 +29,16 @@ export default function useFetch(
setIsSuccess(!!data);
} catch (error) {
setIsError(true);
- console.error(error);
+ if (error instanceof Error) {
+ setErrorStatus(error.message);
+ }
if (showError) {
showBoundary(error);
}
+ } finally {
+ setIsLoading(false);
}
};
- return { data, isSuccess, isError, fetchData };
+ return { data, isSuccess, isLoading, isError, errorStatus, fetchData };
}
diff --git a/admin/src/hooks/useInfiniteFetch.ts b/admin/src/hooks/useInfiniteFetch.ts
index 692ff063..2538618e 100644
--- a/admin/src/hooks/useInfiniteFetch.ts
+++ b/admin/src/hooks/useInfiniteFetch.ts
@@ -7,6 +7,7 @@ interface UseInfiniteFetchProps {
initialPageParam?: number;
getNextPageParam: (currentPageParam: number, lastPage: R) => number | undefined;
startFetching?: boolean;
+ showError?: boolean;
}
interface InfiniteScrollData {
@@ -17,6 +18,7 @@ interface InfiniteScrollData {
hasNextPage: boolean;
isSuccess: boolean;
isError: boolean;
+ errorStatus: string | null;
}
export default function useInfiniteFetch({
@@ -24,6 +26,7 @@ export default function useInfiniteFetch({
initialPageParam = 0,
getNextPageParam,
startFetching = true,
+ showError = true,
}: UseInfiniteFetchProps): InfiniteScrollData {
const { showBoundary } = useErrorBoundary();
@@ -32,6 +35,8 @@ export default function useInfiniteFetch({
const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
+ const [errorStatus, setErrorStatus] = useState(null);
+
const [hasNextPage, setHasNextPage] = useState(true);
const [totalLength, setTotalLength] = useState(0);
@@ -53,6 +58,7 @@ export default function useInfiniteFetch({
setIsLoading(true);
setIsError(false);
setIsSuccess(false);
+ setErrorStatus(null);
try {
const lastPage = await fetch(currentPageParam);
const nextPageParam = getNextPageParam(currentPageParam, lastPage);
@@ -62,9 +68,14 @@ export default function useInfiniteFetch({
setHasNextPage(nextPageParam !== undefined);
setIsSuccess(true);
} catch (error) {
- showBoundary(error);
setIsError(true);
setIsSuccess(false);
+ if (error instanceof Error) {
+ setErrorStatus(error.message);
+ }
+ if (showError) {
+ showBoundary(error);
+ }
} finally {
setIsLoading(false);
}
@@ -91,5 +102,6 @@ export default function useInfiniteFetch({
hasNextPage,
isSuccess,
isError,
+ errorStatus,
};
}
diff --git a/admin/src/pages/LotteryParticipantList/index.tsx b/admin/src/pages/LotteryParticipantList/index.tsx
index 64273ccb..70c4a208 100644
--- a/admin/src/pages/LotteryParticipantList/index.tsx
+++ b/admin/src/pages/LotteryParticipantList/index.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useMemo, useRef, useState } from "react";
+import { FormEvent, useEffect, useMemo, useRef, useState } from "react";
import { useCookies } from "react-cookie";
import { useNavigate } from "react-router-dom";
import { LotteryAPI } from "@/apis/lotteryAPI";
@@ -123,6 +123,11 @@ export default function LotteryParticipantList() {
patchLotteryExpectation(id);
};
+ const handleSubmitSearch = (e: FormEvent) => {
+ e.preventDefault();
+ handleRefetch();
+ };
+
const expectations = useMemo(
() =>
expectation.map((participant) => [
@@ -176,15 +181,15 @@ export default function LotteryParticipantList() {
-
+
+
-