"use client"; import { useEffect, useState } from "react"; import { ChevronDown, Link2, Loader2, Plus, UserRound } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { notify } from "@/lib/notifications/store"; import { cn } from "@/lib/utils"; interface AccountOption { id: string; username?: string | null; displayName?: string | null; valid: boolean; apiConnected?: boolean; browserConnected?: boolean; } function isConnected(account: AccountOption) { return Boolean(account.browserConnected || account.apiConnected); } function statusLabel(account: AccountOption) { const parts: string[] = []; if (account.browserConnected) parts.push("已同步"); if (account.apiConnected) parts.push("API"); if (!parts.length) return "尚未連線"; return parts.join(" · "); } function ConnectionDot({ connected, className }: { connected: boolean; className?: string }) { return ( ); } export function AccountSwitcher() { const [accounts, setAccounts] = useState([]); const [activeAccountId, setActiveAccountId] = useState(null); const [binding, setBinding] = useState(false); const [creating, setCreating] = useState(false); async function load() { const res = await fetch("/api/accounts"); const data = await res.json(); setAccounts(data.accounts ?? []); setActiveAccountId(data.activeAccountId ?? null); } useEffect(() => { load(); const reload = () => load(); window.addEventListener("haixun:accounts-updated", reload); window.addEventListener("focus", reload); return () => { window.removeEventListener("haixun:accounts-updated", reload); window.removeEventListener("focus", reload); }; }, []); const active = accounts.find((account) => account.id === activeAccountId) ?? null; const connected = active ? isConnected(active) : false; async function activate(id: string) { await fetch(`/api/accounts/${id}/activate`, { method: "POST" }); notify({ type: "success", title: "已切換經營帳號" }); window.dispatchEvent(new Event("haixun:accounts-updated")); window.location.reload(); } async function createAccount() { setCreating(true); try { const res = await fetch("/api/accounts", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ displayName: `帳號 ${accounts.length + 1}`, activate: true, }), }); const data = await res.json(); if (!res.ok) { notify({ type: "error", title: "建立帳號失敗", message: data.error }); return; } notify({ type: "success", title: "已建立帳號", message: "請到連線設定頁用 Chrome 擴充同步 Threads session", }); window.dispatchEvent(new Event("haixun:accounts-updated")); load(); } finally { setCreating(false); } } async function bindAccount() { setBinding(true); try { const res = await fetch("/api/accounts/bind", { method: "POST" }); if (!res.ok) { const data = await res.json().catch(() => ({})); notify({ type: "error", title: "無法開始綁定", message: data.error }); setBinding(false); return; } window.location.href = "/api/threads/oauth/authorize"; } catch { setBinding(false); notify({ type: "error", title: "無法開始綁定" }); } } return ( {active?.displayName ?? active?.username ?? "選擇帳號"} {active && } {active ? statusLabel(active) : "新增或選擇帳號"} {accounts.length > 0 ? ( accounts.map((account) => { const accountConnected = isConnected(account); const isActive = account.id === activeAccountId; return ( activate(account.id)}> {account.displayName ?? account.username ?? "未命名帳號"} {account.username ? `@${account.username} · ` : ""} {statusLabel(account)} {isActive && ( 使用中 )} ); }) ) : ( 尚未建立帳號 )} {creating ? : } 新增帳號 {binding ? : } 綁定 Threads API ); }
{active?.displayName ?? active?.username ?? "選擇帳號"}
{active && } {active ? statusLabel(active) : "新增或選擇帳號"}
{account.displayName ?? account.username ?? "未命名帳號"}
{account.username ? `@${account.username} · ` : ""} {statusLabel(account)}