2025-07-27 10:05:37 -07:00
|
|
|
"use client";
|
2025-07-17 04:10:24 -07:00
|
|
|
|
2026-02-05 18:56:38 +02:00
|
|
|
import { BadgeCheck, Loader2, LogOut } from "lucide-react";
|
2025-07-27 10:41:15 -07:00
|
|
|
import { useRouter } from "next/navigation";
|
2026-02-05 18:56:38 +02:00
|
|
|
import { useState } from "react";
|
2025-07-27 10:05:37 -07:00
|
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
2025-07-27 10:41:15 -07:00
|
|
|
import { Button } from "@/components/ui/button";
|
2025-07-17 04:10:24 -07:00
|
|
|
import {
|
2025-07-27 10:05:37 -07:00
|
|
|
DropdownMenu,
|
|
|
|
|
DropdownMenuContent,
|
|
|
|
|
DropdownMenuGroup,
|
|
|
|
|
DropdownMenuItem,
|
|
|
|
|
DropdownMenuLabel,
|
|
|
|
|
DropdownMenuSeparator,
|
|
|
|
|
DropdownMenuTrigger,
|
|
|
|
|
} from "@/components/ui/dropdown-menu";
|
2026-02-05 18:56:38 +02:00
|
|
|
import { logout } from "@/lib/auth-utils";
|
2026-01-16 11:32:06 -08:00
|
|
|
import { cleanupElectric } from "@/lib/electric/client";
|
2026-01-02 01:10:16 -08:00
|
|
|
import { resetUser, trackLogout } from "@/lib/posthog/events";
|
2025-07-17 04:10:24 -07:00
|
|
|
|
|
|
|
|
export function UserDropdown({
|
2025-07-27 10:05:37 -07:00
|
|
|
user,
|
2025-07-17 04:10:24 -07:00
|
|
|
}: {
|
2025-07-27 10:05:37 -07:00
|
|
|
user: {
|
|
|
|
|
name: string;
|
|
|
|
|
email: string;
|
|
|
|
|
avatar: string;
|
|
|
|
|
};
|
2025-07-17 04:10:24 -07:00
|
|
|
}) {
|
2025-07-27 10:05:37 -07:00
|
|
|
const router = useRouter();
|
2026-02-05 18:56:38 +02:00
|
|
|
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
2025-07-17 04:10:24 -07:00
|
|
|
|
2026-01-16 11:32:06 -08:00
|
|
|
const handleLogout = async () => {
|
2026-02-05 18:56:38 +02:00
|
|
|
if (isLoggingOut) return;
|
|
|
|
|
setIsLoggingOut(true);
|
2025-07-27 10:05:37 -07:00
|
|
|
try {
|
2026-01-02 01:10:16 -08:00
|
|
|
// Track logout event and reset PostHog identity
|
|
|
|
|
trackLogout();
|
|
|
|
|
resetUser();
|
|
|
|
|
|
2026-01-16 11:32:06 -08:00
|
|
|
// Best-effort cleanup of Electric SQL / PGlite
|
|
|
|
|
// Even if this fails, login-time cleanup will handle it
|
|
|
|
|
try {
|
|
|
|
|
await cleanupElectric();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.warn("[Logout] Electric cleanup failed (will be handled on next login):", err);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-05 18:56:38 +02:00
|
|
|
// Revoke refresh token on server and clear all tokens from localStorage
|
|
|
|
|
await logout();
|
|
|
|
|
|
2025-07-27 10:05:37 -07:00
|
|
|
if (typeof window !== "undefined") {
|
2026-01-07 18:13:31 +02:00
|
|
|
window.location.href = "/";
|
2025-07-27 10:05:37 -07:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error during logout:", error);
|
2026-02-05 18:56:38 +02:00
|
|
|
// Even if there's an error, try to clear tokens and redirect
|
|
|
|
|
await logout();
|
2025-07-27 10:05:37 -07:00
|
|
|
if (typeof window !== "undefined") {
|
2026-01-07 18:13:31 +02:00
|
|
|
window.location.href = "/";
|
2025-07-27 10:05:37 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-07-17 04:10:24 -07:00
|
|
|
|
2025-07-27 10:05:37 -07:00
|
|
|
return (
|
|
|
|
|
<DropdownMenu>
|
|
|
|
|
<DropdownMenuTrigger asChild>
|
|
|
|
|
<Button variant="ghost" className="relative h-10 w-10 rounded-full">
|
|
|
|
|
<Avatar className="h-8 w-8">
|
|
|
|
|
<AvatarImage src={user.avatar} alt={user.name} />
|
|
|
|
|
<AvatarFallback>{user.name.charAt(0)?.toUpperCase() || "?"}</AvatarFallback>
|
|
|
|
|
</Avatar>
|
|
|
|
|
</Button>
|
|
|
|
|
</DropdownMenuTrigger>
|
2025-12-29 00:06:38 +05:30
|
|
|
<DropdownMenuContent className="w-44 md:w-56" align="end" forceMount>
|
|
|
|
|
<DropdownMenuLabel className="font-normal p-2 md:p-3">
|
2025-07-27 10:05:37 -07:00
|
|
|
<div className="flex flex-col space-y-1">
|
2025-12-29 00:06:38 +05:30
|
|
|
<p className="text-xs md:text-sm font-medium leading-none">{user.name}</p>
|
2025-12-29 00:24:49 +05:30
|
|
|
<p className="text-[10px] md:text-xs leading-none text-muted-foreground">
|
|
|
|
|
{user.email}
|
|
|
|
|
</p>
|
2025-07-27 10:05:37 -07:00
|
|
|
</div>
|
|
|
|
|
</DropdownMenuLabel>
|
|
|
|
|
<DropdownMenuSeparator />
|
|
|
|
|
<DropdownMenuGroup>
|
2025-12-29 00:24:49 +05:30
|
|
|
<DropdownMenuItem
|
|
|
|
|
onClick={() => router.push(`/dashboard/api-key`)}
|
|
|
|
|
className="text-xs md:text-sm"
|
|
|
|
|
>
|
2025-12-29 00:06:38 +05:30
|
|
|
<BadgeCheck className="mr-2 h-3.5 w-3.5 md:h-4 md:w-4" />
|
2025-07-27 10:05:37 -07:00
|
|
|
API Key
|
|
|
|
|
</DropdownMenuItem>
|
|
|
|
|
</DropdownMenuGroup>
|
|
|
|
|
<DropdownMenuSeparator />
|
2026-02-05 18:56:38 +02:00
|
|
|
<DropdownMenuItem
|
|
|
|
|
onClick={handleLogout}
|
|
|
|
|
className="text-xs md:text-sm"
|
|
|
|
|
disabled={isLoggingOut}
|
|
|
|
|
>
|
|
|
|
|
{isLoggingOut ? (
|
|
|
|
|
<Loader2 className="mr-2 h-3.5 w-3.5 md:h-4 md:w-4 animate-spin" />
|
|
|
|
|
) : (
|
|
|
|
|
<LogOut className="mr-2 h-3.5 w-3.5 md:h-4 md:w-4" />
|
|
|
|
|
)}
|
|
|
|
|
{isLoggingOut ? "Logging out..." : "Log out"}
|
2025-07-27 10:05:37 -07:00
|
|
|
</DropdownMenuItem>
|
|
|
|
|
</DropdownMenuContent>
|
|
|
|
|
</DropdownMenu>
|
|
|
|
|
);
|
|
|
|
|
}
|