diff --git a/src/features/auth/api/authApi.ts b/src/features/auth/api/authApi.ts index 7f59e5c..8a043bd 100644 --- a/src/features/auth/api/authApi.ts +++ b/src/features/auth/api/authApi.ts @@ -1,5 +1,5 @@ -import { apiClient } from '@/shared/lib/apiClient'; -import { SocialLoginRequest, AuthResponse } from '../types'; +import { apiClient } from "@/shared/lib/apiClient"; +import { AuthResponse, SocialLoginRequest } from "../types"; export const authApi = { /** @@ -7,11 +7,11 @@ export const authApi = { * @param data 구글/애플/페이스북에서 발급받은 Provider 이름과 Token */ loginWithSocial: async (data: SocialLoginRequest): Promise => { - return apiClient('/auth/social', { - method: 'POST', + return apiClient("api/v1/auth/social", { + method: "POST", body: JSON.stringify(data), }); }, - + // TODO: 이후 필요 시 logout, refreshAccessToken 등 인증 관련 API 추가 }; diff --git a/src/features/auth/components/SocialLoginGroup.tsx b/src/features/auth/components/SocialLoginGroup.tsx index af3a303..a693688 100644 --- a/src/features/auth/components/SocialLoginGroup.tsx +++ b/src/features/auth/components/SocialLoginGroup.tsx @@ -1,39 +1,59 @@ -'use client'; +"use client"; -import React from 'react'; -import { useSocialLogin } from '../hooks/useSocialLogin'; -import { GoogleOAuthProvider } from '@react-oauth/google'; -import FacebookLogin from 'react-facebook-login/dist/facebook-login-render-props'; +import { GoogleOAuthProvider } from "@react-oauth/google"; +import { useSocialLogin } from "../hooks/useSocialLogin"; -const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || ''; -const FACEBOOK_APP_ID = process.env.NEXT_PUBLIC_FACEBOOK_APP_ID || ''; +const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || ""; +const FACEBOOK_APP_ID = process.env.NEXT_PUBLIC_FACEBOOK_APP_ID || ""; /** * 실제 버튼들을 렌더링하고 커스텀 훅(useSocialLogin)을 호출하는 내부 컴포넌트입니다. * 이 컴포넌트는 반드시 GoogleOAuthProvider의 자식으로 존재해야 합니다. */ const SocialLoginButtons = () => { - const { loginWithGoogle, loginWithApple, handleFacebookCallback, isLoading, error } = useSocialLogin(); + const { + loginWithGoogle, + loginWithApple, + handleFacebookCallback, + isLoading, + error, + } = useSocialLogin(); return (
{/* 1. Google 로그인 (useGoogleLogin 훅 연동) */} - {/* 2. Apple 로그인 (react-apple-signin-auth 연동) */} - + */} {/* 3. Facebook 로그인 (react-facebook-login Render Props 연동) */} - ( @@ -60,7 +80,7 @@ const SocialLoginButtons = () => { {isLoading ? '연결 중...' : 'Facebook으로 계속하기'} )} - /> + /> */} {/* 백엔드 연동 에러 메시지 표시 */} {error && ( diff --git a/src/features/auth/hooks/useSocialLogin.ts b/src/features/auth/hooks/useSocialLogin.ts index c957033..547806c 100644 --- a/src/features/auth/hooks/useSocialLogin.ts +++ b/src/features/auth/hooks/useSocialLogin.ts @@ -1,9 +1,9 @@ -import { useState } from 'react'; -import { useRouter } from 'next/navigation'; -import { authApi } from '../api/authApi'; -import { useGoogleLogin } from '@react-oauth/google'; -import appleAuthHelpers from 'react-apple-signin-auth'; -import { useAuthStore } from '@/store/useAuthStore'; +import { useAuthStore } from "@/store/useAuthStore"; +import { useGoogleLogin } from "@react-oauth/google"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import appleAuthHelpers from "react-apple-signin-auth"; +import { authApi } from "../api/authApi"; export const useSocialLogin = () => { const router = useRouter(); @@ -14,24 +14,31 @@ export const useSocialLogin = () => { * [비즈니스 로직 1] 공통 토큰 교환 로직 * 플랫폼별 SDK에서 획득한 토큰을 백엔드로 보내어 VibeRoom 전용 JWT로 교환합니다. */ - const handleSocialLogin = async (provider: 'google' | 'apple' | 'facebook', socialToken: string) => { + const handleSocialLogin = async ( + provider: "google" | "apple" | "facebook", + socialToken: string, + ) => { setIsLoading(true); setError(null); + console.log("token:" + socialToken); try { // 1. 백엔드로 소셜 토큰 전송 (토큰 교환) - const response = await authApi.loginWithSocial({ provider, token: socialToken }); - + const response = await authApi.loginWithSocial({ + provider, + token: socialToken, + }); + console.log(`[${provider}] 백엔드 연동 성공! JWT:`, response.accessToken); - + // 2. 응답받은 VibeRoom 전용 토큰과 유저 정보를 전역 상태 및 쿠키에 저장 useAuthStore.getState().setAuth(response); - + // 3. 메인 대시보드 화면으로 이동 - router.push('/dashboard'); + router.push("/dashboard"); } catch (err) { console.error(`[${provider}] 로그인 실패:`, err); - setError('로그인에 실패했습니다. 다시 시도해 주세요.'); + setError("로그인에 실패했습니다. 다시 시도해 주세요."); } finally { setIsLoading(false); } @@ -43,10 +50,10 @@ export const useSocialLogin = () => { */ const loginWithGoogle = useGoogleLogin({ onSuccess: (tokenResponse) => { - handleSocialLogin('google', tokenResponse.access_token); + handleSocialLogin("google", tokenResponse.access_token); }, onError: () => { - setError('구글 로그인에 실패했습니다. 팝업 차단 여부를 확인해 주세요.'); + setError("구글 로그인에 실패했습니다. 팝업 차단 여부를 확인해 주세요."); }, }); @@ -58,24 +65,24 @@ export const useSocialLogin = () => { try { appleAuthHelpers.signIn({ authOptions: { - clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID || '', - scope: 'email name', + clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID || "", + scope: "email name", redirectURI: window.location.origin, // Apple 요구사항: 현재 도메인 입력 필요 usePopup: true, }, onSuccess: (response: any) => { if (response.authorization?.id_token) { - handleSocialLogin('apple', response.authorization.id_token); + handleSocialLogin("apple", response.authorization.id_token); } }, onError: (err: any) => { - console.error('Apple SignIn error:', err); - setError('애플 로그인 중 오류가 발생했습니다.'); + console.error("Apple SignIn error:", err); + setError("애플 로그인 중 오류가 발생했습니다."); }, }); } catch (err) { console.error(err); - setError('애플 로그인 초기화 실패'); + setError("애플 로그인 초기화 실패"); } }; @@ -85,9 +92,9 @@ export const useSocialLogin = () => { */ const handleFacebookCallback = (response: any) => { if (response?.accessToken) { - handleSocialLogin('facebook', response.accessToken); + handleSocialLogin("facebook", response.accessToken); } else { - setError('페이스북 로그인에 실패했습니다.'); + setError("페이스북 로그인에 실패했습니다."); } }; @@ -98,4 +105,4 @@ export const useSocialLogin = () => { isLoading, error, }; -}; \ No newline at end of file +}; diff --git a/src/features/auth/types/index.ts b/src/features/auth/types/index.ts index 2c1d700..1ec81ef 100644 --- a/src/features/auth/types/index.ts +++ b/src/features/auth/types/index.ts @@ -1,15 +1,9 @@ export interface SocialLoginRequest { - provider: 'google' | 'apple' | 'facebook'; + provider: "GOOGLE" | "apple" | "FACEBOOK"; token: string; // 소셜 프로바이더로부터 발급받은 id_token 또는 access_token } export interface AuthResponse { - accessToken: string; // VibeRoom 전용 JWT (API 요청 시 사용) + accessToken: string; // VibeRoom 전용 JWT (API 요청 시 사용) refreshToken: string; // 토큰 갱신용 - user: { - id: string; - email: string; - name: string; - profileImage?: string; - }; -} \ No newline at end of file +} diff --git a/src/shared/lib/apiClient.ts b/src/shared/lib/apiClient.ts index 0b4175c..664398e 100644 --- a/src/shared/lib/apiClient.ts +++ b/src/shared/lib/apiClient.ts @@ -1,22 +1,23 @@ /** * VibeRoom 공통 API 클라이언트 * 환경 변수(NEXT_PUBLIC_API_BASE_URL)를 기반으로 자동으로 Base URL이 설정됩니다. - * + * * - npm run dev 실행 시: https://api-dev.viberoom.io (from .env.development) * - 빌드 후 운영 환경: https://api.viberoom.io (from .env.production) */ -const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8080'; +const API_BASE_URL = + process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8080"; export const apiClient = async ( endpoint: string, - options: RequestInit = {} + options: RequestInit = {}, ): Promise => { // 엔드포인트 앞의 슬래시(/) 중복 방지 - const url = `${API_BASE_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`; - + const url = `${API_BASE_URL}${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`; + const defaultHeaders = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }; const response = await fetch(url, {