Cleaning up

This commit is contained in:
Gabriel Brown 2025-05-15 16:53:21 -05:00
parent 5dcf2ed423
commit 40ab2d8450
10 changed files with 61 additions and 286 deletions

View File

@ -20,5 +20,5 @@ export async function GET(request: Request) {
} }
// URL to redirect to after sign up process completes // URL to redirect to after sign up process completes
return NextResponse.redirect(`${origin}/protected`); return NextResponse.redirect(origin);
} }

View File

@ -1,10 +1,44 @@
const HomePage = () => { 'use server';
import { FetchDataSteps } from '@/components/tutorial';
import { InfoIcon } from 'lucide-react';
import { getUser } from '@/lib/actions';
import type { User } from '@/utils/supabase';
const HomePage = async () => {
const response = await getUser();
if (!response.success || !response.data) {
return (
<main className='w-full items-center justify-center'>
<div className='flex p-5 items-center justify-center'>
<h1>Make sure you can sign in!</h1>
</div>
</main>
);
}
const user: User = response.data;
return ( return (
<main className='w-full items-center justify-center'> <div className='flex-1 w-full flex flex-col gap-12'>
<div className='flex p-5 items-center justify-center'> <div className='w-full'>
<h1>Make sure you can sign in!</h1> <div className='bg-accent text-sm p-3 px-5
rounded-md text-foreground flex gap-3 items-center'>
<InfoIcon size='16' strokeWidth={2} />
This is a protected component that you can only see as an authenticated
user
</div>
</div> </div>
</main> <div className='flex flex-col gap-2 items-start'>
<h2 className='font-bold text-2xl mb-4'>Your user details</h2>
<pre className='text-xs font-mono p-3 rounded
border max-h-32 overflow-auto'>
{JSON.stringify(user, null, 2)}
</pre>
</div>
<div>
<h2 className='font-bold text-2xl mb-4'>Next steps</h2>
<FetchDataSteps />
</div>
</div>
); );
}; };
export default HomePage; export default HomePage;

View File

@ -1,40 +0,0 @@
'use server';
import { FetchDataSteps } from '@/components/tutorial';
import { createServerClient } from '@/utils/supabase';
import { InfoIcon } from 'lucide-react';
import { redirect } from 'next/navigation';
const ProtectedPage = async () => {
const supabase = await createServerClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
return redirect('sign-in');
}
return (
<div className='flex-1 w-full flex flex-col gap-12'>
<div className='w-full'>
<div className='bg-accent text-sm p-3 px-5 rounded-md text-foreground flex gap-3 items-center'>
<InfoIcon size='16' strokeWidth={2} />
This is a protected page that you can only see as an authenticated
user
</div>
</div>
<div className='flex flex-col gap-2 items-start'>
<h2 className='font-bold text-2xl mb-4'>Your user details</h2>
<pre className='text-xs font-mono p-3 rounded border max-h-32 overflow-auto'>
{JSON.stringify(user, null, 2)}
</pre>
</div>
<div>
<h2 className='font-bold text-2xl mb-4'>Next steps</h2>
<FetchDataSteps />
</div>
</div>
);
};
export default ProtectedPage;

View File

@ -1,28 +0,0 @@
'use server';
import { getSignedUrl, getProfile } from '@/lib/actions';
import Image from 'next/image';
const Page = async () => {
const user = await getProfile();
if (!user.success) throw new Error(user.error);
const imageUrl = await getSignedUrl({
bucket: 'avatars',
url: user.data.avatar_url ?? '',
});
if (!imageUrl.success) throw new Error(imageUrl.error);
return (
<div className='flex justify-center items-center p-8'>
<Image
src={imageUrl.data ?? '/favicon.ico'}
alt='User avatar'
width={150}
height={150}
className='rounded-full'
priority
/>
</div>
);
};
export default Page;

View File

