@bluvo/react
Version:
React hooks for Bluvo SDK - Framework-agnostic state machine for crypto withdrawals
132 lines (131 loc) • 6.01 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useBluvoFlow = useBluvoFlow;
const react_1 = require("react");
const useFlowMachine_1 = require("./useFlowMachine");
function useBluvoFlow(options) {
const [flowClient] = (0, react_1.useState)(() => {
// Lazy import to avoid SSR issues
const { BluvoFlowClient } = require('@bluvo/sdk-ts');
return new BluvoFlowClient(options);
});
const [flowMachine, setFlowMachine] = (0, react_1.useState)(null);
const [exchanges, setExchanges] = (0, react_1.useState)([]);
const [exchangesLoading, setExchangesLoading] = (0, react_1.useState)(false);
const [exchangesError, setExchangesError] = (0, react_1.useState)(null);
const closeOAuthWindowRef = (0, react_1.useRef)(null);
const flow = (0, useFlowMachine_1.useFlowMachine)(flowMachine);
const startWithdrawalFlow = (0, react_1.useCallback)(async (flowOptions) => {
const result = await flowClient.startWithdrawalFlow(flowOptions);
setFlowMachine(result.machine);
closeOAuthWindowRef.current = result.closeOAuthWindow;
return result;
}, [flowClient]);
const resumeWithdrawalFlow = (0, react_1.useCallback)(async (flowOptions) => {
const result = await flowClient.resumeWithdrawalFlow(flowOptions);
setFlowMachine(result.machine);
return result;
}, [flowClient]);
const requestQuote = (0, react_1.useCallback)(async (options) => {
await flowClient.requestQuote(options);
}, [flowClient]);
const executeWithdrawal = (0, react_1.useCallback)(async (quoteId) => {
await flowClient.executeWithdrawal(quoteId);
}, [flowClient]);
const submit2FA = (0, react_1.useCallback)(async (code) => {
await flowClient.submit2FA(code);
}, [flowClient]);
const submitSMS = (0, react_1.useCallback)(async (code) => {
await flowClient.submitSMS(code);
}, [flowClient]);
const retryWithdrawal = (0, react_1.useCallback)(async () => {
await flowClient.retryWithdrawal();
}, [flowClient]);
const listExchanges = (0, react_1.useCallback)(async (status) => {
setExchangesLoading(true);
setExchangesError(null);
try {
const result = await flowClient.loadExchanges(status);
setExchanges(result);
return result;
}
catch (error) {
const errorObj = error instanceof Error ? error : new Error('Failed to load exchanges');
setExchangesError(errorObj);
throw errorObj;
}
finally {
setExchangesLoading(false);
}
}, [flowClient]);
const cancel = (0, react_1.useCallback)(() => {
flowClient.cancel();
setFlowMachine(null);
if (closeOAuthWindowRef.current) {
closeOAuthWindowRef.current();
closeOAuthWindowRef.current = null;
}
}, [flowClient]);
// TEST METHOD - For testing withdrawal completion without real transactions
const testWithdrawalComplete = (0, react_1.useCallback)((transactionId) => {
flowClient.testWithdrawalComplete(transactionId);
}, [flowClient]);
// Cleanup on unmount
(0, react_1.useEffect)(() => {
return () => {
flowClient.dispose();
if (closeOAuthWindowRef.current) {
closeOAuthWindowRef.current();
}
};
}, [flowClient]);
return {
// State
...flow,
// Actions
listExchanges,
startWithdrawalFlow,
resumeWithdrawalFlow,
requestQuote,
executeWithdrawal,
submit2FA,
submitSMS,
retryWithdrawal,
cancel,
testWithdrawalComplete, // TEST METHOD
// Computed state helpers
isExchangesLoading: exchangesLoading || flow.state?.type === 'exchanges:loading',
isExchangesReady: flow.state?.type === 'exchanges:ready' || exchanges.length > 0,
exchangesError: exchangesError || (flow.state?.type === 'exchanges:error' ? flow.error || null : null),
isOAuthPending: flow.state?.type === 'oauth:waiting' || flow.state?.type === 'oauth:processing',
isOAuthComplete: flow.state?.type === 'oauth:completed',
isOAuthWindowBeenClosedByTheUser: flow.state?.type === 'oauth:window_closed_by_user',
isWalletLoading: flow.state?.type === 'wallet:loading',
isWalletReady: flow.state?.type === 'wallet:ready',
isQuoteLoading: flow.state?.type === 'quote:requesting',
isQuoteReady: flow.state?.type === 'quote:ready',
isQuoteExpired: flow.state?.type === 'quote:expired',
isWithdrawing: flow.state?.type?.startsWith('withdraw:') &&
flow.state?.type !== 'withdraw:completed' &&
flow.state?.type !== 'withdraw:fatal' &&
!flow.state?.type?.startsWith('withdraw:error') || false,
isWithdrawalComplete: flow.state?.type === 'withdraw:completed',
hasFatalError: flow.state?.type === 'withdraw:fatal',
requires2FA: flow.state?.type === 'withdraw:error2FA',
requiresValid2FAMethod: (flow.state?.type === 'withdraw:fatal' &&
flow.error?.message?.includes('Two-factor authentication method not supported')) || false,
requiresSMS: flow.state?.type === 'withdraw:errorSMS',
requiresKYC: flow.state?.type === 'withdraw:errorKYC',
hasInsufficientBalance: flow.state?.type === 'withdraw:errorBalance',
canRetry: flow.state?.type === 'withdraw:retrying',
invalid2FAAttempts: flow.context?.invalid2FAAttempts || 0,
// Data
exchanges: flow.context?.exchanges || exchanges,
walletBalances: flow.context?.walletBalances || [],
quote: flow.context?.quote,
withdrawal: flow.context?.withdrawal,
valid2FAMethods: flow.context?.errorDetails?.valid2FAMethods,
// Client instance (for advanced use)
client: flowClient
};
}