Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 15x 15x 9x 9x 1x 1x 8x 8x 16x 8x 4x 9x 8x 8x 9x | import type { Dal } from "../../../dal";
import type { CommunicationGateway } from "../gateway";
import type { CommunicationRequest } from "../types";
export type NewInquiryPayload = {
inquiryId: number;
proId: string;
customerName: string;
customerPhone: string;
customerEmail?: string;
customerLocation?: string;
requirement?: string;
requirementType?: string;
projectTitle?: string;
};
export class NewInquiryHandler {
constructor(
private gateway: CommunicationGateway,
private dal: Dal,
) {}
async handle(payload: NewInquiryPayload): Promise<void> {
const [pro, teamMembers, whatsappRecipients] = await Promise.all([
this.dal.pros.findById(payload.proId),
this.dal.userTenantRoles.getProUsersWithContact(payload.proId),
this.dal.proWhatsAppRecipients.listEligibleByProId(payload.proId),
]);
if (!pro) {
console.error("[COMMUNICATION] Pro not found:", payload.proId);
return;
}
const requests: CommunicationRequest[] = [];
// Email to each team member
for (const member of teamMembers) {
requests.push({
channel: "email",
recipient: member.email,
eventType: "new_inquiry",
proId: payload.proId,
userId: member.userId,
content: {
template: "new-inquiry",
subject: `New inquiry from ${payload.customerName}`,
props: {
customerName: payload.customerName,
customerPhone: payload.customerPhone,
customerEmail: payload.customerEmail,
customerLocation: payload.customerLocation,
requirement: payload.requirement,
requirementType: payload.requirementType,
projectTitle: payload.projectTitle,
},
recipientName: member.name,
},
});
}
// WhatsApp to every verified, opted-in pro recipient.
// Falls back to legacy pros.whatsapp only if the pro has no recipient
// rows at all (e.g. backfill skipped or row deleted) — keeps single-number
// pros covered until they migrate.
const whatsappTargets =
whatsappRecipients.length > 0
? whatsappRecipients.map((r) => r.number)
: pro.whatsapp
? [pro.whatsapp]
: [];
for (const recipient of whatsappTargets) {
requests.push({
channel: "whatsapp",
recipient,
eventType: "new_inquiry",
proId: payload.proId,
content: {
templateName: "int_inquiry_notification",
languageCode: "en",
components: [
{
type: "body",
parameters: [
{ type: "text", text: payload.customerName },
{ type: "text", text: payload.requirementType ?? "General" },
{ type: "text", text: payload.customerPhone },
],
},
],
},
});
}
// WhatsApp confirmation to customer (transactional)
requests.push({
channel: "whatsapp",
recipient: payload.customerPhone,
eventType: "inquiry_confirmation",
proId: payload.proId,
transactional: true,
content: {
templateName: "int_inquiry_confirmation",
languageCode: "en",
components: [
{
type: "body",
parameters: [
{ type: "text", text: payload.customerName },
{ type: "text", text: pro.businessName ?? "" },
],
},
],
},
});
await this.gateway.sendMany(requests);
}
}
|