Start working on Auth flow. Made email templates for auth
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
import { useAuth } from '@/components/context/auth';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
import { AvatarUpload, ProfileForm } from '@/components/default/profile';
|
||||
import { AvatarUpload, ProfileForm, ResetPasswordForm } from '@/components/default/profile';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@ -12,6 +12,8 @@ import {
|
||||
Separator,
|
||||
} from '@/components/ui';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { resetPassword } from '@/lib/actions';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const ProfilePage = () => {
|
||||
const { profile, isLoading, isAuthenticated, updateProfile, refreshUserData } = useAuth();
|
||||
@ -32,12 +34,27 @@ const ProfilePage = () => {
|
||||
full_name: string;
|
||||
email: string;
|
||||
}) => {
|
||||
await updateProfile({
|
||||
full_name: values.full_name,
|
||||
email: values.email,
|
||||
});
|
||||
try {
|
||||
await updateProfile({
|
||||
full_name: values.full_name,
|
||||
email: values.email,
|
||||
});
|
||||
} catch {
|
||||
toast.error('Error updating profile!: ');
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetPasswordSubmit = async (values: {
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}) => {
|
||||
try {
|
||||
await resetPassword(values);
|
||||
} catch {
|
||||
toast.error('Error resetting password!: ');
|
||||
}
|
||||
}
|
||||
|
||||
// Show loading state while checking authentication
|
||||
if (isLoading) {
|
||||
return (
|
||||
@ -75,6 +92,8 @@ const ProfilePage = () => {
|
||||
<AvatarUpload onAvatarUploaded={handleAvatarUploaded} />
|
||||
<Separator />
|
||||
<ProfileForm onSubmit={handleProfileSubmit} />
|
||||
<Separator />
|
||||
<ResetPasswordForm onSubmit={handleResetPasswordSubmit} />
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
@ -1,8 +1,14 @@
|
||||
import { resetPassword } from '@/lib/actions';
|
||||
import { resetPasswordFromEmail } from '@/lib/actions';
|
||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||
import { Input, Label } from '@/components/ui';
|
||||
import { getUser } from '@/lib/actions';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const ResetPassword = async (props: { searchParams: Promise<Message> }) => {
|
||||
const user = await getUser();
|
||||
if (!user.success) {
|
||||
redirect('/sign-in');
|
||||
}
|
||||
const searchParams = await props.searchParams;
|
||||
return (
|
||||
<form className='flex flex-col w-full max-w-md p-4 gap-2 [&>input]:mb-4'>
|
||||
@ -24,7 +30,7 @@ const ResetPassword = async (props: { searchParams: Promise<Message> }) => {
|
||||
placeholder='Confirm password'
|
||||
required
|
||||
/>
|
||||
<SubmitButton formAction={resetPassword}>Reset password</SubmitButton>
|
||||
<SubmitButton formAction={resetPasswordFromEmail}>Reset password</SubmitButton>
|
||||
<FormMessage message={searchParams} />
|
||||
</form>
|
||||
);
|
||||
|
@ -1,10 +1,14 @@
|
||||
import Link from 'next/link';
|
||||
import { signIn } from '@/lib/actions';
|
||||
import { getUser, signIn } from '@/lib/actions';
|
||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||
import { Input, Label } from '@/components/ui';
|
||||
import { redirect } from 'next/navigation';
|
||||
import type { User } from '@/utils/supabase';
|
||||
|
||||
const Login = async (props: { searchParams: Promise<Message> }) => {
|
||||
const searchParams = await props.searchParams;
|
||||
const user = await getUser();
|
||||
if (user.success) redirect('/profile');
|
||||
return (
|
||||
<form className='flex-1 flex flex-col min-w-64'>
|
||||
<h1 className='text-2xl font-medium'>Sign in</h1>
|
||||
|
@ -2,9 +2,13 @@ import Link from 'next/link';
|
||||
import { signUp } from '@/lib/actions';
|
||||
import { FormMessage, type Message, SubmitButton } from '@/components/default';
|
||||
import { Input, Label } from '@/components/ui';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getUser } from '@/lib/actions';
|
||||
|
||||
const SignUp = async (props: { searchParams: Promise<Message> }) => {
|
||||
const searchParams = await props.searchParams;
|
||||
const user = await getUser();
|
||||
if (user.success) redirect('/profile');
|
||||
if ('message' in searchParams) {
|
||||
return (
|
||||
<div
|
||||
|
@ -1,2 +1,3 @@
|
||||
export * from './AvatarUpload';
|
||||
export * from './ProfileForm';
|
||||
export * from './ResetPasswordForm';
|
||||
|
@ -105,11 +105,21 @@ export const forgotPassword = async (formData: FormData) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const resetPassword = async (formData: FormData) => {
|
||||
const supabase = await createServerClient();
|
||||
const password = formData.get('password') as string;
|
||||
const confirmPassword = formData.get('confirmPassword') as string;
|
||||
|
||||
export const resetPassword = async (
|
||||
formData: FormData | {password: string, confirmPassword: string}
|
||||
) => {
|
||||
let password = '';
|
||||
let confirmPassword = '';
|
||||
|
||||
if (formData instanceof FormData) {
|
||||
password = formData.get('password') as string;
|
||||
confirmPassword = formData.get('confirmPassword') as string;
|
||||
} else {
|
||||
password = formData.password;
|
||||
confirmPassword = formData.confirmPassword;
|
||||
}
|
||||
|
||||
if (!password || !confirmPassword) {
|
||||
encodedRedirect(
|
||||
'error',
|
||||
@ -118,6 +128,39 @@ export const resetPassword = async (formData: FormData) => {
|
||||
);
|
||||
}
|
||||
|
||||
const supabase = await createServerClient();
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
encodedRedirect('error', '/reset-password', 'Passwords do not match');
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.updateUser({
|
||||
password: password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
encodedRedirect('error', '/reset-password', 'Password update failed');
|
||||
}
|
||||
|
||||
encodedRedirect('success', '/reset-password', 'Password updated');
|
||||
};
|
||||
|
||||
|
||||
export const resetPasswordFromEmail = async (formData: FormData) => {
|
||||
|
||||
const password = formData.get('password') as string;
|
||||
const confirmPassword = formData.get('confirmPassword') as string;
|
||||
|
||||
if (!password || !confirmPassword) {
|
||||
encodedRedirect(
|
||||
'error',
|
||||
'/reset-password',
|
||||
'Password and confirm password are required',
|
||||
);
|
||||
}
|
||||
|
||||
const supabase = await createServerClient();
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
encodedRedirect('error', '/reset-password', 'Passwords do not match');
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export { createClient } from './client';
|
||||
export { createClient as createServerClient } from './server';
|
||||
export { createServerClient } from './server';
|
||||
export { updateSession } from './middleware';
|
||||
export type * from './utils';
|
||||
export type { Database } from './types';
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import { createServerClient as CreateServerClient } from '@supabase/ssr';
|
||||
import type { Database } from '@/utils/supabase/types';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export const createClient = async () => {
|
||||
export const createServerClient = async () => {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
return createServerClient<Database>(
|
||||
return CreateServerClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
|
Reference in New Issue
Block a user