{"version":3,"sources":["../src/firebase-setup.ts","../src/firestore-operations.ts","../src/hooks/useFirestore.ts"],"sourcesContent":["import { initializeApp, getApps, getApp, FirebaseApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\nimport { getFirestore } from 'firebase/firestore';\nimport { getStorage } from 'firebase/storage';\n\n// Firebase configuration\nconst firebaseConfig = {\n  // These should be set via environment variables in a real app\n  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,\n  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,\n  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,\n  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,\n  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,\n  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,\n  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,\n};\n\n// Initialize Firebase\nlet firebaseApp: FirebaseApp;\n\nif (!getApps().length) {\n  firebaseApp = initializeApp(firebaseConfig);\n} else {\n  firebaseApp = getApp();\n}\n\n// Initialize Firebase services\nconst auth = getAuth(firebaseApp);\nconst db = getFirestore(firebaseApp);\nconst storage = getStorage(firebaseApp);\n\nexport { firebaseApp, auth, db, storage };\n\n// Utility functions\nexport const isFirebaseInitialized = () => {\n  return getApps().length > 0;\n};\n\n// Re-export commonly used Firebase types\nexport type { User } from 'firebase/auth';\nexport type { DocumentData, QueryDocumentSnapshot } from 'firebase/firestore';\nexport type { FirebaseStorage, UploadResult } from 'firebase/storage';\n","import {\n  collection,\n  doc,\n  getDoc,\n  getDocs,\n  setDoc,\n  updateDoc,\n  deleteDoc,\n  query,\n  where,\n  orderBy,\n  limit as limitQuery,\n  startAfter,\n  endBefore,\n  limitToLast,\n  onSnapshot,\n  writeBatch,\n  runTransaction,\n  type QueryConstraint,\n  type DocumentData,\n  type QueryDocumentSnapshot,\n  type Query,\n  type CollectionReference,\n  type Firestore,\n  type Unsubscribe,\n  type DocumentSnapshot,\n  type WhereFilterOp,\n  type OrderByDirection,\n} from 'firebase/firestore';\nimport { db } from './firebase-setup';\nimport type { WithId } from './types';\nimport type { \n  QueryOptions, \n  WhereClause, \n  OrderByClause \n} from './types/query-options';\n\n// Re-export commonly used types for backward compatibility\nexport type { WithId } from './types';\nexport type { QueryOptions, WhereClause, OrderByClause } from './types/query-options';\n\nexport class FirestoreService<T extends DocumentData> {\n  private readonly collectionRef: CollectionReference<T>;\n\n  constructor(collectionName: string, private readonly firestore: Firestore = db) {\n    this.collectionRef = collection(this.firestore, collectionName) as CollectionReference<T>;\n  }\n\n  // Create\n  async create(id: string, data: T): Promise<WithId<T>> {\n    const docRef = doc(this.collectionRef, id);\n    await setDoc(docRef, data);\n    return { id, ...data };\n  }\n\n  // Read\n  async get(id: string): Promise<WithId<T> | null> {\n    const docRef = doc(this.collectionRef, id);\n    const docSnap = await getDoc(docRef);\n    return docSnap.exists() ? { id: docSnap.id, ...docSnap.data() } : null;\n  }\n\n  // Update\n  async update(id: string, data: Partial<T>): Promise<void> {\n    const docRef = doc(this.collectionRef, id);\n    await updateDoc(docRef, data as any);\n  }\n\n  // Delete\n  async delete(id: string): Promise<void> {\n    const docRef = doc(this.collectionRef, id);\n    await deleteDoc(docRef);\n  }\n\n  // Query with filters\n  async query(options: QueryOptions<T> = {}): Promise<WithId<T>[]> {\n    let q: Query<T> = this.collectionRef;\n    const queryConstraints: QueryConstraint[] = [];\n\n    // Apply where clauses\n    if (options.where && options.where.length > 0) {\n      for (const clause of options.where) {\n        queryConstraints.push(\n          where(\n            clause.field as string,\n            clause.operator,\n            clause.value\n          )\n        );\n      }\n    }\n\n    // Apply order by\n    if (options.orderBy && options.orderBy.length > 0) {\n      for (const clause of options.orderBy) {\n        queryConstraints.push(\n          orderBy(\n            clause.field as string,\n            clause.direction || 'asc'\n          )\n        );\n      }\n    }\n\n    // Apply pagination\n    if (options.limit) {\n      if (options.last) {\n        queryConstraints.push(limitToLast(options.limit));\n      } else {\n        queryConstraints.push(limitQuery(options.limit));\n      }\n    }\n\n    if (options.startAfter) {\n      queryConstraints.push(startAfter(options.startAfter));\n    }\n\n    if (options.endBefore) {\n      queryConstraints.push(endBefore(options.endBefore));\n    }\n\n    // Apply all constraints\n    if (queryConstraints.length > 0) {\n      q = query(this.collectionRef, ...queryConstraints);\n    }\n\n    const querySnapshot = await getDocs(q);\n    return querySnapshot.docs.map((doc) => ({\n      id: doc.id,\n      ...doc.data(),\n    } as WithId<T>));\n  }\n\n  // Subscribe to real-time updates\n  subscribe(\n    callback: (data: WithId<T>[]) => void,\n    options: Omit<QueryOptions<T>, 'startAfter' | 'endBefore' | 'last'> = {}\n  ): Unsubscribe {\n    let q: Query<T> = this.collectionRef;\n    const queryConstraints: QueryConstraint[] = [];\n\n    // Apply where clauses\n    if (options.where && options.where.length > 0) {\n      for (const clause of options.where) {\n        queryConstraints.push(\n          where(\n            clause.field as string,\n            clause.operator,\n            clause.value\n          )\n        );\n      }\n    }\n\n\n    // Apply order by\n    if (options.orderBy && options.orderBy.length > 0) {\n      for (const clause of options.orderBy) {\n        queryConstraints.push(\n          orderBy(\n            clause.field as string,\n            clause.direction || 'asc'\n          )\n        );\n      }\n    }\n    // Apply limit\n    if (options.limit) {\n      queryConstraints.push(limitQuery(options.limit));\n    }\n\n    // Apply all constraints\n    if (queryConstraints.length > 0) {\n      q = query(this.collectionRef, ...queryConstraints);\n    }\n\n    return onSnapshot(q, (querySnapshot) => {\n      const data = querySnapshot.docs.map((doc) => ({\n        id: doc.id,\n        ...doc.data(),\n      } as WithId<T>));\n      callback(data);\n    });\n  }\n\n  // Batch operations\n  static createBatch() {\n    return writeBatch(db);\n  }\n\n  // Transaction support\n  static async runTransaction<T>(\n    updateFunction: (transaction: any) => Promise<T>\n  ): Promise<T> {\n    return runTransaction(db, updateFunction);\n  }\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { FirestoreService } from '../firestore-operations';\nimport type { WithId } from '../types';\nimport type { QueryOptions, WhereClause, OrderByClause } from '../types/query-options';\n\n/**\n * Hook to fetch a single document from Firestore\n * @param service Instance of FirestoreService\n * @param id Document ID to fetch\n * @returns { data, loading, error }\n */\nexport function useDocument<T extends object>(\n  service: FirestoreService<T>,\n  id: string\n) {\n  const [data, setData] = useState<WithId<T> | null>(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<Error | null>(null);\n\n  useEffect(() => {\n    const fetchData = async () => {\n      try {\n        setLoading(true);\n        const doc = await service.get(id);\n        setData(doc);\n      } catch (err) {\n        console.error('Error fetching document:', err);\n        setError(err as Error);\n      } finally {\n        setLoading(false);\n      }\n    };\n\n    if (id) {\n      fetchData();\n    } else {\n      setLoading(false);\n    }\n  }, [service, id]);\n\n  return { data, loading, error };\n}\n\n/**\n * Hook to fetch a collection from Firestore with pagination support\n * @param service Instance of FirestoreService\n * @param options Query options (where, orderBy, limit)\n * @returns { data, loading, error, hasMore, fetchMore, refresh }\n */\nexport function useCollection<T extends object>(\n  service: FirestoreService<T>,\n  options: Omit<QueryOptions<T>, 'startAfter' | 'endBefore' | 'last'> = {}\n) {\n  const [data, setData] = useState<WithId<T>[]>([]);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<Error | null>(null);\n  const [hasMore, setHasMore] = useState(true);\n  const lastDocRef = useRef<any>(null);\n\n  const fetchData = async (reset = false) => {\n    if ((!hasMore && !reset) || loading) return;\n    \n    try {\n      setLoading(true);\n      \n      const queryOptions = {\n        ...options,\n        ...(lastDocRef.current && !reset && { startAfter: lastDocRef.current })\n      };\n      \n      // We need to cast here because of TypeScript limitations with spread operator and generics\n      const result = await (service as any).query(queryOptions);\n      \n      setData(prev => reset ? result : [...prev, ...result]);\n      setHasMore(result.length === (options.limit || 20));\n      \n      if (result.length > 0) {\n        lastDocRef.current = result[result.length - 1];\n      }\n    } catch (err) {\n      console.error('Error fetching collection:', err);\n      setError(err as Error);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  const refresh = () => {\n    lastDocRef.current = null;\n    return fetchData(true);\n  };\n\n  useEffect(() => {\n    refresh();\n  }, [JSON.stringify(options)]); // Re-run when options change\n\n  return { \n    data, \n    loading, \n    error, \n    hasMore, \n    fetchMore: () => fetchData(false), \n    refresh \n  };\n}\n\n/**\n * Hook to subscribe to real-time updates for a collection\n * @param service Instance of FirestoreService\n * @param options Query options (where, orderBy, limit)\n * @returns { data, loading, error }\n */\nexport function useRealtimeCollection<T extends object>(\n  service: FirestoreService<T>,\n  options: Omit<QueryOptions<T>, 'startAfter' | 'endBefore' | 'last'> = {}\n) {\n  const [data, setData] = useState<WithId<T>[]>([]);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<Error | null>(null);\n  const unsubscribeRef = useRef<() => void>();\n  const isMounted = useRef(true);\n\n  useEffect(() => {\n    isMounted.current = true;\n    setLoading(true);\n    \n    try {\n      unsubscribeRef.current = service.subscribe(\n        (items) => {\n          if (isMounted.current) {\n            setData(items);\n            setLoading(false);\n          }\n        },\n        options\n      );\n    } catch (err) {\n      console.error('Error setting up realtime subscription:', err);\n      if (isMounted.current) {\n        setError(err as Error);\n        setLoading(false);\n      }\n    }\n\n    // Cleanup subscription on unmount\n    return () => {\n      isMounted.current = false;\n      if (unsubscribeRef.current) {\n        unsubscribeRef.current();\n      }\n    };\n  }, [service, JSON.stringify(options)]);\n\n  return { data, loading, error };\n}\n\n/**\n * Hook to get a Firestore service instance\n * @param collectionName Name of the Firestore collection\n * @returns Instance of FirestoreService\n */\nexport function useFirestoreService<T extends object>(collectionName: string) {\n  const serviceRef = useRef<FirestoreService<T>>();\n  \n  if (!serviceRef.current) {\n    serviceRef.current = new FirestoreService<T>(collectionName);\n  }\n  \n  return serviceRef.current;\n}\n"],"mappings":"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","names":["initializeApp","getApps","getApp","getAuth","getFirestore","getStorage","firebaseConfig","firebaseApp","auth","db","storage","isFirebaseInitialized","getApps","collection","doc","getDoc","getDocs","setDoc","updateDoc","deleteDoc","query","where","orderBy","limitQuery","startAfter","endBefore","limitToLast","onSnapshot","writeBatch","runTransaction","FirestoreService","collectionName","firestore","db","collection","id","data","docRef","doc","setDoc","docSnap","getDoc","updateDoc","deleteDoc","options","q","queryConstraints","clause","where","orderBy","limitToLast","limitQuery","startAfter","endBefore","query","getDocs","callback","onSnapshot","querySnapshot","writeBatch","updateFunction","runTransaction","useEffect","useRef","useState","useDocument","service","id","data","setData","useState","loading","setLoading","error","setError","useEffect","doc","err","useCollection","options","hasMore","setHasMore","lastDocRef","useRef","fetchData","reset","queryOptions","result","prev","refresh","useRealtimeCollection","unsubscribeRef","isMounted","items","useFirestoreService","collectionName","serviceRef","FirestoreService"]}