Feat: Updated Typechecks and Error logs trace

This commit is contained in:
Dharrnn 2025-05-29 23:37:06 +05:30
parent c458d84d17
commit 5b2dcf64cf
2 changed files with 315 additions and 98 deletions

View File

@ -1,80 +1,207 @@
'use client'; 'use client';
import { useEffect } from 'react'; import { useEffect, useState } from 'react';
import { createClient } from '@/lib/supabase/client'; import { createClient } from '@/lib/supabase/client';
import { Loader2 } from 'lucide-react';
interface AuthMessage {
type: 'github-auth-success' | 'github-auth-error';
message?: string;
returnUrl?: string;
}
export default function GitHubOAuthPopup() { export default function GitHubOAuthPopup() {
const [status, setStatus] = useState<'loading' | 'processing' | 'error'>(
'loading',
);
const [errorMessage, setErrorMessage] = useState<string>('');
useEffect(() => { useEffect(() => {
const supabase = createClient(); const supabase = createClient();
const returnUrl = sessionStorage.getItem('returnUrl') || '/dashboard';
const finish = (type: 'success' | 'error', message?: string) => { // Get return URL from sessionStorage (set by parent component)
const returnUrl =
sessionStorage.getItem('github-returnUrl') || '/dashboard';
const postMessage = (message: AuthMessage) => {
try { try {
if (window.opener) { if (window.opener && !window.opener.closed) {
window.opener.postMessage( window.opener.postMessage(message, window.location.origin);
type === 'success'
? { type: 'github-auth-success', returnUrl }
: {
type: 'github-auth-error',
message: message || 'GitHub sign-in failed',
},
window.opener.origin || '*',
);
} }
} catch (err) { } catch (err) {
console.warn('Failed to post message to opener:', err); console.error('Failed to post message to opener:', err);
} }
};
setTimeout(() => window.close(), 150); // Give time for message delivery const handleSuccess = () => {
setStatus('processing');
postMessage({
type: 'github-auth-success',
returnUrl,
});
// Close popup after short delay
setTimeout(() => {
window.close();
}, 500);
};
const handleError = (message: string) => {
setStatus('error');
setErrorMessage(message);
postMessage({
type: 'github-auth-error',
message,
});
// Close popup after delay to show error
setTimeout(() => {
window.close();
}, 2000);
}; };
const handleOAuth = async () => { const handleOAuth = async () => {
const isOAuthCallback = new URLSearchParams(window.location.search).has( try {
'code', const urlParams = new URLSearchParams(window.location.search);
); const isCallback = urlParams.has('code');
const hasError = urlParams.has('error');
if (isOAuthCallback) { // Handle OAuth errors
try { if (hasError) {
const { const error = urlParams.get('error');
data: { session }, const errorDescription = urlParams.get('error_description');
} = await supabase.auth.getSession(); throw new Error(errorDescription || error || 'GitHub OAuth error');
}
if (session) { if (isCallback) {
return finish('success'); // This is the callback from GitHub
setStatus('processing');
try {
// Wait a moment for Supabase to process the session
await new Promise((resolve) => setTimeout(resolve, 1000));
const {
data: { session },
error,
} = await supabase.auth.getSession();
if (error) {
throw error;
}
if (session?.user) {
handleSuccess();
return;
}
// If no session yet, listen for auth state change
const {
data: { subscription },
} = supabase.auth.onAuthStateChange(async (event, session) => {
if (event === 'SIGNED_IN' && session?.user) {
subscription.unsubscribe();
handleSuccess();
} else if (event === 'SIGNED_OUT') {
subscription.unsubscribe();
handleError('Authentication failed - please try again');
}
});
// Cleanup subscription after timeout
setTimeout(() => {
subscription.unsubscribe();
handleError('Authentication timeout - please try again');
}, 10000); // 10 second timeout
} catch (authError: any) {
console.error('Auth processing error:', authError);
handleError(authError.message || 'Authentication failed');
} }
} else {
// Start the OAuth flow
setStatus('loading');
// Fallback if session is not yet populated const { error } = await supabase.auth.signInWithOAuth({
supabase.auth.onAuthStateChange((_event, session) => { provider: 'github',
if (session) finish('success'); options: {
redirectTo: `${window.location.origin}/auth/github-popup`,
queryParams: {
access_type: 'online',
prompt: 'select_account',
},
},
}); });
return; if (error) {
} catch (err: any) { throw error;
console.error('Session error:', err); }
return finish('error', err.message);
} }
}
// Start the GitHub OAuth flow
try {
await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/github-popup`,
},
});
} catch (err: any) { } catch (err: any) {
console.error('OAuth start error:', err); console.error('OAuth error:', err);
finish('error', err.message); handleError(err.message || 'Failed to authenticate with GitHub');
} }
}; };
// Cleanup sessionStorage when popup closes
const handleBeforeUnload = () => {
sessionStorage.removeItem('github-returnUrl');
};
window.addEventListener('beforeunload', handleBeforeUnload);
// Start OAuth process
handleOAuth(); handleOAuth();
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, []); }, []);
const getStatusMessage = () => {
switch (status) {
case 'loading':
return 'Starting GitHub authentication...';
case 'processing':
return 'Completing sign-in...';
case 'error':
return errorMessage || 'Authentication failed';
default:
return 'Processing...';
}
};
const getStatusColor = () => {
switch (status) {
case 'error':
return 'text-red-500';
case 'processing':
return 'text-green-500';
default:
return 'text-muted-foreground';
}
};
return ( return (
<main className="flex items-center justify-center h-screen text-muted-foreground text-sm"> <main className="flex flex-col items-center justify-center h-screen bg-background p-8">
Completing GitHub sign-in... <div className="flex flex-col items-center gap-4 text-center max-w-sm">
{status !== 'error' && (
<Loader2 className="h-8 w-8 animate-spin text-primary" />
)}
<div className="space-y-2">
<h1 className="text-lg font-medium">GitHub Sign-In</h1>
<p className={`text-sm ${getStatusColor()}`}>{getStatusMessage()}</p>
</div>
{status === 'error' && (
<button
onClick={() => window.close()}
className="mt-4 px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors"
>
Close
</button>
)}
</div>
</main> </main>
); );
} }

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { useState, useEffect } from 'react'; import { useState, useEffect, useCallback } from 'react';
import { useTheme } from 'next-themes'; import { useTheme } from 'next-themes';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { Icons } from './home/icons'; import { Icons } from './home/icons';
@ -9,82 +9,172 @@ interface GitHubSignInProps {
returnUrl?: string; returnUrl?: string;
} }
interface AuthMessage {
type: 'github-auth-success' | 'github-auth-error';
message?: string;
returnUrl?: string;
}
export default function GitHubSignIn({ returnUrl }: GitHubSignInProps) { export default function GitHubSignIn({ returnUrl }: GitHubSignInProps) {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
useEffect(() => { // Cleanup function to handle auth state
const handler = (event: MessageEvent) => { const cleanupAuthState = useCallback(() => {
if (event.origin !== window.location.origin) return; sessionStorage.removeItem('isGitHubAuthInProgress');
setIsLoading(false);
}, []);
if (event.data?.type === 'github-auth-success') { // Handle success message
sessionStorage.removeItem('isGitHubAuthInProgress'); const handleSuccess = useCallback(
setIsLoading(false); (data: AuthMessage) => {
window.location.href = cleanupAuthState();
event.data.returnUrl || returnUrl || '/dashboard';
// Add a small delay to ensure state is properly cleared
setTimeout(() => {
window.location.href = data.returnUrl || returnUrl || '/dashboard';
}, 100);
},
[cleanupAuthState, returnUrl],
);
// Handle error message
const handleError = useCallback(
(data: AuthMessage) => {
cleanupAuthState();
toast.error(data.message || 'GitHub sign-in failed. Please try again.');
},
[cleanupAuthState],
);
// Message event handler
useEffect(() => {
const handleMessage = (event: MessageEvent<AuthMessage>) => {
// Security: Only accept messages from same origin
if (event.origin !== window.location.origin) {
console.warn(
'Rejected message from unauthorized origin:',
event.origin,
);
return;
} }
if (event.data?.type === 'github-auth-error') { // Validate message structure
sessionStorage.removeItem('isGitHubAuthInProgress'); if (!event.data?.type || typeof event.data.type !== 'string') {
setIsLoading(false); return;
toast.error(event.data.message || 'GitHub sign-in failed.'); }
switch (event.data.type) {
case 'github-auth-success':
handleSuccess(event.data);
break;
case 'github-auth-error':
handleError(event.data);
break;
default:
// Ignore unknown message types
break;
} }
}; };
window.addEventListener('message', handler); window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handler);
}, [returnUrl]);
const handleGitHubSignIn = () => { return () => {
const popup = window.open( window.removeEventListener('message', handleMessage);
`${window.location.origin}/auth/github-popup`, };
'GitHubOAuth', }, [handleSuccess, handleError]);
'width=500,height=600',
);
if (!popup) { // Cleanup on component unmount
toast.error('Popup was blocked. Please enable popups and try again.'); useEffect(() => {
return; return () => {
} cleanupAuthState();
};
}, [cleanupAuthState]);
setTimeout(() => { const handleGitHubSignIn = async () => {
sessionStorage.setItem('isGitHubAuthInProgress', '1'); if (isLoading) return;
let popupInterval: NodeJS.Timeout | null = null;
try {
setIsLoading(true); setIsLoading(true);
const interval = setInterval(() => { // Store return URL for the popup
if (popup.closed) { if (returnUrl) {
clearInterval(interval); sessionStorage.setItem('github-returnUrl', returnUrl || '/dashboard');
setIsLoading(false); }
// Delay toast to allow success postMessage to clear the flag // Open popup with proper dimensions and features
const popup = window.open(
`${window.location.origin}/auth/github-popup`,
'GitHubOAuth',
'width=500,height=600,scrollbars=yes,resizable=yes,status=yes,location=yes',
);
if (!popup) {
throw new Error(
'Popup was blocked. Please enable popups and try again.',
);
}
// Set loading state and track popup
sessionStorage.setItem('isGitHubAuthInProgress', '1');
// Monitor popup closure
popupInterval = setInterval(() => {
if (popup.closed) {
if (popupInterval) {
clearInterval(popupInterval);
popupInterval = null;
}
// Small delay to allow postMessage to complete
setTimeout(() => { setTimeout(() => {
if (sessionStorage.getItem('isGitHubAuthInProgress')) { if (sessionStorage.getItem('isGitHubAuthInProgress')) {
sessionStorage.removeItem('isGitHubAuthInProgress'); cleanupAuthState();
toast.error('GitHub sign-in was not completed.'); toast.error('GitHub sign-in was cancelled or not completed.');
} }
}, 300); }, 500);
} }
}, 500); }, 1000);
}, 0); } catch (error) {
console.error('GitHub sign-in error:', error);
if (popupInterval) {
clearInterval(popupInterval);
}
cleanupAuthState();
toast.error(
error instanceof Error
? error.message
: 'Failed to start GitHub sign-in',
);
}
}; };
return ( return (
// Matched the button with the GoogleSignIn component
<button <button
onClick={handleGitHubSignIn} onClick={handleGitHubSignIn}
disabled={isLoading} disabled={isLoading}
className="w-full h-[56px] flex items-center justify-center gap-3 rounded-full border border-border bg-background hover:bg-[rgba(255,255,255,0.08)] transition-all text-sm font-normal tracking-normal" className="relative w-full h-12 flex items-center justify-center text-sm font-normal tracking-wide rounded-full bg-background text-foreground border border-border hover:bg-accent/30 transition-all duration-200 disabled:opacity-60 disabled:cursor-not-allowed font-sans"
style={{ aria-label={
fontFamily: '"Google Sans", Arial, sans-serif', isLoading ? 'Signing in with GitHub...' : 'Sign in with GitHub'
fontWeight: 400, }
boxShadow: 'none', type="button"
}}
aria-label="Sign in with GitHub"
> >
<span className="flex items-center justify-center w-6 h-6"> <div className="absolute left-0 inset-y-0 flex items-center pl-1 w-10">
<Icons.github className="w-9 h-9" /> <div className="w-8 h-8 rounded-full flex items-center justify-center text-foreground dark:bg-foreground dark:text-background">
</span> {isLoading ? (
{isLoading ? 'Waiting for GitHub...' : 'Continue with GitHub'} <div className="w-5 h-5 border-2 border-current border-t-transparent rounded-full animate-spin" />
</button> ) : (
<Icons.github className="w-5 h-5" />
)}
</div>
</div>
<span className="ml-9 font-light">
{isLoading ? 'Signing in...' : 'Continue with GitHub'}
</span>
</button>
); );
} }