up
All checks were successful
Deploy to Production / deploy (push) Successful in 8s

This commit is contained in:
lubukhu
2026-01-24 13:35:11 +07:00
parent 6c3e93636e
commit 65fd0158a3
145 changed files with 10262 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
/**
* Game Iframe SDK - React Hook
* Custom hook để sử dụng SDK trong React components
*
* @example
* ```tsx
* import { useGameIframeSDK } from 'game-iframe-sdk/react';
*
* function GamePlayer() {
* const iframeRef = useRef<HTMLIFrameElement>(null);
*
* const {
* isReady,
* sendGameData,
* sendLeaderboard
* } = useGameIframeSDK({
* iframeRef,
* iframeOrigin: 'http://senaai.vn:1357',
* onGameReady: () => console.log('Game ready!'),
* onAnswerReport: (data) => submitToServer(data),
* onFinalResult: (data) => showResults(data),
* });
*
* return <iframe ref={iframeRef} src={gameUrl} />;
* }
* ```
*/
import { useEffect, useRef, useState, useCallback } from 'react';
import { GameIframeSDK } from './GameIframeSDK';
export function useGameIframeSDK(options) {
const { iframeRef, iframeOrigin, readyDelay, autoSendOnReady, debug, onGameReady, onAnswerReport, onFinalResult, onLeaderboardRequest, onError, } = options;
const [isReady, setIsReady] = useState(false);
const sdkRef = useRef(null);
// Use refs for callbacks to avoid re-creating SDK when callbacks change
const callbacksRef = useRef({
onGameReady,
onAnswerReport,
onFinalResult,
onLeaderboardRequest,
onError,
});
// Update callback refs on each render (no effect re-run)
callbacksRef.current = {
onGameReady,
onAnswerReport,
onFinalResult,
onLeaderboardRequest,
onError,
};
// Initialize SDK - only depends on config, NOT callbacks
useEffect(() => {
const sdk = new GameIframeSDK({
iframeOrigin,
readyDelay,
autoSendOnReady,
debug,
});
sdkRef.current = sdk;
// Subscribe to events using refs (stable references)
const unsubscribers = [];
unsubscribers.push(sdk.on('gameReady', () => {
setIsReady(true);
callbacksRef.current.onGameReady?.();
}));
unsubscribers.push(sdk.on('answerReport', (data) => {
callbacksRef.current.onAnswerReport?.(data);
}));
unsubscribers.push(sdk.on('finalResult', (data) => {
callbacksRef.current.onFinalResult?.(data);
}));
unsubscribers.push(sdk.on('leaderboardRequest', (data) => {
callbacksRef.current.onLeaderboardRequest?.(data.top || 10);
}));
unsubscribers.push(sdk.on('error', (err) => {
callbacksRef.current.onError?.(err);
}));
return () => {
unsubscribers.forEach((unsub) => unsub());
sdk.destroy();
sdkRef.current = null;
};
}, [iframeOrigin, readyDelay, autoSendOnReady, debug]); // ✅ No callback deps
// Sync iframe ref with SDK
useEffect(() => {
if (sdkRef.current && iframeRef.current) {
sdkRef.current.setIframe(iframeRef.current);
}
}, [iframeRef.current]);
// Reset ready state when iframe src changes
useEffect(() => {
setIsReady(false);
}, [iframeRef.current?.src]);
// Memoized methods
const sendGameData = useCallback((data) => {
return sdkRef.current?.sendGameData(data) ?? false;
}, []);
const sendLeaderboard = useCallback((data) => {
return sdkRef.current?.sendLeaderboard(data) ?? false;
}, []);
const queueGameData = useCallback((data) => {
sdkRef.current?.queueGameData(data);
}, []);
const reloadIframe = useCallback(() => {
setIsReady(false);
return sdkRef.current?.reloadIframe() ?? false;
}, []);
return {
sdk: sdkRef.current,
isReady,
sendGameData,
sendLeaderboard,
queueGameData,
reloadIframe,
};
}
export default useGameIframeSDK;
//# sourceMappingURL=useGameIframeSDK.js.map