109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
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();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
/**
|
|
* [비즈니스 로직 1] 공통 토큰 교환 로직
|
|
* 플랫폼별 SDK에서 획득한 토큰을 백엔드로 보내어 VibeRoom 전용 JWT로 교환합니다.
|
|
*/
|
|
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,
|
|
});
|
|
|
|
console.log(`[${provider}] 백엔드 연동 성공! JWT:`, response.accessToken);
|
|
|
|
// 2. 응답받은 VibeRoom 전용 토큰과 유저 정보를 전역 상태 및 쿠키에 저장
|
|
useAuthStore.getState().setAuth(response);
|
|
|
|
// 3. 메인 대시보드 화면으로 이동
|
|
router.push("/dashboard");
|
|
} catch (err) {
|
|
console.error(`[${provider}] 로그인 실패:`, err);
|
|
setError("로그인에 실패했습니다. 다시 시도해 주세요.");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* [비즈니스 로직 2] Google Login
|
|
* @react-oauth/google 라이브러리의 훅을 사용하여 구글 로그인 팝업을 호출합니다.
|
|
*/
|
|
const loginWithGoogle = useGoogleLogin({
|
|
onSuccess: (tokenResponse) => {
|
|
handleSocialLogin("google", tokenResponse.access_token);
|
|
},
|
|
onError: () => {
|
|
setError("구글 로그인에 실패했습니다. 팝업 차단 여부를 확인해 주세요.");
|
|
},
|
|
});
|
|
|
|
/**
|
|
* [비즈니스 로직 3] Apple Login
|
|
* react-apple-signin-auth 라이브러리를 사용하여 애플 로그인을 팝업으로 호출합니다.
|
|
*/
|
|
const loginWithApple = () => {
|
|
try {
|
|
appleAuthHelpers.signIn({
|
|
authOptions: {
|
|
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);
|
|
}
|
|
},
|
|
onError: (err: any) => {
|
|
console.error("Apple SignIn error:", err);
|
|
setError("애플 로그인 중 오류가 발생했습니다.");
|
|
},
|
|
});
|
|
} catch (err) {
|
|
console.error(err);
|
|
setError("애플 로그인 초기화 실패");
|
|
}
|
|
};
|
|
|
|
/**
|
|
* [비즈니스 로직 4] Facebook Callback
|
|
* react-facebook-login 컴포넌트에서 콜백으로 받은 토큰을 처리합니다.
|
|
*/
|
|
const handleFacebookCallback = (response: any) => {
|
|
if (response?.accessToken) {
|
|
handleSocialLogin("facebook", response.accessToken);
|
|
} else {
|
|
setError("페이스북 로그인에 실패했습니다.");
|
|
}
|
|
};
|
|
|
|
return {
|
|
loginWithGoogle,
|
|
loginWithApple,
|
|
handleFacebookCallback,
|
|
isLoading,
|
|
error,
|
|
};
|
|
};
|