Files
Haitham Khalifa b538d84e17 Initial commit
2026-02-16 12:18:06 +01:00

288 lines
8.1 KiB
TypeScript

import {
collection,
doc,
getDoc,
getDocs,
setDoc,
updateDoc,
query,
where,
orderBy,
Timestamp,
addDoc,
deleteDoc,
} from 'firebase/firestore';
import { db } from './firebase';
import type {
User,
AgentSettings,
CallTask,
CallAttempt,
CallRecord,
CreditTransaction,
NotificationSettings,
BookedAppointment,
DefaultLimits,
Purchase,
} from './types';
// Users
export const getUser = async (uid: string): Promise<User | null> => {
const docRef = doc(db, 'users', uid);
const docSnap = await getDoc(docRef);
return docSnap.exists() ? (docSnap.data() as User) : null;
};
export const updateUserCredits = async (uid: string, newBalance: number) => {
const docRef = doc(db, 'users', uid);
await updateDoc(docRef, {
creditBalance: newBalance,
updatedAt: Timestamp.now(),
});
};
export const updateUserOnboardingCompleted = async (uid: string, completed: boolean) => {
const docRef = doc(db, 'users', uid);
await updateDoc(docRef, {
onboardingCompleted: completed,
updatedAt: Timestamp.now(),
});
};
// Agent Settings
export const getAgentSettings = async (userId: string): Promise<AgentSettings | null> => {
const docRef = doc(db, 'agentSettings', userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return docSnap.data() as AgentSettings;
}
// Create default if not exists
const defaults: AgentSettings = {
userId,
agentName: 'HolaCompi',
appLanguage: 'English',
primaryCallLanguage: 'English',
secondaryCallLanguages: [],
tone: 'Friendly',
agentInstructions: 'You are HolaCompi, a helpful Spanish friend who makes phone calls on behalf of users.',
createdAt: Timestamp.now(),
updatedAt: Timestamp.now(),
};
await setDoc(docRef, defaults);
return defaults;
};
export const updateAgentSettings = async (userId: string, updates: Partial<AgentSettings>) => {
const docRef = doc(db, 'agentSettings', userId);
await updateDoc(docRef, {
...updates,
updatedAt: Timestamp.now(),
});
};
// Call Tasks
export const createCallTask = async (task: Omit<CallTask, 'id'>): Promise<string> => {
const docRef = await addDoc(collection(db, 'callTasks'), task);
return docRef.id;
};
export const getCallTasks = async (userId: string): Promise<CallTask[]> => {
const q = query(
collection(db, 'callTasks'),
where('userId', '==', userId),
orderBy('scheduledAt', 'desc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as CallTask));
};
export const getCallTask = async (taskId: string): Promise<CallTask | null> => {
const docRef = doc(db, 'callTasks', taskId);
const docSnap = await getDoc(docRef);
return docSnap.exists() ? ({ id: docSnap.id, ...docSnap.data() } as CallTask) : null;
};
export const updateCallTask = async (taskId: string, updates: Partial<CallTask>) => {
const docRef = doc(db, 'callTasks', taskId);
await updateDoc(docRef, {
...updates,
updatedAt: Timestamp.now(),
});
};
export const deleteCallTask = async (taskId: string) => {
await deleteDoc(doc(db, 'callTasks', taskId));
};
// Call Attempts
export const createCallAttempt = async (
taskId: string,
attempt: Omit<CallAttempt, 'id'>
): Promise<string> => {
const docRef = await addDoc(
collection(db, 'callTasks', taskId, 'attempts'),
attempt
);
return docRef.id;
};
export const getCallAttempts = async (taskId: string): Promise<CallAttempt[]> => {
const q = query(
collection(db, 'callTasks', taskId, 'attempts'),
orderBy('startTime', 'desc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as CallAttempt));
};
export const updateCallAttempt = async (
taskId: string,
attemptId: string,
updates: Partial<CallAttempt>
) => {
const docRef = doc(db, 'callTasks', taskId, 'attempts', attemptId);
await updateDoc(docRef, updates);
};
// Calls
export const createCallRecord = async (
record: Omit<CallRecord, 'id' | 'createdAt' | 'updatedAt'>
): Promise<string> => {
const docRef = await addDoc(collection(db, 'calls'), {
...record,
createdAt: Timestamp.now(),
updatedAt: Timestamp.now(),
});
return docRef.id;
};
export const updateCallRecord = async (
callId: string,
updates: Partial<CallRecord>
) => {
const docRef = doc(db, 'calls', callId);
await updateDoc(docRef, { ...updates, updatedAt: Timestamp.now() });
};
export const getCallByVapiCallId = async (vapiCallId: string): Promise<CallRecord | null> => {
const q = query(collection(db, 'calls'), where('vapiCallId', '==', vapiCallId));
const snapshot = await getDocs(q);
if (snapshot.empty) return null;
const docSnap = snapshot.docs[0];
return { id: docSnap.id, ...(docSnap.data() as CallRecord) };
};
// Credit Transactions
export const createCreditTransaction = async (
transaction: Omit<CreditTransaction, 'id'>
): Promise<string> => {
const docRef = await addDoc(collection(db, 'creditLedger'), transaction);
return docRef.id;
};
export const getCreditTransactions = async (userId: string): Promise<CreditTransaction[]> => {
const q = query(
collection(db, 'creditLedger'),
where('userId', '==', userId),
orderBy('createdAt', 'desc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as CreditTransaction));
};
// Purchases
export const createPurchase = async (purchase: Omit<Purchase, 'id'>): Promise<string> => {
const docRef = await addDoc(collection(db, 'purchases'), purchase);
return docRef.id;
};
export const getPurchasesByUser = async (userId: string): Promise<Purchase[]> => {
const q = query(
collection(db, 'purchases'),
where('userId', '==', userId),
orderBy('createdAt', 'desc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as Purchase));
};
// Notification Settings
export const getNotificationSettings = async (userId: string): Promise<NotificationSettings> => {
const docRef = doc(db, 'notificationSettings', userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return docSnap.data() as NotificationSettings;
}
const defaults: NotificationSettings = {
userId,
notifyOnSuccess: true,
notifyOnFailure: true,
emailSummary: false,
autoAddToCalendar: false,
googleCalendarConnected: false,
iCloudCalendarConnected: false,
createdAt: Timestamp.now(),
updatedAt: Timestamp.now(),
};
await setDoc(docRef, defaults);
return defaults;
};
export const updateNotificationSettings = async (
userId: string,
updates: Partial<NotificationSettings>
) => {
const docRef = doc(db, 'notificationSettings', userId);
await updateDoc(docRef, {
...updates,
updatedAt: Timestamp.now(),
});
};
// Booked Appointments
export const createBookedAppointment = async (
appointment: Omit<BookedAppointment, 'id'>
): Promise<string> => {
const docRef = await addDoc(collection(db, 'bookedAppointments'), appointment);
return docRef.id;
};
export const getBookedAppointments = async (userId: string): Promise<BookedAppointment[]> => {
const q = query(
collection(db, 'bookedAppointments'),
where('userId', '==', userId),
orderBy('dateTime', 'asc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as BookedAppointment));
};
// Default Limits
export const getDefaultLimits = async (userId: string): Promise<DefaultLimits> => {
const docRef = doc(db, 'defaultLimits', userId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return docSnap.data() as DefaultLimits;
}
const defaults: DefaultLimits = {
userId,
defaultMaxMinutes: 10,
defaultMaxCredits: 10,
allowAutoExtension: false,
maxExtraMinutes: 0,
defaultMaxRecalls: 2,
minDelayBetweenRecalls: 15,
updatedAt: Timestamp.now(),
};
await setDoc(docRef, defaults);
return defaults;
};
export const updateDefaultLimits = async (userId: string, updates: Partial<DefaultLimits>) => {
const docRef = doc(db, 'defaultLimits', userId);
await updateDoc(docRef, {
...updates,
updatedAt: Timestamp.now(),
});
};