haixunMaster/components/connections/chrome-session-sync.tsx

102 lines
2.9 KiB
TypeScript
Raw Permalink Normal View History

2026-06-21 12:50:31 +00:00
"use client";
import { useCallback, useEffect, useState } from "react";
import { Chrome, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { notify } from "@/lib/notifications/store";
interface ChromeSessionSyncProps {
onSynced?: () => void;
}
export function ChromeSessionSync({ onSynced }: ChromeSessionSyncProps) {
const [extensionReady, setExtensionReady] = useState(false);
const [syncing, setSyncing] = useState(false);
const [activeAccountId, setActiveAccountId] = useState<string | null>(null);
useEffect(() => {
fetch("/api/accounts")
.then((res) => res.json())
.then((data) => setActiveAccountId(data.activeAccountId ?? null))
.catch(() => undefined);
}, []);
const handleMessage = useCallback(
(event: MessageEvent) => {
if (event.source !== window) return;
if (event.data?.type === "HAIXUN_EXTENSION_READY") {
setExtensionReady(true);
return;
}
if (event.data?.type !== "HAIXUN_THREADS_SYNC_RESULT") return;
setSyncing(false);
const data = event.data as {
valid?: boolean;
message?: string;
};
notify({
type: data.valid ? "success" : "error",
title: data.valid ? "已同步到 server" : "同步失敗",
message: data.message,
});
if (data.valid) {
window.dispatchEvent(new CustomEvent("haixun:accounts-updated"));
onSynced?.();
}
},
[onSynced]
);
useEffect(() => {
window.addEventListener("message", handleMessage);
window.postMessage({ type: "HAIXUN_PING_EXTENSION" }, "*");
return () => window.removeEventListener("message", handleMessage);
}, [handleMessage]);
function handleSync() {
setSyncing(true);
window.postMessage(
{
type: "HAIXUN_REQUEST_THREADS_SYNC",
serverUrl: window.location.origin,
accountId: activeAccountId ?? undefined,
},
"*"
);
window.setTimeout(() => {
setSyncing((current) => {
if (current) {
notify({
type: "warning",
title: "尚未收到擴充功能回應",
message: "請在 Chrome 安裝並啟用 extension/haixun-threads-sync 擴充功能。",
});
}
return false;
});
}, 12000);
}
return (
<div className="space-y-3">
<p className="text-xs text-muted-foreground">
{extensionReady ? (
<span className="text-success"></span>
) : (
<span className="text-warning"> extension/haixun-threads-sync</span>
)}
</p>
<Button onClick={handleSync} disabled={syncing} className="w-full sm:w-auto">
{syncing ? <Loader2 className="h-4 w-4 animate-spin" /> : <Chrome className="h-4 w-4" />}
{syncing ? "同步中…" : "從 Chrome 同步到目前帳號"}
</Button>
</div>
);
}