Amba-Agent-App/lib/hooks/useUserWallet.ts
2026-01-16 00:22:35 +03:00

165 lines
4.7 KiB
TypeScript

import { useCallback, useEffect, useMemo, useRef } from 'react';
import { FirebaseAuthTypes } from '../firebase';
import { UserWallet, WalletService } from '../services/walletService';
import { useUserWalletStore } from '../stores/userWalletStore';
import type { WalletCacheEntry } from '../stores/userWalletStore';
import { useGlobalLoading } from './useGlobalLoading';
interface UseUserWalletReturn {
wallet: UserWallet | null;
loading: boolean;
error: string | null;
refreshWallet: () => Promise<void>;
balanceInDollars: number; // Helper to get balance in dollars
formattedBalance: string; // Helper to get formatted balance
addCreditCard: (
cardData: {
cardNumber: string;
expiryDate: string;
cvv: string;
}
) => Promise<void>;
removeCreditCard: (cardId: string) => Promise<void>;
}
const defaultEntry: WalletCacheEntry = {
wallet: null,
loading: false,
error: null,
};
export const useUserWallet = (user: FirebaseAuthTypes.User | null): UseUserWalletReturn => {
const uid = user?.uid ?? null;
const lastUidRef = useRef<string | null>(null);
const ensureSubscription = useUserWalletStore((state) => state.ensureSubscription);
const refreshFromStore = useUserWalletStore((state) => state.refreshWallet);
const removeWallet = useUserWalletStore((state) => state.removeWallet);
const setWalletState = useUserWalletStore((state) => state.setWalletState);
const entry = useUserWalletStore(
useCallback(
(state) => (uid ? state.wallets[uid] ?? defaultEntry : defaultEntry),
[uid]
)
);
const { withLoading } = useGlobalLoading();
useEffect(() => {
if (lastUidRef.current && lastUidRef.current !== uid) {
removeWallet(lastUidRef.current);
}
lastUidRef.current = uid;
}, [uid, removeWallet]);
useEffect(() => {
if (!uid) {
return;
}
ensureSubscription(uid);
}, [ensureSubscription, uid]);
const refreshWallet = useCallback(async () => {
if (!uid) {
return;
}
await withLoading(() => refreshFromStore(uid));
}, [refreshFromStore, uid, withLoading]);
const addCreditCard = useCallback(async (
cardData: {
cardNumber: string;
expiryDate: string;
cvv: string;
}
) => {
if (!uid) {
return;
}
setWalletState(uid, { loading: true, error: null });
try {
const result = await withLoading(() => WalletService.addCreditCard(uid, cardData));
if (!result.success) {
setWalletState(uid, {
loading: false,
error: result.error || 'Failed to add credit card',
});
return;
}
setWalletState(uid, { loading: false, error: null });
} catch (err) {
setWalletState(uid, {
loading: false,
error: err instanceof Error ? err.message : 'Failed to add credit card',
});
}
}, [setWalletState, uid, withLoading]);
const removeCreditCard = useCallback(async (cardId: string) => {
if (!uid) {
return;
}
setWalletState(uid, { loading: true, error: null });
try {
const result = await withLoading(() => WalletService.removeCreditCard(uid, cardId));
if (!result.success) {
setWalletState(uid, {
loading: false,
error: result.error || 'Failed to remove credit card',
});
return;
}
setWalletState(uid, { loading: false, error: null });
} catch (err) {
setWalletState(uid, {
loading: false,
error: err instanceof Error ? err.message : 'Failed to remove credit card',
});
}
}, [setWalletState, uid, withLoading]);
return useMemo(() => {
const wallet = uid ? entry.wallet : null;
const balanceInDollars = wallet ? wallet.balance / 100 : 0;
const formattedBalance = wallet
? `${wallet.currency} ${(wallet.balance / 100).toFixed(2)}`
: `USD 0.00`;
return {
wallet,
loading: uid ? entry.loading : false,
error: uid ? entry.error : null,
refreshWallet,
balanceInDollars,
formattedBalance,
addCreditCard,
removeCreditCard,
};
}, [addCreditCard, entry.error, entry.loading, entry.wallet, refreshWallet, removeCreditCard, uid]);
};
// Standalone function to fetch any user's wallet (useful for admin features)
export const fetchUserWallet = async (uid: string): Promise<UserWallet | null> => {
if (!uid) {
return null;
}
const cached = useUserWalletStore.getState().wallets[uid]?.wallet;
if (cached) {
return cached;
}
try {
return await useUserWalletStore.getState().refreshWallet(uid);
} catch (error) {
console.error('Error fetching user wallet:', error);
const res = await WalletService.getUserWallet(uid);
return res.wallet ?? null;
}
};