Merge pull request #1055 from thejesh23/fix/frontend-ui-race-cleanup

Fix three frontend bugs: children counter, cross-video seek race, poll-interval leak
This commit is contained in:
Shubham Saboo
2026-08-01 17:38:20 -07:00
committed by GitHub
3 changed files with 23 additions and 6 deletions
@@ -958,7 +958,7 @@ export default function Plan() {
<NumberInput
value={field.value}
onChange={field.onChange}
min={1}
min={0}
/>
</FormControl>
<FormMessage />
@@ -1,6 +1,6 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import { useCoAgent, useCopilotAction } from "@copilotkit/react-core";
import { motion, AnimatePresence } from "framer-motion";
import {
@@ -362,10 +362,19 @@ export default function NegotiationBattle() {
}
};
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
// Stop polling on unmount so we don't fetch/setState on an unmounted component
// or keep polling forever when a run never reaches deal/no_deal.
useEffect(() => () => {
if (pollRef.current) clearInterval(pollRef.current);
}, []);
const runNegotiation = async () => {
// This will be handled by the agent automatically
// Just need to poll for state updates
const pollInterval = setInterval(async () => {
if (pollRef.current) clearInterval(pollRef.current);
pollRef.current = setInterval(async () => {
try {
const stateRes = await fetch('http://localhost:8000/get_negotiation_state');
const stateData = await stateRes.json();
@@ -385,7 +394,7 @@ export default function NegotiationBattle() {
});
if (stateData.status === "deal" || stateData.status === "no_deal") {
clearInterval(pollInterval);
if (pollRef.current) clearInterval(pollRef.current);
}
} catch (error) {
console.error('Error polling state:', error);
@@ -160,13 +160,21 @@ export default function Home() {
const jumpToMoment = (moment: Moment) => {
setVideoTimestamp(moment.timestamp);
const switchingVideo = moment.video_id !== selectedVideo;
setSelectedVideo(moment.video_id);
setTimeout(() => {
const seek = () => {
if (videoRef.current) {
videoRef.current.currentTime = moment.timestamp;
videoRef.current.play();
}
}, 100);
};
if (switchingVideo && videoRef.current) {
// The <video src> changes on the re-render triggered above; a fixed 100ms
// timeout races that reload, so seek only once the new file has loaded.
videoRef.current.addEventListener("loadeddata", seek, { once: true });
} else {
setTimeout(seek, 100);
}
};
// Drag and drop