102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
"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>
|
||
);
|
||
} |