161 lines
5 KiB
TypeScript
161 lines
5 KiB
TypeScript
import { NextResponse } from "next/server"
|
|
import { fetchMutation } from "convex/nextjs"
|
|
import { api } from "@/convex/_generated/api"
|
|
import { requirePhoneAgentInternalAuth } from "@/app/api/internal/phone-calls/shared"
|
|
import {
|
|
buildSameDayReminderWindow,
|
|
createFollowupReminderEvent,
|
|
} from "@/lib/google-calendar"
|
|
import { normalizePhoneE164, splitDisplayName } from "@/lib/phone-normalization"
|
|
|
|
function buildReminderTitle(args: {
|
|
kind: "scheduled" | "same-day"
|
|
callerName?: string
|
|
company?: string
|
|
phone?: string
|
|
}) {
|
|
const label = args.kind === "same-day" ? "Same-day callback" : "Callback reminder"
|
|
const identity = [args.callerName, args.company, args.phone]
|
|
.map((value) => String(value || "").trim())
|
|
.filter(Boolean)
|
|
.join(" | ")
|
|
|
|
return identity ? `${label}: ${identity}` : label
|
|
}
|
|
|
|
function buildReminderDescription(args: {
|
|
callerName?: string
|
|
company?: string
|
|
phone?: string
|
|
reason?: string
|
|
summaryText?: string
|
|
adminCallUrl: string
|
|
}) {
|
|
return [
|
|
args.callerName ? `Caller: ${args.callerName}` : "",
|
|
args.company ? `Company: ${args.company}` : "",
|
|
args.phone ? `Phone: ${args.phone}` : "",
|
|
args.reason ? `Reason: ${args.reason}` : "",
|
|
args.summaryText ? `Summary: ${args.summaryText}` : "",
|
|
`RMV admin call detail: ${args.adminCallUrl}`,
|
|
]
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
const authError = await requirePhoneAgentInternalAuth(request)
|
|
if (authError) {
|
|
return authError
|
|
}
|
|
|
|
try {
|
|
const body = await request.json()
|
|
const sessionId = String(body.sessionId || "").trim()
|
|
const kind =
|
|
body.kind === "same-day" ? ("same-day" as const) : ("scheduled" as const)
|
|
|
|
if (!sessionId) {
|
|
return NextResponse.json(
|
|
{ error: "sessionId is required" },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
const url = new URL(request.url)
|
|
const adminCallUrl = `${url.origin}/admin/calls/${sessionId}`
|
|
const normalizedPhone = normalizePhoneE164(body.phone)
|
|
const callerName = String(body.callerName || "").trim()
|
|
const company = String(body.company || "").trim()
|
|
const reason = String(body.reason || "").trim()
|
|
const summaryText = String(body.summaryText || "").trim()
|
|
|
|
let startAt: Date
|
|
let endAt: Date
|
|
if (kind === "same-day") {
|
|
const reminderWindow = buildSameDayReminderWindow()
|
|
startAt = reminderWindow.startAt
|
|
endAt = reminderWindow.endAt
|
|
} else {
|
|
startAt = new Date(String(body.startAt || ""))
|
|
endAt = new Date(String(body.endAt || ""))
|
|
if (Number.isNaN(endAt.getTime()) && !Number.isNaN(startAt.getTime())) {
|
|
endAt = new Date(startAt.getTime() + 15 * 60 * 1000)
|
|
}
|
|
if (Number.isNaN(startAt.getTime()) || Number.isNaN(endAt.getTime()) || startAt.getTime() <= Date.now()) {
|
|
return NextResponse.json(
|
|
{ error: "A future startAt and endAt are required" },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
}
|
|
|
|
const reminder = await createFollowupReminderEvent({
|
|
title: buildReminderTitle({
|
|
kind,
|
|
callerName,
|
|
company,
|
|
phone: normalizedPhone || String(body.phone || "").trim(),
|
|
}),
|
|
description: buildReminderDescription({
|
|
callerName,
|
|
company,
|
|
phone: normalizedPhone || String(body.phone || "").trim(),
|
|
reason,
|
|
summaryText,
|
|
adminCallUrl,
|
|
}),
|
|
startAt,
|
|
endAt,
|
|
})
|
|
|
|
let contactProfileId: string | undefined
|
|
if (normalizedPhone) {
|
|
const nameParts = splitDisplayName(callerName)
|
|
const profile = await fetchMutation(api.contactProfiles.upsertByPhone, {
|
|
normalizedPhone,
|
|
displayName: callerName || undefined,
|
|
firstName: nameParts.firstName || undefined,
|
|
lastName: nameParts.lastName || undefined,
|
|
company: company || undefined,
|
|
lastSummaryText: summaryText || reason || undefined,
|
|
lastReminderAt: Date.now(),
|
|
reminderNotes: reason || undefined,
|
|
source: "phone-agent",
|
|
})
|
|
contactProfileId = profile?._id
|
|
}
|
|
|
|
const call = await fetchMutation(api.voiceSessions.linkPhoneCallLead, {
|
|
sessionId,
|
|
contactProfileId,
|
|
contactDisplayName: callerName || undefined,
|
|
contactCompany: company || undefined,
|
|
reminderStatus: kind === "same-day" ? "sameDay" : "scheduled",
|
|
reminderRequestedAt: Date.now(),
|
|
reminderStartAt: startAt.getTime(),
|
|
reminderEndAt: endAt.getTime(),
|
|
reminderCalendarEventId: reminder.eventId,
|
|
reminderCalendarHtmlLink: reminder.htmlLink || undefined,
|
|
reminderNote: reason || summaryText || undefined,
|
|
})
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
reminder: {
|
|
kind,
|
|
startAt: startAt.toISOString(),
|
|
endAt: endAt.toISOString(),
|
|
eventId: reminder.eventId,
|
|
htmlLink: reminder.htmlLink,
|
|
},
|
|
call,
|
|
})
|
|
} catch (error) {
|
|
console.error("Failed to create phone agent follow-up reminder:", error)
|
|
return NextResponse.json(
|
|
{ error: "Failed to create phone agent follow-up reminder" },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|