Ran prettier. Moved Header to layout file

This commit is contained in:
Gabriel Brown 2025-03-19 15:52:55 -05:00
parent f5e3cb6234
commit 939fd796ee
27 changed files with 482 additions and 447 deletions

View File

@ -1,7 +1,7 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
import './src/env.js';
import { withSentryConfig } from '@sentry/nextjs';

View File

@ -1,35 +1,35 @@
import { type EmailOtpType } from '@supabase/supabase-js'
import { type NextRequest, NextResponse } from 'next/server'
import { type EmailOtpType } from '@supabase/supabase-js';
import { type NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/utils/supabase/server'
import { createClient } from '@/utils/supabase/server';
// Creating a handler to a GET request to route /auth/confirm
export const GET = async (request: NextRequest) => {
const { searchParams } = new URL(request.url)
const token_hash = searchParams.get('token_hash')
const type = searchParams.get('type') as EmailOtpType | null
const next = '/account'
const { searchParams } = new URL(request.url);
const token_hash = searchParams.get('token_hash');
const type = searchParams.get('type') as EmailOtpType | null;
const next = '/account';
// Create redirect link without the secret token
const redirectTo = request.nextUrl.clone()
redirectTo.pathname = next
redirectTo.searchParams.delete('token_hash')
redirectTo.searchParams.delete('type')
const redirectTo = request.nextUrl.clone();
redirectTo.pathname = next;
redirectTo.searchParams.delete('token_hash');
redirectTo.searchParams.delete('type');
if (token_hash && type) {
const supabase = await createClient()
const supabase = await createClient();
const { error } = await supabase.auth.verifyOtp({
type,
token_hash,
})
});
if (!error) {
redirectTo.searchParams.delete('next')
return NextResponse.redirect(redirectTo)
redirectTo.searchParams.delete('next');
return NextResponse.redirect(redirectTo);
}
}
// return the user to an error page with some instructions
redirectTo.pathname = '/error'
return NextResponse.redirect(redirectTo)
}
redirectTo.pathname = '/error';
return NextResponse.redirect(redirectTo);
};

View File

@ -1,4 +1,4 @@
const ErrorPage = () => {
return <p>Sorry, something went wrong</p>
}
return <p>Sorry, something went wrong</p>;
};
export default ErrorPage;

View File

