187 lines
5.3 KiB
TypeScript
Raw Normal View History

2024-10-21 13:57:45 -06:00
"use client"
2024-04-18 15:07:15 -04:00
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
2024-10-21 13:57:45 -06:00
} from "@/components/ui/dropdown-menu"
import { User } from "@/lib/types"
import { useClerk } from "@clerk/nextjs"
2024-11-11 22:02:34 +01:00
import {
Crown,
2024-11-11 22:02:34 +01:00
LayoutDashboard,
LogOut,
Sparkles,
User as UserIcon,
} from "lucide-react"
import Link from "next/link"
2024-10-21 13:57:45 -06:00
import { useRouter } from "next/navigation"
import { useEffect, useState } from "react"
import Avatar from "./avatar"
import { Button } from "./button"
import { TIERS } from "@/lib/tiers"
2024-04-18 15:07:15 -04:00
// TODO: Remove this once we have a proper tier system
const TIER_INFO = {
FREE: {
color: "text-gray-500",
icon: Sparkles,
limit: TIERS.FREE.generations,
},
PRO: {
color: "text-blue-500",
icon: Crown,
limit: TIERS.PRO.generations,
},
ENTERPRISE: {
color: "text-purple-500",
icon: Crown,
limit: TIERS.ENTERPRISE.generations,
},
} as const
2024-04-28 01:17:39 -04:00
export default function UserButton({
userData: initialUserData,
}: {
userData: User
}) {
const [userData, setUserData] = useState<User>(initialUserData)
const [isOpen, setIsOpen] = useState(false)
2024-10-21 13:57:45 -06:00
const { signOut } = useClerk()
const router = useRouter()
2024-04-28 01:17:39 -04:00
const fetchUserData = async () => {
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/user?id=${userData.id}`,
{
headers: {
Authorization: `${process.env.NEXT_PUBLIC_WORKERS_KEY}`,
},
cache: "no-store",
}
)
if (res.ok) {
const updatedUserData = await res.json()
setUserData(updatedUserData)
}
} catch (error) {
console.error("Failed to fetch user data:", error)
}
}
useEffect(() => {
if (isOpen) {
fetchUserData()
}
}, [isOpen])
const tierInfo =
TIER_INFO[userData.tier as keyof typeof TIER_INFO] || TIER_INFO.FREE
const TierIcon = tierInfo.icon
const usagePercentage = Math.floor(
((userData.generations || 0) * 100) / tierInfo.limit
)
const handleUpgrade = async () => {
router.push(`/@${userData.username}`)
}
2024-04-18 15:07:15 -04:00
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
2024-04-18 15:07:15 -04:00
<DropdownMenuTrigger>
<Avatar name={userData.name} avatarUrl={userData.avatarUrl} />
2024-04-18 15:07:15 -04:00
</DropdownMenuTrigger>
<DropdownMenuContent className="w-64" align="end">
2024-05-04 23:31:35 -07:00
<div className="py-1.5 px-2 w-full">
<div className="font-medium">{userData.name}</div>
<div className="text-sm w-full overflow-hidden text-ellipsis whitespace-nowrap text-muted-foreground">
{userData.email}
</div>
</div>
<DropdownMenuSeparator />
2024-11-11 22:02:34 +01:00
<DropdownMenuItem className="cursor-pointer" asChild>
<Link href={"/dashboard"}>
<LayoutDashboard className="mr-2 size-4" />
<span>Dashboard</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
2024-11-11 22:02:34 +01:00
<DropdownMenuItem className="cursor-pointer" asChild>
<Link href={`/@${userData.username}`}>
<UserIcon className="mr-2 size-4" />
<span>Profile</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<div className="py-1.5 px-2 w-full">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1.5">
<TierIcon className={`h-4 w-4 ${tierInfo.color}`} />
<span className="text-sm font-medium">
{userData.tier || "FREE"} Plan
</span>
</div>
{(userData.tier === "FREE" || userData.tier === "PRO") && (
<Button
variant="ghost"
size="sm"
className="h-7 text-xs border-b hover:border-b-foreground"
onClick={handleUpgrade}
>
Upgrade
</Button>
)}
</div>
</div>
<DropdownMenuSeparator />
<div className="px-2 py-1.5">
<div className="w-full">
<div className="flex items-center justify-between text-sm text-muted-foreground mb-2">
<span>AI Usage</span>
<span>
{userData.generations}/{tierInfo.limit}
</span>
</div>
<div className="rounded-full w-full h-2 overflow-hidden bg-secondary mb-1">
<div
className={`h-full rounded-full transition-all duration-300 ${
usagePercentage > 90
? "bg-red-500"
: usagePercentage > 75
? "bg-yellow-500"
: tierInfo.color.replace("text-", "bg-")
}`}
style={{
width: `${Math.min(usagePercentage, 100)}%`,
}}
/>
</div>
</div>
</div>
2024-05-04 23:31:35 -07:00
<DropdownMenuSeparator />
2024-05-17 23:54:34 -07:00
{/* <DropdownMenuItem className="cursor-pointer">
2024-11-11 22:02:34 +01:00
<Pencil className="mr-2 size-4" />
2024-04-18 15:07:15 -04:00
<span>Edit Profile</span>
2024-05-17 23:54:34 -07:00
</DropdownMenuItem> */}
2024-04-28 01:17:39 -04:00
<DropdownMenuItem
onClick={() => signOut(() => router.push("/"))}
className="!text-destructive cursor-pointer"
>
2024-11-11 22:02:34 +01:00
<LogOut className="mr-2 size-4" />
2024-04-18 15:07:15 -04:00
<span>Log Out</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
2024-10-21 13:57:45 -06:00
)
2024-04-18 15:07:15 -04:00
}