/** * Wallet Service - Platform-aware wallet management * Uses Firebase abstraction layer for cross-platform support */ import { doc, collection, FieldValue } from '../firebase'; import { useUserWalletStore } from '../stores/userWalletStore'; import { withGlobalLoading } from '../stores/uiStore'; export interface CreditCard { id: string; cardNumber: string; expiryDate: string; cardType?: string; lastFourDigits: string; createdAt: Date; isActive: boolean; } export interface UserWallet { uid: string; balance: number; currency: string; isActive: boolean; cards: CreditCard[]; createdAt: Date; updatedAt: Date; } export class WalletService { private static snapshotExists(docSnap: any): boolean { const existsValue = docSnap?.exists; if (typeof existsValue === 'function') { try { return !!existsValue.call(docSnap); } catch { return false; } } return !!existsValue; } // Create User Wallet static async createUserWallet(uid: string): Promise<{ success: boolean; error?: string }> { return withGlobalLoading(async () => { try { const walletData: UserWallet = { uid, balance: 0, currency: 'USD', isActive: true, cards: [], createdAt: new Date(), updatedAt: new Date(), }; const walletRef = doc('wallets', uid); await walletRef.set(walletData); console.log('Wallet created successfully for user:', uid); try { await useUserWalletStore.getState().invalidateWallet(uid); } catch (cacheError) { console.warn('Failed to refresh wallet cache after creation', cacheError); } return { success: true }; } catch (error) { console.error('Wallet creation error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to create wallet' }; } }); } // Update Wallet Balance static async updateWalletBalance( uid: string, newBalanceInCents: number ): Promise<{ success: boolean; error?: string }> { return withGlobalLoading(async () => { try { const walletDocRef = doc('wallets', uid); await walletDocRef.update({ balance: newBalanceInCents, updatedAt: new Date(), }); console.log('Wallet balance updated successfully'); try { await useUserWalletStore.getState().invalidateWallet(uid); } catch (cacheError) { console.warn('Failed to refresh wallet cache after balance update', cacheError); } return { success: true }; } catch (error) { console.error('Wallet balance update error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to update wallet balance' }; } }); } // Add Credit Card to Wallet static async addCreditCard( uid: string, cardData: { cardNumber: string; expiryDate: string; cvv: string; } ): Promise<{ success: boolean; error?: string }> { return withGlobalLoading(async () => { try { // Basic validation if (!cardData.cardNumber || !cardData.expiryDate || !cardData.cvv) { return { success: false, error: 'All card fields are required' }; } // Validate card number const cleanCardNumber = cardData.cardNumber.replace(/\s|-/g, ''); if (!/^\d{16}$/.test(cleanCardNumber)) { return { success: false, error: 'Card number must be 16 digits' }; } // Validate expiry date if (!/^(0[1-9]|1[0-2])\/\d{2}$/.test(cardData.expiryDate)) { return { success: false, error: 'Expiry date must be in MM/YY format' }; } // Validate CVV if (!/^\d{3,4}$/.test(cardData.cvv)) { return { success: false, error: 'CVV must be 3 or 4 digits' }; } // Detect card type const cardType = WalletService.detectCardType(cleanCardNumber); // Create card object const newCard: CreditCard = { id: `card_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, cardNumber: WalletService.maskCardNumber(cleanCardNumber), expiryDate: cardData.expiryDate, cardType, lastFourDigits: cleanCardNumber.slice(-4), createdAt: new Date(), isActive: true, }; // Get current wallet const walletDocRef = doc('wallets', uid); const walletDoc = await walletDocRef.get(); if (!WalletService.snapshotExists(walletDoc)) { return { success: false, error: 'Wallet not found' }; } const currentWallet = walletDoc.data() as UserWallet; const updatedCards = [...(currentWallet.cards || []), newCard]; // Update wallet with new card await walletDocRef.update({ cards: updatedCards, updatedAt: new Date(), }); console.log('Credit card added successfully'); try { await useUserWalletStore.getState().invalidateWallet(uid); } catch (cacheError) { console.warn('Failed to refresh wallet cache after adding card', cacheError); } return { success: true }; } catch (error) { console.error('Add credit card error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to add credit card' }; } }); } // Remove Credit Card from Wallet static async removeCreditCard( uid: string, cardId: string ): Promise<{ success: boolean; error?: string }> { return withGlobalLoading(async () => { try { const walletDocRef = doc('wallets', uid); const walletDoc = await walletDocRef.get(); if (!WalletService.snapshotExists(walletDoc)) { return { success: false, error: 'Wallet not found' }; } const currentWallet = walletDoc.data() as UserWallet; const updatedCards = (currentWallet.cards || []).filter(card => card.id !== cardId); await walletDocRef.update({ cards: updatedCards, updatedAt: new Date(), }); console.log('Credit card removed successfully'); try { await useUserWalletStore.getState().invalidateWallet(uid); } catch (cacheError) { console.warn('Failed to refresh wallet cache after removing card', cacheError); } return { success: true }; } catch (error) { console.error('Remove credit card error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to remove credit card' }; } }); } // Helper: Detect card type private static detectCardType(cardNumber: string): string { if (cardNumber.startsWith('4')) { return 'Visa'; } else if (cardNumber.startsWith('5') || cardNumber.startsWith('2')) { return 'MasterCard'; } else if (cardNumber.startsWith('3')) { return 'American Express'; } else if (cardNumber.startsWith('6')) { return 'Discover'; } return 'Unknown'; } // Helper: Mask card number private static maskCardNumber(cardNumber: string): string { return '**** **** **** ' + cardNumber.slice(-4); } // Get User Wallet static async getUserWallet(uid: string): Promise<{ success: boolean; wallet?: UserWallet; error?: string }> { try { const walletDocRef = doc('wallets', uid); const walletDoc = await walletDocRef.get(); if (WalletService.snapshotExists(walletDoc)) { const wallet = walletDoc.data() as UserWallet; return { success: true, wallet }; } return { success: false, error: 'Wallet not found' }; } catch (error) { console.error('Error fetching user wallet:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to fetch wallet' }; } } } export default WalletService;