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

273 lines
8.0 KiB
TypeScript

/**
* 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;