add sign in

This commit is contained in:
2025-04-04 12:23:24 +02:00
parent 27f7d3dd2c
commit 5ca9104e7b
4 changed files with 53 additions and 37 deletions

View File

@@ -6,6 +6,7 @@ import { Geist } from 'next/font/google'
import { MainHeader } from '@/components/header' import { MainHeader } from '@/components/header'
import { ThemeProvider } from '@/components/theme-provider' import { ThemeProvider } from '@/components/theme-provider'
import { TRPCReactProvider } from '@/trpc/react' import { TRPCReactProvider } from '@/trpc/react'
import { SessionProvider } from 'next-auth/react'
import { NextIntlClientProvider } from 'next-intl' import { NextIntlClientProvider } from 'next-intl'
import { getLocale } from 'next-intl/server' import { getLocale } from 'next-intl/server'
@@ -33,6 +34,7 @@ export default async function RootLayout({
<body> <body>
<TRPCReactProvider> <TRPCReactProvider>
<NextIntlClientProvider> <NextIntlClientProvider>
<SessionProvider>
<ThemeProvider <ThemeProvider
attribute='class' attribute='class'
defaultTheme='system' defaultTheme='system'
@@ -42,6 +44,7 @@ export default async function RootLayout({
<MainHeader /> <MainHeader />
{children} {children}
</ThemeProvider> </ThemeProvider>
</SessionProvider>
</NextIntlClientProvider> </NextIntlClientProvider>
</TRPCReactProvider> </TRPCReactProvider>
</body> </body>

View File

@@ -9,6 +9,7 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu' } from '@/components/ui/dropdown-menu'
import { LogIn, LogOut, Menu, Moon, Settings, Sun, User, X } from 'lucide-react' import { LogIn, LogOut, Menu, Moon, Settings, Sun, User, X } from 'lucide-react'
import { signIn, signOut, useSession } from 'next-auth/react'
import { useTheme } from 'next-themes' import { useTheme } from 'next-themes'
import Link from 'next/link' import Link from 'next/link'
import { useState } from 'react' import { useState } from 'react'
@@ -16,21 +17,8 @@ import { useState } from 'react'
export function MainHeader() { export function MainHeader() {
const { setTheme, theme } = useTheme() const { setTheme, theme } = useTheme()
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const { data: session, status } = useSession()
// Mock authentication state - replace with your actual auth logic const isAuthenticated = status === 'authenticated'
const [isAuthenticated, setIsAuthenticated] = useState(false)
// Mock user data - replace with your actual user data
const userData = {
name: 'Player123',
avatar: '/placeholder.svg?height=40&width=40',
}
// Toggle authentication for demo purposes
const toggleAuth = () => {
setIsAuthenticated(!isAuthenticated)
}
return ( return (
<header className='sticky top-0 z-40 border-gray-200 border-b bg-white dark:border-zinc-800 dark:bg-zinc-900'> <header className='sticky top-0 z-40 border-gray-200 border-b bg-white dark:border-zinc-800 dark:bg-zinc-900'>
<div className='container mx-auto px-4'> <div className='container mx-auto px-4'>
@@ -97,7 +85,7 @@ export function MainHeader() {
</DropdownMenu> </DropdownMenu>
{/* Sign In Button or User Menu */} {/* Sign In Button or User Menu */}
{isAuthenticated ? ( {isAuthenticated && session?.user && session.user.name ? (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
<Button <Button
@@ -105,9 +93,12 @@ export function MainHeader() {
className='relative h-9 w-9 rounded-full' className='relative h-9 w-9 rounded-full'
> >
<Avatar className='h-9 w-9'> <Avatar className='h-9 w-9'>
<AvatarImage src={userData.avatar} alt={userData.name} /> <AvatarImage
src={session.user.image ?? ''}
alt={session.user.name}
/>
<AvatarFallback className='bg-violet-50 text-violet-600 dark:bg-violet-900/50 dark:text-violet-300'> <AvatarFallback className='bg-violet-50 text-violet-600 dark:bg-violet-900/50 dark:text-violet-300'>
{userData.name.slice(0, 2).toUpperCase()} {session.user.name?.slice(0, 2).toUpperCase()}
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
</Button> </Button>
@@ -115,11 +106,14 @@ export function MainHeader() {
<DropdownMenuContent className='w-56' align='end' forceMount> <DropdownMenuContent className='w-56' align='end' forceMount>
<div className='flex items-center justify-start gap-2 p-2'> <div className='flex items-center justify-start gap-2 p-2'>
<div className='flex flex-col space-y-1 leading-none'> <div className='flex flex-col space-y-1 leading-none'>
<p className='font-medium'>{userData.name}</p> <p className='font-medium'>{session.user.name}</p>
</div> </div>
</div> </div>
<DropdownMenuItem asChild> <DropdownMenuItem asChild>
<Link href='/profile' className='flex w-full items-center'> <Link
href={`/players/${session.user.discord_id}`}
className='flex w-full items-center'
>
<User className='mr-2 h-4 w-4' /> <User className='mr-2 h-4 w-4' />
<span>Profile</span> <span>Profile</span>
</Link> </Link>
@@ -130,7 +124,7 @@ export function MainHeader() {
<span>Settings</span> <span>Settings</span>
</Link> </Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem onClick={toggleAuth}> <DropdownMenuItem onClick={() => signOut()}>
<LogOut className='mr-2 h-4 w-4' /> <LogOut className='mr-2 h-4 w-4' />
<span>Log out</span> <span>Log out</span>
</DropdownMenuItem> </DropdownMenuItem>
@@ -141,7 +135,7 @@ export function MainHeader() {
variant='default' variant='default'
size='sm' size='sm'
className='bg-violet-600 hover:bg-violet-700 dark:text-zinc-100' className='bg-violet-600 hover:bg-violet-700 dark:text-zinc-100'
onClick={toggleAuth} onClick={() => signIn('discord')}
> >
<LogIn className='mr-2 h-4 w-4' /> <LogIn className='mr-2 h-4 w-4' />
Sign In Sign In

View File

@@ -20,15 +20,11 @@ declare module 'next-auth' {
interface Session extends DefaultSession { interface Session extends DefaultSession {
user: { user: {
id: string id: string
discord_id: string
// ...other properties // ...other properties
// role: UserRole; // role: UserRole;
} & DefaultSession['user'] } & DefaultSession['user']
} }
// interface User {
// // ...other properties
// // role: UserRole;
// }
} }
/** /**
@@ -38,7 +34,27 @@ declare module 'next-auth' {
*/ */
export const authConfig = { export const authConfig = {
providers: [ providers: [
DiscordProvider, DiscordProvider({
profile(profile) {
if (profile.avatar === null) {
const defaultAvatarNumber =
profile.discriminator === '0'
? Number(BigInt(profile.id) >> BigInt(22)) % 6
: Number.parseInt(profile.discriminator) % 5
profile.image_url = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`
} else {
const format = profile.avatar.startsWith('a_') ? 'gif' : 'png'
profile.image_url = `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`
}
return {
id: profile.id,
name: profile.global_name ?? profile.username,
email: profile.email,
image: profile.image_url,
discord_id: profile.id.toString(),
}
},
}),
/** /**
* ...add more providers here. * ...add more providers here.
* *
@@ -61,6 +77,7 @@ export const authConfig = {
user: { user: {
...session.user, ...session.user,
id: user.id, id: user.id,
discord_id: session.user.discord_id,
}, },
}), }),
}, },

View File

@@ -62,6 +62,8 @@ export const users = pgTable('user', (d) => ({
}) })
.default(sql`CURRENT_TIMESTAMP`), .default(sql`CURRENT_TIMESTAMP`),
image: d.varchar({ length: 255 }), image: d.varchar({ length: 255 }),
discord_id: d.varchar({ length: 255 }),
role: d.varchar({ length: 255 }).notNull().default('user'),
})) }))
export const usersRelations = relations(users, ({ many }) => ({ export const usersRelations = relations(users, ({ many }) => ({