deploy: harden lead and call notification delivery
This commit is contained in:
parent
656b78bf8e
commit
78ddcb9146
3 changed files with 50 additions and 22 deletions
|
|
@ -36,16 +36,31 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
const url = new URL(request.url)
|
const url = new URL(request.url)
|
||||||
const summaryText = buildPhoneCallSummary(detail)
|
const summaryText = buildPhoneCallSummary(detail)
|
||||||
const notificationResult = await sendPhoneCallSummaryEmail({
|
let notificationResult:
|
||||||
detail: {
|
| { status: "pending" | "sent" | "failed" | "disabled"; error?: string }
|
||||||
...detail,
|
| undefined
|
||||||
call: {
|
|
||||||
...detail.call,
|
try {
|
||||||
summaryText,
|
notificationResult = await sendPhoneCallSummaryEmail({
|
||||||
|
detail: {
|
||||||
|
...detail,
|
||||||
|
call: {
|
||||||
|
...detail.call,
|
||||||
|
summaryText,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
adminUrl: url.origin,
|
||||||
adminUrl: url.origin,
|
})
|
||||||
})
|
} catch (notificationError) {
|
||||||
|
console.error("Failed to send phone call summary email:", notificationError)
|
||||||
|
notificationResult = {
|
||||||
|
status: "failed",
|
||||||
|
error:
|
||||||
|
notificationError instanceof Error
|
||||||
|
? notificationError.message
|
||||||
|
: "Unknown phone call notification error.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result = await fetchMutation(api.voiceSessions.completeSession, {
|
const result = await fetchMutation(api.voiceSessions.completeSession, {
|
||||||
sessionId: detail.call.id,
|
sessionId: detail.call.id,
|
||||||
|
|
@ -58,10 +73,13 @@ export async function POST(request: Request) {
|
||||||
? String(body.recordingError)
|
? String(body.recordingError)
|
||||||
: undefined,
|
: undefined,
|
||||||
summaryText,
|
summaryText,
|
||||||
notificationStatus: notificationResult.status,
|
notificationStatus: notificationResult?.status || "failed",
|
||||||
notificationSentAt:
|
notificationSentAt:
|
||||||
notificationResult.status === "sent" ? Date.now() : undefined,
|
notificationResult?.status === "sent" ? Date.now() : undefined,
|
||||||
notificationError: notificationResult.error,
|
notificationError:
|
||||||
|
notificationResult?.status === "sent"
|
||||||
|
? undefined
|
||||||
|
: notificationResult?.error || "Phone call notification did not run.",
|
||||||
})
|
})
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
|
|
|
||||||
17
lib/ghl.ts
17
lib/ghl.ts
|
|
@ -1,6 +1,19 @@
|
||||||
const GHL_API_BASE = "https://services.leadconnectorhq.com"
|
const GHL_API_BASE = "https://services.leadconnectorhq.com"
|
||||||
const GHL_API_VERSION = "2021-07-28"
|
const GHL_API_VERSION = "2021-07-28"
|
||||||
|
|
||||||
|
export function getGhlApiToken() {
|
||||||
|
return (
|
||||||
|
process.env.GHL_PRIVATE_INTEGRATION_TOKEN ||
|
||||||
|
process.env.GHL_API_TOKEN ||
|
||||||
|
""
|
||||||
|
).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGhlConfigured() {
|
||||||
|
const locationId = (process.env.GHL_LOCATION_ID || "").trim()
|
||||||
|
return Boolean(locationId && getGhlApiToken())
|
||||||
|
}
|
||||||
|
|
||||||
export async function createGHLContact(data: {
|
export async function createGHLContact(data: {
|
||||||
email: string
|
email: string
|
||||||
firstName?: string
|
firstName?: string
|
||||||
|
|
@ -10,8 +23,8 @@ export async function createGHLContact(data: {
|
||||||
source?: string
|
source?: string
|
||||||
tags?: string[]
|
tags?: string[]
|
||||||
}) {
|
}) {
|
||||||
const locationId = process.env.GHL_LOCATION_ID
|
const locationId = (process.env.GHL_LOCATION_ID || "").trim()
|
||||||
const apiToken = process.env.GHL_API_TOKEN
|
const apiToken = getGhlApiToken()
|
||||||
|
|
||||||
if (!locationId || !apiToken) {
|
if (!locationId || !apiToken) {
|
||||||
console.warn("GHL credentials incomplete; skipping contact creation.")
|
console.warn("GHL credentials incomplete; skipping contact creation.")
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
sendTransactionalEmail,
|
sendTransactionalEmail,
|
||||||
TO_EMAIL,
|
TO_EMAIL,
|
||||||
} from "@/lib/email"
|
} from "@/lib/email"
|
||||||
import { createGHLContact } from "@/lib/ghl"
|
import { createGHLContact, isGhlConfigured } from "@/lib/ghl"
|
||||||
import {
|
import {
|
||||||
createSmsConsentPayload,
|
createSmsConsentPayload,
|
||||||
isValidConsentTimestamp,
|
isValidConsentTimestamp,
|
||||||
|
|
@ -143,16 +143,10 @@ function getConfiguredTenantDomains() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultDeps(): LeadSubmissionDeps {
|
function defaultDeps(): LeadSubmissionDeps {
|
||||||
const ghlSyncEnabled = String(process.env.ENABLE_GHL_SYNC || "")
|
|
||||||
.trim()
|
|
||||||
.toLowerCase() === "true"
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
storageConfigured: isConvexConfigured(),
|
storageConfigured: isConvexConfigured(),
|
||||||
emailConfigured: isEmailConfigured(),
|
emailConfigured: isEmailConfigured(),
|
||||||
ghlConfigured:
|
ghlConfigured: isGhlConfigured(),
|
||||||
ghlSyncEnabled &&
|
|
||||||
Boolean(process.env.GHL_API_TOKEN && process.env.GHL_LOCATION_ID),
|
|
||||||
ingest: ingestLead,
|
ingest: ingestLead,
|
||||||
updateLeadStatus: updateLeadSyncStatus,
|
updateLeadStatus: updateLeadSyncStatus,
|
||||||
sendEmail: (to, subject, html, replyTo) =>
|
sendEmail: (to, subject, html, replyTo) =>
|
||||||
|
|
@ -635,6 +629,9 @@ export async function processLeadSubmission(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
deps.logger.warn("GHL credentials incomplete; skipping Rocky GHL sync.")
|
deps.logger.warn("GHL credentials incomplete; skipping Rocky GHL sync.")
|
||||||
|
warnings.push(
|
||||||
|
"GHL sync skipped: set GHL_PRIVATE_INTEGRATION_TOKEN (preferred) or GHL_API_TOKEN with GHL_LOCATION_ID."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leadId) {
|
if (leadId) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue