Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion umc-master/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ํ™ˆ๋งˆ์Šคํ„ฐ</title>
<script src="https://t1.kakaocdn.net/kakao_js_sdk/2.7.4/kakao.min.js" crossorigin="anonymous"></script>
<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
</head>
<body>
<div id="root"></div>
Expand Down
50 changes: 15 additions & 35 deletions umc-master/src/apis/authApi.ts
Original file line number Diff line number Diff line change
@@ -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;
};
10 changes: 3 additions & 7 deletions umc-master/src/apis/axios-instance.ts
Original file line number Diff line number Diff line change
@@ -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,
});
Expand Down Expand Up @@ -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);
}
}
Expand Down
30 changes: 30 additions & 0 deletions umc-master/src/components/Auth/AuthWrapper.tsx
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 5 additions & 5 deletions umc-master/src/components/Modal/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ import { getUsers } from '@apis/profileApi';
interface ProfileModalProps {
isOpen: boolean;
onClose: () => void;
profileImage: string;
}

const ProfileModal: React.FC<ProfileModalProps> = ({ isOpen, onClose }) => {
const ProfileModal: React.FC<ProfileModalProps> = ({ isOpen, onClose, profileImage }) => {
if (!isOpen) return null;
const navigate = useNavigate();
const { clearAuth } = useAuthStore();
const { user, fetchUser } = useUserStore();

useEffect(() => {
fetchUser(); // ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
fetchUser();
}, []);
getUsers();

Expand All @@ -39,7 +40,7 @@ const ProfileModal: React.FC<ProfileModalProps> = ({ isOpen, onClose }) => {
<CloseIcon />
</CloseButton>
<ProfileWrapper>
<ProfileImage />
<ProfileImage src={profileImage} alt="Profile Image" />
<Typography variant="titleXSmall">{user?.nickname} ๋‹˜</Typography>
</ProfileWrapper>
<MenuList>
Expand Down Expand Up @@ -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%;
Expand Down Expand Up @@ -138,7 +139,6 @@ const MenuItem = styled.li`
}
`;

// "๋งˆ์ดํŽ˜์ด์ง€" ๋งํฌ ์ „์šฉ ์ปดํฌ๋„ŒํŠธ
const MenuItemLink = styled(Link)`
display: flex;
align-items: center;
Expand Down
28 changes: 22 additions & 6 deletions umc-master/src/components/NavigationBar/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,34 @@ const NavigationBar: React.FC<NavigationBarProps> = ({ login }) => {
}, []);
getUsers();

const handleNavClick = () => {
window.scrollTo(0, 0);
};

const toggleAlarmModal = () => setIsAlarmModalOpen((prev) => !prev);
const toggleProfileModal = () => setIsProfileModalOpen((prev) => !prev);

return (
<Container>
<Nav>
<LeftSection>
<NavLink to={RoutePaths.MAIN}>
<NavLink to={RoutePaths.MAIN} onClick={handleNavClick}>
<Logo src={LogoImage} alt="Logo" />
</NavLink>
<Typography variant="titleXxSmall">
<MenuItems>
<StyledNavLink to={RoutePaths.MAGAZINE}>๋งค๊ฑฐ์ง„</StyledNavLink>
<StyledNavLink to={RoutePaths.COMMUNITY}>๊ฟ€ํŒ๋‚˜๋ˆ”</StyledNavLink>
<StyledNavLink to={RoutePaths.SAVE_TIP}>์ €์žฅํ•œ ๊ฟ€ํŒ</StyledNavLink>
<StyledNavLink to={RoutePaths.CHALLENGE}>์ฑŒ๋ฆฐ์ง€</StyledNavLink>
<StyledNavLink to={RoutePaths.MAGAZINE} onClick={handleNavClick}>
๋งค๊ฑฐ์ง„
</StyledNavLink>
<StyledNavLink to={RoutePaths.COMMUNITY} onClick={handleNavClick}>
๊ฟ€ํŒ๋‚˜๋ˆ”
</StyledNavLink>
<StyledNavLink to={RoutePaths.SAVE_TIP} onClick={handleNavClick}>
์ €์žฅํ•œ ๊ฟ€ํŒ
</StyledNavLink>
<StyledNavLink to={RoutePaths.CHALLENGE} onClick={handleNavClick}>
์ฑŒ๋ฆฐ์ง€
</StyledNavLink>
</MenuItems>
</Typography>
</LeftSection>
Expand All @@ -63,7 +75,11 @@ const NavigationBar: React.FC<NavigationBarProps> = ({ login }) => {
</Nav>

<AlarmModal isOpen={isAlarmModalOpen} onClose={toggleAlarmModal} />
<ProfileModal isOpen={isProfileModalOpen} onClose={toggleProfileModal} />
<ProfileModal
isOpen={isProfileModalOpen}
onClose={toggleProfileModal}
profileImage={user?.profile_image_url || gray_character}
/>
</Container>
);
};
Expand Down
70 changes: 29 additions & 41 deletions umc-master/src/pages/auth/KakaoCallback.tsx
Original file line number Diff line number Diff line change
@@ -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 <div>์นด์นด์˜ค ๋กœ๊ทธ์ธ ์ค‘โ€ฆ</div>;
return <></>;
};

export default KakaoCallback;
Loading