import { collection, doc, type DocumentData, type FirestoreDataConverter, type QueryDocumentSnapshot, type SnapshotOptions, } from 'firebase/firestore'; import { db } from '@/lib/firebase'; import type { UserDocument, UserFirestoreDocument } from '@/types/firestore'; type TimestampFieldValue = { toDate: () => Date; }; function hasToDate(value: unknown): value is TimestampFieldValue { return ( typeof value === 'object' && value !== null && 'toDate' in value && typeof value.toDate === 'function' ); } export function mapTimestampFields< Source extends Record, Result extends Record, >(data: Source, fields: Array) { const nextData = { ...data } as Record; for (const field of fields) { const value = nextData[field as string]; if (hasToDate(value)) { nextData[field as string] = value.toDate(); } } return nextData as Result; } const converter = ( fromFirestoreMapper: (data: DbModel) => AppModel ): FirestoreDataConverter => ({ toFirestore: (value) => value as DocumentData, fromFirestore: ( snapshot: QueryDocumentSnapshot, options: SnapshotOptions ) => fromFirestoreMapper(snapshot.data(options) as DbModel), }); const userConverter = converter((data) => mapTimestampFields(data, [ 'createdAt', 'updatedAt', ]) ); export const collectionNames = { users: 'users', } as const; export const usersCollectionRef = collection(db, collectionNames.users); export const usersCollection = usersCollectionRef.withConverter(userConverter); export const userDoc = (uid: string) => doc(usersCollection, uid); export const userDocRef = (uid: string) => doc(usersCollectionRef, uid);