diff --git a/umc-master/index.html b/umc-master/index.html
index e76b095..14b710e 100644
--- a/umc-master/index.html
+++ b/umc-master/index.html
@@ -11,7 +11,7 @@
/>
홈마스터
-
+
diff --git a/umc-master/src/apis/authApi.ts b/umc-master/src/apis/authApi.ts
index 55d9c5c..0052887 100644
--- a/umc-master/src/apis/authApi.ts
+++ b/umc-master/src/apis/authApi.ts
@@ -1,38 +1,18 @@
-// import axiosInstance from '@apis/axios-instance';
+import axiosInstance from '@apis/axios-instance';
-// interface UserSignup {
-// email: string;
-// password: string;
-// nickname: string;
-// hashtags: string[];
-// }
+interface UserSignup {
+ email: string;
+ password: string;
+ nickname: string;
+ hashtags: string[];
+}
-// export const postSignup = async ({ email, password, nickname, hashtags } : UserSignup) => {
-// const { data } = await axiosInstance.post(`/signup`, {
-// email,
-// password,
-// nickname,
-// hashtags,
-// });
-// return data;
-// };
-
-import axios from 'axios';
-
-export const postSignup = async () => {
- try {
- const response = await axios.post('https://api.hmaster.shop/api/v1/signup', {
- email: 'ekos555@naver.com',
- password: 'asfa1234!@',
- nickname: 'rael',
- hashtags: ['봄', '패션', '청소', '요리', '재활용', '주택']
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
- console.log('회원가입 성공:', response.data);
- } catch (error) {
- console.error('회원가입 오류:', error);
- }
+export const postSignup = async ({ email, password, nickname, hashtags }: UserSignup) => {
+ const { data } = await axiosInstance.post(`/signup`, {
+ email,
+ password,
+ nickname,
+ hashtags,
+ });
+ return data;
};
diff --git a/umc-master/src/apis/axios-instance.ts b/umc-master/src/apis/axios-instance.ts
index 6afb7ac..5add23a 100644
--- a/umc-master/src/apis/axios-instance.ts
+++ b/umc-master/src/apis/axios-instance.ts
@@ -1,11 +1,12 @@
-import RoutePaths from '@router/routePaths';
import { useTokenStore } from '@store/tokenStore';
import axios, { AxiosInstance } from 'axios';
+const { accessToken } = useTokenStore.getState();
+
const axiosInstance: AxiosInstance = axios.create({
headers: {
accept: 'application/json',
- Authorization: `Bearer ${import.meta.env.VITE_ACCESS_TOKEN}`,
+ Authorization: `Bearer ${accessToken}`,
},
baseURL: import.meta.env.VITE_BASE_URL,
});
@@ -69,11 +70,6 @@ axiosInstance.interceptors.response.use(
console.error('토큰 갱신 실패:', refreshError);
useTokenStore.getState().clearTokens();
- // 로그인 페이지로 리다이렉트
- if (window.location.pathname !== RoutePaths.LOGIN) {
- window.location.href = RoutePaths.LOGIN;
- }
-
return Promise.reject(refreshError);
}
}
diff --git a/umc-master/src/components/Auth/AuthWrapper.tsx b/umc-master/src/components/Auth/AuthWrapper.tsx
new file mode 100644
index 0000000..933ab93
--- /dev/null
+++ b/umc-master/src/components/Auth/AuthWrapper.tsx
@@ -0,0 +1,30 @@
+import { useEffect } from 'react';
+import { useNavigate, useLocation } from 'react-router-dom';
+import { useTokenStore } from '@store/tokenStore';
+import RoutePaths from '@router/routePaths';
+
+interface AuthWrapperProps {
+ children: React.ReactNode;
+}
+
+const AuthWrapper = ({ children }: AuthWrapperProps) => {
+ const navigate = useNavigate();
+ const location = useLocation();
+ const { accessToken } = useTokenStore.getState();
+
+ useEffect(() => {
+ // 로그인 페이지가 아니고 토큰이 없는 경우 리다이렉트
+ if (!accessToken && location.pathname !== RoutePaths.LANDING) {
+ navigate(RoutePaths.LOGIN, { replace: true });
+ }
+ }, [accessToken, location.pathname, navigate]);
+
+ // 토큰이 없고 로그인 페이지가 아닌 경우 아무것도 렌더링하지 않음
+ if (!accessToken && location.pathname !== RoutePaths.LOGIN) {
+ return null;
+ }
+
+ return <>{children}>;
+};
+
+export default AuthWrapper;
diff --git a/umc-master/src/components/Modal/profile.tsx b/umc-master/src/components/Modal/profile.tsx
index 0c0d5ed..5f4d3d2 100644
--- a/umc-master/src/components/Modal/profile.tsx
+++ b/umc-master/src/components/Modal/profile.tsx
@@ -14,16 +14,17 @@ import { getUsers } from '@apis/profileApi';
interface ProfileModalProps {
isOpen: boolean;
onClose: () => void;
+ profileImage: string;
}
-const ProfileModal: React.FC = ({ isOpen, onClose }) => {
+const ProfileModal: React.FC = ({ isOpen, onClose, profileImage }) => {
if (!isOpen) return null;
const navigate = useNavigate();
const { clearAuth } = useAuthStore();
const { user, fetchUser } = useUserStore();
useEffect(() => {
- fetchUser(); // 컴포넌트 마운트 시 사용자 정보 가져오기
+ fetchUser();
}, []);
getUsers();
@@ -39,7 +40,7 @@ const ProfileModal: React.FC = ({ isOpen, onClose }) => {
-
+
{user?.nickname} 님
@@ -109,7 +110,7 @@ const ProfileWrapper = styled.div`
padding: 20px 0;
`;
-const ProfileImage = styled.div`
+const ProfileImage = styled.img`
width: 60px;
height: 60px;
border-radius: 50%;
@@ -138,7 +139,6 @@ const MenuItem = styled.li`
}
`;
-// "마이페이지" 링크 전용 컴포넌트
const MenuItemLink = styled(Link)`
display: flex;
align-items: center;
diff --git a/umc-master/src/components/NavigationBar/NavigationBar.tsx b/umc-master/src/components/NavigationBar/NavigationBar.tsx
index 9846272..698f53a 100644
--- a/umc-master/src/components/NavigationBar/NavigationBar.tsx
+++ b/umc-master/src/components/NavigationBar/NavigationBar.tsx
@@ -26,6 +26,10 @@ const NavigationBar: React.FC = ({ login }) => {
}, []);
getUsers();
+ const handleNavClick = () => {
+ window.scrollTo(0, 0);
+ };
+
const toggleAlarmModal = () => setIsAlarmModalOpen((prev) => !prev);
const toggleProfileModal = () => setIsProfileModalOpen((prev) => !prev);
@@ -33,15 +37,23 @@ const NavigationBar: React.FC = ({ login }) => {
-
+
);
};
diff --git a/umc-master/src/pages/auth/KakaoCallback.tsx b/umc-master/src/pages/auth/KakaoCallback.tsx
index ff9e035..918e89d 100644
--- a/umc-master/src/pages/auth/KakaoCallback.tsx
+++ b/umc-master/src/pages/auth/KakaoCallback.tsx
@@ -1,54 +1,42 @@
import React, { useEffect } from 'react';
-import axios from 'axios';
import { useNavigate } from 'react-router-dom';
+import axiosInstance from '@apis/axios-instance';
+import { useTokenStore } from '@store/tokenStore';
+import { useAuthStore } from '@store/authStore';
const KakaoCallback: React.FC = () => {
-
+ const { setAuth } = useAuthStore();
+ const { setTokens } = useTokenStore();
const navigate = useNavigate();
useEffect(() => {
- const getAccessToken = async () => {
- const queryParams = new URLSearchParams(window.location.search);
- const code = queryParams.get('code');
-
- if (!code) {
- console.error('Authorization code not found');
- return;
- }
-
- try {
- // 카카오에서 Access Token 요청
- const response = await axios.post('https://kauth.kakao.com/oauth/token', {
- grant_type: 'authorization_code',
- client_id: import.meta.env.VITE_KAKAO_API_KEY,
- redirect_uri: 'http://localhost:3000/oauth/kakao/callback',
- code,
- });
-
- const kakaoAccessToken = response.data.access_token;
-
- // 백엔드로 카카오 Access Token 전송
- const backendResponse = await axios.post('http://localhost:3000/login/kakao', {
- kakaoAccessToken,
+ const urlParams = new URLSearchParams(window.location.search);
+ const code = urlParams.get('code');
+
+ if (code) {
+ console.log('✅ 카카오 로그인 코드 확인:', code);
+
+ axiosInstance
+ .post('/login/kakao', { code })
+ .then((response) => {
+ const { accessToken, refreshToken } = response.data.result;
+ setTokens({ accessToken, refreshToken });
+ localStorage.setItem('accessToken', accessToken);
+ localStorage.setItem('refreshToken', refreshToken);
+ setAuth(true);
+ navigate('/main');
+ })
+ .catch(() => {
+ // console.error('❌ 카카오 로그인 실패:', error.response?.data || error.message);
+ // alert(error.response?.data?.message || '카카오 로그인에 실패했습니다.');
+ navigate('/');
});
-
- const { accessToken, refreshToken } = backendResponse.data.result;
-
- // Access Token 및 Refresh Token 저장 (예: 로컬 스토리지)
- localStorage.setItem('accessToken', accessToken);
- localStorage.setItem('refreshToken', refreshToken);
-
- // 홈 또는 사용자 대시보드로 이동
- navigate('/');
- } catch (error) {
- console.error('Failed to login with Kakao:', error);
- }
- };
-
- getAccessToken();
+ } else {
+ console.warn('⚠️ 카카오 로그인 코드 없음');
+ }
}, [navigate]);
- return 카카오 로그인 중…
;
+ return <>>;
};
export default KakaoCallback;
diff --git a/umc-master/src/pages/auth/Login_components/InputForm.tsx b/umc-master/src/pages/auth/Login_components/InputForm.tsx
index 2204ddb..5fafebb 100644
--- a/umc-master/src/pages/auth/Login_components/InputForm.tsx
+++ b/umc-master/src/pages/auth/Login_components/InputForm.tsx
@@ -4,7 +4,7 @@ import styled from 'styled-components';
import Input from '@components/Input/Input';
import useInput from '@hooks/useInput';
import { validateEmailFormat, validatePasswordFormat } from '@utils/validation';
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import Button from '@components/Button/Button';
import Kakao_Image from '@assets/kakao_login/kakao_login_large_wide.png';
import { useNavigate } from 'react-router-dom';
@@ -12,14 +12,49 @@ import axiosInstance from '@apis/axios-instance';
import { useAuthStore } from '@store/authStore';
import { useTokenStore } from '@store/tokenStore';
+const KAKAO_REDIRECT_URI =
+ import.meta.env.MODE === 'development'
+ ? 'http://localhost:5173/oauth/kakao/callback'
+ : 'https://www.hmaster.shop/oauth/kakao/callback';
+
const InputForm: React.FC = () => {
const { setAuth } = useAuthStore();
- const { setTokens } = useTokenStore.getState();
+ const { setTokens } = useTokenStore();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (!window.Kakao) {
+ console.warn('⚠️ window.Kakao가 없음, SDK 로드 시작');
+
+ const script = document.createElement('script');
+ script.src = 'https://developers.kakao.com/sdk/js/kakao.js';
+ script.async = true;
+ script.onload = () => {
+ console.log('✅ 카카오 SDK 로드 완료:', window.Kakao);
+ if (window.Kakao && !window.Kakao.isInitialized()) {
+ console.error('❌ window.Kakao는 있지만 초기화되지 않음! init() 필요');
+ window.Kakao.init(import.meta.env.VITE_JAVASCRIPT_KEY);
+ console.log('✅ 카카오 SDK 강제 초기화 완료');
+ }
+ };
+ document.head.appendChild(script);
+ } else {
+ console.log('✅ window.Kakao 이미 로드됨');
+ if (!window.Kakao.isInitialized()) {
+ console.error('❌ window.Kakao는 있지만 초기화되지 않음! init() 필요');
+ window.Kakao.init(import.meta.env.VITE_JAVASCRIPT_KEY);
+ console.log('✅ 카카오 SDK 강제 초기화 완료');
+ }
+ }
+ }, []);
const handleKakaoLogin = () => {
- const KAKAO_API_KEY = import.meta.env.VITE_KAKAO_API_KEY;
- const kakaoAuthUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_API_KEY}&redirect_uri=http://localhost:3000/oauth/kakao/callback&response_type=code`;
- window.location.href = kakaoAuthUrl;
+ const clientId = import.meta.env.VITE_JAVASCRIPT_KEY;
+ const redirectUri = encodeURIComponent(KAKAO_REDIRECT_URI);
+ const fallbackUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`;
+
+ console.log('✅ fallback URL로 리디렉션:', fallbackUrl);
+ window.location.href = fallbackUrl;
};
const handleEmailLogin = async () => {
@@ -72,13 +107,12 @@ const InputForm: React.FC = () => {
e.preventDefault();
setIsSubmitted(true);
- // 이메일 및 비밀번호가 비어있는지 체크하고 오류 메시지 표시
if (!email) {
handleEmailError('이메일을 입력해주세요.');
} else {
const emailError = validateEmailFormat(email);
if (emailError) {
- handleEmailError(emailError); // 이메일 오류 처리
+ handleEmailError(emailError);
}
}
@@ -87,7 +121,7 @@ const InputForm: React.FC = () => {
} else {
const passwordError = validatePasswordFormat(password);
if (passwordError) {
- handlePasswordError(passwordError); // 비밀번호 오류 처리
+ handlePasswordError(passwordError);
}
}
@@ -110,8 +144,6 @@ const InputForm: React.FC = () => {
await handleEmailLogin();
};
- const navigate = useNavigate(); // 추가
-
return (
@@ -132,7 +164,7 @@ const InputForm: React.FC = () => {
-