commit
2eaf4ad75b
@ -113,6 +113,11 @@ export const useChatSocket = (
|
|||||||
emit("fetch_balance", { chatId });
|
emit("fetch_balance", { chatId });
|
||||||
}, [emit, chatId]);
|
}, [emit, chatId]);
|
||||||
|
|
||||||
|
// Auto top-up: silent flow (no UI prompt)
|
||||||
|
const autoTopUpInProgressRef = useRef(false);
|
||||||
|
// Timer for delayed unlock after error
|
||||||
|
const autoTopUpUnlockTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
// Auto top-up: use existing single checkout flow
|
// Auto top-up: use existing single checkout flow
|
||||||
const { handleSingleCheckout, isLoading: isAutoTopUpLoading } =
|
const { handleSingleCheckout, isLoading: isAutoTopUpLoading } =
|
||||||
useSingleCheckout({
|
useSingleCheckout({
|
||||||
@ -120,15 +125,18 @@ export const useChatSocket = (
|
|||||||
onError: () => {
|
onError: () => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error("Auto top-up payment failed");
|
console.error("Auto top-up payment failed");
|
||||||
// Release in-flight lock on error so a future event can retry
|
// Throttle retries: keep the lock for 30 seconds after an error
|
||||||
autoTopUpInProgressRef.current = false;
|
if (autoTopUpUnlockTimerRef.current) {
|
||||||
|
clearTimeout(autoTopUpUnlockTimerRef.current);
|
||||||
|
}
|
||||||
|
autoTopUpUnlockTimerRef.current = setTimeout(() => {
|
||||||
|
autoTopUpInProgressRef.current = false;
|
||||||
|
autoTopUpUnlockTimerRef.current = null;
|
||||||
|
}, 30_000);
|
||||||
},
|
},
|
||||||
returnUrl: typeof window !== "undefined" ? window.location.href : "",
|
returnUrl: typeof window !== "undefined" ? window.location.href : "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto top-up: silent flow (no UI prompt)
|
|
||||||
const autoTopUpInProgressRef = useRef(false);
|
|
||||||
|
|
||||||
const balancePollId = useRef<NodeJS.Timeout | null>(null);
|
const balancePollId = useRef<NodeJS.Timeout | null>(null);
|
||||||
// Avoid immediate leave_chat right after join in React 18 StrictMode (dev) double-invoke
|
// Avoid immediate leave_chat right after join in React 18 StrictMode (dev) double-invoke
|
||||||
// We debounce leave so that a quick remount cancels it, but real navigation (or chat switch) proceeds.
|
// We debounce leave so that a quick remount cancels it, but real navigation (or chat switch) proceeds.
|
||||||
@ -203,12 +211,20 @@ export const useChatSocket = (
|
|||||||
// If auto top-up was in-flight, release the lock only after balance became positive
|
// If auto top-up was in-flight, release the lock only after balance became positive
|
||||||
if (autoTopUpInProgressRef.current && b?.data?.balance > 0) {
|
if (autoTopUpInProgressRef.current && b?.data?.balance > 0) {
|
||||||
autoTopUpInProgressRef.current = false;
|
autoTopUpInProgressRef.current = false;
|
||||||
|
if (autoTopUpUnlockTimerRef.current) {
|
||||||
|
clearTimeout(autoTopUpUnlockTimerRef.current);
|
||||||
|
autoTopUpUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
useSocketEvent("balance_updated", b => {
|
useSocketEvent("balance_updated", b => {
|
||||||
setBalance(prev => (prev ? { ...prev, balance: b.data.balance } : null));
|
setBalance(prev => (prev ? { ...prev, balance: b.data.balance } : null));
|
||||||
if (autoTopUpInProgressRef.current && b?.data?.balance > 0) {
|
if (autoTopUpInProgressRef.current && b?.data?.balance > 0) {
|
||||||
autoTopUpInProgressRef.current = false;
|
autoTopUpInProgressRef.current = false;
|
||||||
|
if (autoTopUpUnlockTimerRef.current) {
|
||||||
|
clearTimeout(autoTopUpUnlockTimerRef.current);
|
||||||
|
autoTopUpUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
useSocketEvent("session_started", s => setSession(s.data));
|
useSocketEvent("session_started", s => setSession(s.data));
|
||||||
@ -310,6 +326,16 @@ export const useChatSocket = (
|
|||||||
};
|
};
|
||||||
}, [session, endSession]);
|
}, [session, endSession]);
|
||||||
|
|
||||||
|
// Cleanup pending unlock timer on unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (autoTopUpUnlockTimerRef.current) {
|
||||||
|
clearTimeout(autoTopUpUnlockTimerRef.current);
|
||||||
|
autoTopUpUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const isAvailableChatting =
|
const isAvailableChatting =
|
||||||
!!balance?.balance && !!session && !isSessionExpired;
|
!!balance?.balance && !!session && !isSessionExpired;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user