/** * OAuth Callback Page * Handles OAuth provider redirects and completes authentication */ import React, { useEffect, useState } from 'react'; import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { Loader2, AlertCircle, CheckCircle } from 'lucide-react'; import { handleOAuthCallback } from '../api/oauth'; import { setCookie } from '../utils/cookies'; import SmoothScheduleLogo from '../components/SmoothScheduleLogo'; const OAuthCallback: React.FC = () => { const [status, setStatus] = useState<'processing' | 'success' | 'error'>('processing'); const [errorMessage, setErrorMessage] = useState(''); const navigate = useNavigate(); const { provider } = useParams<{ provider: string }>(); const location = useLocation(); useEffect(() => { const processCallback = async () => { try { // Check if we're in a popup window const isPopup = window.opener && window.opener !== window; // Extract OAuth callback parameters // Try both query params and hash params (some providers use hash) const searchParams = new URLSearchParams(location.search); const hashParams = new URLSearchParams(location.hash.substring(1)); const code = searchParams.get('code') || hashParams.get('code'); const state = searchParams.get('state') || hashParams.get('state'); const error = searchParams.get('error') || hashParams.get('error'); const errorDescription = searchParams.get('error_description') || hashParams.get('error_description'); // Check for OAuth errors if (error) { const message = errorDescription || error || 'Authentication failed'; throw new Error(message); } // Validate required parameters if (!code || !state) { throw new Error('Missing required OAuth parameters'); } if (!provider) { throw new Error('Missing OAuth provider'); } // Exchange code for tokens const response = await handleOAuthCallback(provider, code, state); // Store tokens in cookies (accessible across subdomains) setCookie('access_token', response.access, 7); setCookie('refresh_token', response.refresh, 7); // Clear session cookie to prevent interference with JWT document.cookie = 'sessionid=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.lvh.me'; document.cookie = 'sessionid=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; setStatus('success'); // Determine redirect URL based on user role const user = response.user; const currentHostname = window.location.hostname; const currentPort = window.location.port; let targetUrl = '/'; let needsRedirect = false; // Platform users (superuser, platform_manager, platform_support) if (['superuser', 'platform_manager', 'platform_support'].includes(user.role)) { const targetHostname = 'platform.lvh.me'; needsRedirect = currentHostname !== targetHostname; if (needsRedirect) { const portStr = currentPort ? `:${currentPort}` : ''; targetUrl = `http://${targetHostname}${portStr}/`; } } // Business users - redirect to their business subdomain else if (user.business_subdomain) { const targetHostname = `${user.business_subdomain}.lvh.me`; needsRedirect = currentHostname !== targetHostname; if (needsRedirect) { const portStr = currentPort ? `:${currentPort}` : ''; targetUrl = `http://${targetHostname}${portStr}/`; } } // Handle popup vs redirect flows if (isPopup) { // Post message to parent window window.opener.postMessage( { type: 'oauth-success', provider, user: response.user, needsRedirect, targetUrl, }, window.location.origin ); // Close popup after short delay setTimeout(() => { window.close(); }, 1000); } else { // Standard redirect flow setTimeout(() => { if (needsRedirect) { // Redirect to different subdomain window.location.href = targetUrl; } else { // Navigate to dashboard on same subdomain navigate(targetUrl); } }, 1500); } } catch (err: any) { console.error('OAuth callback error:', err); setStatus('error'); setErrorMessage(err.message || 'Authentication failed. Please try again.'); // If in popup, post error to parent if (window.opener && window.opener !== window) { window.opener.postMessage( { type: 'oauth-error', provider, error: err.message || 'Authentication failed', }, window.location.origin ); // Close popup after delay setTimeout(() => { window.close(); }, 3000); } } }; processCallback(); }, [provider, location, navigate]); const handleTryAgain = () => { const currentHostname = window.location.hostname; const currentPort = window.location.port; const portStr = currentPort ? `:${currentPort}` : ''; // Redirect to login page if (currentHostname.includes('platform.lvh.me')) { window.location.href = `http://platform.lvh.me${portStr}/login`; } else if (currentHostname.includes('.lvh.me')) { // On business subdomain - go to their login window.location.href = `http://${currentHostname}${portStr}/login`; } else { // Fallback navigate('/login'); } }; return (
Please wait while we authenticate your account
Redirecting to your dashboard...
{errorMessage}
Authenticating with{' '} {provider}
If the problem persists, please contact support