Wfdash-OnlineShop/src/lib/webhookService.ts
gpt-engineer-app[bot] 57b2cf99f9 Changes
2026-02-12 23:36:41 +00:00

144 lines
3.5 KiB
TypeScript

import { CartItem } from '@/types';
const WEBHOOK_URL = 'https://n8nmac.apphub.co.za/webhook/wfsales_quotes';
const TIMEOUT_MS = 10_000;
interface CustomerInfo {
name: string;
email: string;
phone: string;
company: string;
}
interface WebhookPayload {
source: string;
request_type: string;
quote_request_id: string;
customer: {
name: string;
email: string;
phone: string;
company: string;
};
cart: {
cart_id: string;
currency: string;
subtotal: number;
items: {
sku: string;
description: string;
quantity: number;
unit: string;
}[];
};
metadata: {
website: string;
submitted_at: string;
};
}
function generateUUID(): string {
return crypto.randomUUID();
}
function isValidEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
export function validateQuoteRequest(
customer: CustomerInfo,
items: CartItem[]
): { valid: boolean; error?: string } {
if (!customer.name.trim()) {
return { valid: false, error: 'Customer name is required.' };
}
if (!customer.email.trim() || !isValidEmail(customer.email.trim())) {
return { valid: false, error: 'A valid email address is required.' };
}
if (items.length === 0) {
return { valid: false, error: 'Cart is empty.' };
}
return { valid: true };
}
export function buildPayload(
customer: CustomerInfo,
items: CartItem[]
): WebhookPayload {
return {
source: 'online_shop',
request_type: 'quote_request',
quote_request_id: generateUUID(),
customer: {
name: customer.name.trim(),
email: customer.email.trim(),
phone: customer.phone?.trim() || '',
company: customer.company?.trim() || '',
},
cart: {
cart_id: generateUUID(),
currency: 'ZAR',
subtotal: 0,
items: items.map((item) => ({
sku: item.product.sku || '',
description: item.product.name,
quantity: item.quantity || 1,
unit: 'each',
})),
},
metadata: {
website: 'Q - PORTAL',
submitted_at: new Date().toISOString(),
},
};
}
export async function sendQuoteWebhook(
customer: CustomerInfo,
items: CartItem[]
): Promise<{ success: boolean; error?: string }> {
const validation = validateQuoteRequest(customer, items);
if (!validation.valid) {
return { success: false, error: validation.error };
}
const payload = buildPayload(customer, items);
console.log('📤 Webhook request payload:', JSON.stringify(payload, null, 2));
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
try {
const response = await fetch(WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal: controller.signal,
});
const responseBody = await response.text();
console.log('📥 Webhook response status:', response.status);
console.log('📥 Webhook response body:', responseBody);
if (!response.ok) {
return {
success: false,
error: `Webhook returned status ${response.status}. Please try again.`,
};
}
return { success: true };
} catch (err: unknown) {
const message =
err instanceof DOMException && err.name === 'AbortError'
? 'Request timed out after 10 seconds. Please try again.'
: err instanceof Error
? err.message
: 'Unknown error';
console.error('❌ Webhook error:', message);
return { success: false, error: message };
} finally {
clearTimeout(timeout);
}
}