import React, { useEffect, useState, useRef } from 'react'; import { Compass, Loader2, LogIn, UserPlus, AlertCircle, CheckCircle } from 'lucide-react'; import { JoinTourLoginModal } from '../components/JoinTourLoginModal'; interface JoinTourPageProps { onLoginSuccess: (user: any) => void; onGoToSignup: () => void; onViewTour: (tourId: string) => void; onGoToHome: () => void; } export const JoinTourPage: React.FC = ({ onLoginSuccess, onGoToSignup, onViewTour, onGoToHome }) => { const [inviteToken, setInviteToken] = useState(null); const [isLoginOpen, setIsLoginOpen] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [successMsg, setSuccessMsg] = useState(''); const [tourId, setTourId] = useState(null); // Guard chống React StrictMode chạy effect 2 lần trong dev mode const hasJoinedRef = useRef(false); // Sync inviteToken from URL when modal opens to ensure fresh value useEffect(() => { if (isLoginOpen) { const params = new URLSearchParams(window.location.search); const token = params.get('token'); if (token) { setInviteToken(token); localStorage.setItem('pendingInviteToken', token); } } }, [isLoginOpen]); // Check for real authenticated user (not guest) const hasRealToken = !!localStorage.getItem('token') && !localStorage.getItem('guest_token'); useEffect(() => { const params = new URLSearchParams(window.location.search); const token = params.get('token'); setInviteToken(token); if (token) { localStorage.setItem('pendingInviteToken', token); // Nếu đã đăng nhập (có token thực, không phải guest), tự động thực hiện join const systemToken = localStorage.getItem('token'); const guestToken = localStorage.getItem('guest_token'); if (systemToken && !guestToken && !hasJoinedRef.current) { hasJoinedRef.current = true; handleJoinTour(token, systemToken); } } else { setError('Mã lời mời không tồn tại hoặc không hợp lệ.'); } }, []); const handleJoinTour = async (token: string, authToken: string) => { setLoading(true); setError(''); try { console.log('[JoinTour] Attempting to join with token'); const res = await fetch('/api/v1/tours/join-by-token', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}` }, body: JSON.stringify({ token }) }); const data = await res.json(); if (!res.ok) { console.error('[JoinTour] Join failed with status', res.status, 'message:', data.message); // Show real backend error message throw new Error(data.message || `Không thể gia nhập tour (${res.status}). Vui lòng kiểm tra lại mã lời mời.`); } console.log('[JoinTour] Join successful, message:', data.message); setSuccessMsg(data.message || 'Bạn đã tham gia tour thành công!'); setTourId(data.tourId); // Đợi 500ms để đảm bảo các thay đổi cache ở backend hoàn tất trước khi tiếp tục await new Promise((resolve) => setTimeout(resolve, 500)); localStorage.removeItem('pendingInviteToken'); } catch (err: any) { console.error('[JoinTour] Error:', err.message); setError(err.message || 'Đã xảy ra lỗi khi gia nhập tour.'); // Keep the pendingInviteToken in localStorage so user can retry } finally { setLoading(false); } }; const handleJoinSuccess = (user: any, tourData: any) => { console.log('[JoinTour] Join successful via modal, tourId:', tourData.tourId); setTourId(tourData.tourId); setSuccessMsg(tourData.message || 'Bạn đã tham gia tour thành công!'); onLoginSuccess(user); }; const isLoggedIn = !!localStorage.getItem('token') && !localStorage.getItem('guest_token'); return (
{/* Logo/Icon */}
{loading ? (

Đang xử lý tham gia hành trình...

Vui lòng đợi trong giây lát.

) : error ? (

Gia nhập thất bại

{error}

{isLoggedIn ? ( ) : ( <> )}
) : successMsg ? (

Thành công!

{successMsg}

) : (

Chào mừng bạn!

Bạn nhận được một lời mời tham gia hành trình du lịch. Vui lòng đăng nhập hoặc tạo tài khoản để có thể join và xem các hoạt động, chi phí của tour.

)}
setIsLoginOpen(false)} inviteToken={inviteToken || ''} onSwitchToSignup={onGoToSignup} onJoinSuccess={handleJoinSuccess} />
); };