Making progress.
This commit is contained in:
@ -6,38 +6,38 @@ import { type NextRequest } from 'next/server';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export const GET = async (request: NextRequest) => {
|
||||
const { searchParams, origin } = new URL(request.url);
|
||||
const code = searchParams.get('code');
|
||||
const token_hash = searchParams.get('token');
|
||||
const type = searchParams.get('type') as EmailOtpType | null;
|
||||
const redirectTo = searchParams.get('redirect_to') ?? '/';
|
||||
const supabase = await createServerClient();
|
||||
const { searchParams, origin } = new URL(request.url);
|
||||
const code = searchParams.get('code');
|
||||
const token_hash = searchParams.get('token');
|
||||
const type = searchParams.get('type') as EmailOtpType | null;
|
||||
const redirectTo = searchParams.get('redirect_to') ?? '/';
|
||||
const supabase = await createServerClient();
|
||||
|
||||
if (code) {
|
||||
const { error } = await supabase.auth.exchangeCodeForSession(code);
|
||||
if (error) {
|
||||
console.error('OAuth error:', error);
|
||||
return redirect(`/sign-in?error=${encodeURIComponent(error.message)}`);
|
||||
}
|
||||
return redirect(redirectTo);
|
||||
}
|
||||
if (code) {
|
||||
const { error } = await supabase.auth.exchangeCodeForSession(code);
|
||||
if (error) {
|
||||
console.error('OAuth error:', error);
|
||||
return redirect(`/sign-in?error=${encodeURIComponent(error.message)}`);
|
||||
}
|
||||
return redirect(redirectTo);
|
||||
}
|
||||
|
||||
if (token_hash && type) {
|
||||
const { error } = await supabase.auth.verifyOtp({
|
||||
type,
|
||||
token_hash,
|
||||
});
|
||||
if (!error) {
|
||||
if (type === 'signup' || type === 'magiclink' || type === 'email')
|
||||
return redirect('/');
|
||||
if (type === 'recovery' || type === 'email_change')
|
||||
return redirect('/profile');
|
||||
if (type === 'invite') return redirect('/sign-up');
|
||||
}
|
||||
return redirect(
|
||||
`/?error=${encodeURIComponent(error?.message ?? 'Unknown error')}`,
|
||||
);
|
||||
}
|
||||
if (token_hash && type) {
|
||||
const { error } = await supabase.auth.verifyOtp({
|
||||
type,
|
||||
token_hash,
|
||||
});
|
||||
if (!error) {
|
||||
if (type === 'signup' || type === 'magiclink' || type === 'email')
|
||||
return redirect('/');
|
||||
if (type === 'recovery' || type === 'email_change')
|
||||
return redirect('/profile');
|
||||
if (type === 'invite') return redirect('/sign-up');
|
||||
}
|
||||
return redirect(
|
||||
`/?error=${encodeURIComponent(error?.message ?? 'Unknown error')}`,
|
||||
);
|
||||
}
|
||||
|
||||
return redirect('/');
|
||||
return redirect('/');
|
||||
};
|
||||
|
@ -6,34 +6,34 @@ import { useEffect } from 'react';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
const AuthSuccessPage = () => {
|
||||
const { refreshUserData } = useAuth();
|
||||
const router = useRouter();
|
||||
const { refreshUserData } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const handleAuthSuccess = async () => {
|
||||
// Refresh the auth context to pick up the new session
|
||||
await refreshUserData();
|
||||
useEffect(() => {
|
||||
const handleAuthSuccess = async () => {
|
||||
// Refresh the auth context to pick up the new session
|
||||
await refreshUserData();
|
||||
|
||||
// Small delay to ensure state is updated
|
||||
setTimeout(() => {
|
||||
router.push('/');
|
||||
}, 100);
|
||||
};
|
||||
// Small delay to ensure state is updated
|
||||
setTimeout(() => {
|
||||
router.push('/');
|
||||
}, 100);
|
||||
};
|
||||
|
||||
handleAuthSuccess().catch((error) => {
|
||||
console.error(`Error: ${error instanceof Error ? error.message : error}`);
|
||||
});
|
||||
}, [refreshUserData, router]);
|
||||
handleAuthSuccess().catch((error) => {
|
||||
console.error(`Error: ${error instanceof Error ? error.message : error}`);
|
||||
});
|
||||
}, [refreshUserData, router]);
|
||||
|
||||
// Show loading while processing
|
||||
return (
|
||||
<div className='flex items-center justify-center min-h-screen'>
|
||||
<div className='flex flex-col items-center space-y-4'>
|
||||
<Loader2 className='h-8 w-8 animate-spin' />
|
||||
<p>Completing sign in...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
// Show loading while processing
|
||||
return (
|
||||
<div className='flex items-center justify-center min-h-screen'>
|
||||
<div className='flex flex-col items-center space-y-4'>
|
||||
<Loader2 className='h-8 w-8 animate-spin' />
|
||||
<p>Completing sign in...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthSuccessPage;
|
||||
|
@ -72,58 +72,63 @@ const ForgotPassword = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className='min-w-xs md:min-w-sm'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-2xl font-medium'>Reset Password</CardTitle>
|
||||
<CardDescription className='text-sm text-foreground'>
|
||||
Don't have an account?{' '}
|
||||
<Link className='font-medium underline' href='/sign-up'>
|
||||
Sign up
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleForgotPassword)}
|
||||
className='flex flex-col min-w-64 space-y-6'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<SubmitButton
|
||||
disabled={isLoading}
|
||||
pendingText='Resetting Password...'
|
||||
>
|
||||
Reset Password
|
||||
</SubmitButton>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ success: statusMessage }} />
|
||||
))}
|
||||
</form>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className='w-full mx-auto text-center pt-2 md:pt-10'>
|
||||
<div className='mx-auto flex flex-col items-center justify-center'>
|
||||
<Card className='min-w-xs sm:min-w-sm sm:max-w-xs max-w-lg'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-2xl font-medium'>Reset Password</CardTitle>
|
||||
<CardDescription className='text-sm text-foreground'>
|
||||
Don't have an account?{' '}
|
||||
<Link className='font-medium underline' href='/sign-up'>
|
||||
Sign up
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleForgotPassword)}
|
||||
className='flex flex-col min-w-64 space-y-6'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<SubmitButton
|
||||
disabled={isLoading}
|
||||
pendingText='Resetting Password...'
|
||||
>
|
||||
Reset Password
|
||||
</SubmitButton>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ success: statusMessage }} />
|
||||
))}
|
||||
</form>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ForgotPassword;
|
||||
|
@ -24,8 +24,7 @@ import { useAuth } from '@/components/context';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { StatusMessage, SubmitButton } from '@/components/default';
|
||||
import { Separator } from '@/components/ui';
|
||||
import { SignInWithMicrosoft } from '@/components/default/auth/SignInWithMicrosoft';
|
||||
import { SignInWithApple } from '@/components/default/auth/SignInWithApple';
|
||||
import { SignInWithApple, SignInWithMicrosoft } from '@/components/default/auth';
|
||||
|
||||
const formSchema = z.object({
|
||||
email: z.string().email({
|
||||
@ -78,93 +77,98 @@ const Login = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className='min-w-xs md:min-w-sm'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-3xl font-medium'>Sign In</CardTitle>
|
||||
<CardDescription className='text-foreground'>
|
||||
Don't have an account?{' '}
|
||||
<Link className='font-medium underline' href='/sign-up'>
|
||||
Sign up
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSignIn)}
|
||||
className='flex flex-col min-w-64 space-y-6 pb-4'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className='flex justify-between'>
|
||||
<FormLabel className='text-lg'>Password</FormLabel>
|
||||
<Link
|
||||
className='text-xs text-foreground underline text-right'
|
||||
href='/forgot-password'
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Your password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ message: statusMessage }} />
|
||||
))}
|
||||
<SubmitButton
|
||||
disabled={isLoading}
|
||||
pendingText='Signing In...'
|
||||
className='text-[1.0rem] cursor-pointer'
|
||||
>
|
||||
Sign in
|
||||
</SubmitButton>
|
||||
</form>
|
||||
</Form>
|
||||
<div className='w-full mx-auto text-center pt-2 md:pt-10'>
|
||||
<div className='mx-auto flex flex-col items-center justify-center'>
|
||||
<Card className='min-w-xs md:min-w-sm sm:max-w-xs max-w-lg'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-3xl font-medium'>Sign In</CardTitle>
|
||||
<CardDescription className='text-foreground'>
|
||||
Don't have an account?{' '}
|
||||
<Link className='font-medium underline' href='/sign-up'>
|
||||
Sign up
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSignIn)}
|
||||
className='flex flex-col min-w-64 space-y-6 pb-4'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
<span className='text-sm text-muted-foreground'>or</span>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
</div>
|
||||
<SignInWithMicrosoft />
|
||||
<SignInWithApple />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className='flex justify-between'>
|
||||
<FormLabel className='text-lg'>Password</FormLabel>
|
||||
<Link
|
||||
className='text-xs text-foreground underline text-right'
|
||||
href='/forgot-password'
|
||||
>
|
||||
Forgot Password?
|
||||
</Link>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Your password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ message: statusMessage }} />
|
||||
))}
|
||||
<SubmitButton
|
||||
disabled={isLoading}
|
||||
pendingText='Signing In...'
|
||||
className='text-[1.0rem] cursor-pointer'
|
||||
>
|
||||
Sign in
|
||||
</SubmitButton>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
<span className='text-sm text-muted-foreground'>or</span>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
</div>
|
||||
<SignInWithMicrosoft />
|
||||
<SignInWithApple />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -99,112 +99,116 @@ const SignUp = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className='min-w-xs md:min-w-sm'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-3xl font-medium'>Sign Up</CardTitle>
|
||||
<CardDescription className='text-foreground'>
|
||||
Already have an account?{' '}
|
||||
<Link className='text-primary font-medium underline' href='/sign-in'>
|
||||
Sign in
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSignUp)}
|
||||
className='flex flex-col mx-auto space-y-4 mb-4'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' placeholder='Full Name' {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Your password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='confirmPassword'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Confirm Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Confirm password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ success: statusMessage }} />
|
||||
))}
|
||||
<SubmitButton
|
||||
className='text-[1.0rem] cursor-pointer'
|
||||
disabled={isLoading}
|
||||
pendingText='Signing Up...'
|
||||
>
|
||||
Sign Up
|
||||
</SubmitButton>
|
||||
</form>
|
||||
</Form>
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
<span className='text-sm text-muted-foreground'>or</span>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
</div>
|
||||
<SignInWithMicrosoft />
|
||||
<SignInWithApple />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className='w-full mx-auto text-center pt-2 md:pt-10'>
|
||||
<div className='mx-auto flex flex-col items-center justify-center'>
|
||||
<Card className='min-w-xs md:min-w-sm sm:max-w-xs lg:max-w-lg'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-3xl font-medium'>Sign Up</CardTitle>
|
||||
<CardDescription className='text-foreground'>
|
||||
Already have an account?{' '}
|
||||
<Link className='text-primary font-medium underline' href='/sign-in'>
|
||||
Sign in
|
||||
</Link>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSignUp)}
|
||||
className='flex flex-col mx-auto space-y-4 mb-4'
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type='text' placeholder='Full Name' {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='email'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='email'
|
||||
placeholder='you@example.com'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='password'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Your password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='confirmPassword'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className='text-lg'>Confirm Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='Confirm password'
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{statusMessage &&
|
||||
(statusMessage.includes('Error') ||
|
||||
statusMessage.includes('error') ||
|
||||
statusMessage.includes('failed') ||
|
||||
statusMessage.includes('invalid') ? (
|
||||
<StatusMessage message={{ error: statusMessage }} />
|
||||
) : (
|
||||
<StatusMessage message={{ success: statusMessage }} />
|
||||
))}
|
||||
<SubmitButton
|
||||
className='text-[1.0rem] cursor-pointer'
|
||||
disabled={isLoading}
|
||||
pendingText='Signing Up...'
|
||||
>
|
||||
Sign Up
|
||||
</SubmitButton>
|
||||
</form>
|
||||
</Form>
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
<span className='text-sm text-muted-foreground'>or</span>
|
||||
<Separator className='flex-1 bg-accent py-0.5' />
|
||||
</div>
|
||||
<SignInWithMicrosoft type='signUp' />
|
||||
<SignInWithApple type='signUp' />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default SignUp;
|
||||
|
Reference in New Issue
Block a user