@ -3,6 +3,9 @@ import { GeistSans } from 'geist/font/sans';
import { cn } from '@/lib/utils';
import { ThemeProvider } from '@/components/context/Theme';
import { TVModeProvider } from '@/components/context/TVMode';
import { createClient } from '@/utils/supabase/server';
import LoginForm from '@/components/auth/LoginForm';
import Header from '@/components/defaults/Header';
import { type Metadata } from 'next';
export const metadata: Metadata = {
@ -28,20 +31,14 @@ export const metadata: Metadata = {
],
};
const RootLayout = ({
children,
}: Readonly<{ children: React.ReactNode }>) => {
const RootLayout = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
return (
<html
lang='en'
className={`${GeistSans.variable}`}
suppressHydrationWarning
>
<body
className={cn(
'min-h-screen bg-background font-sans antialiased'
)}
>
<body className={cn('min-h-screen bg-background font-sans antialiased')}>
<ThemeProvider
attribute='class'
defaultTheme='system'
@ -49,7 +46,10 @@ const RootLayout = ({
disableTransitionOnChange
>
<TVModeProvider>
{children}
<main className='min-h-screen'>
<Header />
{children}
</main>
</TVModeProvider>
</ThemeProvider>
</body>

View File

@ -1,6 +1,5 @@
'use server'
'use server';
import LoginForm from '@/components/auth/LoginForm';
import Header from '@/components/defaults/Header';
import { createClient } from '@/utils/supabase/server';
const HomePage = async () => {
@ -8,21 +7,15 @@ const HomePage = async () => {
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
return (
<main className="min-h-screen">
<Header />
<div className="flex flex-col items-center justify-center md:min-h-[80vh]">
<LoginForm />
</div>
</main>
<div className='flex flex-col items-center justify-center md:min-h-[70vh]'>
<LoginForm />
</div>
);
}
return (
<main>
<Header />
<div className="flex flex-col items-center justify-center">
<h1>Hello, {session.user.email}</h1>
</div>
</main>
<div className='flex flex-col items-center justify-center'>
<h1>Hello, {session.user.email}</h1>
</div>
);
};
export default HomePage;

View File

@ -1,4 +1,4 @@
'use client'
'use client';
import { useState, useEffect } from 'react';
import Image from 'next/image';
@ -13,6 +13,7 @@ import {
import { createClient } from '@/utils/supabase/client';
import type { Session } from '@supabase/supabase-js';
import { Button } from '@/components/ui/button';
import { redirect } from 'next/navigation';
const AvatarDropdown = () => {
const supabase = createClient();
@ -23,7 +24,9 @@ const AvatarDropdown = () => {
// Function to fetch the session
async function fetchSession() {
try {
const { data: { session } } = await supabase.auth.getSession();
const {
data: { session },
} = await supabase.auth.getSession();
setSession(session);
} catch (error) {
console.error('Error fetching session:', error);
@ -33,17 +36,16 @@ const AvatarDropdown = () => {
}
// Call the function
fetchSession()
.catch((error) => {
console.error('Error fetching session:', error);
});
fetchSession().catch((error) => {
console.error('Error fetching session:', error);
});
// Set up auth state change listener
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setSession(session);
}
);
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});
// Clean up the subscription when component unmounts
return () => {
@ -54,11 +56,12 @@ const AvatarDropdown = () => {
// Handle sign out
const handleSignOut = async () => {
await supabase.auth.signOut();
redirect('/');
};
// Show nothing while loading
if (loading) {
return <div className="animate-pulse h-8 w-8 rounded-full bg-gray-300" />;
return <div className='animate-pulse h-8 w-8 rounded-full bg-gray-300' />;
}
// If no session, return empty div
@ -67,14 +70,16 @@ const AvatarDropdown = () => {
}
// Get user details
const pfp = session.user?.user_metadata?.avatar_url as string ??
session.user?.user_metadata?.picture as string ??
'/images/default_user_pfp.png';
const name: string = session.user?.user_metadata?.full_name as string ??
session.user?.user_metadata?.name as string ??
session.user?.email as string ??
'Profile' as string;
const pfp =
(session.user?.user_metadata?.avatar_url as string) ??
(session.user?.user_metadata?.picture as string) ??
'/images/default_user_pfp.png';
const name: string =
(session.user?.user_metadata?.full_name as string) ??
(session.user?.user_metadata?.name as string) ??
(session.user?.email as string) ??
('Profile' as string);
// If no session, return empty div
if (!session) return <div />;
@ -84,7 +89,7 @@ const AvatarDropdown = () => {
<DropdownMenuTrigger>
<Image
src={pfp}
alt="User profile"
alt='User profile'
width={35}
height={35}
className='rounded-full border-2 border-white m-auto mr-1 md:mr-2
@ -103,5 +108,5 @@ const AvatarDropdown = () => {
</DropdownMenu>
</div>
);
}
};
export default AvatarDropdown;

View File

@ -1,4 +1,4 @@
'use client'
'use client';
import { login, signup } from '@/server/actions/auth';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
@ -22,20 +22,20 @@ import {
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
} from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import MicrosoftSignIn from '@/components/auth/microsoft/SignIn';
import AppleSignIn from './apple/SignIn';
const formSchema = z.object({
fullName: z.string().optional(),
email: z.string().email("Must be a valid email!"),
password: z.string().min(8, "Must be at least 8 characters!"),
email: z.string().email('Must be a valid email!'),
password: z.string().min(8, 'Must be at least 8 characters!'),
});
const LoginForm = () => {
const formRef = useRef<HTMLFormElement>(null);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
@ -68,21 +68,17 @@ const LoginForm = () => {
>
<CardHeader className='flex items-center justify-center'>
<CardTitle>Sign In</CardTitle>
<CardDescription>
Log in or create an account.
</CardDescription>
<CardDescription>Log in or create an account.</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form ref={formRef} className="space-y-4">
<form ref={formRef} className='space-y-4'>
<FormField
control={form.control}
name="fullName"
name='fullName'
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='fullName'>
Full Name
</FormLabel>
<FormLabel htmlFor='fullName'>Full Name</FormLabel>
<FormControl>
<Input id='fullName' type='text' {...field} />
</FormControl>
@ -95,12 +91,10 @@ const LoginForm = () => {
/>
<FormField
control={form.control}
name="email"
name='email'
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='email'>
Email
</FormLabel>
<FormLabel htmlFor='email'>Email</FormLabel>
<FormControl>
<Input id='email' type='email' {...field} required />
</FormControl>
@ -110,12 +104,10 @@ const LoginForm = () => {
/>
<FormField
control={form.control}
name="password"
name='password'
render={({ field }) => (
<FormItem>
<FormLabel>
Password
</FormLabel>
<FormLabel>Password</FormLabel>
<FormControl>
<Input id='password' type='password' {...field} required />
</FormControl>
@ -123,12 +115,12 @@ const LoginForm = () => {
</FormItem>
)}
/>
<div className="flex gap-4 justify-center items-center">
<div className='flex gap-4 justify-center items-center'>
<Button
type='button'
className='w-5/12 font-semibold bg-gradient-to-r
from-primary via-primary to-primarydark
hover:from-primary hover:via-primarydark hover:to-primarydark'
hover:from-primary hover:via-primarydark hover:to-primarydark'
onClick={handleLogin}
>
Log in
@ -137,7 +129,7 @@ const LoginForm = () => {
type='button'
className='w-5/12 font-semibold bg-gradient-to-l
from-primary via-primary to-primarydark
hover:from-primary hover:via-primarydark hover:to-primarydark'
hover:from-primary hover:via-primarydark hover:to-primarydark'
onClick={handleSignup}
>
Sign up
@ -149,13 +141,11 @@ const LoginForm = () => {
<CardFooter className='flex flex-col items-center justify-center w-full'>
<div className='flex flex-row items-center justify-between w-5/6'>
<Separator className='w-5/12 h-0.5 rounded-3xl' />
<p className='text-center text-muted-foreground font-semibold'>
or
</p>
<p className='text-center text-muted-foreground font-semibold'>or</p>
<Separator className='w-5/12 h-0.5 rounded-3xl' />
</div>
<div className='m-1'>
< MicrosoftSignIn />
<MicrosoftSignIn />
<div className='my-2'>
<AppleSignIn />
</div>

View File

@ -11,12 +11,11 @@ const AppleSignIn = () => {
<Image
src='/images/apple_black.svg'
alt='Apple Logo'
width={16} height={16}
width={16}
height={16}
className='invert dark:invert-0'
/>
<p className='font-semibold dark:text-slate-950'>
Sign in with Apple
</p>
<p className='font-semibold dark:text-slate-950'>Sign in with Apple</p>
</Button>
);
};

View File

@ -11,7 +11,8 @@ const MicrosoftSignIn = () => {
<Image
src='/images/microsoft_logo.png'
alt='Microsoft Logo'
width={20} height={20}
width={20}
height={20}
/>
<p className='font-semibold dark:text-slate-950'>
Sign in with Microsoft

View File

@ -1,8 +1,9 @@
'use client';
import React, { createContext, useContext, useState } from 'react';
import React, { createContext, useContext, useState, useEffect } from 'react';
import Image from 'next/image';
import type { ReactNode } from 'react';
//import { useSession } from 'next-auth/react';
import type { Session } from '@supabase/supabase-js';
import { createClient } from '@/utils/supabase/client';
interface TVModeContextProps {
tvMode: boolean;
@ -35,8 +36,45 @@ export const useTVMode = () => {
export const TVToggle = () => {
const { tvMode, toggleTVMode } = useTVMode();
//const { data: session } = useSession();
//if (!session) return <div />;
const supabase = createClient();
const [session, setSession] = useState<Session | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Function to fetch the session
async function fetchSession() {
try {
const {
data: { session },
} = await supabase.auth.getSession();
setSession(session);
} catch (error) {
console.error('Error fetching session:', error);
} finally {
setLoading(false);
}
}
// Call the function
fetchSession().catch((error) => {
console.error('Error fetching session:', error);
});
// Set up auth state change listener
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});
// Clean up the subscription when component unmounts
return () => {
subscription.unsubscribe();
};
}, [supabase]);
if (loading || !session) return <div />;
return (
<button onClick={toggleTVMode} className='mr-4 mt-1'>
{tvMode ? (

View File

@ -11,7 +11,7 @@ const Header = () => {
<div className='w-full flex flex-row items-end justify-end'>
<div className='flex flex-row my-auto items-center pt-2 pr-0 sm:pr-8 sm:pt-4'>
<AvatarDropdown />
<div className='mb-0.5'>
<div className='mb-0.5 ml-2'>
<TVToggle />
</div>
<ThemeToggle />
@ -27,7 +27,7 @@ const Header = () => {
pt-2 pr-0 sm:pt-4 sm:pr-8'
>
<AvatarDropdown />
<div className='mb-0.5'>
<div className='mb-0.5 ml-2'>
<TVToggle />
</div>
<ThemeToggle />

View File

@ -1,9 +1,9 @@
"use client"
'use client';
import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import * as React from 'react';
import * as AvatarPrimitive from '@radix-ui/react-avatar';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
@ -12,13 +12,13 @@ const Avatar = React.forwardRef<
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
className,
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName
));
Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
@ -26,11 +26,11 @@ const AvatarImage = React.forwardRef<
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
className={cn('aspect-square h-full w-full', className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
@ -39,12 +39,12 @@ const AvatarFallback = React.forwardRef<
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
'flex h-full w-full items-center justify-center rounded-full bg-muted',
className,
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
export { Avatar, AvatarImage, AvatarFallback }
export { Avatar, AvatarImage, AvatarFallback };

View File

@ -1,57 +1,57 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
variant: "default",
size: "default",
variant: 'default',
size: 'default',
},
}
)
},
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : 'button';
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
);
},
);
Button.displayName = 'Button';
export { Button, buttonVariants }
export { Button, buttonVariants };

View File

@ -1,6 +1,6 @@
import * as React from "react"
import * as React from 'react';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const Card = React.forwardRef<
HTMLDivElement,
@ -9,13 +9,13 @@ const Card = React.forwardRef<
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
className
'rounded-xl border bg-card text-card-foreground shadow',
className,
)}
{...props}
/>
))
Card.displayName = "Card"
));
Card.displayName = 'Card';
const CardHeader = React.forwardRef<
HTMLDivElement,
@ -23,11 +23,11 @@ const CardHeader = React.forwardRef<
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
className={cn('flex flex-col space-y-1.5 p-6', className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
));
CardHeader.displayName = 'CardHeader';
const CardTitle = React.forwardRef<
HTMLDivElement,
@ -35,11 +35,11 @@ const CardTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
className={cn('font-semibold leading-none tracking-tight', className)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
));
CardTitle.displayName = 'CardTitle';
const CardDescription = React.forwardRef<
HTMLDivElement,
@ -47,19 +47,19 @@ const CardDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
));
CardDescription.displayName = 'CardDescription';
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
));
CardContent.displayName = 'CardContent';
const CardFooter = React.forwardRef<
HTMLDivElement,
@ -67,10 +67,17 @@ const CardFooter = React.forwardRef<
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
className={cn('flex items-center p-6 pt-0', className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
));
CardFooter.displayName = 'CardFooter';
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View File

