{isLoggedIn ? (
-
-
- {isProfileClicked && currentUser && (
-
- {currentUser.nickName}
- {currentUser.email}
- 마이페이지
- {/* TODO: 로그아웃 기능 구현 */}
- 로그아웃
-
- )}
-
+
) : (
로그인
diff --git a/src/home/components/Notification/Notification.tsx b/src/home/components/Notification/Notification.tsx
index bd652db9..3c80a872 100644
--- a/src/home/components/Notification/Notification.tsx
+++ b/src/home/components/Notification/Notification.tsx
@@ -1,7 +1,9 @@
-import { useRef, useState } from 'react';
+import { Suspense, useEffect, useRef, useState } from 'react';
import { IcNoticeLine } from '@yourssu/design-system-react';
+import { ErrorBoundary } from 'react-error-boundary';
+import { useGetAnnouncement } from '@/home/hooks/useGetAnnouncement';
import { useInterval } from '@/hooks/useInterval';
import {
@@ -12,65 +14,75 @@ import {
StyledNotificationContainer,
} from './Notification.style';
-const Dummy = [
- '그거 아시나요?? 지금은 2월이라는 거? 당연함 2월임',
- '안녕하세요~~ 공지입니다.',
- '가나다라마바사아자차카타파하갸냐댜랴먀뱌샤야쟈챠캬탸퍄햐거너더러머버서어저처커터퍼허겨녀뎌려며벼셔여져쳐켜텨펴혀',
- '이거슨 테스트여',
-];
-
-// TODO: 추후 공지사항 API 연결 확인 필요
-export const Notification = () => {
- const [currentIndex, setCurrentIndex] = useState(1);
+const NotificationContent = () => {
+ const { data: announcements } = useGetAnnouncement();
+ const [currentIndex, setCurrentIndex] = useState(0);
const [activeTransition, setActiveTransition] = useState(true);
const slideRef = useRef(null);
- const notificationArray = [Dummy[Dummy.length - 1], ...Dummy, Dummy[0]].map(
- (notification, index) => ({
- id: index + 1,
- notification,
- })
- );
+
+ const notificationArray =
+ announcements.length > 0
+ ? [...announcements, announcements[0]].map((announcement, index) => ({
+ id: index + 1,
+ notification: announcement.title,
+ }))
+ : [];
useInterval(() => setCurrentIndex((prev) => prev + 1), 5000);
- const InfiniteSlideHandler = (nextIndex: number) => {
- setTimeout(() => {
- if (slideRef.current) {
- setActiveTransition(false);
- }
- setCurrentIndex(nextIndex);
+ useEffect(() => {
+ const handleInfiniteSlide = (nextIndex: number) => {
setTimeout(() => {
if (slideRef.current) {
- setActiveTransition(true);
+ setActiveTransition(false);
}
- }, 100);
- }, 500);
- };
-
- if (currentIndex === notificationArray.length - 1) {
- InfiniteSlideHandler(1);
- }
+ setCurrentIndex(nextIndex);
+ setTimeout(() => {
+ if (slideRef.current) {
+ setActiveTransition(true);
+ }
+ }, 100);
+ }, 500);
+ };
+ if (currentIndex === notificationArray.length - 1) {
+ handleInfiniteSlide(0);
+ }
+ }, [currentIndex, notificationArray.length]);
- if (currentIndex === 0) {
- InfiniteSlideHandler(Dummy.length);
- }
+ return (
+
+ {announcements.length === 0 ? (
+ 공지사항이 없습니다.
+ ) : (
+
+ {notificationArray.map((item) => (
+ {item.notification}
+ ))}
+
+ )}
+
+ );
+};
+export const Notification = () => {
return (
-
-
- {notificationArray.map((item) => (
- {item.notification}
- ))}
-
-
+ (
+ Error: {error.message}
+ )}
+ >
+ 로딩중...}>
+
+
+
);
diff --git a/src/home/components/SignupContents/EmailForm/EmailForm.tsx b/src/home/components/SignupContents/EmailForm/EmailForm.tsx
index 654e5e56..2ccc4cb6 100644
--- a/src/home/components/SignupContents/EmailForm/EmailForm.tsx
+++ b/src/home/components/SignupContents/EmailForm/EmailForm.tsx
@@ -3,6 +3,7 @@ import { BoxButton, PlainButton, SuffixTextField } from '@yourssu/design-system-
import { EMAIL_DOMAIN } from '@/constants/email.constant';
import { EmailFormProps } from '@/home/components/SignupContents/EmailForm/EmailForm.type.ts';
import { useEmailForm } from '@/home/components/SignupContents/EmailForm/useEmailForm.ts';
+import { usePreventDuplicateClick } from '@/hooks/usePreventDuplicateClick.ts';
import {
StyledSignupButtonText,
@@ -18,7 +19,8 @@ import {
} from './EmailForm.style';
export const EmailForm = ({ onConfirm }: EmailFormProps) => {
- const { email, emailSending, emailError, onEmailSubmit, onChange } = useEmailForm({ onConfirm });
+ const { email, emailError, onEmailSubmit, onChange } = useEmailForm({ onConfirm });
+ const { disabled, handleClick } = usePreventDuplicateClick();
return (
@@ -47,8 +49,8 @@ export const EmailForm = ({ onConfirm }: EmailFormProps) => {
size="large"
variant="filled"
rounding={8}
- disabled={email === '' || emailSending}
- onClick={onEmailSubmit}
+ disabled={email === '' || disabled}
+ onClick={() => handleClick(onEmailSubmit)}
>
인증 메일 받기
diff --git a/src/home/components/SignupContents/EmailForm/useEmailForm.ts b/src/home/components/SignupContents/EmailForm/useEmailForm.ts
index 04768bf3..57bdde54 100644
--- a/src/home/components/SignupContents/EmailForm/useEmailForm.ts
+++ b/src/home/components/SignupContents/EmailForm/useEmailForm.ts
@@ -7,7 +7,6 @@ import { useFullEmail } from '@/hooks/useFullEmail';
export const useEmailForm = ({ onConfirm }: EmailFormProps) => {
const [email, setEmail] = useState('');
const [emailError, setEmailError] = useState(undefined);
- const [emailSending, setEmailSending] = useState(false);
const fullEmail = useFullEmail(email);
const onChange = (e: React.ChangeEvent) => {
@@ -15,17 +14,13 @@ export const useEmailForm = ({ onConfirm }: EmailFormProps) => {
};
const onEmailSubmit = async () => {
- setEmailSending(true);
-
const res = await postAuthVerificationEmail({ email: fullEmail, verificationType: 'SIGN_UP' });
if (res.data) {
onConfirm(fullEmail);
} else {
setEmailError(res.error?.response?.data.message || '이메일을 다시 확인해주세요.');
}
-
- setEmailSending(false);
};
- return { email, emailError, emailSending, onChange, onEmailSubmit };
+ return { email, emailError, onChange, onEmailSubmit };
};
diff --git a/src/home/components/SignupContents/SignupForm/SignupForm.tsx b/src/home/components/SignupContents/SignupForm/SignupForm.tsx
index b004f428..750ccc04 100644
--- a/src/home/components/SignupContents/SignupForm/SignupForm.tsx
+++ b/src/home/components/SignupContents/SignupForm/SignupForm.tsx
@@ -2,6 +2,7 @@ import { BoxButton, PasswordTextField, SimpleTextField } from '@yourssu/design-s
import { SignupFormProps } from '@/home/components/SignupContents/SignupForm/SignUpForm.type.ts';
import { useSignUpForm } from '@/home/components/SignupContents/SignupForm/useSignUpForm.ts';
+import { usePreventDuplicateClick } from '@/hooks/usePreventDuplicateClick.ts';
import { useSignupFormValidation } from '@/hooks/useSignupFormValidator.ts';
import {
@@ -19,6 +20,8 @@ export const SignupForm = ({ email, onConfirm }: SignupFormProps) => {
const { nicknameValidOnce, passwordValidOnce, isFormValid, isNicknameValid, isPasswordValid } =
useSignupFormValidation(nickname, password);
+ const { disabled, handleClick } = usePreventDuplicateClick();
+
return (
회원가입
@@ -39,7 +42,7 @@ export const SignupForm = ({ email, onConfirm }: SignupFormProps) => {
/>
{
@@ -51,8 +54,8 @@ export const SignupForm = ({ email, onConfirm }: SignupFormProps) => {
rounding={8}
size="large"
variant="filled"
- onClick={onFormConfirm}
- disabled={!isFormValid}
+ onClick={() => handleClick(onFormConfirm)}
+ disabled={!isFormValid || disabled}
>
회원가입
diff --git a/src/home/components/UserInformationCard/UserInformationCard.tsx b/src/home/components/UserInformationCard/UserInformationCard.tsx
index fa6a18f5..3587d73a 100644
--- a/src/home/components/UserInformationCard/UserInformationCard.tsx
+++ b/src/home/components/UserInformationCard/UserInformationCard.tsx
@@ -3,8 +3,8 @@ import { useState } from 'react';
import { BoxButton, IcSettingLine, SimpleTextField } from '@yourssu/design-system-react';
import { useTheme } from 'styled-components';
-import Ppussung from '@/assets/home/defaultProfile.png';
-import { ProfileSvg } from '@/home/components/UserInformationCard/ProfileSVG';
+import Ppussung from '@/assets/defaultProfile.png';
+import { ProfileSvg } from '@/components/ProfileSvg/ProfileSVG';
import {
StyledButtonContainer,
diff --git a/src/home/hooks/useGetAnnouncement.ts b/src/home/hooks/useGetAnnouncement.ts
index d5dad54e..f160c99f 100644
--- a/src/home/hooks/useGetAnnouncement.ts
+++ b/src/home/hooks/useGetAnnouncement.ts
@@ -1,12 +1,11 @@
-import { useQuery } from '@tanstack/react-query';
+import { useSuspenseQuery } from '@tanstack/react-query';
import { getAnnouncement } from '@/home/apis/getAnnouncement';
export const useGetAnnouncement = () => {
- return useQuery({
+ return useSuspenseQuery({
queryKey: ['announcement'],
- queryFn: () => {
- return getAnnouncement();
- },
+ queryFn: getAnnouncement,
+ select: (data) => data.announcementList,
});
};
diff --git a/src/home/hooks/useGetUserData.ts b/src/home/hooks/useGetUserData.ts
index 6233a2fe..c9eb309a 100644
--- a/src/home/hooks/useGetUserData.ts
+++ b/src/home/hooks/useGetUserData.ts
@@ -1,19 +1,17 @@
import { useQuery } from '@tanstack/react-query';
-import { useSetRecoilState } from 'recoil';
+import { useRecoilValue } from 'recoil';
import { getUserData } from '@/home/apis/getUserData';
-import { UserState } from '@/home/recoil/UserState';
+
+import { LogInState } from '../recoil/LogInState';
export const useGetUserData = () => {
- const setUserData = useSetRecoilState(UserState);
+ const isLoggedIn = useRecoilValue(LogInState);
+
return useQuery({
queryKey: ['userData'],
- queryFn: async () => {
- const data = await getUserData();
- setUserData(data);
-
- return data;
- },
- enabled: false,
+ queryFn: getUserData,
+ enabled: isLoggedIn,
+ staleTime: Infinity,
});
};
diff --git a/src/home/hooks/usePostLogin.ts b/src/home/hooks/usePostLogin.ts
new file mode 100644
index 00000000..51692cf3
--- /dev/null
+++ b/src/home/hooks/usePostLogin.ts
@@ -0,0 +1,31 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import axios from 'axios';
+import { useSetRecoilState } from 'recoil';
+
+import { api } from '@/service/TokenService';
+
+import { postAuthSignIn } from '../apis/postAuthSignIn';
+import { LogInState } from '../recoil/LogInState';
+
+export const usePostLogin = () => {
+ const queryClient = useQueryClient();
+ const setIsLoggedIn = useSetRecoilState(LogInState);
+
+ return useMutation({
+ mutationFn: postAuthSignIn,
+ onSuccess: (data) => {
+ api.setAccessToken(data.accessToken, data.accessTokenExpiredIn);
+ api.setRefreshToken(data.refreshToken, data.refreshTokenExpiredIn);
+ setIsLoggedIn(true);
+ queryClient.invalidateQueries({ queryKey: ['userData'] });
+ },
+ throwOnError: (error) => {
+ // response status code가 401일 경우 에러가 ErrorBoundary로 전달되지 않도록 함
+ if (axios.isAxiosError(error)) {
+ return error.response?.status != 401;
+ }
+
+ return true;
+ },
+ });
+};
diff --git a/src/home/pages/Home/Home.tsx b/src/home/pages/Home/Home.tsx
index f3c6953d..139545c2 100644
--- a/src/home/pages/Home/Home.tsx
+++ b/src/home/pages/Home/Home.tsx
@@ -1,12 +1,9 @@
-import { useRecoilValue } from 'recoil';
-
import { RealTimeKeyword } from '@/components/RealTimeKeyword/RealTimeKeyword.tsx';
import { DrawerRanking } from '@/home/components/DrawerRanking/DrawerRanking';
import { Header } from '@/home/components/Header/Header';
import { Nav } from '@/home/components/Nav/Nav';
import { Notification } from '@/home/components/Notification/Notification';
import { SocialNetworkService } from '@/home/components/SocialNetworkService/SocialNetworkService';
-import { LogInState } from '@/home/recoil/LogInState';
import {
StyledComponentContainer,
@@ -15,11 +12,9 @@ import {
} from './Home.style';
export const Home = () => {
- const isLoggedIn = useRecoilValue(LogInState);
-
return (
-
+
diff --git a/src/home/pages/Login/Login.tsx b/src/home/pages/Login/Login.tsx
index 1e9ef2ff..efbc8eee 100644
--- a/src/home/pages/Login/Login.tsx
+++ b/src/home/pages/Login/Login.tsx
@@ -6,19 +6,14 @@ import {
PlainButton,
SuffixTextField,
} from '@yourssu/design-system-react';
-import { useErrorBoundary } from 'react-error-boundary';
import { useNavigate } from 'react-router-dom';
-import { useSetRecoilState } from 'recoil';
import { EMAIL_DOMAIN } from '@/constants/email.constant';
-import { postAuthSignIn } from '@/home/apis/postAuthSignIn';
import { StyledSignupContentTitle } from '@/home/components/SignupContents/SignupContents.style';
import { SignupFrame } from '@/home/components/SignupFrame/SignupFrame';
-import { useGetUserData } from '@/home/hooks/useGetUserData';
-import { LogInState } from '@/home/recoil/LogInState';
+import { usePostLogin } from '@/home/hooks/usePostLogin';
import { useFullEmail } from '@/hooks/useFullEmail';
import { useRedirectLoggedInEffect } from '@/hooks/useRedirectLoggedInEffect';
-import { api } from '@/service/TokenService';
import {
StyledBottomButtonContainer,
@@ -30,34 +25,20 @@ import {
export const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
- const [failedLogin, setFailedLogin] = useState(false);
- const setIsLoggedIn = useSetRecoilState(LogInState);
- const { showBoundary } = useErrorBoundary();
- const { refetch } = useGetUserData();
+
const navigate = useNavigate();
const fullEmail = useFullEmail(email);
+ const loginMutation = usePostLogin();
- const handleLoginClick = async () => {
- const { data, error } = await postAuthSignIn({ email: fullEmail, password });
-
- if (data) {
- api.setAccessToken(data.accessToken, data.accessTokenExpiredIn);
- api.setRefreshToken(data.refreshToken, data.refreshTokenExpiredIn);
- setIsLoggedIn(true);
- refetch();
- navigate('/');
- return;
- }
-
- if (error?.response?.status == 401) {
- setFailedLogin(true);
- return;
- }
-
- if (error?.response?.status != 400) {
- showBoundary(error);
- return;
- }
+ const handleClickLogin = () => {
+ loginMutation.mutate(
+ { email: fullEmail, password },
+ {
+ onSuccess: () => {
+ navigate('/');
+ },
+ }
+ );
};
// 로그인 상태에서는 홈으로 리다이렉트
@@ -72,22 +53,28 @@ export const Login = () => {
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="ppushoong"
- isNegative={failedLogin}
+ isNegative={loginMutation.isError}
suffix={EMAIL_DOMAIN}
/>
setPassword(e.target.value)}
- isNegative={failedLogin}
+ isNegative={loginMutation.isError}
/>
-
+
로그인
diff --git a/src/home/pages/Withdraw/Withdraw.tsx b/src/home/pages/Withdraw/Withdraw.tsx
index 8ad7563c..a31d0059 100644
--- a/src/home/pages/Withdraw/Withdraw.tsx
+++ b/src/home/pages/Withdraw/Withdraw.tsx
@@ -1,11 +1,13 @@
import { useState } from 'react';
import { BoxButton, CheckBox } from '@yourssu/design-system-react';
+import { ErrorBoundary } from 'react-error-boundary';
import { useNavigate } from 'react-router-dom';
import Logo from '@/assets/soomsil_logo.svg';
-import { postWithdraw } from '@/home/apis/postWithdraw';
+import { Fallback } from '@/components/Fallback/Fallback';
import { WithdrawSuccess } from '@/home/components/WithdrawSuccess/WithdrawSuccess';
+import { usePostWithdraw } from '@/hooks/usePostWithdraw';
import {
StyledButtonText,
@@ -22,6 +24,7 @@ export const Withdraw = () => {
const navigate = useNavigate();
const [agreed, setAgreed] = useState(false);
const [draw, setDraw] = useState(false);
+ const withdrawMutation = usePostWithdraw();
const handleGoToHome = () => {
navigate('/');
@@ -31,60 +34,63 @@ export const Withdraw = () => {
setAgreed((prevAgreed) => !prevAgreed);
};
- const handleWithdrawAgree = async () => {
- try {
- const { success, error } = await postWithdraw();
- if (success) {
- setDraw((prevDraw) => !prevDraw);
- } else if (error) {
- alert(`탈퇴 처리에 실패했습니다: ${error.message}`);
+ const handleWithdrawAgree = () => {
+ withdrawMutation.mutate(
+ {},
+ {
+ onSuccess: () => {
+ setDraw((prevDraw) => !prevDraw);
+ },
}
- } catch (error) {
- if (error instanceof Error) {
- alert(`탈퇴 처리 중 오류가 발생했습니다: ${error.message}`);
- } else {
- alert(`알 수 없는 오류가 발생했습니다`);
- }
- }
+ );
};
return (
-
-
-
- {draw ? (
-
- ) : (
- <>
- 계정 탈퇴
- 계정 탈퇴 전 꼭 확인하세요.
-
- 탈퇴하는 즉시 데이터가 제거되며, 복구가 불가능합니다.
-
- 닉네임, 이메일 등 사용자를 특정할 수 있는 모든 계정 정보가 지워집니다.
-
-
- 등록된 글이나 댓글의 삭제를 원한다면 탈퇴 이전에 삭제하시기 바랍니다.
-
-
-
-
- 안내사항을 확인하였으며, 이에 동의합니다.
-
-
-
- 탈퇴하기
-
- >
- )}
-
-
+
+
+
+
+ {draw ? (
+
+ ) : (
+ <>
+ 계정 탈퇴
+ 계정 탈퇴 전 꼭 확인하세요.
+
+
+ 탈퇴하는 즉시 데이터가 제거되며, 복구가 불가능합니다.
+
+
+ 닉네임, 이메일 등 사용자를 특정할 수 있는 모든 계정 정보가 지워집니다.
+
+
+ 등록된 글이나 댓글의 삭제를 원한다면 탈퇴 이전에 삭제하시기 바랍니다.
+
+
+
+
+ 안내사항을 확인하였으며, 이에 동의합니다.
+
+
+
+ 탈퇴하기
+
+ >
+ )}
+
+
+
);
};
diff --git a/src/home/recoil/UserState.ts b/src/home/recoil/UserState.ts
deleted file mode 100644
index 711e7916..00000000
--- a/src/home/recoil/UserState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { atom } from 'recoil';
-
-import { UserData } from '@/home/types/user.type';
-
-import { persistAtom } from './persistAtom';
-
-export const UserState = atom({
- key: 'UserState',
- default: null,
- effects_UNSTABLE: [persistAtom],
-});
diff --git a/src/home/types/announcement.type.ts b/src/home/types/announcement.type.ts
index 883ed33e..79e742d7 100644
--- a/src/home/types/announcement.type.ts
+++ b/src/home/types/announcement.type.ts
@@ -1,3 +1,8 @@
+export interface Announcement {
+ id: number;
+ title: string;
+}
+
export interface AnnouncementResponse {
- // TODO: 추후 API 관련 타입 정의 필요
+ announcementList: Announcement[];
}
diff --git a/src/hooks/usePostWithdraw.ts b/src/hooks/usePostWithdraw.ts
new file mode 100644
index 00000000..e0b15d0d
--- /dev/null
+++ b/src/hooks/usePostWithdraw.ts
@@ -0,0 +1,17 @@
+import { useMutation } from '@tanstack/react-query';
+
+import { postWithdraw } from '@/home/apis/postWithdraw';
+
+import { useResetUserInfo } from './useResetUserInfo';
+
+export const usePostWithdraw = () => {
+ const resetUserInfo = useResetUserInfo();
+
+ return useMutation({
+ mutationFn: postWithdraw,
+ onSuccess: () => {
+ resetUserInfo();
+ },
+ throwOnError: true,
+ });
+};
diff --git a/src/hooks/usePreventDuplicateClick.ts b/src/hooks/usePreventDuplicateClick.ts
new file mode 100644
index 00000000..c71161f1
--- /dev/null
+++ b/src/hooks/usePreventDuplicateClick.ts
@@ -0,0 +1,20 @@
+import { useCallback, useRef, useState } from 'react';
+
+export const usePreventDuplicateClick = () => {
+ const [disabled, setDisabled] = useState(false);
+ const loadingRef = useRef(false);
+
+ const handleClick = useCallback(async (callback: () => Promise) => {
+ if (loadingRef.current) return;
+
+ loadingRef.current = true;
+ setDisabled(true);
+
+ await callback();
+
+ loadingRef.current = false;
+ setDisabled(false);
+ }, []);
+
+ return { disabled, handleClick };
+};
diff --git a/src/hooks/useResetUserInfo.ts b/src/hooks/useResetUserInfo.ts
new file mode 100644
index 00000000..c31116ad
--- /dev/null
+++ b/src/hooks/useResetUserInfo.ts
@@ -0,0 +1,13 @@
+import { useSetRecoilState } from 'recoil';
+
+import { LogInState } from '@/home/recoil/LogInState';
+import { api } from '@/service/TokenService';
+
+export const useResetUserInfo = () => {
+ const resetLoginState = useSetRecoilState(LogInState);
+
+ return () => {
+ resetLoginState(false);
+ api.logout();
+ };
+};
diff --git a/src/hooks/useSignupFormValidator.ts b/src/hooks/useSignupFormValidator.ts
index bde5e5df..f3de8a89 100644
--- a/src/hooks/useSignupFormValidator.ts
+++ b/src/hooks/useSignupFormValidator.ts
@@ -1,19 +1,28 @@
import { useMemo, useRef } from 'react';
+import { hasNumberAndEnglishWithSymbols, hasNumberOrEnglishOrHangulOrSpace } from '@yourssu/utils';
+
export const useSignupFormValidation = (nickname: string, password: string) => {
const nicknameValidOnce = useRef(false);
const passwordValidOnce = useRef(false);
- const hasOnlyNumberAndEnglish = (value: string) => /^[a-zA-Z0-9]*$/.test(value);
- const hasOnlyNumberEnglishAndHangul = (value: string) =>
- /^[ㄱ-ㅎ|가-힣|a-z|A-Z|0-9|]*$/.test(value);
+ function isBlank(value: string): boolean {
+ return /^\s*$/.test(value);
+ }
const isNicknameValid = useMemo(() => {
- return nickname.length >= 2 && nickname.length <= 12 && hasOnlyNumberEnglishAndHangul(nickname);
+ return (
+ nickname.length >= 2 &&
+ nickname.length <= 12 &&
+ hasNumberOrEnglishOrHangulOrSpace(nickname) &&
+ !isBlank(nickname)
+ );
}, [nickname]);
const isPasswordValid = useMemo(() => {
- return password.length >= 8 && hasOnlyNumberAndEnglish(password);
+ return (
+ password.length >= 8 && password.length <= 100 && hasNumberAndEnglishWithSymbols(password)
+ );
}, [password]);
return {
diff --git a/src/main.tsx b/src/main.tsx
index 93b3bcd2..90512edf 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,16 +1,20 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { YDSWrapper } from '@yourssu/design-system-react';
+import { YLSWrapper } from '@yourssu/logging-system-react';
import ReactDOM from 'react-dom/client';
import { App } from './App';
import './index.css';
const queryClient = new QueryClient();
+const baseURL = import.meta.env.VITE_API_YLS_URL;
ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
-
+
+
+
+
+
);
diff --git a/src/recoil/DialogState.ts b/src/recoil/DialogState.ts
new file mode 100644
index 00000000..ddb52983
--- /dev/null
+++ b/src/recoil/DialogState.ts
@@ -0,0 +1,8 @@
+import { atom } from 'recoil';
+
+import { DialogData } from '@/types/dialog.type';
+
+export const DialogState = atom({
+ key: 'DialogState',
+ default: null,
+});
diff --git a/src/types/dialog.type.ts b/src/types/dialog.type.ts
new file mode 100644
index 00000000..791b04e2
--- /dev/null
+++ b/src/types/dialog.type.ts
@@ -0,0 +1,6 @@
+import { DIALOG } from '@/constants/dialog.constant';
+
+export interface DialogData {
+ open: boolean;
+ type: keyof typeof DIALOG;
+}