Skip to content

Commit 0fa0670

Browse files
committed
fix: prevent duplicate prompt dispatch from QR pick polling
Use a ref-based guard (pickedRef) to ensure sendPrompt is called exactly once, regardless of effect re-runs or in-flight fetch races. Also generate a fresh session ID each time the modal opens.
1 parent 3e7bc4e commit 0fa0670

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

apps/app/src/app/page.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function HomePage() {
1616

1717
const [demoDrawerOpen, setDemoDrawerOpen] = useState(false);
1818
const [qrOpen, setQrOpen] = useState(false);
19-
const [qrSessionId] = useState(() => typeof crypto !== "undefined" ? crypto.randomUUID().slice(0, 12) : "fallback");
19+
const [qrSessionId, setQrSessionId] = useState("");
2020
const [scanStatus, setScanStatus] = useState<"waiting" | "scanned" | "picked">("waiting");
2121
const { agent } = useAgent();
2222
const { copilotkit } = useCopilotKit();
@@ -27,6 +27,9 @@ export default function HomePage() {
2727
useEffect(() => { agentRef.current = agent; }, [agent]);
2828
useEffect(() => { copilotkitRef.current = copilotkit; }, [copilotkit]);
2929

30+
// Guard: prevent duplicate prompt dispatch across re-renders
31+
const pickedRef = useRef(false);
32+
3033
const sendPrompt = useCallback((prompt: string) => {
3134
const a = agentRef.current;
3235
const ck = copilotkitRef.current;
@@ -40,25 +43,26 @@ export default function HomePage() {
4043
};
4144

4245
const openQrModal = () => {
46+
pickedRef.current = false;
4347
setScanStatus("waiting");
48+
setQrSessionId(crypto.randomUUID().slice(0, 12));
4449
setQrOpen(true);
4550
};
4651

4752
// Poll for QR pick status
4853
useEffect(() => {
49-
if (!qrOpen) return;
50-
let picked = false;
54+
if (!qrOpen || !qrSessionId) return;
5155
const interval = setInterval(async () => {
52-
if (picked) return;
56+
if (pickedRef.current) return;
5357
try {
5458
const res = await fetch(`/api/pick?sessionId=${qrSessionId}`);
5559
const data = await res.json();
5660
if (data.status === "scanned") {
5761
setScanStatus("scanned");
58-
} else if (data.status === "picked" && data.prompt) {
59-
picked = true;
60-
setScanStatus("picked");
62+
} else if (data.status === "picked" && data.prompt && !pickedRef.current) {
63+
pickedRef.current = true;
6164
clearInterval(interval);
65+
setScanStatus("picked");
6266
setTimeout(() => {
6367
setQrOpen(false);
6468
sendPrompt(data.prompt);

0 commit comments

Comments
 (0)