This commit introduces several new scripts for managing database operations, including user creation, permission grants, and data migrations. It also adds new documentation files to guide users through the setup and configuration processes. Additionally, the project structure is updated to enhance organization and maintainability, ensuring a smoother development experience for contributors. These changes support the ongoing transition to a web-based architecture and improve overall project functionality.
170 lines
5.3 KiB
TypeScript
170 lines
5.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { useSession, signOut } from 'next-auth/react';
|
|
import Link from 'next/link';
|
|
import { useRouter } from 'next/navigation';
|
|
import { User, Upload, Users, LogIn, UserPlus } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from '@/components/ui/popover';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
import { LoginDialog } from '@/components/LoginDialog';
|
|
import { RegisterDialog } from '@/components/RegisterDialog';
|
|
import { ManageUsersPageClient } from '@/app/admin/users/ManageUsersPageClient';
|
|
|
|
function UserMenu() {
|
|
const { data: session, status } = useSession();
|
|
const router = useRouter();
|
|
const [loginDialogOpen, setLoginDialogOpen] = useState(false);
|
|
const [registerDialogOpen, setRegisterDialogOpen] = useState(false);
|
|
const [manageUsersOpen, setManageUsersOpen] = useState(false);
|
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
|
|
const handleSignOut = async () => {
|
|
await signOut({ callbackUrl: '/' });
|
|
};
|
|
|
|
if (status === 'loading') {
|
|
return <div className="h-9 w-9 animate-pulse rounded-full bg-gray-200 dark:bg-gray-700" />;
|
|
}
|
|
|
|
if (session?.user) {
|
|
return (
|
|
<>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
asChild
|
|
className="bg-blue-100 hover:bg-blue-200 dark:bg-blue-900 dark:hover:bg-blue-800"
|
|
>
|
|
<Link href="/upload" aria-label="Upload Photos">
|
|
<Upload className="h-5 w-5" />
|
|
</Link>
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Upload your own photos</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-9 w-9 rounded-full"
|
|
aria-label="Account menu"
|
|
>
|
|
<User className="h-5 w-5 text-orange-600" />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-56 p-2 z-[110]" align="end">
|
|
<div className="space-y-1">
|
|
<div className="px-2 py-1.5">
|
|
<p className="text-sm font-medium text-secondary">
|
|
{session.user.name || 'User'}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
{session.user.email}
|
|
</p>
|
|
</div>
|
|
<div className="border-t pt-1">
|
|
<Button
|
|
variant="ghost"
|
|
className="w-full justify-start text-sm text-secondary hover:text-secondary hover:bg-secondary/10"
|
|
onClick={() => {
|
|
setPopoverOpen(false);
|
|
router.push('/upload');
|
|
}}
|
|
>
|
|
<Upload className="mr-2 h-4 w-4" />
|
|
Upload Photos
|
|
</Button>
|
|
{session.user.isAdmin && (
|
|
<Button
|
|
variant="ghost"
|
|
className="w-full justify-start text-sm text-secondary hover:text-secondary hover:bg-secondary/10"
|
|
onClick={() => {
|
|
setPopoverOpen(false);
|
|
setManageUsersOpen(true);
|
|
}}
|
|
>
|
|
<Users className="mr-2 h-4 w-4" />
|
|
Manage Users
|
|
</Button>
|
|
)}
|
|
<Button
|
|
variant="ghost"
|
|
className="w-full justify-start text-sm text-secondary hover:text-secondary hover:bg-secondary/10"
|
|
onClick={() => {
|
|
setPopoverOpen(false);
|
|
handleSignOut();
|
|
}}
|
|
>
|
|
Sign out
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
{manageUsersOpen && (
|
|
<ManageUsersPageClient onClose={() => setManageUsersOpen(false)} />
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => setLoginDialogOpen(true)}
|
|
className="flex items-center gap-2"
|
|
>
|
|
<LogIn className="h-4 w-4" />
|
|
<span className="hidden sm:inline">Sign in</span>
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
onClick={() => setRegisterDialogOpen(true)}
|
|
className="flex items-center gap-2"
|
|
>
|
|
<UserPlus className="h-4 w-4" />
|
|
<span className="hidden sm:inline">Sign up</span>
|
|
</Button>
|
|
<LoginDialog
|
|
open={loginDialogOpen}
|
|
onOpenChange={(open) => {
|
|
setLoginDialogOpen(open);
|
|
}}
|
|
onOpenRegister={() => {
|
|
setLoginDialogOpen(false);
|
|
setRegisterDialogOpen(true);
|
|
}}
|
|
/>
|
|
<RegisterDialog
|
|
open={registerDialogOpen}
|
|
onOpenChange={(open) => {
|
|
setRegisterDialogOpen(open);
|
|
}}
|
|
onOpenLogin={() => {
|
|
setRegisterDialogOpen(false);
|
|
setLoginDialogOpen(true);
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default UserMenu;
|