186 lines
6.3 KiB
TypeScript
186 lines
6.3 KiB
TypeScript
import { logDone, logError, logIntent } from "../../config/logger.js";
|
|
|
|
export interface DispatchResult {
|
|
success: boolean;
|
|
providerResponse?: string;
|
|
error?: string;
|
|
}
|
|
|
|
function formatResponseFailure(endpoint: string, data: unknown): string {
|
|
const serialized = JSON.stringify(data);
|
|
return `${endpoint} returned success=false${serialized && serialized !== "{}" ? ` data=${serialized}` : " without error details"}`;
|
|
}
|
|
|
|
function getApiBaseUrl(): string {
|
|
const raw = process.env.API_URL || "";
|
|
|
|
if (!raw.trim()) {
|
|
return "";
|
|
}
|
|
|
|
try {
|
|
return new URL(raw).origin;
|
|
} catch {
|
|
return raw.replace(/\/$/, "");
|
|
}
|
|
}
|
|
|
|
function buildApiUrl(path: string): string {
|
|
return `${getApiBaseUrl()}${path}`;
|
|
}
|
|
|
|
function formatDispatchError(error: unknown): string {
|
|
if (typeof error === "object" && error !== null && "isAxiosError" in error) {
|
|
const axiosError = error as {
|
|
message?: string;
|
|
response?: { status?: number; data?: unknown };
|
|
};
|
|
const details = [
|
|
axiosError.response?.status ? `status=${axiosError.response.status}` : undefined,
|
|
axiosError.response?.data !== undefined ? `data=${JSON.stringify(axiosError.response.data)}` : undefined,
|
|
axiosError.message ? `message=${axiosError.message}` : undefined,
|
|
].filter(Boolean);
|
|
|
|
return details.join(" ") || "Axios request failed without details";
|
|
}
|
|
|
|
return error instanceof Error ? error.message : String(error);
|
|
}
|
|
|
|
export async function dispatchWhatsApp(params: {
|
|
companyId: string;
|
|
appointmentId: string;
|
|
type: string;
|
|
systemToken: string;
|
|
phoneNumber: string;
|
|
message: string;
|
|
companyOwnerId: string;
|
|
}): Promise<DispatchResult> {
|
|
try {
|
|
if (!params.phoneNumber.trim() || !params.message.trim() || !params.companyOwnerId.trim()) {
|
|
return { success: false, error: "WhatsApp dispatch requires phoneNumber, message, and companyOwnerId" };
|
|
}
|
|
|
|
// Send worker-rendered content directly so cancellation jobs survive appointment deletion.
|
|
const axios = (await import("axios")).default;
|
|
const response = await axios.post(
|
|
buildApiUrl("/notifications/send-wap"),
|
|
{
|
|
systemToken: params.systemToken,
|
|
phoneNumber: params.phoneNumber,
|
|
message: params.message,
|
|
companyId: params.companyId,
|
|
sessionUser: params.companyOwnerId,
|
|
},
|
|
{
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
|
|
logDone(`WhatsApp dispatched for company ${params.companyId}`);
|
|
return { success: true, providerResponse: JSON.stringify(response.data) };
|
|
} catch (error) {
|
|
const msg = formatDispatchError(error);
|
|
logError(`WhatsApp dispatch failed for company ${params.companyId}:`, msg);
|
|
return { success: false, error: msg };
|
|
}
|
|
}
|
|
|
|
export async function dispatchEmail(params: {
|
|
appointmentId: string;
|
|
systemToken: string;
|
|
type: string;
|
|
email: string;
|
|
subject: string;
|
|
message: string;
|
|
}): Promise<DispatchResult> {
|
|
try {
|
|
if (!params.email.trim() || !params.subject.trim() || !params.message.trim()) {
|
|
return { success: false, error: "Email dispatch requires email, subject, and message" };
|
|
}
|
|
|
|
// Send worker-rendered content directly so cancellation jobs survive appointment deletion.
|
|
const axios = (await import("axios")).default;
|
|
const response = await axios.post(
|
|
buildApiUrl("/notifications/send-email"),
|
|
{
|
|
systemToken: params.systemToken,
|
|
email: params.email,
|
|
subject: params.subject,
|
|
message: params.message,
|
|
},
|
|
{
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
|
|
const responseData = response.data as { success?: boolean };
|
|
if (responseData.success === false) {
|
|
return {
|
|
success: false,
|
|
error: formatResponseFailure("notifications/send-email", response.data),
|
|
};
|
|
}
|
|
|
|
logDone(`Email dispatched to ${params.email}`);
|
|
return { success: true, providerResponse: JSON.stringify(response.data) };
|
|
} catch (error) {
|
|
const msg = formatDispatchError(error);
|
|
logError(`Email dispatch failed for ${params.email}:`, msg);
|
|
return { success: false, error: msg };
|
|
}
|
|
}
|
|
|
|
export async function dispatchSystem(params: {
|
|
systemToken: string;
|
|
userId: string;
|
|
subject: string;
|
|
message: string;
|
|
companyId?: string;
|
|
serviceId?: number;
|
|
conversationId?: string;
|
|
type?: string;
|
|
code?: string;
|
|
}): Promise<DispatchResult> {
|
|
try {
|
|
if (!params.userId.trim() || !params.subject.trim() || !params.message.trim()) {
|
|
return { success: false, error: "System dispatch requires userId, subject, and message" };
|
|
}
|
|
|
|
// Delegate to the server API for system notification
|
|
const axios = (await import("axios")).default;
|
|
const response = await axios.post(
|
|
buildApiUrl("/systemnotifications/create"),
|
|
{
|
|
userId: params.userId,
|
|
subject: params.subject,
|
|
message: params.message,
|
|
companyId: params.companyId,
|
|
serviceId: params.serviceId,
|
|
conversationId: params.conversationId,
|
|
type: params.type,
|
|
code: params.code,
|
|
systemToken: params.systemToken,
|
|
},
|
|
{
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
|
|
const responseData = response.data as { success?: boolean };
|
|
if (responseData.success === false) {
|
|
return {
|
|
success: false,
|
|
error: formatResponseFailure("systemnotifications/create", response.data),
|
|
};
|
|
}
|
|
|
|
logDone(`System notification dispatched to user ${params.userId}`);
|
|
return { success: true, providerResponse: JSON.stringify(response.data) };
|
|
} catch (error) {
|
|
const msg = formatDispatchError(error);
|
|
logError(`System notification dispatch failed for user ${params.userId}:`, msg);
|
|
return { success: false, error: msg };
|
|
}
|
|
}
|