Some checks failed
Build and Deploy / build (push) Has been cancelled
- Email capture popup with scroll (10%) and exit intent triggers - First name field and full tracking (UTM, device, time on page) - Mautic API integration for contact creation - GeoIP detection for country/region - 4 locale support (sr, en, de, fr) - Mautic tracking script in layout
121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
interface MauticToken {
|
|
access_token: string;
|
|
expires_in: number;
|
|
token_type: string;
|
|
}
|
|
|
|
let cachedToken: MauticToken | null = null;
|
|
let tokenExpiresAt: number = 0;
|
|
|
|
async function getMauticToken(): Promise<string> {
|
|
if (cachedToken && Date.now() < tokenExpiresAt - 60000) {
|
|
return cachedToken.access_token;
|
|
}
|
|
|
|
const clientId = process.env.MAUTIC_CLIENT_ID;
|
|
const clientSecret = process.env.MAUTIC_CLIENT_SECRET;
|
|
const apiUrl = process.env.MAUTIC_API_URL || "https://mautic.nodecrew.me";
|
|
|
|
if (!clientId || !clientSecret) {
|
|
throw new Error("Mautic credentials not configured");
|
|
}
|
|
|
|
const response = await fetch(`${apiUrl}/oauth/v2/token`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: "client_credentials",
|
|
client_id: clientId,
|
|
client_secret: clientSecret,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
console.error("Mautic token error:", response.status, errorText);
|
|
throw new Error(`Failed to get Mautic token: ${response.status} - ${errorText}`);
|
|
}
|
|
|
|
const token: MauticToken = await response.json();
|
|
cachedToken = token;
|
|
tokenExpiresAt = Date.now() + token.expires_in * 1000;
|
|
|
|
return token.access_token;
|
|
}
|
|
|
|
export async function createMauticContact(
|
|
email: string,
|
|
tags: string[],
|
|
additionalData?: {
|
|
firstName?: string;
|
|
lastName?: string;
|
|
country?: string;
|
|
city?: string;
|
|
phone?: string;
|
|
website?: string;
|
|
preferredLocale?: string;
|
|
ipAddress?: string;
|
|
utmSource?: string;
|
|
utmMedium?: string;
|
|
utmCampaign?: string;
|
|
utmContent?: string;
|
|
pageUrl?: string;
|
|
}
|
|
): Promise<{ success: boolean; alreadyExists?: boolean; contactId?: number }> {
|
|
try {
|
|
const token = await getMauticToken();
|
|
const apiUrl = process.env.MAUTIC_API_URL || "https://mautic.nodecrew.me";
|
|
|
|
const payload: any = {
|
|
email,
|
|
tags: tags.join(","),
|
|
};
|
|
|
|
if (additionalData) {
|
|
if (additionalData.firstName) payload.firstname = additionalData.firstName;
|
|
if (additionalData.lastName) payload.lastname = additionalData.lastName;
|
|
if (additionalData.country) payload.country = additionalData.country;
|
|
if (additionalData.city) payload.city = additionalData.city;
|
|
if (additionalData.phone) payload.phone = additionalData.phone;
|
|
if (additionalData.preferredLocale) payload.preferred_locale = additionalData.preferredLocale;
|
|
if (additionalData.utmSource) payload.utm_source = additionalData.utmSource;
|
|
if (additionalData.utmMedium) payload.utm_medium = additionalData.utmMedium;
|
|
if (additionalData.utmCampaign) payload.utm_campaign = additionalData.utmCampaign;
|
|
if (additionalData.utmContent) payload.utm_content = additionalData.utmContent;
|
|
if (additionalData.pageUrl) payload.page_url = additionalData.pageUrl;
|
|
}
|
|
|
|
const response = await fetch(`${apiUrl}/api/contacts/new`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Authorization": `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
if (response.status === 409) {
|
|
return { success: true, alreadyExists: true };
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
console.error("Mautic API error:", response.status, errorText);
|
|
throw new Error(`Mautic API error: ${response.status} - ${errorText}`);
|
|
}
|
|
|
|
const responseData = await response.json();
|
|
console.log("Mautic API success:", responseData);
|
|
|
|
return {
|
|
success: true,
|
|
contactId: responseData.contact?.id
|
|
};
|
|
} catch (error) {
|
|
console.error("Mautic contact creation failed:", error);
|
|
throw error;
|
|
}
|
|
}
|