mirror of https://github.com/kortix-ai/suna.git
Feat: Added Continue with Github using Supabase sign in OAuth
This commit is contained in:
parent
416e28f408
commit
c458d84d17
|
@ -0,0 +1,80 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { createClient } from '@/lib/supabase/client';
|
||||
|
||||
export default function GitHubOAuthPopup() {
|
||||
useEffect(() => {
|
||||
const supabase = createClient();
|
||||
const returnUrl = sessionStorage.getItem('returnUrl') || '/dashboard';
|
||||
|
||||
const finish = (type: 'success' | 'error', message?: string) => {
|
||||
try {
|
||||
if (window.opener) {
|
||||
window.opener.postMessage(
|
||||
type === 'success'
|
||||
? { type: 'github-auth-success', returnUrl }
|
||||
: {
|
||||
type: 'github-auth-error',
|
||||
message: message || 'GitHub sign-in failed',
|
||||
},
|
||||
window.opener.origin || '*',
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to post message to opener:', err);
|
||||
}
|
||||
|
||||
setTimeout(() => window.close(), 150); // Give time for message delivery
|
||||
};
|
||||
|
||||
const handleOAuth = async () => {
|
||||
const isOAuthCallback = new URLSearchParams(window.location.search).has(
|
||||
'code',
|
||||
);
|
||||
|
||||
if (isOAuthCallback) {
|
||||
try {
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (session) {
|
||||
return finish('success');
|
||||
}
|
||||
|
||||
// Fallback if session is not yet populated
|
||||
supabase.auth.onAuthStateChange((_event, session) => {
|
||||
if (session) finish('success');
|
||||
});
|
||||
|
||||
return;
|
||||
} catch (err: any) {
|
||||
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) {
|
||||
console.error('OAuth start error:', err);
|
||||
finish('error', err.message);
|
||||
}
|
||||
};
|
||||
|
||||
handleOAuth();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className="flex items-center justify-center h-screen text-muted-foreground text-sm">
|
||||
Completing GitHub sign-in...
|
||||
</main>
|
||||
);
|
||||
}
|
|
@ -28,6 +28,7 @@ import {
|
|||
DialogDescription,
|
||||
DialogFooter,
|
||||
} from '@/components/ui/dialog';
|
||||
import GitHubSignIn from '@/components/GithubSignIn';
|
||||
|
||||
function LoginContent() {
|
||||
const router = useRouter();
|
||||
|
@ -387,11 +388,17 @@ function LoginContent() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Google Sign In */}
|
||||
<div className="w-full">
|
||||
<GoogleSignIn returnUrl={returnUrl || undefined} />
|
||||
{/* OAuth Sign In */}
|
||||
<div className="w-full flex flex-col gap-3 mb-6">
|
||||
<div className="w-full">
|
||||
<GoogleSignIn returnUrl={returnUrl || undefined} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<GitHubSignIn returnUrl={returnUrl || undefined} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Divider */}
|
||||
<div className="relative my-8">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { toast } from 'sonner';
|
||||
import { Icons } from './home/icons';
|
||||
|
||||
interface GitHubSignInProps {
|
||||
returnUrl?: string;
|
||||
}
|
||||
|
||||
export default function GitHubSignIn({ returnUrl }: GitHubSignInProps) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
|
||||
if (event.data?.type === 'github-auth-success') {
|
||||
sessionStorage.removeItem('isGitHubAuthInProgress');
|
||||
setIsLoading(false);
|
||||
window.location.href =
|
||||
event.data.returnUrl || returnUrl || '/dashboard';
|
||||
}
|
||||
|
||||
if (event.data?.type === 'github-auth-error') {
|
||||
sessionStorage.removeItem('isGitHubAuthInProgress');
|
||||
setIsLoading(false);
|
||||
toast.error(event.data.message || 'GitHub sign-in failed.');
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handler);
|
||||
return () => window.removeEventListener('message', handler);
|
||||
}, [returnUrl]);
|
||||
|
||||
const handleGitHubSignIn = () => {
|
||||
const popup = window.open(
|
||||
`${window.location.origin}/auth/github-popup`,
|
||||
'GitHubOAuth',
|
||||
'width=500,height=600',
|
||||
);
|
||||
|
||||
if (!popup) {
|
||||
toast.error('Popup was blocked. Please enable popups and try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
sessionStorage.setItem('isGitHubAuthInProgress', '1');
|
||||
setIsLoading(true);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (popup.closed) {
|
||||
clearInterval(interval);
|
||||
setIsLoading(false);
|
||||
|
||||
// Delay toast to allow success postMessage to clear the flag
|
||||
setTimeout(() => {
|
||||
if (sessionStorage.getItem('isGitHubAuthInProgress')) {
|
||||
sessionStorage.removeItem('isGitHubAuthInProgress');
|
||||
toast.error('GitHub sign-in was not completed.');
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}, 500);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleGitHubSignIn}
|
||||
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"
|
||||
style={{
|
||||
fontFamily: '"Google Sans", Arial, sans-serif',
|
||||
fontWeight: 400,
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
aria-label="Sign in with GitHub"
|
||||
>
|
||||
<span className="flex items-center justify-center w-6 h-6">
|
||||
<Icons.github className="w-9 h-9" />
|
||||
</span>
|
||||
{isLoading ? 'Waiting for GitHub...' : 'Continue with GitHub'}
|
||||
</button>
|
||||
|
||||
);
|
||||
}
|
|
@ -2461,4 +2461,25 @@ export const Icons = {
|
|||
</defs>
|
||||
</svg>
|
||||
),
|
||||
};
|
||||
github: ({
|
||||
className,
|
||||
color = 'currentColor',
|
||||
}: {
|
||||
className?: string;
|
||||
color?: string;
|
||||
}) => (
|
||||
<svg
|
||||
className={cn('w-9 h-9', className)}
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill={color}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 0C5.37 0 0 5.373 0 12.01c0 5.303 3.438 9.8 8.207 11.387.6.113.82-.26.82-.577v-2.256c-3.338.727-4.033-1.416-4.033-1.416-.546-1.39-1.333-1.76-1.333-1.76-1.09-.745.082-.729.082-.729 1.205.085 1.84 1.26 1.84 1.26 1.07 1.836 2.807 1.306 3.492.998.108-.775.42-1.307.763-1.606-2.665-.307-5.466-1.34-5.466-5.968 0-1.318.47-2.396 1.24-3.24-.125-.307-.537-1.545.116-3.22 0 0 1.008-.324 3.3 1.23a11.44 11.44 0 013.006-.404c1.02.005 2.047.137 3.006.404 2.29-1.554 3.297-1.23 3.297-1.23.655 1.675.243 2.913.12 3.22.77.844 1.237 1.922 1.237 3.24 0 4.64-2.805 5.658-5.48 5.96.43.37.814 1.103.814 2.222v3.293c0 .32.216.694.825.577C20.565 21.807 24 17.31 24 12.01 24 5.373 18.627 0 12 0z"
|
||||
/>
|
||||
</svg>
|
||||
),
|
||||
};
|
|
@ -34,6 +34,7 @@ import { useAccounts } from '@/hooks/use-accounts';
|
|||
import { isLocalMode, config } from '@/lib/config';
|
||||
import { toast } from 'sonner';
|
||||
import { useModal } from '@/hooks/use-modal-store';
|
||||
import GitHubSignIn from '@/components/GithubSignIn';
|
||||
|
||||
// Custom dialog overlay with blur effect
|
||||
const BlurredDialogOverlay = () => (
|
||||
|
@ -145,7 +146,7 @@ export function HeroSection() {
|
|||
if (error instanceof BillingError) {
|
||||
console.log('Handling BillingError from hero section:', error.detail);
|
||||
// Open the payment required dialog modal instead of showing the alert
|
||||
onOpen("paymentRequiredDialog");
|
||||
onOpen('paymentRequiredDialog');
|
||||
// Don't show toast for billing errors
|
||||
} else {
|
||||
// Handle other errors (e.g., network, other API errors)
|
||||
|
@ -380,9 +381,10 @@ export function HeroSection() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Google Sign In */}
|
||||
{/* OAuth Sign In */}
|
||||
<div className="w-full">
|
||||
<GoogleSignIn returnUrl="/dashboard" />
|
||||
<GitHubSignIn returnUrl="/dashboard" />
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
|
|
Loading…
Reference in New Issue