@ -1,44 +1,44 @@
"use client"
'use client';
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"
import * as React from 'react';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { Check, ChevronRight, Circle } from 'lucide-react';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
inset && "pl-8",
className
'flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
inset && 'pl-8',
className,
)}
{...props}
>
{children}
<ChevronRight className="ml-auto" />
<ChevronRight className='ml-auto' />
</DropdownMenuPrimitive.SubTrigger>
))
));
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@ -47,14 +47,14 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
className
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
className,
)}
{...props}
/>
))
));
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@ -65,33 +65,33 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
className
'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
className,
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
inset && "pl-8",
className
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
inset && 'pl-8',
className,
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
@ -100,22 +100,22 @@ const DropdownMenuCheckboxItem = React.forwardRef<
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
<DropdownMenuPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
<Check className='h-4 w-4' />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
));
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@ -124,38 +124,38 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="h-2 w-2 fill-current" />
<Circle className='h-2 w-2 fill-current' />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
'px-2 py-1.5 text-sm font-semibold',
inset && 'pl-8',
className,
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
@ -163,11 +163,11 @@ const DropdownMenuSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
className={cn('-mx-1 my-1 h-px bg-muted', className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@ -175,12 +175,12 @@ const DropdownMenuShortcut = ({
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
);
};
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
export {
DropdownMenu,
@ -198,4 +198,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
};

View File

@ -1,8 +1,8 @@
"use client"
'use client';
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import * as React from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import { Slot } from '@radix-ui/react-slot';
import {
Controller,
FormProvider,
@ -10,27 +10,27 @@ import {
type ControllerProps,
type FieldPath,
type FieldValues,
} from "react-hook-form"
} from 'react-hook-form';
import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { cn } from '@/lib/utils';
import { Label } from '@/components/ui/label';
const Form = FormProvider
const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
name: TName
}
name: TName;
};
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
{} as FormFieldContextValue,
);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
@ -38,21 +38,21 @@ const FormField = <
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
);
};
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
const fieldState = getFieldState(fieldContext.name, formState)
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>")
throw new Error('useFormField should be used within <FormField>');
}
const { id } = itemContext
const { id } = itemContext;
return {
id,
@ -61,53 +61,54 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
};
};
type FormItemContextValue = {
id: string
}
id: string;
};
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
{} as FormItemContextValue,
);
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
const id = React.useId();
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
<div ref={ref} className={cn('space-y-2', className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = "FormItem"
);
});
FormItem.displayName = 'FormItem';
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
const { error, formItemId } = useFormField();
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
className={cn(error && 'text-destructive', className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = "FormLabel"
);
});
FormLabel.displayName = 'FormLabel';
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
const { error, formItemId, formDescriptionId, formMessageId } =
useFormField();
return (
<Slot
@ -121,50 +122,50 @@ const FormControl = React.forwardRef<
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = "FormControl"
);
});
FormControl.displayName = 'FormControl';
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
const { formDescriptionId } = useFormField();
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-[0.8rem] text-muted-foreground", className)}
className={cn('text-[0.8rem] text-muted-foreground', className)}
{...props}
/>
)
})
FormDescription.displayName = "FormDescription"
);
});
FormDescription.displayName = 'FormDescription';
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const body = error ? String(error?.message ?? "") : children
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message ?? '') : children;
if (!body) {
return null
return null;
}
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-[0.8rem] font-medium text-destructive", className)}
className={cn('text-[0.8rem] font-medium text-destructive', className)}
{...props}
>
{body}
</p>
)
})
FormMessage.displayName = "FormMessage"
);
});
FormMessage.displayName = 'FormMessage';
export {
useFormField,
@ -175,4 +176,4 @@ export {
FormDescription,
FormMessage,
FormField,
}
};

