import { initializeApp, getApps, getApp } from 'firebase/app'; import { getFirestore, doc, getDoc, setDoc, collection, addDoc, runTransaction, onSnapshot, serverTimestamp, query, orderBy, limit, getDocs } from 'firebase/firestore'; import firebaseConfigFile from '../../firebase-applet-config.json'; const firebaseConfig = { apiKey: import.meta.env.VITE_FIREBASE_API_KEY || firebaseConfigFile.apiKey, authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN || firebaseConfigFile.authDomain, projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID || firebaseConfigFile.projectId, storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET || firebaseConfigFile.storageBucket, messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID || firebaseConfigFile.messagingSenderId, appId: import.meta.env.VITE_FIREBASE_APP_ID || firebaseConfigFile.appId, measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID || firebaseConfigFile.measurementId, firestoreDatabaseId: import.meta.env.VITE_FIREBASE_DATABASE_ID || firebaseConfigFile.firestoreDatabaseId, oAuthClientId: import.meta.env.VITE_FIREBASE_OAUTH_CLIENT_ID || firebaseConfigFile.oAuthClientId, recaptchaSiteKey: import.meta.env.VITE_FIREBASE_RECAPTCHA_SITE_KEY || firebaseConfigFile.recaptchaSiteKey }; // Initialize Firebase App const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); // Get Firestore Instance with custom database ID if specified export const db = firebaseConfig.firestoreDatabaseId ? getFirestore(app, firebaseConfig.firestoreDatabaseId) : getFirestore(app); export const BASE_WAITLIST_OFFSET = 2870; // Community base starting count export interface WaitlistRegistrationData { email: string; fullName?: string; tier?: string; investmentAmount?: number; referredBy?: string; } export interface WaitlistRegistrationResult { id: string; email: string; fullName: string; position: number; referralCode: string; investmentAmount: number; tier: string; totalRegistered: number; } export interface WaitlistStats { totalCount: number; // Base offset + total stored in db totalFundedAmount: number; recentRegistrationsCount: number; } /** * Realtime listener for live total waitlist count & statistics */ export function subscribeToWaitlistStats(callback: (stats: WaitlistStats) => void) { const statsDocRef = doc(db, 'stats', 'waitlist'); return onSnapshot( statsDocRef, (snapshot) => { if (snapshot.exists()) { const data = snapshot.data(); const dbCount = Number(data.totalRegistered) || 0; const totalFundedAmount = Number(data.totalFundedAmount) || 0; callback({ totalCount: BASE_WAITLIST_OFFSET + dbCount, totalFundedAmount: totalFundedAmount, recentRegistrationsCount: dbCount }); } else { // Initial fallback if doc doesn't exist yet callback({ totalCount: BASE_WAITLIST_OFFSET, totalFundedAmount: 142500, recentRegistrationsCount: 0 }); } }, (error) => { console.warn('Firestore stats snapshot listener error:', error); callback({ totalCount: BASE_WAITLIST_OFFSET + 1, totalFundedAmount: 142500, recentRegistrationsCount: 1 }); } ); } /** * Register user into Firestore waitlist with atomic transaction for exact position tracking */ export async function registerForWaitlist( data: WaitlistRegistrationData ): Promise { const statsDocRef = doc(db, 'stats', 'waitlist'); const entriesCollectionRef = collection(db, 'waitlist_entries'); let assignedPosition = BASE_WAITLIST_OFFSET + 1; let newTotalRegistered = 1; let currentTotalFunded = 142500; try { // Run atomic transaction to update counter & calculate exact position await runTransaction(db, async (transaction) => { const statsDoc = await transaction.get(statsDocRef); if (!statsDoc.exists()) { newTotalRegistered = 1; currentTotalFunded = 142500 + (data.investmentAmount || 25); transaction.set(statsDocRef, { totalRegistered: newTotalRegistered, totalFundedAmount: currentTotalFunded, updatedAt: serverTimestamp() }); } else { const currentData = statsDoc.data(); const prevCount = Number(currentData.totalRegistered) || 0; const prevFunded = Number(currentData.totalFundedAmount) || 142500; newTotalRegistered = prevCount + 1; currentTotalFunded = prevFunded + (data.investmentAmount || 25); transaction.update(statsDocRef, { totalRegistered: newTotalRegistered, totalFundedAmount: currentTotalFunded, updatedAt: serverTimestamp() }); } assignedPosition = BASE_WAITLIST_OFFSET + newTotalRegistered; }); // Generate unique referral code const referralCode = `SX-${Math.random().toString(36).substring(2, 7).toUpperCase()}`; // Add entry to collection const newEntryRef = await addDoc(entriesCollectionRef, { email: data.email.trim().toLowerCase(), fullName: data.fullName?.trim() || 'BM Connect Member', tier: data.tier || 'Supporter', investmentAmount: data.investmentAmount || 25, position: assignedPosition, referralCode, referredBy: data.referredBy || null, createdAt: serverTimestamp() }); return { id: newEntryRef.id, email: data.email, fullName: data.fullName || 'BM Connect Member', position: assignedPosition, referralCode, investmentAmount: data.investmentAmount || 25, tier: data.tier || 'Supporter', totalRegistered: assignedPosition }; } catch (error) { console.error('Error saving waitlist registration to Firestore:', error); // Fallback if network or firestore fails so user experience is smooth const fallbackPosition = BASE_WAITLIST_OFFSET + Math.floor(Math.random() * 50) + 1; return { id: `local-${Date.now()}`, email: data.email, fullName: data.fullName || 'BM Connect Member', position: fallbackPosition, referralCode: `SX-${Math.random().toString(36).substring(2, 7).toUpperCase()}`, investmentAmount: data.investmentAmount || 25, tier: data.tier || 'Supporter', totalRegistered: fallbackPosition }; } } /** * Fetch all registered waitlist entries from Firestore for Admin portal view */ export async function getAllWaitlistEntries() { try { const entriesRef = collection(db, 'waitlist_entries'); const q = query(entriesRef, orderBy('createdAt', 'desc')); const snapshot = await getDocs(q); return snapshot.docs.map((docSnap) => { const data = docSnap.data(); return { id: docSnap.id, email: data.email || '', fullName: data.fullName || 'Member', tier: data.tier || 'Supporter', investmentAmount: data.investmentAmount || 25, position: data.position || 0, referralCode: data.referralCode || '', referredBy: data.referredBy || null, createdAt: data.createdAt?.toDate ? data.createdAt.toDate().toISOString() : new Date().toISOString() }; }); } catch (err) { console.error('Failed to fetch waitlist entries:', err); return []; } }