fix(web): wire Refresh Groups button to syncGroupsAction with live SSE refresh
The button was a placeholder that submitted to a no-op server action,
so clicking did nothing. Replace with a small client component that:
1. Calls syncGroupsAction(accountId) to pgNotify the bot.
2. Listens for the bot's groups.synced event over SSE and
router.refresh()es when it arrives so the new rows appear without
a manual reload.
3. Disables the button + shows a Syncing… label while the sync is
in flight, with a 15s safety timeout if the bot or SSE channel
drops so the spinner doesn't strand.
Drop the in-place <form action={async() => 'use server'}> placeholder.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
40d788302c
commit
5c48e0e85f
@ -4,7 +4,6 @@ import {
|
||||
ArrowLeftIcon,
|
||||
SearchIcon,
|
||||
UsersIcon,
|
||||
RefreshCwIcon,
|
||||
Users2Icon,
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@ -16,6 +15,7 @@ import {
|
||||
} from "@/components/ui/card";
|
||||
import { getSeededOperator } from "@/lib/operator";
|
||||
import { listGroupsForAccount } from "@/lib/queries";
|
||||
import { RefreshGroupsClient } from "./refresh-groups-client";
|
||||
|
||||
interface Props {
|
||||
params: Promise<{ id: string }>;
|
||||
@ -57,13 +57,7 @@ export default async function GroupsListPage({ params, searchParams }: Props) {
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Refresh button — no-op placeholder, wired in Task 17 */}
|
||||
<form action={async () => { "use server"; /* wired in Task 17 */ }}>
|
||||
<Button type="submit" variant="outline" size="sm" className="shrink-0">
|
||||
<RefreshCwIcon />
|
||||
Refresh Groups
|
||||
</Button>
|
||||
</form>
|
||||
<RefreshGroupsClient accountId={account.id} />
|
||||
</div>
|
||||
|
||||
{/* Search */}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useTransition } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Loader2Icon, RefreshCwIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useEvents } from "@/hooks/use-events";
|
||||
import { syncGroupsAction } from "@/actions/accounts";
|
||||
|
||||
interface RefreshGroupsClientProps {
|
||||
accountId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Two-stage refresh button:
|
||||
* 1. Click → server action pgNotifies the bot to start a sync.
|
||||
* 2. Bot finishes → emits `groups.synced` over SSE → router.refresh()
|
||||
* re-fetches the page so the new rows appear without the operator
|
||||
* having to reload manually.
|
||||
*
|
||||
* The button stays in its "syncing" state until either the
|
||||
* `groups.synced` event arrives for this account or 15 s pass (so a
|
||||
* disconnected bot doesn't strand the spinner forever).
|
||||
*/
|
||||
export function RefreshGroupsClient({ accountId }: RefreshGroupsClientProps) {
|
||||
const router = useRouter();
|
||||
const [pending, start] = useTransition();
|
||||
const [waiting, setWaiting] = useState(false);
|
||||
|
||||
useEvents({
|
||||
"groups.synced": (data) => {
|
||||
if (data.accountId !== accountId) return;
|
||||
setWaiting(false);
|
||||
router.refresh();
|
||||
},
|
||||
});
|
||||
|
||||
function trigger() {
|
||||
start(async () => {
|
||||
const fd = new FormData();
|
||||
fd.append("accountId", accountId);
|
||||
await syncGroupsAction(fd);
|
||||
setWaiting(true);
|
||||
// Belt-and-braces: if the bot is unreachable or the SSE channel
|
||||
// drops, drop the spinner after 15 s instead of leaving it stuck.
|
||||
window.setTimeout(() => setWaiting(false), 15_000);
|
||||
});
|
||||
}
|
||||
|
||||
const busy = pending || waiting;
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0"
|
||||
disabled={busy}
|
||||
onClick={trigger}
|
||||
>
|
||||
{busy ? (
|
||||
<Loader2Icon className="size-4 animate-spin" />
|
||||
) : (
|
||||
<RefreshCwIcon className="size-4" />
|
||||
)}
|
||||
{busy ? "Syncing…" : "Refresh Groups"}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user