View File

@ -1,22 +1,22 @@
import * as React from "react"
import * as React from 'react';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
className,
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
);
},
);
Input.displayName = 'Input';
export { Input }
export { Input };

View File

@ -1,14 +1,14 @@
"use client"
'use client';
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
);
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
@ -20,7 +20,7 @@ const Label = React.forwardRef<
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
));
Label.displayName = LabelPrimitive.Root.displayName;
export { Label }
export { Label };

View File

@ -1,9 +1,9 @@
"use client"
'use client';
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import * as React from 'react';
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
@ -11,38 +11,38 @@ const ScrollArea = React.forwardRef<
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
className={cn('relative overflow-hidden', className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
<ScrollAreaPrimitive.Viewport className='h-full w-full rounded-[inherit]'>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
));
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
>(({ className, orientation = 'vertical', ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
'flex touch-none select-none transition-colors',
orientation === 'vertical' &&
'h-full w-2.5 border-l border-l-transparent p-[1px]',
orientation === 'horizontal' &&
'h-2.5 flex-col border-t border-t-transparent p-[1px]',
className,
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
<ScrollAreaPrimitive.ScrollAreaThumb className='relative flex-1 rounded-full bg-border' />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
export { ScrollArea, ScrollBar }
export { ScrollArea, ScrollBar };

View File

@ -1,31 +1,31 @@
"use client"
'use client';
import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"
import * as React from 'react';
import * as SeparatorPrimitive from '@radix-ui/react-separator';
import { cn } from "@/lib/utils"
import { cn } from '@/lib/utils';
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref
{ className, orientation = 'horizontal', decorative = true, ...props },
ref,
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
'shrink-0 bg-border',
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
className,
)}
{...props}
/>
)
)
Separator.displayName = SeparatorPrimitive.Root.displayName
),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator }
export { Separator };