@ -6,7 +6,6 @@ import {
Avatar, Avatar,
AvatarFallback, AvatarFallback,
AvatarImage, AvatarImage,
Button,
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
@ -17,16 +16,12 @@ import {
import { getSignedUrl, getProfile, signOut } from '@/lib/actions'; import { getSignedUrl, getProfile, signOut } from '@/lib/actions';
import type { Profile } from '@/utils/supabase'; import type { Profile } from '@/utils/supabase';
import Link from 'next/link';
const AvatarDropdown = () => { const AvatarDropdown = () => {
const router = useRouter();
const [profile, setProfile] = useState<Profile | undefined>(undefined); const [profile, setProfile] = useState<Profile | undefined>(undefined);
const [signedUrl, setSignedUrl] = useState<string | undefined>(undefined); const [signedUrl, setSignedUrl] = useState<string | undefined>(undefined);
const handleEditProfile = async () => {
router.push('/profile');
};
const handleSignOut = async () => { const handleSignOut = async () => {
await signOut(); await signOut();
}; };
@ -78,14 +73,15 @@ const AvatarDropdown = () => {
<DropdownMenuLabel>{profile?.full_name}</DropdownMenuLabel> <DropdownMenuLabel>{profile?.full_name}</DropdownMenuLabel>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem asChild> <DropdownMenuItem asChild>
<Button onClick={handleEditProfile} variant={'secondary'} className='w-full text-left'> <Link href='/profile' className='w-full justify-center'>
Edit profile Edit profile
</Button> </Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator className='h-[2px]' />
<DropdownMenuItem asChild> <DropdownMenuItem asChild>
<Button onClick={handleSignOut} variant={'secondary'} className='w-full text-left'> <button onClick={handleSignOut} className='w-full justify-center'>
Sign out Log out
</Button> </button>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View File

@ -32,7 +32,7 @@ export const signUp = async (formData: FormData) => {
}); });
if (error) { if (error) {
return redirect('/protected'); return redirect('/');
//return encodedRedirect('error', '/sign-up', //return encodedRedirect('error', '/sign-up',
//'Thanks for signing up! Please check your email for a verification link.'); //'Thanks for signing up! Please check your email for a verification link.');
} else { } else {
@ -49,8 +49,8 @@ export const signUp = async (formData: FormData) => {
} catch (error) { } catch (error) {
console.error('Error updating profile: ', error); console.error('Error updating profile: ', error);
} finally { } finally {
return redirect('/protected'); return redirect('/');
//return encodedRedirect('success', '/protected', //return encodedRedirect('success', '/',
//'Thanks for signing up! Please check your email for a verification link.); //'Thanks for signing up! Please check your email for a verification link.);
} }
} }
@ -69,7 +69,7 @@ export const signIn = async (formData: FormData) => {
if (error) { if (error) {
return encodedRedirect('error', '/sign-in', error.message); return encodedRedirect('error', '/sign-in', error.message);
} }
return redirect('/protected'); return redirect('/');
}; };
export const forgotPassword = async (formData: FormData) => { export const forgotPassword = async (formData: FormData) => {
@ -83,7 +83,7 @@ export const forgotPassword = async (formData: FormData) => {
} }
const { error } = await supabase.auth.resetPasswordForEmail(email, { const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${origin}/auth/callback?redirect_to=/protected/reset-password`, redirectTo: `${origin}/auth/callback?redirect_to=/reset-password`,
}); });
if (error) { if (error) {
@ -113,7 +113,7 @@ export const resetPassword = async (formData: FormData) => {
if (!password || !confirmPassword) { if (!password || !confirmPassword) {
encodedRedirect( encodedRedirect(
'error', 'error',
'/protected/reset-password', '/reset-password',
'Password and confirm password are required', 'Password and confirm password are required',
); );
} }
@ -121,7 +121,7 @@ export const resetPassword = async (formData: FormData) => {
if (password !== confirmPassword) { if (password !== confirmPassword) {
encodedRedirect( encodedRedirect(
'error', 'error',
'/protected/reset-password', '/reset-password',
'Passwords do not match', 'Passwords do not match',
); );
} }
@ -133,12 +133,12 @@ export const resetPassword = async (formData: FormData) => {
if (error) { if (error) {
encodedRedirect( encodedRedirect(
'error', 'error',
'/protected/reset-password', '/reset-password',
'Password update failed', 'Password update failed',
); );
} }
encodedRedirect('success', '/protected/reset-password', 'Password updated'); encodedRedirect('success', '/reset-password', 'Password updated');
}; };
export const signOut = async () => { export const signOut = async () => {

View File

@ -41,13 +41,13 @@ export const updateSession = async (request: NextRequest) => {
const user = await supabase.auth.getUser(); const user = await supabase.auth.getUser();
// protected routes // protected routes
if (request.nextUrl.pathname.startsWith('/protected') && user.error) { if (request.nextUrl.pathname.startsWith('/reset-password') && user.error) {
return NextResponse.redirect(new URL('/sign-in', request.url)); return NextResponse.redirect(new URL('/sign-in', request.url));
} }
if (request.nextUrl.pathname === '/' && !user.error) { //if (request.nextUrl.pathname === '/' && !user.error) {
return NextResponse.redirect(new URL('/protected', request.url)); //return NextResponse.redirect(new URL('/protected', request.url));
} //}
return response; return response;
} catch (e) { } catch (e) {

View File

@ -1,4 +1,5 @@
import type { Database } from '@/utils/supabase/types'; import type { Database } from '@/utils/supabase/types';
export type { User } from '@supabase/supabase-js';
// Table row types // Table row types
export type Profile = Database['public']['Tables']['profiles']['Row']; export type Profile = Database['public']['Tables']['profiles']['Row'];

View File

@ -1,188 +0,0 @@
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json | undefined }
| Json[];
export type Database = {
public: {
Tables: {
profiles: {
Row: {
avatar_url: string | null;
email: string | null;
full_name: string | null;
id: string;
provider: string | null;
updated_at: string | null;
};
Insert: {
avatar_url?: string | null;
email?: string | null;
full_name?: string | null;
id: string;
provider?: string | null;
updated_at?: string | null;
};
Update: {
avatar_url?: string | null;
email?: string | null;
full_name?: string | null;
id?: string;
provider?: string | null;
updated_at?: string | null;
};
Relationships: [];
};
statuses: {
Row: {
created_at: string;
id: string;
status: string;
updated_by_id: string | null;
user_id: string;
};
Insert: {
created_at?: string;
id?: string;
status: string;
updated_by_id?: string | null;
user_id: string;
};
Update: {
created_at?: string;
id?: string;
status?: string;
updated_by_id?: string | null;
user_id?: string;
};
Relationships: [];
};
};
Views: {
[_ in never]: never;
};
Functions: {
[_ in never]: never;
};
Enums: {
[_ in never]: never;
};
CompositeTypes: {
[_ in never]: never;
};
};
};
type DefaultSchema = Database[Extract<keyof Database, 'public'>];
export type Tables<
DefaultSchemaTableNameOrOptions extends
| keyof (DefaultSchema['Tables'] & DefaultSchema['Views'])
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends {
Row: infer R;
}
? R
: never
: DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] &
DefaultSchema['Views'])
? (DefaultSchema['Tables'] &
DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends {
Row: infer R;
}
? R
: never
: never;
export type TablesInsert<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema['Tables']
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
Insert: infer I;
}
? I
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
Insert: infer I;
}
? I
: never
: never;
export type TablesUpdate<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema['Tables']
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
Update: infer U;
}
? U
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
Update: infer U;
}
? U
: never
: never;
export type Enums<
DefaultSchemaEnumNameOrOptions extends
| keyof DefaultSchema['Enums']
| { schema: keyof Database },
EnumName extends DefaultSchemaEnumNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums']
: never = never,
> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName]
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums']
? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions]
: never;
export type CompositeTypes<
PublicCompositeTypeNameOrOptions extends
| keyof DefaultSchema['CompositeTypes']
| { schema: keyof Database },
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
schema: keyof Database;
}
? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes']
: never = never,
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes']
? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions]
: never;
export const Constants = {
public: {
Enums: {},
},
} as const;