fix(client): cancel all character timeouts (#58116)

This commit is contained in:
Oliver Eyton-Williams
2025-01-14 22:10:17 +01:00
committed by GitHub
parent c0460c9a81
commit f2b025a321
@@ -19,6 +19,10 @@ interface CharacterStyles {
opacity?: number;
}
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export function Character({
position,
opacity,
@@ -30,55 +34,64 @@ export function Character({
const [mouthIsOpen, setMouthIsOpen] = useState(false);
useEffect(() => {
let blinkInterval: NodeJS.Timeout | null = null;
let talkInterval: NodeJS.Timeout | null = null;
let blinkIntervalId: NodeJS.Timeout;
let blinkTimeoutId: NodeJS.Timeout;
if (isBlinking) {
const msBetweenIntervals = Math.floor(Math.random() * 3000) + 2000;
blinkInterval = setInterval(() => {
const msBlinkDelay = Math.floor(Math.random() * 1000);
setTimeout(() => {
const blinkPeriod = getRandomInt(2000, 5000);
blinkIntervalId = setInterval(() => {
const blinkJitter = getRandomInt(0, 1000);
blinkTimeoutId = setTimeout(() => {
setEyesAreOpen(false);
setTimeout(() => {
blinkTimeoutId = setTimeout(() => {
setEyesAreOpen(true);
}, 30); // always unblink after 30ms
}, msBlinkDelay);
}, msBetweenIntervals);
}, blinkJitter);
}, blinkPeriod);
}
// Clear intervals when component is unmounted or conditions change
return () => {
setEyesAreOpen(true);
clearInterval(blinkIntervalId);
clearTimeout(blinkTimeoutId);
};
}, [isBlinking]);
useEffect(() => {
let talkIntervalId: NodeJS.Timeout;
let mouthOpenTimeoutId: NodeJS.Timeout;
let mouthCloseTimeoutId: NodeJS.Timeout;
if (isTalking) {
const talk = () => {
const openTimeout = getRandomInt(0, 100);
const closeTimeout = getRandomInt(150, 300);
setTimeout(() => {
mouthOpenTimeoutId = setTimeout(() => {
setMouthIsOpen(true);
}, openTimeout);
setTimeout(() => {
mouthCloseTimeoutId = setTimeout(() => {
setMouthIsOpen(false);
}, closeTimeout);
};
talk();
talkInterval = setInterval(() => {
talkIntervalId = setInterval(() => {
talk();
}, 300);
}
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Clear intervals when component is unmounted or conditions change
return () => {
setEyesAreOpen(true);
setMouthIsOpen(false);
if (blinkInterval) clearInterval(blinkInterval);
if (talkInterval) clearInterval(talkInterval);
clearInterval(talkIntervalId);
clearTimeout(mouthOpenTimeoutId);
clearTimeout(mouthCloseTimeoutId);
};
}, [isBlinking, isTalking]);
}, [isTalking]);
const characterWrapStyles: CharacterStyles = {
opacity