View File

@ -1,6 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
return twMerge(clsx(inputs));
}

View File

@ -1,9 +1,9 @@
import { type NextRequest } from 'next/server'
import { updateSession } from '@/utils/supabase/middleware'
import { type NextRequest } from 'next/server';
import { updateSession } from '@/utils/supabase/middleware';
export async function middleware(request: NextRequest) {
// update user's auth session
return await updateSession(request)
return await updateSession(request);
}
export const config = {
@ -17,4 +17,4 @@ export const config = {
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
};

View File

@ -1,32 +1,33 @@
'use server'
'use server';
import 'server-only';
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { createClient } from '@/utils/supabase/server'
import { createClient } from '@/utils/supabase/server';
export const login = async (formData: FormData) => {
const supabase = await createClient()
const supabase = await createClient();
// type-casting here for convenience
// in practice, you should validate your inputs
const data = {
email: formData.get('email') as string,
password: formData.get('password') as string,
}
};
const { error } = await supabase.auth.signInWithPassword(data)
const { error } = await supabase.auth.signInWithPassword(data);
if (error) {
redirect('/error')
redirect('/error');
}
revalidatePath('/', 'layout')
revalidatePath('/', 'layout');
redirect('/');
};
export const signup = async (formData: FormData) => {
const supabase = await createClient()
const supabase = await createClient();
// type-casting here for convenience
// in practice, you should validate your inputs
@ -34,13 +35,14 @@ export const signup = async (formData: FormData) => {
fullName: formData.get('fullName') as string,
email: formData.get('email') as string,
password: formData.get('password') as string,
}
};
const { error } = await supabase.auth.signUp(data)
const { error } = await supabase.auth.signUp(data);
if (error) {
redirect('/error')
redirect('/error');
}
revalidatePath('/', 'layout')
revalidatePath('/', 'layout');
redirect('/');
};

