feat: add Twilio SMS/call integration with settings, templates, and conversation history
This commit is contained in:
@@ -17,6 +17,7 @@ import { paymentsReportsStorage } from './payments-reports-storage';
|
||||
import { patientDocumentsStorage } from './patientDocuments-storage';
|
||||
import * as exportPaymentsReportsStorage from "./export-payments-reports-storage";
|
||||
import { cronJobLogStorage } from "./cron-job-log-storage";
|
||||
import { twilioStorage } from "./twilio-storage";
|
||||
|
||||
|
||||
export const storage = {
|
||||
@@ -37,6 +38,7 @@ export const storage = {
|
||||
...patientDocumentsStorage,
|
||||
...exportPaymentsReportsStorage,
|
||||
...cronJobLogStorage,
|
||||
...twilioStorage,
|
||||
|
||||
};
|
||||
|
||||
|
||||
72
apps/Backend/src/storage/twilio-storage.ts
Normal file
72
apps/Backend/src/storage/twilio-storage.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { prisma as db } from "@repo/db/client";
|
||||
|
||||
export type TwilioSettingsData = {
|
||||
accountSid: string;
|
||||
authToken: string;
|
||||
phoneNumber: string;
|
||||
greetingMessage?: string | null;
|
||||
};
|
||||
|
||||
export type CommunicationCreateData = {
|
||||
patientId: number;
|
||||
userId?: number;
|
||||
channel: "sms" | "voice";
|
||||
direction: "outbound" | "inbound";
|
||||
status: "queued" | "sent" | "delivered" | "failed" | "completed" | "busy" | "no_answer";
|
||||
body?: string;
|
||||
callDuration?: number;
|
||||
twilioSid?: string;
|
||||
};
|
||||
|
||||
export const twilioStorage = {
|
||||
async getTwilioSettings(userId: number) {
|
||||
return db.twilioSettings.findUnique({ where: { userId } });
|
||||
},
|
||||
|
||||
async upsertTwilioSettings(userId: number, data: TwilioSettingsData) {
|
||||
return db.twilioSettings.upsert({
|
||||
where: { userId },
|
||||
update: data,
|
||||
create: { userId, ...data },
|
||||
});
|
||||
},
|
||||
|
||||
async createCommunication(data: CommunicationCreateData) {
|
||||
return db.communication.create({ data: data as any });
|
||||
},
|
||||
|
||||
async getCommunicationsByPatient(patientId: number) {
|
||||
return db.communication.findMany({
|
||||
where: { patientId },
|
||||
orderBy: { createdAt: "asc" },
|
||||
});
|
||||
},
|
||||
|
||||
async getTemplates(userId: number): Promise<Record<string, string>> {
|
||||
const settings = await db.twilioSettings.findUnique({ where: { userId } });
|
||||
if (!settings?.templates) return {};
|
||||
return settings.templates as Record<string, string>;
|
||||
},
|
||||
|
||||
async saveTemplate(userId: number, key: string, body: string) {
|
||||
const settings = await db.twilioSettings.findUnique({ where: { userId } });
|
||||
const existing = (settings?.templates as Record<string, string>) || {};
|
||||
const updated = { ...existing, [key]: body };
|
||||
return db.twilioSettings.upsert({
|
||||
where: { userId },
|
||||
update: { templates: updated },
|
||||
create: { userId, accountSid: "", authToken: "", phoneNumber: "", templates: updated },
|
||||
});
|
||||
},
|
||||
|
||||
async getRecentCommunicationsByUser(userId: number, limit = 20) {
|
||||
return db.communication.findMany({
|
||||
where: { patient: { userId } },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: limit,
|
||||
include: {
|
||||
patient: { select: { id: true, firstName: true, lastName: true, phone: true } },
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user