/** * Recipient Service - Platform-aware recipient management * Uses Firebase abstraction layer for cross-platform support */ import { doc, collection } from '../firebase'; export interface Recipient { id: string; uid: string; fullName: string; phoneNumber: string; createdAt: Date; updatedAt: Date; isActive: boolean; } export class RecipientService { private static snapshotExists(docSnap: any): boolean { const existsValue = docSnap?.exists; if (typeof existsValue === 'function') { try { return !!existsValue.call(docSnap); } catch { return false; } } return !!existsValue; } // Add a new recipient static async addRecipient( uid: string, recipientData: { fullName: string; phoneNumber: string; } ): Promise<{ success: boolean; error?: string; recipientId?: string }> { try { // Validate input if (!recipientData.fullName.trim()) { return { success: false, error: 'Full name is required' }; } if (!recipientData.phoneNumber.trim()) { return { success: false, error: 'Phone number is required' }; } // Basic phone number validation const cleanPhone = recipientData.phoneNumber.replace(/[^+\d]/g, ''); if (cleanPhone.length < 7) { return { success: false, error: 'Please enter a valid phone number' }; } // Check if recipient already exists const existingRecipient = await RecipientService.getRecipientByPhone(uid, cleanPhone); if (existingRecipient) { return { success: false, error: 'This recipient already exists' }; } // Generate recipient ID const recipientId = `recipient_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const newRecipient: Recipient = { id: recipientId, uid, fullName: recipientData.fullName.trim(), phoneNumber: cleanPhone, createdAt: new Date(), updatedAt: new Date(), isActive: true, }; // Save to Firestore const recipientRef = doc('recipients', recipientId); await recipientRef.set(newRecipient); return { success: true, recipientId }; } catch (error) { console.error('Add recipient error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to add recipient' }; } } // Get all recipients for a user static async getUserRecipients(uid: string): Promise { try { const recipientsCollection = collection('recipients'); const querySnapshot = await recipientsCollection .where('uid', '==', uid) .where('isActive', '==', true) .get(); const recipients: Recipient[] = []; querySnapshot.forEach((docData: any) => { recipients.push(docData.data() as Recipient); }); // Sort by creation date (newest first) recipients.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); return recipients; } catch (error) { console.error('Error fetching user recipients:', error); throw error; } } // Get recipient by phone number for a specific user static async getRecipientByPhone(uid: string, phoneNumber: string): Promise { try { const recipientsCollection = collection('recipients'); const querySnapshot = await recipientsCollection .where('uid', '==', uid) .where('phoneNumber', '==', phoneNumber) .where('isActive', '==', true) .get(); if (querySnapshot.empty) { return null; } return querySnapshot.docs[0].data() as Recipient; } catch (error) { console.error('Error fetching recipient by phone:', error); throw error; } } // Update recipient static async updateRecipient( recipientId: string, updates: { fullName?: string; phoneNumber?: string; } ): Promise<{ success: boolean; error?: string }> { try { const recipientRef = doc('recipients', recipientId); const recipientDoc = await recipientRef.get(); if (!RecipientService.snapshotExists(recipientDoc)) { return { success: false, error: 'Recipient not found' }; } const updateData: any = { updatedAt: new Date(), }; if (updates.fullName) { updateData.fullName = updates.fullName.trim(); } if (updates.phoneNumber) { const cleanPhone = updates.phoneNumber.replace(/[^+\d]/g, ''); if (cleanPhone.length < 7) { return { success: false, error: 'Please enter a valid phone number' }; } updateData.phoneNumber = cleanPhone; } await recipientRef.update(updateData); console.log('Recipient updated successfully'); return { success: true }; } catch (error) { console.error('Update recipient error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to update recipient' }; } } // Delete recipient (soft delete) static async deleteRecipient(recipientId: string): Promise<{ success: boolean; error?: string }> { try { const recipientRef = doc('recipients', recipientId); await recipientRef.update({ isActive: false, updatedAt: new Date(), }); console.log('Recipient deleted successfully'); return { success: true }; } catch (error) { console.error('Delete recipient error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to delete recipient' }; } } // Hard delete recipient (permanent) static async permanentDeleteRecipient(recipientId: string): Promise<{ success: boolean; error?: string }> { try { const recipientRef = doc('recipients', recipientId); await recipientRef.delete(); console.log('Recipient permanently deleted'); return { success: true }; } catch (error) { console.error('Permanent delete recipient error:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to permanently delete recipient' }; } } static async getRecipientById(recipientId: string): Promise<{ success: boolean; recipient?: Recipient; error?: string }> { try { const recipientRef = doc('recipients', recipientId); const docSnap = await recipientRef.get(); if (!RecipientService.snapshotExists(docSnap)) { return { success: false, error: 'Recipient not found' }; } const data = docSnap.data() as Recipient | undefined; if (!data) { return { success: false, error: 'Recipient data unavailable' }; } const recipient: Recipient = { ...data, id: data.id ?? recipientId, createdAt: (data.createdAt as any)?.toDate?.() ?? data.createdAt ?? new Date(), updatedAt: (data.updatedAt as any)?.toDate?.() ?? data.updatedAt ?? new Date(), }; return { success: true, recipient }; } catch (error) { console.error('Error fetching recipient by id:', error); return { success: false, error: error instanceof Error ? error.message : 'Failed to fetch recipient', }; } } } export default RecipientService;