View File

@ -1,8 +1,8 @@
import { createBrowserClient } from '@supabase/ssr'
import { createBrowserClient } from '@supabase/ssr';
export const createClient = () => {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);
};

View File

@ -1,31 +1,33 @@
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value))
cookiesToSet.forEach(({ name, value, options }) =>
request.cookies.set(name, value),
);
supabaseResponse = NextResponse.next({
request,
})
});
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
supabaseResponse.cookies.set(name, value, options),
);
},
},
}
)
},
);
// refreshing the auth token
await supabase.auth.getUser()
return supabaseResponse
await supabase.auth.getUser();
return supabaseResponse;
}

View File

@ -1,8 +1,8 @@
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export async function createClient() {
const cookieStore = await cookies()
const cookieStore = await cookies();
// Create a server's supabase client with newly configured cookie,
// which could be used to maintain user's session
@ -12,13 +12,13 @@ export async function createClient() {
{
cookies: {
getAll() {
return cookieStore.getAll()
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
cookieStore.set(name, value, options),
);
} catch {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
@ -26,6 +26,6 @@ export async function createClient() {
}
},
},
}
)
},
);
}

View File

@ -2,72 +2,69 @@ import { type Config } from 'tailwindcss';
import { fontFamily } from 'tailwindcss/defaultTheme';
export default {
darkMode: ['class'],
content: ['./src/**/*.tsx'],
darkMode: ['class'],
content: ['./src/**/*.tsx'],
theme: {
extend: {
fontFamily: {
sans: [
'var(--font-geist-sans)',
...fontFamily.sans
]
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))'
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))'
},
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))'
},
primarydark: {
DEFAULT: 'hsl(var(--primary-dark))',
foreground: 'hsl(var(--primary-foreground))'
},
primarylight: {
DEFAULT: 'hsl(var(--primary-light))',
foreground: 'hsl(var(--primary-foreground))'
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))'
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))'
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))'
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))'
},
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
chart: {
'1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))'
}
}
}
extend: {
fontFamily: {
sans: ['var(--font-geist-sans)', ...fontFamily.sans],
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)',
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))',
},
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
primarydark: {
DEFAULT: 'hsl(var(--primary-dark))',
foreground: 'hsl(var(--primary-foreground))',
},
primarylight: {
DEFAULT: 'hsl(var(--primary-light))',
foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))',
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))',
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))',
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))',
},
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
chart: {
'1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))',
},
},
},
},
plugins: [require("tailwindcss-animate")],
plugins: [require('tailwindcss-animate')],
} satisfies Config;