o2o-castad-frontend/src/pages/Login/LoginSection.tsx
김성경 f36fd5a3cb feat: Meta 픽셀 및 전환 추적 연동
- index.html에 Meta Pixel 스크립트 및 noscript 폴백 추가 (PageView 자동 추적)
- 전환 추적 유틸 추가 (trackViewContent, trackCompleteRegistration,
  trackFirstVideoCreated) — 서버 CAPI와 동일 event_id로 픽셀 발화해 중복제거
- 랜딩 진입 시 UTM 파라미터 first-touch 캡처 (localStorage 보존,
  가입 전환 시 서버로 전달 후 제거)
- 카카오 로그인 콜백에서 is_new_user 판정 시 CompleteRegistration 발화
  (토큰 리다이렉트 경로 + code 콜백 경로 모두 처리)
- 영상 생성 완료 시 FirstVideoCreated 발화
- KakaoCallbackResponse 타입을 백엔드 LoginResponse 구조에 맞게 수정
  (user 객체 제거, is_new_user 평탄화)
- logout이 refresh_token을 body로 전달하도록 수정, 실패해도
  로컬 데이터는 항상 삭제되도록 try/finally 처리

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 10:28:51 +09:00

110 lines
3.1 KiB
TypeScript
Executable File

import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { getKakaoLoginUrl, kakaoCallback, trackCompleteRegistration } from '../../utils/api';
interface LoginSectionProps {
onBack: () => void;
onLogin: () => void;
}
const LoginSection: React.FC<LoginSectionProps> = ({ onBack, onLogin }) => {
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// 카카오 콜백 처리 (URL에서 code 파라미터 확인)
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
handleKakaoCallback(code);
}
}, []);
const handleKakaoCallback = async (code: string) => {
setIsLoading(true);
setError(null);
try {
const response = await kakaoCallback(code);
// 신규 가입이면 Meta CompleteRegistration 전환 이벤트 발화
// (서버가 계정당 최초 1회 판정 — App.tsx 경로와 중복 호출돼도 무해)
if (response.is_new_user) {
await trackCompleteRegistration();
}
// URL에서 code 파라미터 제거
const url = new URL(window.location.href);
url.searchParams.delete('code');
window.history.replaceState({}, document.title, url.pathname);
// 로그인 성공
onLogin();
} catch (err) {
console.error('Kakao callback failed:', err);
setError(t('login.kakaoLoginFailed'));
// URL에서 code 파라미터 제거
const url = new URL(window.location.href);
url.searchParams.delete('code');
window.history.replaceState({}, document.title, url.pathname);
} finally {
setIsLoading(false);
}
};
const handleKakaoLogin = async () => {
setIsLoading(true);
setError(null);
try {
const response = await getKakaoLoginUrl();
// 카카오 로그인 페이지로 리다이렉트
window.location.href = response.auth_url;
} catch (err) {
console.error('Failed to get Kakao login URL:', err);
setError(t('login.loginUrlFailed'));
setIsLoading(false);
}
};
return (
<div className="login-container">
{/* Back Button */}
<button onClick={onBack} className="login-back-btn" disabled={isLoading}>
<img src="/assets/images/icon-back.svg" alt="Back" />
<span>{t('login.back')}</span>
</button>
<div className="login-content">
{/* Logo */}
<div className="login-logo">
<img src="/assets/images/ADO2_with Slogan_white.svg" alt="ADO2" />
</div>
{/* Error Message */}
{error && (
<div className="login-error">
{error}
</div>
)}
{/* Kakao Login Button */}
<button
onClick={handleKakaoLogin}
className="btn-kakao"
disabled={isLoading}
>
{isLoading ? t('login.loggingIn') : t('login.kakaoStart')}
</button>
</div>
</div>
);
};
export default LoginSection;