11/**
2- * AuthPage - 통합 로그인/회원가입 페이지
3- * Firebase 소셜 로그인 (Google, GitHub, Kakao )
2+ * AuthPage - 로그인 페이지
3+ * Firebase 소셜 로그인 (Google)
44 *
5- * WHY: LoginPage와 SignupPage가 100% 동일한 기능 수행
6- * TRADEOFF: 단일 컴포넌트로 통합 > 중복 코드 145줄 제거
5+ * WHY: Google OAuth 하나로 로그인/회원가입 자동 처리
6+ * 신규 유저는 initializeAuthListener에서 자동 등록됨
77 */
88
99import { useState } from 'react' ;
10- import { useNavigate , useLocation } from 'react-router-dom' ;
10+ import { useNavigate } from 'react-router-dom' ;
1111import { useTranslation } from 'react-i18next' ;
1212import { motion } from 'framer-motion' ;
13- import { loginWithGoogle , loginWithGithub , loginWithKakao } from '@/services/firebase' ;
14- import { Github } from 'lucide-react' ;
13+ import { loginWithGoogle } from '@/services/firebase' ;
1514import { logger } from '@/utils/logger' ;
1615import { useStore } from '@/stores/store' ;
1716
1817export default function AuthPage ( ) {
1918 const { t } = useTranslation ( ) ;
2019 const navigate = useNavigate ( ) ;
21- const location = useLocation ( ) ;
2220 const setSidebarOpen = useStore ( ( s ) => s . setSidebarOpen ) ;
2321 const [ error , setError ] = useState < string | null > ( null ) ;
2422 const [ loading , setLoading ] = useState ( false ) ;
2523
26- // URL 경로로 로그인/회원가입 구분
27- const isSignup = location . pathname === '/signup' ;
28- const pageTitle = isSignup ? t ( 'auth.signup' ) : t ( 'auth.login' ) ;
29- const errorPrefix = isSignup ? t ( 'auth.signup' ) : t ( 'auth.login' ) ;
30- const linkPath = isSignup ? '/login' : '/signup' ;
31- const linkText = isSignup ? t ( 'auth.go_login' ) : t ( 'auth.go_signup' ) ;
32- const linkPrompt = isSignup ? t ( 'auth.have_account' ) : t ( 'auth.no_account' ) ;
33-
3424 const handleGoogleLogin = async ( ) => {
3525 try {
3626 setError ( null ) ;
3727 setLoading ( true ) ;
3828 await loginWithGoogle ( ) ;
39- setSidebarOpen ( false ) ; // 로그인 성공 시 사이드바 닫기
29+ setSidebarOpen ( false ) ;
4030 navigate ( '/courses' ) ;
4131 } catch ( err ) {
42- setError ( t ( 'auth.google_failed' , { action : errorPrefix } ) ) ;
32+ setError ( t ( 'auth.google_failed' , { action : t ( 'auth.login' ) } ) ) ;
4333 logger . error ( 'Google login failed:' , err ) ;
4434 } finally {
4535 setLoading ( false ) ;
4636 }
4737 } ;
4838
49- const handleGithubLogin = async ( ) => {
50- try {
51- setError ( null ) ;
52- setLoading ( true ) ;
53- await loginWithGithub ( ) ;
54- setSidebarOpen ( false ) ; // 로그인 성공 시 사이드바 닫기
55- navigate ( '/courses' ) ;
56- } catch ( err ) {
57- setError ( t ( 'auth.github_failed' , { action : errorPrefix } ) ) ;
58- logger . error ( 'GitHub login failed:' , err ) ;
59- } finally {
60- setLoading ( false ) ;
61- }
62- } ;
63-
64- const handleKakaoLogin = async ( ) => {
65- try {
66- setError ( null ) ;
67- setLoading ( true ) ;
68- await loginWithKakao ( ) ;
69- setSidebarOpen ( false ) ; // 로그인 성공 시 사이드바 닫기
70- navigate ( '/courses' ) ;
71- } catch ( err ) {
72- setError ( t ( 'auth.kakao_failed' , { action : errorPrefix } ) ) ;
73- logger . error ( 'Kakao login failed:' , err ) ;
74- } finally {
75- setLoading ( false ) ;
76- }
77- } ;
78-
7939 return (
8040 < div className = "min-h-screen flex items-center justify-center px-6" >
8141 < motion . div
@@ -87,56 +47,32 @@ export default function AuthPage() {
8747 { /* 타이틀 */ }
8848 < div className = "text-center mb-12" >
8949 < h1 className = "text-4xl font-bold text-text mb-4" >
90- { pageTitle }
50+ { t ( 'auth.login' ) }
9151 </ h1 >
9252 < p className = "text-text-secondary" >
9353 { t ( 'auth.social_subtitle' ) }
9454 </ p >
9555 </ div >
9656
97- { /* 소셜 로그인 버튼들 */ }
98- < div className = "flex justify-center gap-6" >
99- { /* Google */ }
57+ { /* Google 로그인 버튼 */ }
58+ < div className = "flex justify-center" >
10059 < motion . button
101- whileHover = { { scale : 1.1 } }
60+ whileHover = { { scale : 1.05 } }
10261 whileTap = { { scale : 0.95 } }
10362 onClick = { handleGoogleLogin }
10463 disabled = { loading }
105- className = "w-16 h-16 flex items-center justify-center bg-white border-2 border-border rounded-full shadow-md hover:shadow-lg hover:border-primary transition-all disabled:opacity-50"
106- aria-label = { t ( 'auth.google_auth' , { action : pageTitle } ) }
64+ className = "flex items-center gap-3 px-8 py-4 bg-white border-2 border-border rounded-2xl shadow-md hover:shadow-lg hover:border-primary transition-all disabled:opacity-50"
65+ aria-label = { t ( 'auth.google_auth' , { action : t ( 'auth.login' ) } ) }
10766 >
108- < svg className = "w-7 h-7 " viewBox = "0 0 24 24" >
67+ < svg className = "w-6 h-6 " viewBox = "0 0 24 24" >
10968 < path fill = "#4285F4" d = "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
11069 < path fill = "#34A853" d = "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
11170 < path fill = "#FBBC05" d = "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
11271 < path fill = "#EA4335" d = "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
11372 </ svg >
114- </ motion . button >
115-
116- { /* GitHub */ }
117- < motion . button
118- whileHover = { { scale : 1.1 } }
119- whileTap = { { scale : 0.95 } }
120- onClick = { handleGithubLogin }
121- disabled = { loading }
122- className = "w-16 h-16 flex items-center justify-center bg-[#24292e] border-2 border-[#24292e] rounded-full shadow-md hover:shadow-lg hover:bg-[#1a1e22] transition-all disabled:opacity-50"
123- aria-label = { t ( 'auth.github_auth' , { action : pageTitle } ) }
124- >
125- < Github className = "w-7 h-7 text-white" />
126- </ motion . button >
127-
128- { /* Kakao */ }
129- < motion . button
130- whileHover = { { scale : 1.1 } }
131- whileTap = { { scale : 0.95 } }
132- onClick = { handleKakaoLogin }
133- disabled = { loading }
134- className = "w-16 h-16 flex items-center justify-center bg-[#FEE500] border-2 border-[#FEE500] rounded-full shadow-md hover:shadow-lg hover:bg-[#FFEB3B] transition-all disabled:opacity-50"
135- aria-label = { t ( 'auth.kakao_auth' , { action : pageTitle } ) }
136- >
137- < svg className = "w-7 h-7 text-[#3C1E1E]" viewBox = "0 0 24 24" fill = "currentColor" >
138- < path d = "M12 3C6.477 3 2 6.477 2 10.75c0 2.745 1.79 5.155 4.5 6.645l-1.125 4.125c-.075.27.21.495.45.345l5.25-3.495c.315.03.63.045.945.045 5.523 0 9.98-3.477 9.98-7.75S17.523 3 12 3z" />
139- </ svg >
73+ < span className = "text-base font-medium text-gray-700" >
74+ { t ( 'auth.google_auth' , { action : t ( 'auth.login' ) } ) }
75+ </ span >
14076 </ motion . button >
14177 </ div >
14278
@@ -150,14 +86,6 @@ export default function AuthPage() {
15086 { error }
15187 </ motion . div >
15288 ) }
153-
154- { /* 하단 텍스트 */ }
155- < p className = "mt-8 text-center text-sm text-text-tertiary" >
156- { linkPrompt } { ' ' }
157- < a href = { linkPath } className = "text-primary hover:underline font-medium" >
158- { linkText }
159- </ a >
160- </ p >
16189 </ motion . div >
16290 </ div >
16391 ) ;
0 commit comments