Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
156 lines
No EOL
4.1 KiB
TypeScript
156 lines
No EOL
4.1 KiB
TypeScript
export interface WebhookResponse {
|
|
success: boolean
|
|
message: string
|
|
error?: string
|
|
}
|
|
|
|
export interface ContactFormWebhookData {
|
|
firstName: string
|
|
lastName: string
|
|
email: string
|
|
phone: string
|
|
company?: string
|
|
message: string
|
|
source?: string
|
|
page?: string
|
|
timestamp: string
|
|
url: string
|
|
}
|
|
|
|
export interface RequestMachineFormWebhookData {
|
|
firstName: string
|
|
lastName: string
|
|
email: string
|
|
phone: string
|
|
company: string
|
|
employeeCount: string
|
|
machineType: string
|
|
machineCount: string
|
|
message?: string
|
|
marketingConsent: boolean
|
|
termsAgreement: boolean
|
|
source?: string
|
|
page?: string
|
|
timestamp: string
|
|
url: string
|
|
}
|
|
|
|
export class WebhookClient {
|
|
private static async sendToWebhook(
|
|
webhookUrl: string,
|
|
payload: any,
|
|
webhookType: 'contact' | 'request-machine'
|
|
): Promise<WebhookResponse> {
|
|
try {
|
|
// Send initial request
|
|
const response = await fetch(webhookUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload),
|
|
})
|
|
|
|
if (response.ok) {
|
|
return {
|
|
success: true,
|
|
message: `${webhookType} form submitted successfully`
|
|
}
|
|
}
|
|
|
|
// Log the error and retry once
|
|
console.error(`Webhook failed for ${webhookType}:`, response.status, response.statusText)
|
|
|
|
const retryResponse = await fetch(webhookUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload),
|
|
})
|
|
|
|
if (retryResponse.ok) {
|
|
return {
|
|
success: true,
|
|
message: `${webhookType} form submitted successfully (retry)`
|
|
}
|
|
}
|
|
|
|
console.error(`Webhook retry failed for ${webhookType}:`, retryResponse.status, retryResponse.statusText)
|
|
return {
|
|
success: false,
|
|
message: 'Failed to submit to webhook after retry',
|
|
error: `${retryResponse.status} ${retryResponse.statusText}`
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`Webhook error for ${webhookType}:`, error)
|
|
return {
|
|
success: false,
|
|
message: 'Failed to submit to webhook',
|
|
error: error instanceof Error ? error.message : 'Unknown error'
|
|
}
|
|
}
|
|
}
|
|
|
|
static async submitContactForm(data: ContactFormWebhookData): Promise<WebhookResponse> {
|
|
const webhookUrl = process.env.GHL_CONTACT_WEBHOOK_URL
|
|
|
|
if (!webhookUrl) {
|
|
return {
|
|
success: false,
|
|
message: 'Webhook URL not configured',
|
|
error: 'GHL_CONTACT_WEBHOOK_URL environment variable not set'
|
|
}
|
|
}
|
|
|
|
const ghlPayload = {
|
|
firstName: data.firstName,
|
|
lastName: data.lastName,
|
|
email: data.email,
|
|
phone: data.phone,
|
|
company: data.company || '',
|
|
custom1: data.message,
|
|
custom2: data.source || 'website',
|
|
custom3: data.page || window.location.pathname,
|
|
custom4: data.timestamp,
|
|
custom5: data.url,
|
|
}
|
|
|
|
return this.sendToWebhook(webhookUrl, ghlPayload, 'contact')
|
|
}
|
|
|
|
static async submitRequestMachineForm(data: RequestMachineFormWebhookData): Promise<WebhookResponse> {
|
|
const webhookUrl = process.env.GHL_REQUEST_MACHINE_WEBHOOK_URL
|
|
|
|
if (!webhookUrl) {
|
|
return {
|
|
success: false,
|
|
message: 'Webhook URL not configured',
|
|
error: 'GHL_REQUEST_MACHINE_WEBHOOK_URL environment variable not set'
|
|
}
|
|
}
|
|
|
|
const ghlPayload = {
|
|
firstName: data.firstName,
|
|
lastName: data.lastName,
|
|
email: data.email,
|
|
phone: data.phone,
|
|
company: data.company,
|
|
custom1: data.employeeCount,
|
|
custom2: data.machineType,
|
|
custom3: data.machineCount,
|
|
custom4: data.message || '',
|
|
custom5: data.source || 'website',
|
|
custom6: data.page || window.location.pathname,
|
|
custom7: data.timestamp,
|
|
custom8: data.url,
|
|
custom9: data.marketingConsent ? 'Consented' : 'Not Consented',
|
|
custom10: data.termsAgreement ? 'Agreed' : 'Not Agreed',
|
|
tags: ['Machine Request'],
|
|
custom11: 'Free Consultation Request',
|
|
}
|
|
|
|
return this.sendToWebhook(webhookUrl, ghlPayload, 'request-machine')
|
|
}
|
|
} |