Refactor AccountSwitcher / LoginArea

This commit is contained in:
Alex Gleason 2025-04-18 15:36:58 -05:00
parent d88285480c
commit dec966b693
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 116 additions and 97 deletions

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React from 'react';
import { ChevronDown, LogOut, User, UserPlus } from 'lucide-react'; import { ChevronDown, LogOut, UserPlus } from 'lucide-react';
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -8,110 +8,65 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu.tsx'; } from '@/components/ui/dropdown-menu.tsx';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx';
import { Button } from '@/components/ui/button.tsx';
import LoginDialog from './LoginDialog';
import SignupDialog from './SignupDialog';
import { useLoggedInAccounts } from '@/hooks/useLoggedInAccounts'; import { useLoggedInAccounts } from '@/hooks/useLoggedInAccounts';
export function AccountSwitcher() { interface AccountSwitcherProps {
onAddAccountClick: () => void;
}
export function AccountSwitcher({ onAddAccountClick }: AccountSwitcherProps) {
const { currentUser, otherUsers, setLogin, removeLogin } = useLoggedInAccounts(); const { currentUser, otherUsers, setLogin, removeLogin } = useLoggedInAccounts();
const [loginDialogOpen, setLoginDialogOpen] = useState(false); if (!currentUser) return null;
const [signupDialogOpen, setSignupDialogOpen] = useState(false);
const handleLogin = () => {
setLoginDialogOpen(false);
setSignupDialogOpen(false);
};
if (!currentUser) {
return (
<>
<Button
onClick={() => setLoginDialogOpen(true)}
className='flex items-center gap-2 px-4 py-2 rounded-full bg-primary text-primary-foreground w-full font-medium transition-all hover:bg-primary/90 animate-scale-in'
>
<User className='w-4 h-4' />
<span>Log in</span>
</Button>
<LoginDialog
isOpen={loginDialogOpen}
onClose={() => setLoginDialogOpen(false)}
onLogin={handleLogin}
onSignup={() => setSignupDialogOpen(true)}
/>
<SignupDialog
isOpen={signupDialogOpen}
onClose={() => setSignupDialogOpen(false)}
/>
</>
);
}
return ( return (
<> <DropdownMenu>
<DropdownMenu> <DropdownMenuTrigger asChild>
<DropdownMenuTrigger asChild> <button className='flex items-center gap-3 p-3 rounded-full hover:bg-accent transition-all w-full text-foreground'>
<button className='flex items-center gap-3 p-3 rounded-full hover:bg-accent transition-all w-full text-foreground'> <Avatar className='w-10 h-10'>
<Avatar className='w-10 h-10'> <AvatarImage src={currentUser.metadata.picture} alt={currentUser.metadata.name} />
<AvatarImage src={currentUser.metadata.picture} alt={currentUser.metadata.name} /> <AvatarFallback>{currentUser.metadata.name?.charAt(0)}</AvatarFallback>
<AvatarFallback>{currentUser.metadata.name?.charAt(0)}</AvatarFallback> </Avatar>
</Avatar> <div className='flex-1 text-left hidden md:block'>
<div className='flex-1 text-left hidden md:block'> <p className='font-medium text-sm'>{currentUser.metadata.name}</p>
<p className='font-medium text-sm'>{currentUser.metadata.name}</p> </div>
</div> <ChevronDown className='w-4 h-4 text-muted-foreground' />
<ChevronDown className='w-4 h-4 text-muted-foreground' /> </button>
</button> </DropdownMenuTrigger>
</DropdownMenuTrigger> <DropdownMenuContent className='w-56 p-2 animate-scale-in'>
<DropdownMenuContent className='w-56 p-2 animate-scale-in'> <div className='font-medium text-sm px-2 py-1.5'>Switch Account</div>
<div className='font-medium text-sm px-2 py-1.5'>Switch Account</div> {otherUsers.map((user) => (
{otherUsers.map((user) => (
<DropdownMenuItem
key={user.id}
onClick={() => setLogin(user.id)}
className='flex items-center gap-2 cursor-pointer p-2 rounded-md'
>
<Avatar className='w-8 h-8'>
<AvatarImage src={user.metadata.picture} alt={user.metadata.name} />
<AvatarFallback>{user.metadata.name?.charAt(0)}</AvatarFallback>
</Avatar>
<div className='flex-1'>
<p className='text-sm font-medium'>{user.metadata.name}</p>
</div>
{user.id === currentUser.id && <div className='w-2 h-2 rounded-full bg-primary'></div>}
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuItem <DropdownMenuItem
onClick={() => setLoginDialogOpen(true)} key={user.id}
onClick={() => setLogin(user.id)}
className='flex items-center gap-2 cursor-pointer p-2 rounded-md' className='flex items-center gap-2 cursor-pointer p-2 rounded-md'
> >
<UserPlus className='w-4 h-4' /> <Avatar className='w-8 h-8'>
<span>Add another account</span> <AvatarImage src={user.metadata.picture} alt={user.metadata.name} />
<AvatarFallback>{user.metadata.name?.charAt(0)}</AvatarFallback>
</Avatar>
<div className='flex-1'>
<p className='text-sm font-medium'>{user.metadata.name}</p>
</div>
{user.id === currentUser.id && <div className='w-2 h-2 rounded-full bg-primary'></div>}
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem ))}
onClick={() => removeLogin(currentUser.id)} <DropdownMenuSeparator />
className='flex items-center gap-2 cursor-pointer p-2 rounded-md text-red-500' <DropdownMenuItem
> onClick={onAddAccountClick}
<LogOut className='w-4 h-4' /> className='flex items-center gap-2 cursor-pointer p-2 rounded-md'
<span>Log out</span> >
</DropdownMenuItem> <UserPlus className='w-4 h-4' />
</DropdownMenuContent> <span>Add another account</span>
</DropdownMenu> </DropdownMenuItem>
<DropdownMenuItem
<LoginDialog onClick={() => removeLogin(currentUser.id)}
isOpen={loginDialogOpen} className='flex items-center gap-2 cursor-pointer p-2 rounded-md text-red-500'
onClose={() => setLoginDialogOpen(false)} >
onLogin={handleLogin} <LogOut className='w-4 h-4' />
onSignup={() => setSignupDialogOpen(true)} <span>Log out</span>
/> </DropdownMenuItem>
</DropdownMenuContent>
<SignupDialog </DropdownMenu>
isOpen={signupDialogOpen}
onClose={() => setSignupDialogOpen(false)}
/>
</>
); );
} }

View File

@ -0,0 +1,64 @@
import React, { useState } from 'react';
import { User } from 'lucide-react';
import { Button } from '@/components/ui/button.tsx';
import LoginDialog from './LoginDialog';
import SignupDialog from './SignupDialog';
import { useLoggedInAccounts } from '@/hooks/useLoggedInAccounts';
import { AccountSwitcher } from './AccountSwitcher';
export function LoginArea() {
const { currentUser } = useLoggedInAccounts();
const [loginDialogOpen, setLoginDialogOpen] = useState(false);
const [signupDialogOpen, setSignupDialogOpen] = useState(false);
const handleLogin = () => {
setLoginDialogOpen(false);
setSignupDialogOpen(false);
};
if (!currentUser) {
return (
<>
<Button
onClick={() => setLoginDialogOpen(true)}
className='flex items-center gap-2 px-4 py-2 rounded-full bg-primary text-primary-foreground w-full font-medium transition-all hover:bg-primary/90 animate-scale-in'
>
<User className='w-4 h-4' />
<span>Log in</span>
</Button>
<LoginDialog
isOpen={loginDialogOpen}
onClose={() => setLoginDialogOpen(false)}
onLogin={handleLogin}
onSignup={() => setSignupDialogOpen(true)}
/>
<SignupDialog
isOpen={signupDialogOpen}
onClose={() => setSignupDialogOpen(false)}
/>
</>
);
}
return (
<>
<AccountSwitcher
onAddAccountClick={() => setLoginDialogOpen(true)}
/>
<LoginDialog
isOpen={loginDialogOpen}
onClose={() => setLoginDialogOpen(false)}
onLogin={handleLogin}
onSignup={() => setSignupDialogOpen(true)}
/>
<SignupDialog
isOpen={signupDialogOpen}
onClose={() => setSignupDialogOpen(false)}
/>
</>
);
}