"use client"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Card, CardDescription, CardContent, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { PasswordInput } from "@/components/ui/password-input"; import { client, signOut, user, useSession } from "@/lib/auth-client"; import { Session } from "@/lib/auth-types"; import { MobileIcon } from "@radix-ui/react-icons"; import { Edit, Fingerprint, Laptop, Loader2, LogOut, Plus, QrCode, ShieldCheck, ShieldOff, Trash, X, } from "lucide-react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { toast } from "sonner"; import { UAParser } from "ua-parser-js"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import QRCode from "react-qr-code"; import CopyButton from "@/components/ui/copy-button"; export default function UserCard(props: { session: Session | null; activeSessions: Session["session"][]; }) { const router = useRouter(); const { data, isPending, error } = useSession(); const [ua, setUa] = useState(); const session = data || props.session; useEffect(() => { setUa(new UAParser(session?.session.userAgent)); }, [session?.session.userAgent]); const [isTerminating, setIsTerminating] = useState(); const { data: qr } = useQuery({ queryKey: ["two-factor-qr"], queryFn: async () => { const res = await client.twoFactor.getTotpUri(); if (res.error) { throw res.error; } return res.data; }, enabled: !!session?.user.twoFactorEnabled, }); const [isPendingTwoFa, setIsPendingTwoFa] = useState(false); const [twoFaPassword, setTwoFaPassword] = useState(""); const [twoFactorDialog, setTwoFactorDialog] = useState(false); const [isSignOut, setIsSignOut] = useState(false); const [emailVerificationPending, setEmailVerificationPending] = useState(false); return ( User
{session?.user.name.charAt(0)}

{session?.user.name}

{session?.user.email}

{session?.user.emailVerified ? null : ( Verify Your Email Address Please verify your email address. Check your inbox for the verification email. If you haven't received the email, click the button below to resend. )}

Active Sessions

{props.activeSessions .filter((session) => session.userAgent) .map((session) => { return (
{new UAParser(session.userAgent).getDevice().type === "mobile" ? ( ) : ( )} {new UAParser(session.userAgent).getOS().name},{" "} {new UAParser(session.userAgent).getBrowser().name}
); })}

Passkeys

Two Factor

{!!session?.user.twoFactorEnabled && ( Scan QR Code Scan the QR code with your TOTP app

Copy URI to clipboard

)} {session?.user.twoFactorEnabled ? "Disable 2FA" : "Enable 2FA"} {session?.user.twoFactorEnabled ? "Disable the second factor authentication from your account" : "Enable 2FA to secure your account"}
setTwoFaPassword(e.target.value)} />
); } async function convertImageToBase64(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(file); }); } function ChangePassword() { const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); const [signOutDevices, setSignOutDevices] = useState(false); return ( Change Password Change your password
setCurrentPassword(e.target.value)} autoComplete="new-password" placeholder="Password" /> setNewPassword(e.target.value)} autoComplete="new-password" placeholder="New Password" /> setConfirmPassword(e.target.value)} autoComplete="new-password" placeholder="Confirm Password" />
checked ? setSignOutDevices(true) : setSignOutDevices(false) } />

Sign out from other devices

); } function EditUserDialog(props: { session: Session | null }) { const [name, setName] = useState(); const router = useRouter(); const [image, setImage] = useState(null); const [imagePreview, setImagePreview] = useState(null); const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setImage(file); const reader = new FileReader(); reader.onloadend = () => { setImagePreview(reader.result as string); }; reader.readAsDataURL(file); } }; const [open, setOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); return ( Edit User Edit user information
{ setName(e.target.value); }} />
{imagePreview && (
Profile preview
)}
{imagePreview && ( { setImage(null); setImagePreview(null); }} /> )}
); } function AddPasskey() { const [isOpen, setIsOpen] = useState(false); const [passkeyName, setPasskeyName] = useState(""); const queryClient = useQueryClient(); const [isLoading, setIsLoading] = useState(false); const handleAddPasskey = async () => { if (!passkeyName) { toast.error("Passkey name is required"); return; } setIsLoading(true); const res = await client.passkey.addPasskey({ name: passkeyName, }); if (res?.error) { toast.error(res?.error.message); } else { setIsOpen(false); toast.success("Passkey added successfully. You can now use it to login."); } setIsLoading(false); }; return ( Add New Passkey Create a new passkey to securely access your account without a password.
setPasskeyName(e.target.value)} />
); } function ListPasskeys() { const { data, error } = client.useListPasskeys(); const [isOpen, setIsOpen] = useState(false); const [passkeyName, setPasskeyName] = useState(""); const handleAddPasskey = async () => { if (!passkeyName) { toast.error("Passkey name is required"); return; } setIsLoading(true); const res = await client.passkey.addPasskey({ name: passkeyName, }); setIsLoading(false); if (res?.error) { toast.error(res?.error.message); } else { toast.success("Passkey added successfully. You can now use it to login."); } }; const [isLoading, setIsLoading] = useState(false); const [isDeletePasskey, setIsDeletePasskey] = useState(false); return ( Passkeys List of passkeys {data?.length ? ( Name {data.map((passkey) => ( {passkey.name || "My Passkey"} ))}
) : (

No passkeys found

)} {!data?.length && (
setPasskeyName(e.target.value)} placeholder="My Passkey" />
)}
); }