From 7141ec71e7f841720c1e174580c66d6b978b6baa Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 03:18:32 +0900
Subject: [PATCH 01/14] =?UTF-8?q?feat:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=EC=9D=B8=EC=A6=9D=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20?=
 =?UTF-8?q?=EC=97=B0=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/hooks/challenge.ts          |  9 ++++++---
 components/home/certifyModal.tsx | 10 ++++++++--
 components/home/challenge.tsx    | 10 +++++++++-
 utils/atom.tsx                   |  2 ++
 4 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/apis/hooks/challenge.ts b/apis/hooks/challenge.ts
index fa63eb8..042174f 100644
--- a/apis/hooks/challenge.ts
+++ b/apis/hooks/challenge.ts
@@ -65,11 +65,14 @@ function usePostNewChallenge(
   return { mutate };
 }
 
-function usePostAttendance() {
+function usePostAttendance(challengeIdx: number) {
   const queryClient = useQueryClient();
   const { mutate } = useMutation({
-    mutationKey: ["postAttendance"],
-    mutationFn: (body: AttendanceRequestBody) => postAttendance(body),
+    mutationKey: ["postAttendance", challengeIdx],
+    mutationFn: (attendanceCode: string) =>
+      postAttendance({ challengeIdx, attendanceCode }),
+    onSuccess: () => window.alert("챌린지가 성공적으로 인증되었습니다."),
+    onError: () => window.alert("다시 시도해주세요."),
   });
 
   return { mutate };
diff --git a/components/home/certifyModal.tsx b/components/home/certifyModal.tsx
index 6e5155e..3854390 100644
--- a/components/home/certifyModal.tsx
+++ b/components/home/certifyModal.tsx
@@ -3,6 +3,9 @@ import FlexBox from "../Flexbox";
 import TextInput from "../Input";
 import { useState } from "react";
 import CloseIcon from "@/public/svgs/Close.svg";
+import { usePostAttendance } from "@/apis/hooks/challenge";
+import { useAtom } from "jotai";
+import { challengeIdxAtom } from "@/utils/atom";
 
 interface CertifyModalProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -19,9 +22,12 @@ export default function CertifyModal({
     text: "",
   });
 
+  const [challengeIdx] = useAtom(challengeIdxAtom);
+  const { mutate } = usePostAttendance(challengeIdx);
+
   const onCertify = () => {
+    // mutate(number);
     setIsModalVisible(false);
-    notify("챌린지가 성공적으로 인증되었습니다.");
   };
 
   return (
@@ -32,7 +38,7 @@ export default function CertifyModal({
           <CloseIcon width={20} height={20} />
         </div>
       </FlexBox>
-      <FlexBox className="w-full gap-1  mb-3">
+      <FlexBox className="w-full gap-1 mb-3">
         <TextInput
           value={number}
           setValue={setNumber}
diff --git a/components/home/challenge.tsx b/components/home/challenge.tsx
index fa16c5c..71b8516 100644
--- a/components/home/challenge.tsx
+++ b/components/home/challenge.tsx
@@ -2,6 +2,8 @@ import { NextPage } from "next";
 import FlexBox from "../Flexbox";
 import { useRouter } from "next/router";
 import { Challenge as ChallengeType } from "@/apis/challenge";
+import { useAtom } from "jotai";
+import { challengeIdxAtom } from "@/utils/atom";
 
 interface ChallengeProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -13,6 +15,12 @@ const Challenge: NextPage<ChallengeProps> = ({
   challengeInfo,
 }) => {
   const router = useRouter();
+  const [, setChallengeIdx] = useAtom(challengeIdxAtom);
+
+  const onClickCertifyBtn = () => {
+    setChallengeIdx(challengeInfo.challengeIdx);
+    setIsModalVisible(true);
+  };
 
   return (
     <FlexBox direction="col" className="p-4 w-full rounded-lg border gap-4">
@@ -47,7 +55,7 @@ const Challenge: NextPage<ChallengeProps> = ({
         </FlexBox>
         <div
           className="w-full border border-main-color rounded-lg py-2 text-center text-main-color h2"
-          onClick={() => setIsModalVisible(true)}
+          onClick={onClickCertifyBtn}
         >
           인증하기
         </div>
diff --git a/utils/atom.tsx b/utils/atom.tsx
index 00faa57..3fd41cd 100644
--- a/utils/atom.tsx
+++ b/utils/atom.tsx
@@ -1,3 +1,5 @@
 import { atom } from "jotai";
 
 export const isAdminAtom = atom<boolean>(true);
+
+export const challengeIdxAtom = atom<number>(-1);

From e21fb0bcda61a03e59649422af79ef6f3c920965 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 12:11:40 +0900
Subject: [PATCH 02/14] =?UTF-8?q?fix:=20=20/challenges/attendance=20Respon?=
 =?UTF-8?q?se=20Body=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/admin.ts       | 12 ++++++++++--
 apis/hooks/admin.ts |  2 +-
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/apis/admin.ts b/apis/admin.ts
index 73a36b5..e3be523 100644
--- a/apis/admin.ts
+++ b/apis/admin.ts
@@ -1,5 +1,5 @@
 import { CalendarDate } from "./calendar";
-import client, { ResponseBody } from "./client";
+import client, { ResponseBody, ResponseBody2 } from "./client";
 
 export interface Program {
   name: string;
@@ -12,7 +12,15 @@ export interface Program {
   description: string;
 }
 
-async function postAttendanceCode(challengeIdx: number): Promise<ResponseBody> {
+interface PostAttendanceCodeBody extends ResponseBody2 {
+  result: {
+    code: number;
+  };
+}
+
+async function postAttendanceCode(
+  challengeIdx: number,
+): Promise<PostAttendanceCodeBody> {
   const { data } = await client.post(`/challenges/attendance/${challengeIdx}`);
   return data;
 }
diff --git a/apis/hooks/admin.ts b/apis/hooks/admin.ts
index 6e9d0af..4c9cbee 100644
--- a/apis/hooks/admin.ts
+++ b/apis/hooks/admin.ts
@@ -6,7 +6,7 @@ function usePostAttendanceCode(challengeIdx: number) {
   const { mutate } = useMutation({
     mutationKey: ["postAttendanceCode", challengeIdx],
     mutationFn: () => postAttendanceCode(challengeIdx),
-    onSuccess: (data) => window.alert(`인증번호: ${data}`),
+    onSuccess: (data) => window.alert(`인증번호: ${data.result.code}`),
     onError: () => window.alert("에러 발생. 앱 관리자에게 문의해주세요."),
   });
 

From cce6a865d03f9f81f8eed41aa0c15d3989f3331f Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 12:30:20 +0900
Subject: [PATCH 03/14] =?UTF-8?q?fix:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20DTO?=
 =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20api=20=EC=88=98?=
 =?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/challenge.ts                  |  5 +++--
 components/home/adminChallenge.tsx | 12 +++++++++---
 components/home/challenge.tsx      |  4 ++--
 components/home/tag.tsx            | 11 +++++++++++
 4 files changed, 25 insertions(+), 7 deletions(-)
 create mode 100644 components/home/tag.tsx

diff --git a/apis/challenge.ts b/apis/challenge.ts
index a7e55a2..e1c4ca9 100644
--- a/apis/challenge.ts
+++ b/apis/challenge.ts
@@ -7,10 +7,11 @@ interface GetMyChallengeListResponse extends ResponseBody {
 export interface Challenge {
   challengeIdx: number;
   name: string;
-  participantsNum: number;
+  participantsCount: number;
   location: string;
+  locatedPlace: string;
   schedule: string;
-  attendanceRate: number;
+  myAttendanceRate: number;
   totalAttendanceRate: number;
 }
 interface GetChallengeAdsResponse extends ResponseBody2 {
diff --git a/components/home/adminChallenge.tsx b/components/home/adminChallenge.tsx
index ea9ecdf..d61b0d4 100644
--- a/components/home/adminChallenge.tsx
+++ b/components/home/adminChallenge.tsx
@@ -3,6 +3,7 @@ import FlexBox from "../Flexbox";
 import { useRouter } from "next/router";
 import { Challenge as ChallengeType } from "@/apis/challenge";
 import { usePostAttendanceCode } from "@/apis/hooks/admin";
+import Tag from "./tag";
 
 interface ChallengeProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -21,11 +22,16 @@ const AdminChallenge: NextPage<ChallengeProps> = ({
   return (
     <FlexBox direction="col" className="p-4 w-full rounded-lg border gap-4">
       <FlexBox direction="col" className="w-full gap-1">
-        <FlexBox className="w-full justify-between items-start">
+        <FlexBox className="w-full items-center gap-2">
           <div className="h2">{challengeInfo.name}</div>
+          <FlexBox className="gap-1">
+            <Tag name={challengeInfo.location} />
+            <Tag name="예술(변경필)" />
+          </FlexBox>
         </FlexBox>
         <div className="h4 self-start">
-          {challengeInfo.location} | {challengeInfo.schedule}
+          {challengeInfo.locatedPlace ?? challengeInfo.location} |{" "}
+          {challengeInfo.schedule}
         </div>
       </FlexBox>
       <FlexBox direction="col" className="w-full gap-2">
@@ -33,7 +39,7 @@ const AdminChallenge: NextPage<ChallengeProps> = ({
           <div className="h5 text-grey-500">전체달성률</div>
           <div className="h3">
             {challengeInfo.totalAttendanceRate}%(
-            {challengeInfo.participantsNum}명)
+            {challengeInfo.participantsCount}명 참여 중)
           </div>
         </FlexBox>
         <FlexBox className="w-full gap-2">
diff --git a/components/home/challenge.tsx b/components/home/challenge.tsx
index 71b8516..af53167 100644
--- a/components/home/challenge.tsx
+++ b/components/home/challenge.tsx
@@ -32,7 +32,7 @@ const Challenge: NextPage<ChallengeProps> = ({
         <FlexBox className="w-full justify-between items-start">
           <div className="h2">{challengeInfo.name}</div>
           <div className="h4 text-grey-500">
-            {challengeInfo.participantsNum}명 참여 중
+            {challengeInfo.participantsCount}명 참여 중
           </div>
         </FlexBox>
         <div className="h4 self-start">
@@ -46,7 +46,7 @@ const Challenge: NextPage<ChallengeProps> = ({
         >
           <FlexBox className="gap-1">
             <div className="h5 text-grey-500">개인달성률</div>
-            <div className="h3">{challengeInfo.attendanceRate}%</div>
+            <div className="h3">{challengeInfo.myAttendanceRate}%</div>
           </FlexBox>
           <FlexBox className="gap-1">
             <div className="h5 text-grey-500">전체달성률</div>
diff --git a/components/home/tag.tsx b/components/home/tag.tsx
new file mode 100644
index 0000000..7c2817b
--- /dev/null
+++ b/components/home/tag.tsx
@@ -0,0 +1,11 @@
+import { NextPage } from "next";
+
+interface TagProps {
+  name: string;
+}
+
+const Tag: NextPage<TagProps> = ({ name }: TagProps) => {
+  return <div className="rounded-xl text-main-color h5">#{name}</div>;
+};
+
+export default Tag;

From 77e03303e66ba11c175abe37aaf42826356afb95 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 12:44:58 +0900
Subject: [PATCH 04/14] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?=
 =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EB=AC=B8=EA=B5=AC=20toast=20>=20alert?=
 =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pages/mypage/index.tsx | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/pages/mypage/index.tsx b/pages/mypage/index.tsx
index 9a82402..83de89b 100644
--- a/pages/mypage/index.tsx
+++ b/pages/mypage/index.tsx
@@ -14,14 +14,8 @@ const MyPage: NextPage = () => {
   const { data } = useGetMyInfo();
   const { mutate } = usePatchLogout();
 
-  const notify = () => {
-    toast.info("이미 관리자 인증을 완료하셨습니다.", {
-      position: "bottom-center",
-    });
-  };
-
   const certifyAdmin = () => {
-    if (data.result.isAdmin) notify();
+    if (data.result.isAdmin) window.alert("이미 관리자 인증을 완료하셨습니다.");
     else router.push("/mypage/admin");
   };
 

From 60fdf727631bac943d757bea8d1130dc763cb60c Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:03:52 +0900
Subject: [PATCH 05/14] =?UTF-8?q?fix:=20/programs=20host=20=ED=95=AD?=
 =?UTF-8?q?=EB=AA=A9=EC=9D=80=20atom=EC=9C=BC=EB=A1=9C=20=EC=B2=98?=
 =?UTF-8?q?=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/admin.ts           |  1 +
 pages/challenge/add.tsx | 22 ++++++++++++++--------
 pages/login.tsx         |  4 +++-
 utils/atom.tsx          |  2 ++
 4 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/apis/admin.ts b/apis/admin.ts
index e3be523..8a36b86 100644
--- a/apis/admin.ts
+++ b/apis/admin.ts
@@ -6,6 +6,7 @@ export interface Program {
   dueDate: CalendarDate;
   openDate: CalendarDate;
   location: string;
+  locatedPlace: string;
   category: string;
   host: string;
   schedule: string;
diff --git a/pages/challenge/add.tsx b/pages/challenge/add.tsx
index e10f9d5..589077c 100644
--- a/pages/challenge/add.tsx
+++ b/pages/challenge/add.tsx
@@ -9,20 +9,24 @@ import dayjs from "dayjs";
 import { NextPage } from "next";
 import { useEffect, useState } from "react";
 import "dayjs/locale/ko";
+import { useAtom } from "jotai";
+import { centerNameAtom } from "@/utils/atom";
 dayjs.locale("ko");
 
 const AddChallenge: NextPage = () => {
   const [name, setName] = useState<string>("");
   const [startDate, setStartDate] = useState<string>("");
   const [endDate, setEndDate] = useState<string>("");
-  const [location, setLocation] = useState<string>("");
+  const [location, setLocation] = useState<string>(""); // 지역태그
   const [category, setCategory] = useState<string>("");
-  const [host, setHost] = useState<string>("");
+  const [place, setPlace] = useState<string>("");
   const [phoneNum, setPhoneNum] = useState<string>("");
   const [detail, setDetail] = useState<string>("");
 
   const { mutate } = usePostProgram();
 
+  const [centerName] = useAtom(centerNameAtom);
+
   const registerProgram = () => {
     mutate({
       name,
@@ -36,9 +40,10 @@ const AddChallenge: NextPage = () => {
         month: Number(dayjs(startDate).format("M")),
         day: Number(dayjs(startDate).format("D")),
       },
-      location: location,
-      category: category,
-      host: host,
+      location,
+      locatedPlace: place,
+      category,
+      host: centerName,
       schedule: dayjs(endDate).format("ddd"),
       description:
         detail.trim().length === 0
@@ -78,11 +83,12 @@ const AddChallenge: NextPage = () => {
             isError={false}
           />
           <ChallengeInput
-            title="주최 기관"
+            title="장소"
             inputType="text"
-            value={host}
-            setValue={setHost}
+            value={place}
+            setValue={setPlace}
             isError={false}
+            placeholder="프로그램 시행 장소"
           />
           <ChallengeInput
             title="담당자 전화번호"
diff --git a/pages/login.tsx b/pages/login.tsx
index 865f232..564baa8 100644
--- a/pages/login.tsx
+++ b/pages/login.tsx
@@ -12,7 +12,7 @@ import {
 } from "@/apis/client";
 import { SignIn } from "@/apis/auth";
 import { atom, useAtom } from "jotai";
-import { isAdminAtom } from "@/utils/atom";
+import { centerNameAtom, isAdminAtom } from "@/utils/atom";
 
 interface userProps {
   loginId: string;
@@ -22,6 +22,7 @@ interface userProps {
 const Login: NextPage = () => {
   const router = useRouter();
   const [isAdmin, setIsAdmin] = useAtom(isAdminAtom);
+  const [, setCenterName] = useAtom(centerNameAtom);
 
   const [userInfo, setUserInfo] = useState<userProps>({
     loginId: "",
@@ -58,6 +59,7 @@ const Login: NextPage = () => {
       const accessToken = data.result.accessToken;
       const refreshToken = data.result.refreshToken;
       const isAdmin = data.result.isAdmin;
+      if (isAdmin) setCenterName(data.result.centerName);
       setIsAdmin(isAdmin);
       setIsAdminAtLocalStorage(isAdmin);
       setTokenFromLocalStorage(accessToken);
diff --git a/utils/atom.tsx b/utils/atom.tsx
index 3fd41cd..1854b56 100644
--- a/utils/atom.tsx
+++ b/utils/atom.tsx
@@ -3,3 +3,5 @@ import { atom } from "jotai";
 export const isAdminAtom = atom<boolean>(true);
 
 export const challengeIdxAtom = atom<number>(-1);
+
+export const centerNameAtom = atom<string>("");

From 2d5ef36aaad06043ae0e4240a216ada86975045f Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:04:09 +0900
Subject: [PATCH 06/14] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=95=84?=
 =?UTF-8?q?=EC=9B=83=20=EC=97=90=EB=9F=AC=EC=8B=9C=20main=EC=9C=BC?=
 =?UTF-8?q?=EB=A1=9C=20=EA=B0=80=EA=B2=8C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/hooks/mypage.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apis/hooks/mypage.ts b/apis/hooks/mypage.ts
index 43bee93..1dfe763 100644
--- a/apis/hooks/mypage.ts
+++ b/apis/hooks/mypage.ts
@@ -28,7 +28,7 @@ function usePatchLogout() {
       localStorage.removeItem("access_token");
       router.push("/main");
     },
-    onError: () => router.push("/404"),
+    onError: () => router.push("/main"),
   });
 
   return { mutate };

From 41e2dd417f3f9ac97b2175a767a716e7546a54c2 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:06:37 +0900
Subject: [PATCH 07/14] =?UTF-8?q?fix:=20=ED=94=84=EB=A1=9C=EA=B7=B8?=
 =?UTF-8?q?=EB=9E=A8=20=EB=93=B1=EB=A1=9D=EC=8B=9C=20validation=20?=
 =?UTF-8?q?=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pages/challenge/add.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pages/challenge/add.tsx b/pages/challenge/add.tsx
index 589077c..5effdbb 100644
--- a/pages/challenge/add.tsx
+++ b/pages/challenge/add.tsx
@@ -118,7 +118,7 @@ const AddChallenge: NextPage = () => {
             endDate.length === 0 ||
             location.length === 0 ||
             category.length === 0 ||
-            host.length === 0 ||
+            place.length === 0 ||
             phoneNum.length === 0
           }
         />

From 861be3cb8c82497eb9917ec6fe790439e0763b15 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:10:46 +0900
Subject: [PATCH 08/14] =?UTF-8?q?fix:=20=EC=9D=BC=EB=B0=98=20=EC=82=AC?=
 =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=B0=B8=EC=97=AC=20=EC=A4=91=EC=9D=B8=20?=
 =?UTF-8?q?=EC=B1=8C=EB=A6=B0=EC=A7=80=20=EC=A1=B0=ED=9A=8C=EC=97=90?=
 =?UTF-8?q?=EB=8F=84=20=ED=83=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/home/challenge.tsx | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/components/home/challenge.tsx b/components/home/challenge.tsx
index af53167..a945d86 100644
--- a/components/home/challenge.tsx
+++ b/components/home/challenge.tsx
@@ -4,6 +4,7 @@ import { useRouter } from "next/router";
 import { Challenge as ChallengeType } from "@/apis/challenge";
 import { useAtom } from "jotai";
 import { challengeIdxAtom } from "@/utils/atom";
+import Tag from "./tag";
 
 interface ChallengeProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -30,13 +31,22 @@ const Challenge: NextPage<ChallengeProps> = ({
         onClick={() => router.push("/challenge")}
       >
         <FlexBox className="w-full justify-between items-start">
-          <div className="h2">{challengeInfo.name}</div>
+          <FlexBox className="gap-2">
+            <div className="h2">{challengeInfo.name}</div>
+            <FlexBox className="gap-1">
+              {challengeInfo.location !== null ? (
+                <Tag name={challengeInfo.location} />
+              ) : null}
+              <Tag name="예술(변경필)" />
+            </FlexBox>
+          </FlexBox>
           <div className="h4 text-grey-500">
             {challengeInfo.participantsCount}명 참여 중
           </div>
         </FlexBox>
         <div className="h4 self-start">
-          {challengeInfo.location} | {challengeInfo.schedule}
+          {challengeInfo.locatedPlace ?? challengeInfo.location} | 매주{" "}
+          {challengeInfo.schedule}요일
         </div>
       </FlexBox>
       <FlexBox direction="col" className="w-full gap-1">

From b449046d2791dcd29bdb9837ffa1b819de113c09 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:11:22 +0900
Subject: [PATCH 09/14] =?UTF-8?q?fix:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=ED=83=9C=EA=B7=B8=20Null=20=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20va?=
 =?UTF-8?q?lidation=20=EC=B2=98=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/home/adminChallenge.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/components/home/adminChallenge.tsx b/components/home/adminChallenge.tsx
index d61b0d4..387d54a 100644
--- a/components/home/adminChallenge.tsx
+++ b/components/home/adminChallenge.tsx
@@ -25,7 +25,9 @@ const AdminChallenge: NextPage<ChallengeProps> = ({
         <FlexBox className="w-full items-center gap-2">
           <div className="h2">{challengeInfo.name}</div>
           <FlexBox className="gap-1">
-            <Tag name={challengeInfo.location} />
+            {challengeInfo.location !== null ? (
+              <Tag name={challengeInfo.location} />
+            ) : null}
             <Tag name="예술(변경필)" />
           </FlexBox>
         </FlexBox>

From 0a9d6b76c9f21da7860c2480e057ff9de848dcc2 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:53:47 +0900
Subject: [PATCH 10/14] =?UTF-8?q?fix:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=EA=B2=80=EC=83=89=20interface=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/hooks/challenge.ts          | 1 -
 components/home/searchResult.tsx | 3 ++-
 pages/challenge/join.tsx         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/apis/hooks/challenge.ts b/apis/hooks/challenge.ts
index 042174f..2c83b9d 100644
--- a/apis/hooks/challenge.ts
+++ b/apis/hooks/challenge.ts
@@ -39,7 +39,6 @@ function useGetChallengeSearch(keyword: string) {
   const { data } = useQuery({
     queryKey: ["getChallengeSearch", keyword],
     queryFn: () => getChallengeSearch(keyword),
-    enabled: keyword.trim().length !== 0,
   });
 
   return { data };
diff --git a/components/home/searchResult.tsx b/components/home/searchResult.tsx
index fc067e7..2488cc0 100644
--- a/components/home/searchResult.tsx
+++ b/components/home/searchResult.tsx
@@ -24,7 +24,8 @@ export default function SearchResult({
       <FlexBox direction="col" className="gap-1 items-start">
         <div className="h3">{challengeInfo.name}</div>
         <div className="h4 text-grey-700">
-          {challengeInfo.location} | {challengeInfo.schedule}
+          {challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}{" "}
+          매주 {challengeInfo.schedule}요일
         </div>
       </FlexBox>
       <div className="h2 text-main-color p-2" onClick={onClick}>
diff --git a/pages/challenge/join.tsx b/pages/challenge/join.tsx
index ccae235..19febba 100644
--- a/pages/challenge/join.tsx
+++ b/pages/challenge/join.tsx
@@ -13,7 +13,7 @@ import CheckIcon from "@/public/svgs/Check.svg";
 const JoinChallenge: NextPage = () => {
   const [keyword, setKeyword] = useState<string>("");
 
-  const { data } = useGetChallengeSearch(keyword);
+  const { data } = useGetChallengeSearch(keyword.trim());
 
   const notify = (title: string) => {
     toast.success(`${title}에 성공적으로 참여하셨습니다.`, {

From bbfeed8eb61dfe06ff9d6a8ed16a47d348306229 Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 13:54:03 +0900
Subject: [PATCH 11/14] =?UTF-8?q?fix:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?=
 =?UTF-8?q?=EC=9D=B8=EC=A6=9D=ED=95=98=EA=B8=B0=20=EC=A3=BC=EC=84=9D=20?=
 =?UTF-8?q?=ED=95=B4=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/home/certifyModal.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/components/home/certifyModal.tsx b/components/home/certifyModal.tsx
index 3854390..4abd1f6 100644
--- a/components/home/certifyModal.tsx
+++ b/components/home/certifyModal.tsx
@@ -26,7 +26,7 @@ export default function CertifyModal({
   const { mutate } = usePostAttendance(challengeIdx);
 
   const onCertify = () => {
-    // mutate(number);
+    mutate(number);
     setIsModalVisible(false);
   };
 

From 03e85143d787c3af88dcf0520c378fd07fb8df2a Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 14:02:22 +0900
Subject: [PATCH 12/14] =?UTF-8?q?fix:=20challenge=20get=20API=EC=97=90?=
 =?UTF-8?q?=EC=84=9C=20location,=20=ED=83=9C=EA=B7=B8=20=EC=82=AD=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/challenge.ts                  |  1 -
 components/home/adminChallenge.tsx | 13 +++----------
 components/home/challenge.tsx      | 15 +++------------
 components/home/tag.tsx            | 11 -----------
 4 files changed, 6 insertions(+), 34 deletions(-)
 delete mode 100644 components/home/tag.tsx

diff --git a/apis/challenge.ts b/apis/challenge.ts
index e1c4ca9..d71a874 100644
--- a/apis/challenge.ts
+++ b/apis/challenge.ts
@@ -8,7 +8,6 @@ export interface Challenge {
   challengeIdx: number;
   name: string;
   participantsCount: number;
-  location: string;
   locatedPlace: string;
   schedule: string;
   myAttendanceRate: number;
diff --git a/components/home/adminChallenge.tsx b/components/home/adminChallenge.tsx
index 387d54a..6807323 100644
--- a/components/home/adminChallenge.tsx
+++ b/components/home/adminChallenge.tsx
@@ -3,7 +3,6 @@ import FlexBox from "../Flexbox";
 import { useRouter } from "next/router";
 import { Challenge as ChallengeType } from "@/apis/challenge";
 import { usePostAttendanceCode } from "@/apis/hooks/admin";
-import Tag from "./tag";
 
 interface ChallengeProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -22,18 +21,12 @@ const AdminChallenge: NextPage<ChallengeProps> = ({
   return (
     <FlexBox direction="col" className="p-4 w-full rounded-lg border gap-4">
       <FlexBox direction="col" className="w-full gap-1">
-        <FlexBox className="w-full items-center gap-2">
+        <FlexBox className="w-full items-start">
           <div className="h2">{challengeInfo.name}</div>
-          <FlexBox className="gap-1">
-            {challengeInfo.location !== null ? (
-              <Tag name={challengeInfo.location} />
-            ) : null}
-            <Tag name="예술(변경필)" />
-          </FlexBox>
         </FlexBox>
         <div className="h4 self-start">
-          {challengeInfo.locatedPlace ?? challengeInfo.location} |{" "}
-          {challengeInfo.schedule}
+          {challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}
+          매주 {challengeInfo.schedule}요일
         </div>
       </FlexBox>
       <FlexBox direction="col" className="w-full gap-2">
diff --git a/components/home/challenge.tsx b/components/home/challenge.tsx
index a945d86..a743b14 100644
--- a/components/home/challenge.tsx
+++ b/components/home/challenge.tsx
@@ -4,7 +4,6 @@ import { useRouter } from "next/router";
 import { Challenge as ChallengeType } from "@/apis/challenge";
 import { useAtom } from "jotai";
 import { challengeIdxAtom } from "@/utils/atom";
-import Tag from "./tag";
 
 interface ChallengeProps {
   setIsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
@@ -31,22 +30,14 @@ const Challenge: NextPage<ChallengeProps> = ({
         onClick={() => router.push("/challenge")}
       >
         <FlexBox className="w-full justify-between items-start">
-          <FlexBox className="gap-2">
-            <div className="h2">{challengeInfo.name}</div>
-            <FlexBox className="gap-1">
-              {challengeInfo.location !== null ? (
-                <Tag name={challengeInfo.location} />
-              ) : null}
-              <Tag name="예술(변경필)" />
-            </FlexBox>
-          </FlexBox>
+          <div className="h2">{challengeInfo.name}</div>
           <div className="h4 text-grey-500">
             {challengeInfo.participantsCount}명 참여 중
           </div>
         </FlexBox>
         <div className="h4 self-start">
-          {challengeInfo.locatedPlace ?? challengeInfo.location} | 매주{" "}
-          {challengeInfo.schedule}요일
+          {challengeInfo.locatedPlace ? `${challengeInfo.locatedPlace} | ` : ""}
+          매주 {challengeInfo.schedule}요일
         </div>
       </FlexBox>
       <FlexBox direction="col" className="w-full gap-1">
diff --git a/components/home/tag.tsx b/components/home/tag.tsx
deleted file mode 100644
index 7c2817b..0000000
--- a/components/home/tag.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { NextPage } from "next";
-
-interface TagProps {
-  name: string;
-}
-
-const Tag: NextPage<TagProps> = ({ name }: TagProps) => {
-  return <div className="rounded-xl text-main-color h5">#{name}</div>;
-};
-
-export default Tag;

From 7d75fd479a566cdf24145644783e92bdfc1289fb Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 15:13:38 +0900
Subject: [PATCH 13/14] =?UTF-8?q?fix:=20atomWithStorage=20=EC=82=AC?=
 =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20=EC=83=88=EB=A1=9C=EA=B3=A0?=
 =?UTF-8?q?=EC=B9=A8=EC=8B=9C=20atom=EA=B0=92=20=EB=82=A0=EB=9D=BC?=
 =?UTF-8?q?=EA=B0=80=EB=8A=94=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 apis/client.ts  |  12 --
 next.config.js  |   2 +
 package.json    |   1 +
 pages/_app.tsx  |  18 +-
 pages/index.tsx |   2 -
 pages/login.tsx |   9 +-
 utils/atom.tsx  |   8 +-
 yarn.lock       | 474 +++++++++++++++++++++++++++++++++++++++++++++++-
 8 files changed, 491 insertions(+), 35 deletions(-)

diff --git a/apis/client.ts b/apis/client.ts
index 3e200f3..04a1d94 100644
--- a/apis/client.ts
+++ b/apis/client.ts
@@ -22,18 +22,6 @@ const getTokenFromLocalStorage = () => {
   return accessToken;
 };
 
-export const setIsAdminAtLocalStorage = (is_admin: string) => {
-  localStorage.setItem("is_admin", is_admin);
-};
-
-const getIsAdminFromLocalStorage = () => {
-  const isAdmin = localStorage.getItem("is_admin");
-  if (!isAdmin) {
-    return null;
-  }
-  return isAdmin;
-};
-
 const client = axios.create({
   baseURL: process.env.NEXT_PUBLIC_API_URL,
   withCredentials: true,
diff --git a/next.config.js b/next.config.js
index 7c6ec5f..322def9 100644
--- a/next.config.js
+++ b/next.config.js
@@ -20,6 +20,8 @@ const nextConfig = {
   env: {
     NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
   },
+
+  transpilePackages: ["jotai-devtools"],
 };
 
 module.exports = nextConfig;
diff --git a/package.json b/package.json
index 7255eb2..4788177 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
     "embla-carousel-react": "^8.1.3",
     "gh-pages": "^6.1.1",
     "jotai": "^2.8.3",
+    "jotai-devtools": "^0.10.0",
     "lottie-web": "^5.12.2",
     "moment": "^2.30.1",
     "next": "12.3.4",
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 3d16134..61b6de8 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -7,16 +7,22 @@ import RootLayout from "@/components/Layout";
 import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
 import { AppProps } from "next/app";
+import { DevTools } from "jotai-devtools";
+import "jotai-devtools/styles.css";
+import { Provider } from "jotai";
 
 const queryClient = new QueryClient();
 
 export default function App({ Component, pageProps }: AppProps) {
   return (
-    <QueryClientProvider client={queryClient}>
-      <RootLayout>
-        <Component {...pageProps} />
-      </RootLayout>
-      <ReactQueryDevtools initialIsOpen={false} />
-    </QueryClientProvider>
+    <Provider>
+      <QueryClientProvider client={queryClient}>
+        <RootLayout>
+          <Component {...pageProps} />
+        </RootLayout>
+        <ReactQueryDevtools initialIsOpen={false} />
+        <DevTools />
+      </QueryClientProvider>
+    </Provider>
   );
 }
diff --git a/pages/index.tsx b/pages/index.tsx
index 3dac6e5..1c53497 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -8,8 +8,6 @@ import FlexBox from "@/components/Flexbox";
 import { ToastContainer, Zoom, toast } from "react-toastify";
 import "react-toastify/dist/ReactToastify.css";
 import CheckIcon from "@/public/svgs/Check.svg";
-import { atom, useAtomValue } from "jotai";
-import { isAdminAtom } from "@/utils/atom";
 
 const Home: NextPage = () => {
   const notify = (msg: string) => {
diff --git a/pages/login.tsx b/pages/login.tsx
index 564baa8..45ded44 100644
--- a/pages/login.tsx
+++ b/pages/login.tsx
@@ -5,11 +5,7 @@ import { useRouter } from "next/router";
 import Button from "@/components/Button";
 import LogoLetterIcon from "@/public/svgs/LogoLetter.svg";
 import { useMutation } from "@tanstack/react-query";
-import {
-  ResponseBody,
-  setIsAdminAtLocalStorage,
-  setTokenFromLocalStorage,
-} from "@/apis/client";
+import { ResponseBody, setTokenFromLocalStorage } from "@/apis/client";
 import { SignIn } from "@/apis/auth";
 import { atom, useAtom } from "jotai";
 import { centerNameAtom, isAdminAtom } from "@/utils/atom";
@@ -21,7 +17,7 @@ interface userProps {
 
 const Login: NextPage = () => {
   const router = useRouter();
-  const [isAdmin, setIsAdmin] = useAtom(isAdminAtom);
+  const [, setIsAdmin] = useAtom(isAdminAtom);
   const [, setCenterName] = useAtom(centerNameAtom);
 
   const [userInfo, setUserInfo] = useState<userProps>({
@@ -61,7 +57,6 @@ const Login: NextPage = () => {
       const isAdmin = data.result.isAdmin;
       if (isAdmin) setCenterName(data.result.centerName);
       setIsAdmin(isAdmin);
-      setIsAdminAtLocalStorage(isAdmin);
       setTokenFromLocalStorage(accessToken);
 
       router.push("/");
diff --git a/utils/atom.tsx b/utils/atom.tsx
index 1854b56..e9457a4 100644
--- a/utils/atom.tsx
+++ b/utils/atom.tsx
@@ -1,7 +1,11 @@
 import { atom } from "jotai";
+import { atomWithStorage } from "jotai/utils";
 
-export const isAdminAtom = atom<boolean>(true);
+export const isAdminAtom = atomWithStorage("isAdmin", false);
+isAdminAtom.debugLabel = "isAdminAtom";
 
 export const challengeIdxAtom = atom<number>(-1);
+challengeIdxAtom.debugLabel = "challengeIdxAtom";
 
-export const centerNameAtom = atom<string>("");
+export const centerNameAtom = atomWithStorage("centerName", "");
+centerNameAtom.debugLabel = "centerNameAtom";
diff --git a/yarn.lock b/yarn.lock
index be40653..0c03905 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1447,7 +1447,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4":
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4":
   version: 7.24.7
   resolution: "@babel/runtime@npm:7.24.7"
   dependencies:
@@ -1561,6 +1561,58 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@floating-ui/core@npm:^1.6.0":
+  version: 1.6.4
+  resolution: "@floating-ui/core@npm:1.6.4"
+  dependencies:
+    "@floating-ui/utils": "npm:^0.2.4"
+  checksum: 10c0/545684b6f76cda7579b6049bafb9903542d3f9c177300192fe83db19d99b1df285bc33aba3b8ec2978d021151c4168356876e8181002dd2ff4fb93d9e4b7bf71
+  languageName: node
+  linkType: hard
+
+"@floating-ui/dom@npm:^1.0.0":
+  version: 1.6.7
+  resolution: "@floating-ui/dom@npm:1.6.7"
+  dependencies:
+    "@floating-ui/core": "npm:^1.6.0"
+    "@floating-ui/utils": "npm:^0.2.4"
+  checksum: 10c0/5255f522534e0022b554c366b969fa26951677a1cf39ddd58614071a909a340c5e1ffe645501037b221808f01bfac4e7edba14728978ee7e2438e8432c1a163f
+  languageName: node
+  linkType: hard
+
+"@floating-ui/react-dom@npm:^2.1.1":
+  version: 2.1.1
+  resolution: "@floating-ui/react-dom@npm:2.1.1"
+  dependencies:
+    "@floating-ui/dom": "npm:^1.0.0"
+  peerDependencies:
+    react: ">=16.8.0"
+    react-dom: ">=16.8.0"
+  checksum: 10c0/732ab64600c511ceb0563b87bc557aa61789fec4f416a3f092bab89e508fa1d3ee5ade0f42051cc56eb5e4db867b87ab7fd48ce82db9fd4c01d94ffa08f60115
+  languageName: node
+  linkType: hard
+
+"@floating-ui/react@npm:^0.26.9":
+  version: 0.26.19
+  resolution: "@floating-ui/react@npm:0.26.19"
+  dependencies:
+    "@floating-ui/react-dom": "npm:^2.1.1"
+    "@floating-ui/utils": "npm:^0.2.4"
+    tabbable: "npm:^6.0.0"
+  peerDependencies:
+    react: ">=16.8.0"
+    react-dom: ">=16.8.0"
+  checksum: 10c0/c87483e088a48be40cc0e7a33f332f1f1cda43005a53ee506f36d7714383f555a22f2e4222b2ca515086c156fccb8853566adcf98168a6015fa9bc10dbf938b1
+  languageName: node
+  linkType: hard
+
+"@floating-ui/utils@npm:^0.2.4":
+  version: 0.2.4
+  resolution: "@floating-ui/utils@npm:0.2.4"
+  checksum: 10c0/154924b01157cb45cf305f4835d7f603e931dda8b00bbe52666729bccc5e7b99630e8b951333725e526d4e53d9b342976434ad5750b8b1da58728e3698bdcc2b
+  languageName: node
+  linkType: hard
+
 "@humanwhocodes/config-array@npm:^0.11.13":
   version: 0.11.14
   resolution: "@humanwhocodes/config-array@npm:0.11.14"
@@ -1642,6 +1694,48 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@mantine/code-highlight@npm:^7.10.1":
+  version: 7.11.0
+  resolution: "@mantine/code-highlight@npm:7.11.0"
+  dependencies:
+    clsx: "npm:^2.1.1"
+    highlight.js: "npm:^11.9.0"
+  peerDependencies:
+    "@mantine/core": 7.11.0
+    "@mantine/hooks": 7.11.0
+    react: ^18.2.0
+    react-dom: ^18.2.0
+  checksum: 10c0/10f39458db2f8c28ca3cfc12cbe2c773f6cae2757fca7c87821d96b88a92104386fe2e600690f097bb6fb124cafe615a6b67437533226b0c7f5081257cb1d264
+  languageName: node
+  linkType: hard
+
+"@mantine/core@npm:^7.10.1":
+  version: 7.11.0
+  resolution: "@mantine/core@npm:7.11.0"
+  dependencies:
+    "@floating-ui/react": "npm:^0.26.9"
+    clsx: "npm:^2.1.1"
+    react-number-format: "npm:^5.3.1"
+    react-remove-scroll: "npm:^2.5.7"
+    react-textarea-autosize: "npm:8.5.3"
+    type-fest: "npm:^4.12.0"
+  peerDependencies:
+    "@mantine/hooks": 7.11.0
+    react: ^18.2.0
+    react-dom: ^18.2.0
+  checksum: 10c0/41fb80ed5e9cfe67bca3dd9a764c00e66f8c78b92f2f71f4f4fd73b1621d682053b07532590a609bce7e876d8d4f67d69fcacc37168a294595b8af7c2ffce616
+  languageName: node
+  linkType: hard
+
+"@mantine/hooks@npm:^7.10.1":
+  version: 7.11.0
+  resolution: "@mantine/hooks@npm:7.11.0"
+  peerDependencies:
+    react: ^18.2.0
+  checksum: 10c0/5fb96b46145f0f1fbbe2a4934ce26e374e59dfc4b0d7b1f0b96e4d9a93997315bb57e5d2747331648e33280669404555a52b0e9857bb8b81b1121fe02eede5ac
+  languageName: node
+  linkType: hard
+
 "@next/env@npm:12.3.4":
   version: 12.3.4
   resolution: "@next/env@npm:12.3.4"
@@ -1814,6 +1908,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@redux-devtools/extension@npm:^3.3.0":
+  version: 3.3.0
+  resolution: "@redux-devtools/extension@npm:3.3.0"
+  dependencies:
+    "@babel/runtime": "npm:^7.23.2"
+    immutable: "npm:^4.3.4"
+  peerDependencies:
+    redux: ^3.1.0 || ^4.0.0 || ^5.0.0
+  checksum: 10c0/a582d26687fdcbb9fc98181a6a28c7e286a6a74f35f5bba181b9b8b766029d34754bd8f8e60acaa757a34aca385056783d2efb95f943282f2ee66039931c942f
+  languageName: node
+  linkType: hard
+
 "@rushstack/eslint-patch@npm:^1.3.3":
   version: 1.10.3
   resolution: "@rushstack/eslint-patch@npm:1.10.3"
@@ -2057,6 +2163,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/base16@npm:^1.0.2":
+  version: 1.0.5
+  resolution: "@types/base16@npm:1.0.5"
+  checksum: 10c0/c3859a03ab50bf96e9d08ffb97209f150fd7c7bcfe5fa04b5dc9c874740b9c4f0d6774c6a364dce0aa00b1d3bc5ee80fb07d9cfde83b82dae7e0a2f575eca4b1
+  languageName: node
+  linkType: hard
+
 "@types/cacheable-request@npm:^6.0.1":
   version: 6.0.3
   resolution: "@types/cacheable-request@npm:6.0.3"
@@ -2116,6 +2229,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/lodash@npm:^4.14.178, @types/lodash@npm:^4.14.191":
+  version: 4.17.6
+  resolution: "@types/lodash@npm:4.17.6"
+  checksum: 10c0/3b197ac47af9443fee8c4719c5ffde527d7febc018b827d44a6bc2523c728c7adfdd25196fdcfe3eed827993e0c41a917d0da6e78938b18b2be94164789f1117
+  languageName: node
+  linkType: hard
+
 "@types/node@npm:*":
   version: 20.14.8
   resolution: "@types/node@npm:20.14.8"
@@ -2870,6 +2990,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"base16@npm:^1.0.0":
+  version: 1.0.0
+  resolution: "base16@npm:1.0.0"
+  checksum: 10c0/af1aee7b297d968528ef47c8de2c5274029743e8a4a5f61ec823e36b673781691d124168cb22936c7997f53d89b344c58bf7ecf93eeb148cffa7e3fb4e4b8b18
+  languageName: node
+  linkType: hard
+
 "big-integer@npm:^1.6.16":
   version: 1.6.52
   resolution: "big-integer@npm:1.6.52"
@@ -3144,14 +3271,14 @@ __metadata:
   languageName: node
   linkType: hard
 
-"clsx@npm:^2.0.0, clsx@npm:^2.1.0":
+"clsx@npm:^2.0.0, clsx@npm:^2.1.0, clsx@npm:^2.1.1":
   version: 2.1.1
   resolution: "clsx@npm:2.1.1"
   checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839
   languageName: node
   linkType: hard
 
-"color-convert@npm:^1.9.0":
+"color-convert@npm:^1.9.0, color-convert@npm:^1.9.3":
   version: 1.9.3
   resolution: "color-convert@npm:1.9.3"
   dependencies:
@@ -3176,13 +3303,33 @@ __metadata:
   languageName: node
   linkType: hard
 
-"color-name@npm:~1.1.4":
+"color-name@npm:^1.0.0, color-name@npm:~1.1.4":
   version: 1.1.4
   resolution: "color-name@npm:1.1.4"
   checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
   languageName: node
   linkType: hard
 
+"color-string@npm:^1.6.0":
+  version: 1.9.1
+  resolution: "color-string@npm:1.9.1"
+  dependencies:
+    color-name: "npm:^1.0.0"
+    simple-swizzle: "npm:^0.2.2"
+  checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404
+  languageName: node
+  linkType: hard
+
+"color@npm:^3.2.1":
+  version: 3.2.1
+  resolution: "color@npm:3.2.1"
+  dependencies:
+    color-convert: "npm:^1.9.3"
+    color-string: "npm:^1.6.0"
+  checksum: 10c0/39345d55825884c32a88b95127d417a2c24681d8b57069413596d9fcbb721459ef9d9ec24ce3e65527b5373ce171b73e38dbcd9c830a52a6487e7f37bf00e83c
+  languageName: node
+  linkType: hard
+
 "combined-stream@npm:^1.0.8":
   version: 1.0.8
   resolution: "combined-stream@npm:1.0.8"
@@ -3347,7 +3494,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"csstype@npm:3.1.3, csstype@npm:^3.0.2":
+"csstype@npm:3.1.3, csstype@npm:^3.0.10, csstype@npm:^3.0.2":
   version: 3.1.3
   resolution: "csstype@npm:3.1.3"
   checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248
@@ -3507,6 +3654,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"detect-node-es@npm:^1.1.0":
+  version: 1.1.0
+  resolution: "detect-node-es@npm:1.1.0"
+  checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe
+  languageName: node
+  linkType: hard
+
 "detect-node@npm:^2.0.4, detect-node@npm:^2.1.0":
   version: 2.1.0
   resolution: "detect-node@npm:2.1.0"
@@ -3521,6 +3675,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"diff-match-patch@npm:^1.0.0":
+  version: 1.0.5
+  resolution: "diff-match-patch@npm:1.0.5"
+  checksum: 10c0/142b6fad627b9ef309d11bd935e82b84c814165a02500f046e2773f4ea894d10ed3017ac20454900d79d4a0322079f5b713cf0986aaf15fce0ec4a2479980c86
+  languageName: node
+  linkType: hard
+
 "diff@npm:^5.1.0":
   version: 5.2.0
   resolution: "diff@npm:5.2.0"
@@ -4503,6 +4664,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"get-nonce@npm:^1.0.0":
+  version: 1.0.1
+  resolution: "get-nonce@npm:1.0.1"
+  checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162
+  languageName: node
+  linkType: hard
+
 "get-stream@npm:^5.1.0":
   version: 5.2.0
   resolution: "get-stream@npm:5.2.0"
@@ -4785,6 +4953,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"highlight.js@npm:^11.9.0":
+  version: 11.9.0
+  resolution: "highlight.js@npm:11.9.0"
+  checksum: 10c0/27cfa8717dc9d200aecbdb383eb122d5f45ce715d2f468583785d36fbfe5076ce033abb02486dc13b407171721cda6f474ed3f3a5a8e8c3d91367fa5f51ee374
+  languageName: node
+  linkType: hard
+
 "hoist-non-react-statics@npm:^3.3.0":
   version: 3.3.2
   resolution: "hoist-non-react-statics@npm:3.3.2"
@@ -4847,6 +5022,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"immutable@npm:^4.3.4":
+  version: 4.3.6
+  resolution: "immutable@npm:4.3.6"
+  checksum: 10c0/7d0952a768b4fadcee47230ed86dc9505a4517095eceaf5a47e65288571c42400c6e4a2ae21eca4eda957cb7bc50720213135b62cf6a181639111f8acae128c3
+  languageName: node
+  linkType: hard
+
 "import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0":
   version: 3.3.0
   resolution: "import-fresh@npm:3.3.0"
@@ -4899,6 +5081,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"invariant@npm:^2.2.4":
+  version: 2.2.4
+  resolution: "invariant@npm:2.2.4"
+  dependencies:
+    loose-envify: "npm:^1.0.0"
+  checksum: 10c0/5af133a917c0bcf65e84e7f23e779e7abc1cd49cb7fdc62d00d1de74b0d8c1b5ee74ac7766099fb3be1b05b26dfc67bab76a17030d2fe7ea2eef867434362dfc
+  languageName: node
+  linkType: hard
+
 "ip-address@npm:^9.0.5":
   version: 9.0.5
   resolution: "ip-address@npm:9.0.5"
@@ -4936,6 +5127,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"is-arrayish@npm:^0.3.1":
+  version: 0.3.2
+  resolution: "is-arrayish@npm:0.3.2"
+  checksum: 10c0/f59b43dc1d129edb6f0e282595e56477f98c40278a2acdc8b0a5c57097c9eff8fe55470493df5775478cf32a4dc8eaf6d3a749f07ceee5bc263a78b2434f6a54
+  languageName: node
+  linkType: hard
+
 "is-async-function@npm:^2.0.0":
   version: 2.0.0
   resolution: "is-async-function@npm:2.0.0"
@@ -5218,6 +5416,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"javascript-stringify@npm:^2.1.0":
+  version: 2.1.0
+  resolution: "javascript-stringify@npm:2.1.0"
+  checksum: 10c0/374e74ebff29b94de78da39daa6e530999c58a145aeb293dc21180c4584459b14d9e5721d9bc6ed4eba319c437ef0145c157c946b70ecddcff6668682a002bcc
+  languageName: node
+  linkType: hard
+
 "jiti@npm:^1.21.0":
   version: 1.21.6
   resolution: "jiti@npm:1.21.6"
@@ -5227,6 +5432,27 @@ __metadata:
   languageName: node
   linkType: hard
 
+"jotai-devtools@npm:^0.10.0":
+  version: 0.10.0
+  resolution: "jotai-devtools@npm:0.10.0"
+  dependencies:
+    "@mantine/code-highlight": "npm:^7.10.1"
+    "@mantine/core": "npm:^7.10.1"
+    "@mantine/hooks": "npm:^7.10.1"
+    "@redux-devtools/extension": "npm:^3.3.0"
+    clsx: "npm:^2.1.1"
+    javascript-stringify: "npm:^2.1.0"
+    jsondiffpatch: "npm:^0.5.0"
+    react-base16-styling: "npm:^0.9.1"
+    react-error-boundary: "npm:^4.0.13"
+    react-json-tree: "npm:^0.18.0"
+    react-resizable-panels: "npm:2.0.10"
+  peerDependencies:
+    react: ">=17.0.0"
+  checksum: 10c0/ae00930ebec9c0b26dfb9dc83ab38ed298179c9da033d73d8b57e6ed6b12e3991f2f0781ffd3b82cd7729fbbea362c6bf2e92dcc28665179e0e5b5f91d3b08ca
+  languageName: node
+  linkType: hard
+
 "jotai@npm:^2.8.3":
   version: 2.8.3
   resolution: "jotai@npm:2.8.3"
@@ -5352,6 +5578,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"jsondiffpatch@npm:^0.5.0":
+  version: 0.5.0
+  resolution: "jsondiffpatch@npm:0.5.0"
+  dependencies:
+    chalk: "npm:^3.0.0"
+    diff-match-patch: "npm:^1.0.0"
+  bin:
+    jsondiffpatch: bin/jsondiffpatch
+  checksum: 10c0/272271b92b20ebd303c002b4ffad6bcbf52dadb667c338509296b3c25e954535e5aa86c3675df5ae1525edad9ea7f7191c8beb921f0ee87569a58b4810299d87
+  languageName: node
+  linkType: hard
+
 "jsonfile@npm:^6.0.1":
   version: 6.1.0
   resolution: "jsonfile@npm:6.1.0"
@@ -5451,6 +5689,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"lodash.curry@npm:^4.1.1":
+  version: 4.1.1
+  resolution: "lodash.curry@npm:4.1.1"
+  checksum: 10c0/f0431947dc9236df879fc13eb40c31a2839c958bd0eaa39170a5758c25a7d85d461716a851ab45a175371950b283480615cdd4b07fb0dd1afff7a2914a90696f
+  languageName: node
+  linkType: hard
+
 "lodash.debounce@npm:^4.0.8":
   version: 4.0.8
   resolution: "lodash.debounce@npm:4.0.8"
@@ -6500,6 +6745,21 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-base16-styling@npm:^0.9.1":
+  version: 0.9.1
+  resolution: "react-base16-styling@npm:0.9.1"
+  dependencies:
+    "@babel/runtime": "npm:^7.16.7"
+    "@types/base16": "npm:^1.0.2"
+    "@types/lodash": "npm:^4.14.178"
+    base16: "npm:^1.0.0"
+    color: "npm:^3.2.1"
+    csstype: "npm:^3.0.10"
+    lodash.curry: "npm:^4.1.1"
+  checksum: 10c0/00ed3bbc4b7cf829117eb38d2e350b03ef6a746a3b58e57494a2cf8a3de6f98494ee9209543a399d474e8a6c0172584b3b61309e59e57c2b2694b5dc910a14a1
+  languageName: node
+  linkType: hard
+
 "react-calendar@npm:^5.0.0":
   version: 5.0.0
   resolution: "react-calendar@npm:5.0.0"
@@ -6543,6 +6803,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-error-boundary@npm:^4.0.13":
+  version: 4.0.13
+  resolution: "react-error-boundary@npm:4.0.13"
+  dependencies:
+    "@babel/runtime": "npm:^7.12.5"
+  peerDependencies:
+    react: ">=16.13.1"
+  checksum: 10c0/6f3e0e4d7669f680ccf49c08c9571519c6e31f04dcfc30a765a7136c7e6fbbbe93423dd5a9fce12107f8166e54133e9dd5c2079a00c7a38201ac811f7a28b8e7
+  languageName: node
+  linkType: hard
+
 "react-is@npm:^16.13.1, react-is@npm:^16.7.0":
   version: 16.13.1
   resolution: "react-is@npm:16.13.1"
@@ -6550,6 +6821,20 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-json-tree@npm:^0.18.0":
+  version: 0.18.0
+  resolution: "react-json-tree@npm:0.18.0"
+  dependencies:
+    "@babel/runtime": "npm:^7.20.6"
+    "@types/lodash": "npm:^4.14.191"
+    react-base16-styling: "npm:^0.9.1"
+  peerDependencies:
+    "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  checksum: 10c0/628c76339bd47dee0dbc378d57eb07051b4e2cd52f8b0794f640bed8fd33a64b2573035e298cae6ca8a8b3e969eb122fc74d2fabe738be10080f8cd5e0497589
+  languageName: node
+  linkType: hard
+
 "react-lifecycles-compat@npm:^3.0.0":
   version: 3.0.4
   resolution: "react-lifecycles-compat@npm:3.0.4"
@@ -6572,6 +6857,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-number-format@npm:^5.3.1":
+  version: 5.4.0
+  resolution: "react-number-format@npm:5.4.0"
+  dependencies:
+    prop-types: "npm:^15.7.2"
+  peerDependencies:
+    react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
+    react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
+  checksum: 10c0/19785cbf7fcb6db7e34d29136ac8daf1708b46bba2a38e2e8851a65bd1e9c6463b13c31f17de156afbf681da43a2934565be9d8955aec23084a19a8d45f79149
+  languageName: node
+  linkType: hard
+
 "react-query@npm:^3.39.3":
   version: 3.39.3
   resolution: "react-query@npm:3.39.3"
@@ -6590,6 +6887,81 @@ __metadata:
   languageName: node
   linkType: hard
 
+"react-remove-scroll-bar@npm:^2.3.6":
+  version: 2.3.6
+  resolution: "react-remove-scroll-bar@npm:2.3.6"
+  dependencies:
+    react-style-singleton: "npm:^2.2.1"
+    tslib: "npm:^2.0.0"
+  peerDependencies:
+    "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/4e32ee04bf655a8bd3b4aacf6ffc596ae9eb1b9ba27eef83f7002632ee75371f61516ae62250634a9eae4b2c8fc6f6982d9b182de260f6c11841841e6e2e7515
+  languageName: node
+  linkType: hard
+
+"react-remove-scroll@npm:^2.5.7":
+  version: 2.5.10
+  resolution: "react-remove-scroll@npm:2.5.10"
+  dependencies:
+    react-remove-scroll-bar: "npm:^2.3.6"
+    react-style-singleton: "npm:^2.2.1"
+    tslib: "npm:^2.1.0"
+    use-callback-ref: "npm:^1.3.0"
+    use-sidecar: "npm:^1.1.2"
+  peerDependencies:
+    "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/5057ebf11cf6b7a9126087c37be56f08bb96065906d871e7715f94caf74d980e01df8ad074e049d9d2f40d2946e50c14bd3c77966bcf4bf1d53ca303ecc64955
+  languageName: node
+  linkType: hard
+
+"react-resizable-panels@npm:2.0.10":
+  version: 2.0.10
+  resolution: "react-resizable-panels@npm:2.0.10"
+  peerDependencies:
+    react: ^16.14.0 || ^17.0.0 || ^18.0.0
+    react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
+  checksum: 10c0/51ec6171692cb36252f3d839af3e274898a98caeddf33f3c3b5feb8858df0cb1a8c0f865494e08fcbc8a03f9b214d8b5d49dbb5bb3210a225a294bda38734eba
+  languageName: node
+  linkType: hard
+
+"react-style-singleton@npm:^2.2.1":
+  version: 2.2.1
+  resolution: "react-style-singleton@npm:2.2.1"
+  dependencies:
+    get-nonce: "npm:^1.0.0"
+    invariant: "npm:^2.2.4"
+    tslib: "npm:^2.0.0"
+  peerDependencies:
+    "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/6d66f3bdb65e1ec79089f80314da97c9a005087a04ee034255a5de129a4c0d9fd0bf99fa7bf642781ac2dc745ca687aae3de082bd8afdd0d117bc953241e15ad
+  languageName: node
+  linkType: hard
+
+"react-textarea-autosize@npm:8.5.3":
+  version: 8.5.3
+  resolution: "react-textarea-autosize@npm:8.5.3"
+  dependencies:
+    "@babel/runtime": "npm:^7.20.13"
+    use-composed-ref: "npm:^1.3.0"
+    use-latest: "npm:^1.2.1"
+  peerDependencies:
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  checksum: 10c0/33d38a6d96cf584842695b50c341980944ece23a42155bf0bd1958f02396adb185c7720b88678dc677817fe111783059c0ebcdf7761644006892583b10e258ee
+  languageName: node
+  linkType: hard
+
 "react-toastify@npm:^10.0.5":
   version: 10.0.5
   resolution: "react-toastify@npm:10.0.5"
@@ -6961,6 +7333,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"simple-swizzle@npm:^0.2.2":
+  version: 0.2.2
+  resolution: "simple-swizzle@npm:0.2.2"
+  dependencies:
+    is-arrayish: "npm:^0.3.1"
+  checksum: 10c0/df5e4662a8c750bdba69af4e8263c5d96fe4cd0f9fe4bdfa3cbdeb45d2e869dff640beaaeb1ef0e99db4d8d2ec92f85508c269f50c972174851bc1ae5bd64308
+  languageName: node
+  linkType: hard
+
 "slash@npm:^3.0.0":
   version: 3.0.0
   resolution: "slash@npm:3.0.0"
@@ -7280,6 +7661,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"tabbable@npm:^6.0.0":
+  version: 6.2.0
+  resolution: "tabbable@npm:6.2.0"
+  checksum: 10c0/ced8b38f05f2de62cd46836d77c2646c42b8c9713f5bd265daf0e78ff5ac73d3ba48a7ca45f348bafeef29b23da7187c72250742d37627883ef89cbd7fa76898
+  languageName: node
+  linkType: hard
+
 "tailwind-scrollbar-hide@npm:^1.1.7":
   version: 1.1.7
   resolution: "tailwind-scrollbar-hide@npm:1.1.7"
@@ -7440,7 +7828,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"tslib@npm:^2.0.3, tslib@npm:^2.4.0":
+"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0":
   version: 2.6.3
   resolution: "tslib@npm:2.6.3"
   checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a
@@ -7477,6 +7865,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"type-fest@npm:^4.12.0":
+  version: 4.20.1
+  resolution: "type-fest@npm:4.20.1"
+  checksum: 10c0/c31da16fe170a74c5b7e102e70e764ba8ec6ade128e782a56f842aefa07307df5a6353e6b5601d3b30ff2d856d8b955f89813df639e4758fedcf8e426b2d854e
+  languageName: node
+  linkType: hard
+
 "typed-array-buffer@npm:^1.0.2":
   version: 1.0.2
   resolution: "typed-array-buffer@npm:1.0.2"
@@ -7657,6 +8052,72 @@ __metadata:
   languageName: node
   linkType: hard
 
+"use-callback-ref@npm:^1.3.0":
+  version: 1.3.2
+  resolution: "use-callback-ref@npm:1.3.2"
+  dependencies:
+    tslib: "npm:^2.0.0"
+  peerDependencies:
+    "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/d232c37160fe3970c99255da19b5fb5299fb5926a5d6141d928a87feb47732c323d29be2f8137d3b1e5499c70d284cd1d9cfad703cc58179db8be24d7dd8f1f2
+  languageName: node
+  linkType: hard
+
+"use-composed-ref@npm:^1.3.0":
+  version: 1.3.0
+  resolution: "use-composed-ref@npm:1.3.0"
+  peerDependencies:
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  checksum: 10c0/e64ce52f4b18c020407636784192726807404a2552609acf7497b66a2b7070674fb5d2b950d426c4aa85f353e2bbecb02ebf9c5b865cd06797938c70bcbf5d26
+  languageName: node
+  linkType: hard
+
+"use-isomorphic-layout-effect@npm:^1.1.1":
+  version: 1.1.2
+  resolution: "use-isomorphic-layout-effect@npm:1.1.2"
+  peerDependencies:
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/d8deea8b85e55ac6daba237a889630bfdbf0ebf60e9e22b6a78a78c26fabe6025e04ada7abef1e444e6786227d921e648b2707db8b3564daf757264a148a6e23
+  languageName: node
+  linkType: hard
+
+"use-latest@npm:^1.2.1":
+  version: 1.2.1
+  resolution: "use-latest@npm:1.2.1"
+  dependencies:
+    use-isomorphic-layout-effect: "npm:^1.1.1"
+  peerDependencies:
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/1958886fc35262d973f5cd4ce16acd6ce3a66707a72761c93abd1b5ae64e1a11efa83f68e6c8c9bf1647628037980ce59df64cba50adb36bd4071851e70527d2
+  languageName: node
+  linkType: hard
+
+"use-sidecar@npm:^1.1.2":
+  version: 1.1.2
+  resolution: "use-sidecar@npm:1.1.2"
+  dependencies:
+    detect-node-es: "npm:^1.1.0"
+    tslib: "npm:^2.0.0"
+  peerDependencies:
+    "@types/react": ^16.9.0 || ^17.0.0 || ^18.0.0
+    react: ^16.8.0 || ^17.0.0 || ^18.0.0
+  peerDependenciesMeta:
+    "@types/react":
+      optional: true
+  checksum: 10c0/89f0018fd9aee1fc17c85ac18c4bf8944d460d453d0d0e04ddbc8eaddf3fa591e9c74a1f8a438a1bff368a7a2417fab380bdb3df899d2194c4375b0982736de0
+  languageName: node
+  linkType: hard
+
 "use-sync-external-store@npm:1.2.0":
   version: 1.2.0
   resolution: "use-sync-external-store@npm:1.2.0"
@@ -7707,6 +8168,7 @@ __metadata:
     eslint-plugin-react: "npm:^7.34.3"
     gh-pages: "npm:^6.1.1"
     jotai: "npm:^2.8.3"
+    jotai-devtools: "npm:^0.10.0"
     lottie-web: "npm:^5.12.2"
     moment: "npm:^2.30.1"
     next: "npm:12.3.4"

From ad569f44f46323d9ed2c4bb14b381a63eb2cccfe Mon Sep 17 00:00:00 2001
From: iOdiO89 <117376841+iOdiO89@users.noreply.github.com>
Date: Tue, 2 Jul 2024 15:28:49 +0900
Subject: [PATCH 14/14] =?UTF-8?q?fix:=20=EC=9D=B8=EC=A6=9D=EB=B2=88?=
 =?UTF-8?q?=ED=98=B8=20=EB=AF=B8=EC=9E=85=EB=A0=A5=EC=8B=9C=20api=20?=
 =?UTF-8?q?=ED=98=B8=EC=B6=9C=20X?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/home/certifyModal.tsx | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/components/home/certifyModal.tsx b/components/home/certifyModal.tsx
index 4abd1f6..fdba25f 100644
--- a/components/home/certifyModal.tsx
+++ b/components/home/certifyModal.tsx
@@ -26,8 +26,15 @@ export default function CertifyModal({
   const { mutate } = usePostAttendance(challengeIdx);
 
   const onCertify = () => {
-    mutate(number);
-    setIsModalVisible(false);
+    if (number.length === 0)
+      setNumError({
+        status: true,
+        text: "인증번호가 입력되지 않았습니다.",
+      });
+    else {
+      mutate(number);
+      setIsModalVisible(false);
+    }
   };
 
   return (