"use client" import { useState, useEffect } from "react" import { Loader2, Link as LinkIcon, Unlink, Shield } from "lucide-react" import { motion } from "motion/react" import { FaGoogle, FaDiscord } from "react-icons/fa" import { authClient } from "@/lib/auth-client" interface LinkedAccount { id: string providerId: string accountId: string createdAt: Date updatedAt: Date userId: string scopes: string[] } interface AuthMethods { hasPassword: boolean passkeyCount: number oauthProviders: { providerId: string; id: string }[] totalAuthMethods: number } const providerConfig: Record | null; color: string; bgColor: string }> = { google: { name: "Google", icon: FaGoogle, color: "text-red-400", bgColor: "bg-red-500/10 border-red-500/20" }, discord: { name: "Discord", icon: FaDiscord, color: "text-indigo-400", bgColor: "bg-indigo-500/10 border-indigo-500/20" }, credential: { name: "Password", icon: null, color: "text-text/60", bgColor: "bg-text/5 border-border" }, } interface SettingsAccountsTabProps { authMethods: AuthMethods | null isLoadingAuthMethods: boolean onRefreshAuthMethods: () => Promise } export function SettingsAccountsTab({ authMethods, isLoadingAuthMethods, onRefreshAuthMethods }: SettingsAccountsTabProps) { const [accounts, setAccounts] = useState([]) const [isLoadingAccounts, setIsLoadingAccounts] = useState(true) const [accountsError, setAccountsError] = useState(null) const [unlinking, setUnlinking] = useState(null) const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(() => { // Check for OAuth callback success on initial render if (typeof window !== "undefined") { const params = new URLSearchParams(window.location.search) if (params.has("linked")) { window.history.replaceState({}, "", window.location.pathname) return { type: "success", text: "Account linked successfully!" } } } return null }) useEffect(() => { fetchAccounts() }, []) async function fetchAccounts() { try { const { data, error } = await authClient.listAccounts() if (error || !data) { setAccountsError("Failed to load linked accounts") setAccounts([]) } else { setAccounts(Array.isArray(data) ? data : []) setAccountsError(null) } } catch { setAccountsError("Failed to load linked accounts. Please try again.") setAccounts([]) } finally { setIsLoadingAccounts(false) } } const refreshAccounts = async () => { try { const { data } = await authClient.listAccounts() if (data) setAccounts(Array.isArray(data) ? data : accounts) } catch { // silently fail on refresh } } const refreshData = async () => { await Promise.all([refreshAccounts(), onRefreshAuthMethods()]) } const handleLink = async (provider: "google" | "discord") => { setMessage(null) try { const { data, error } = await authClient.linkSocial({ provider, callbackURL: window.location.origin + "/profile?linked=true", }) if (error) { setMessage({ type: "error", text: error.message || "Failed to link account" }) return } if (data?.url) { window.location.assign(data.url) } } catch { setMessage({ type: "error", text: "Failed to initiate account linking" }) } } const handleUnlink = async (providerId: string) => { if (authMethods && authMethods.totalAuthMethods <= 1) return setUnlinking(providerId) setMessage(null) try { const { error } = await authClient.unlinkAccount({ providerId, }) if (error) { setMessage({ type: "error", text: error.message || "Failed to unlink account" }) } else { setMessage({ type: "success", text: `${providerConfig[providerId]?.name || providerId} account unlinked` }) await refreshData() } } catch { setMessage({ type: "error", text: "Failed to unlink account" }) } finally { setUnlinking(null) } } const linkedProviders = new Set(accounts.map((a) => a.providerId)) const availableProviders = ["google", "discord"].filter((p) => !linkedProviders.has(p)) const isOnlyAuthMethod = authMethods ? authMethods.totalAuthMethods <= 1 : true return ( {/* Warning if only one auth method */} {isOnlyAuthMethod && !isLoadingAuthMethods && (

Single authentication method

You only have one way to sign in. Consider linking a social account or adding a passkey.

)} {message && (

{message.text}

)} {/* Linked Accounts */}

Linked Accounts

{accountsError ? (

{accountsError}

) : isLoadingAccounts ? (
) : (
{/* Password status */} {authMethods && (

Password

{authMethods.hasPassword ? "Configured" : "Not set"}

{authMethods.hasPassword ? "Active" : "Inactive"}
)} {/* OAuth accounts */} {accounts.map((account) => { const config = providerConfig[account.providerId] || { name: account.providerId, icon: null, color: "text-text/60", bgColor: "bg-text/5 border-border", } const canUnlink = !isOnlyAuthMethod return (
{config.icon ? : }

{config.name}

Linked

) })} {/* Passkeys count */} {authMethods && authMethods.passkeyCount > 0 && (

Passkeys

{authMethods.passkeyCount} registered

Active
)}
)}
{/* Link New Account */} {availableProviders.length > 0 && (

Link a Social Account

{availableProviders.map((provider) => { const config = providerConfig[provider] if (!config) return null return ( ) })}
)}
) }