mirror of
https://github.com/Dokploy/website.git
synced 2026-06-15 20:25:25 +02:00
feat: integrate Slack notifications for contact form submissions
- Added a new Slack notification feature to alert sales or support channels upon contact form submissions. - Implemented a `notifySlack` function to format and send messages to Slack using a webhook. - Enhanced error handling to ensure email notifications proceed even if Slack notifications fail.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { getHubSpotUTK, submitToHubSpot } from "@/lib/hubspot";
|
||||
import { notifySlack } from "@/lib/slack";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { Resend } from "resend";
|
||||
@@ -70,6 +71,23 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification to Slack (sales or support channel)
|
||||
try {
|
||||
const slackSuccess = await notifySlack(body);
|
||||
if (slackSuccess) {
|
||||
console.log(
|
||||
`Successfully sent ${body.inquiryType} inquiry notification to Slack`,
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
`Failed to send ${body.inquiryType} inquiry notification to Slack, but continuing with email`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error sending to Slack:", error);
|
||||
// Continue with email even if Slack fails
|
||||
}
|
||||
|
||||
// Format email content
|
||||
const emailSubject = `[${body.inquiryType.toUpperCase()}] New contact form submission from ${body.firstName} ${body.lastName}`;
|
||||
const emailBody = `
|
||||
|
||||
167
apps/website/lib/slack.ts
Normal file
167
apps/website/lib/slack.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
interface ContactFormData {
|
||||
inquiryType: "support" | "sales" | "other";
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
company: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface SlackMessage {
|
||||
text?: string;
|
||||
blocks?: SlackBlock[];
|
||||
}
|
||||
|
||||
interface SlackBlock {
|
||||
type: string;
|
||||
text?: {
|
||||
type: string;
|
||||
text: string;
|
||||
};
|
||||
fields?: Array<{
|
||||
type: string;
|
||||
text: string;
|
||||
}>;
|
||||
elements?: Array<{
|
||||
type: string;
|
||||
text: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format contact form data as a Slack message with blocks
|
||||
*/
|
||||
function formatContactDataForSlack(
|
||||
contactData: ContactFormData,
|
||||
): SlackMessage {
|
||||
// Get emoji and label based on inquiry type
|
||||
let inquiryTypeEmoji: string;
|
||||
let inquiryTypeLabel: string;
|
||||
|
||||
switch (contactData.inquiryType) {
|
||||
case "sales":
|
||||
inquiryTypeEmoji = "💰";
|
||||
inquiryTypeLabel = "Sales";
|
||||
break;
|
||||
case "support":
|
||||
inquiryTypeEmoji = "🛟";
|
||||
inquiryTypeLabel = "Support";
|
||||
break;
|
||||
case "other":
|
||||
inquiryTypeEmoji = "📝";
|
||||
inquiryTypeLabel = "Other";
|
||||
break;
|
||||
default:
|
||||
inquiryTypeEmoji = "📧";
|
||||
inquiryTypeLabel = "Contact";
|
||||
}
|
||||
|
||||
return {
|
||||
text: `New ${contactData.inquiryType} inquiry from ${contactData.firstName} ${contactData.lastName}`,
|
||||
blocks: [
|
||||
{
|
||||
type: "header",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: `${inquiryTypeEmoji} New ${inquiryTypeLabel} Inquiry`,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
fields: [
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `*Name:*\n${contactData.firstName} ${contactData.lastName}`,
|
||||
},
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `*Email:*\n${contactData.email}`,
|
||||
},
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `*Company:*\n${contactData.company}`,
|
||||
},
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `*Type:*\n${inquiryTypeLabel}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: `*Message:*\n${contactData.message}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
type: "context",
|
||||
elements: [
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: "Sent from Dokploy website contact form",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to Slack using a webhook URL
|
||||
*/
|
||||
export async function sendToSlack(
|
||||
contactData: ContactFormData,
|
||||
webhookUrl: string,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
if (!webhookUrl) {
|
||||
console.error("Slack webhook URL is not configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
const message = formatContactDataForSlack(contactData);
|
||||
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(message),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error("Slack webhook error:", response.status, errorText);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log("Slack notification sent successfully");
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error sending to Slack:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send contact form notification to Slack
|
||||
* All inquiry types (sales, support, other) are sent to the same Slack channel
|
||||
*/
|
||||
export async function notifySlack(
|
||||
contactData: ContactFormData,
|
||||
): Promise<boolean> {
|
||||
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
|
||||
|
||||
if (!webhookUrl) {
|
||||
console.warn(
|
||||
"Slack webhook URL is not configured (SLACK_WEBHOOK_URL)",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return await sendToSlack(contactData, webhookUrl);
|
||||
}
|
||||
Reference in New Issue
Block a user