Add Google Sheets webhook, email to Cgabijendra@gmail.com, WhatsApp button
- Every inquiry fires 3 simultaneous destinations: Google Sheet, email, Kondesk - Email to Cgabijendra@gmail.com with HTML template + reply-to set to the lead - GOOGLE_SHEET_WEBHOOK env var (set once Google Apps Script is deployed) - WhatsApp floating button bottom-right, links to +61 405 580 047 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
29cfa0b9ac
commit
91b7a948fd
4 changed files with 193 additions and 60 deletions
89
google-apps-script.js
Normal file
89
google-apps-script.js
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
// ============================================================
|
||||||
|
// Careers Gateway — Google Apps Script Webhook
|
||||||
|
// Paste this into Extensions → Apps Script in your Google Sheet
|
||||||
|
// Deploy as: Web App → Execute as: Me → Access: Anyone
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
const NOTIFY_EMAIL = 'Cgabijendra@gmail.com';
|
||||||
|
const SHEET_NAME = 'Inquiries';
|
||||||
|
|
||||||
|
function doPost(e) {
|
||||||
|
try {
|
||||||
|
var data = JSON.parse(e.postData.contents);
|
||||||
|
appendToSheet(data);
|
||||||
|
sendNotificationEmail(data);
|
||||||
|
return ok();
|
||||||
|
} catch (err) {
|
||||||
|
return ContentService
|
||||||
|
.createTextOutput(JSON.stringify({ success: false, error: err.message }))
|
||||||
|
.setMimeType(ContentService.MimeType.JSON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow CORS preflight
|
||||||
|
function doGet(e) {
|
||||||
|
return ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendToSheet(data) {
|
||||||
|
var ss = SpreadsheetApp.getActiveSpreadsheet();
|
||||||
|
var sheet = ss.getSheetByName(SHEET_NAME);
|
||||||
|
if (!sheet) {
|
||||||
|
sheet = ss.insertSheet(SHEET_NAME);
|
||||||
|
sheet.appendRow([
|
||||||
|
'Date (AEST)', 'Full Name', 'Email', 'Phone',
|
||||||
|
'Service', 'Course Name', 'CRICOS Code', 'Institution', 'Message', 'Source'
|
||||||
|
]);
|
||||||
|
// Bold the header row
|
||||||
|
sheet.getRange(1, 1, 1, 10).setFontWeight('bold').setBackground('#1a2744').setFontColor('#ffffff');
|
||||||
|
sheet.setFrozenRows(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sheet.appendRow([
|
||||||
|
data.submittedAt || new Date().toLocaleString('en-AU', { timeZone: 'Australia/Sydney' }),
|
||||||
|
data.fullName || '',
|
||||||
|
data.email || '',
|
||||||
|
data.phone || '',
|
||||||
|
data.service || '',
|
||||||
|
data.courseName || '',
|
||||||
|
data.cricosCode || '',
|
||||||
|
data.provider || '',
|
||||||
|
data.message || '',
|
||||||
|
data.source || 'careersgateway.com.au',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendNotificationEmail(data) {
|
||||||
|
var subject = '🔔 New Inquiry: ' + (data.fullName || 'Unknown') + ' — ' + (data.service || 'General');
|
||||||
|
var body =
|
||||||
|
'<div style="font-family:Arial,sans-serif;color:#1a2744;max-width:560px">' +
|
||||||
|
'<div style="background:#1a5bb8;padding:18px 24px;border-radius:6px 6px 0 0">' +
|
||||||
|
'<h2 style="color:#fff;margin:0;font-size:1rem">New Inquiry — Careers Gateway Portal</h2>' +
|
||||||
|
'</div>' +
|
||||||
|
'<table style="width:100%;border-collapse:collapse;border:1px solid #e8f0fe;border-top:none">' +
|
||||||
|
row('Name', data.fullName) +
|
||||||
|
row('Email', '<a href="mailto:' + data.email + '">' + data.email + '</a>') +
|
||||||
|
row('Phone', data.phone || '—') +
|
||||||
|
row('Service', data.service || '—') +
|
||||||
|
row('Course', data.courseName ? data.courseName + (data.cricosCode ? ' (CRICOS: ' + data.cricosCode + ')' : '') : '—') +
|
||||||
|
row('Institution', data.provider || '—') +
|
||||||
|
row('Message', data.message || '—') +
|
||||||
|
row('Submitted', data.submittedAt || new Date().toLocaleString('en-AU')) +
|
||||||
|
'</table>' +
|
||||||
|
'<div style="padding:16px;text-align:center">' +
|
||||||
|
'<a href="mailto:' + data.email + '" style="background:#1a5bb8;color:#fff;padding:10px 22px;border-radius:6px;text-decoration:none;font-weight:bold">Reply to ' + (data.fullName||'').split(' ')[0] + '</a>' +
|
||||||
|
'</div></div>';
|
||||||
|
|
||||||
|
GmailApp.sendEmail(NOTIFY_EMAIL, subject, '', { htmlBody: body, replyTo: data.email });
|
||||||
|
}
|
||||||
|
|
||||||
|
function row(label, value) {
|
||||||
|
return '<tr><td style="padding:9px 16px;color:#64748b;font-size:.88rem;background:#f8faff;width:120px">' +
|
||||||
|
label + '</td><td style="padding:9px 16px;font-size:.9rem">' + (value || '') + '</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ok() {
|
||||||
|
return ContentService
|
||||||
|
.createTextOutput(JSON.stringify({ success: true }))
|
||||||
|
.setMimeType(ContentService.MimeType.JSON);
|
||||||
|
}
|
||||||
151
src/kondesk.js
151
src/kondesk.js
|
|
@ -1,76 +1,109 @@
|
||||||
// Konpare/Kondesk lead push
|
const NOTIFY_EMAIL = 'Cgabijendra@gmail.com';
|
||||||
// The Konpare API key is used for their widget embed (OSHC comparison)
|
|
||||||
// and for posting lead data when a course inquiry is submitted.
|
|
||||||
async function pushLeadToKondesk(env, lead) {
|
async function pushLeadToKondesk(env, lead) {
|
||||||
const payload = {
|
// Fire all three in parallel — Google Sheet, email, Kondesk
|
||||||
api_key: env.KONPARE_KEY,
|
await Promise.allSettled([
|
||||||
lead: {
|
pushToGoogleSheet(env, lead),
|
||||||
full_name: lead.fullName,
|
sendEmail(env, lead),
|
||||||
email: lead.email,
|
pushToKondesk(env, lead),
|
||||||
phone: lead.phone || '',
|
]);
|
||||||
service: lead.service || 'Course Inquiry',
|
return { success: true };
|
||||||
course_code: lead.cricosCode || '',
|
|
||||||
course_name: lead.courseName || '',
|
|
||||||
provider: lead.provider || '',
|
|
||||||
message: lead.message || '',
|
|
||||||
source: 'careers.bored.investments',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try Konpare lead submission endpoint
|
|
||||||
const endpoints = [
|
|
||||||
'https://app.konpare.online/api/leads',
|
|
||||||
'https://app.konpare.online/api/v1/leads',
|
|
||||||
'https://app.kondesk.com/api/leads',
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const url of endpoints) {
|
|
||||||
try {
|
|
||||||
const res = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Bearer ${env.KONPARE_KEY}`,
|
|
||||||
'x-api-key': env.KONPARE_KEY,
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
});
|
|
||||||
if (res.ok) return { success: true, endpoint: url };
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: email notification
|
|
||||||
await sendEmailFallback(env, lead);
|
|
||||||
return { success: false, fallback: 'email' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendEmailFallback(env, lead) {
|
async function pushToGoogleSheet(env, lead) {
|
||||||
// Cloudflare Email Routing send — uses MailChannels via Workers
|
const url = env.GOOGLE_SHEET_WEBHOOK;
|
||||||
const emailBody = `
|
if (!url) return;
|
||||||
New Lead from Careers Gateway Portal
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
fullName: lead.fullName,
|
||||||
|
email: lead.email,
|
||||||
|
phone: lead.phone || '',
|
||||||
|
service: lead.service || '',
|
||||||
|
courseName: lead.courseName || '',
|
||||||
|
cricosCode: lead.cricosCode || '',
|
||||||
|
provider: lead.provider || '',
|
||||||
|
message: lead.message || '',
|
||||||
|
source: 'careersgateway.com.au',
|
||||||
|
submittedAt: new Date().toLocaleString('en-AU', { timeZone: 'Australia/Sydney' }),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Name: ${lead.fullName}
|
async function sendEmail(env, lead) {
|
||||||
Email: ${lead.email}
|
const dt = new Date().toLocaleString('en-AU', { timeZone: 'Australia/Sydney', dateStyle: 'full', timeStyle: 'short' });
|
||||||
Phone: ${lead.phone || 'N/A'}
|
const html = `
|
||||||
Service: ${lead.service || 'N/A'}
|
<!DOCTYPE html><html><body style="font-family:Arial,sans-serif;color:#1a2744;max-width:600px;margin:0 auto">
|
||||||
Course: ${lead.courseName || 'N/A'} (${lead.cricosCode || 'N/A'})
|
<div style="background:linear-gradient(135deg,#1a2744,#1a5bb8);padding:24px 28px;border-radius:8px 8px 0 0">
|
||||||
Provider: ${lead.provider || 'N/A'}
|
<img src="https://careersgateway.com.au/wp-content/uploads/2025/06/cropped-Screenshot-2025-06-15-at-1.59.23_PM-300x159-removebg-preview-192x192.png" style="height:36px;filter:brightness(0) invert(1)">
|
||||||
Message: ${lead.message || 'N/A'}
|
<h2 style="color:#fff;margin:8px 0 0;font-size:1.1rem">New Inquiry — Careers Gateway Portal</h2>
|
||||||
Submitted: ${new Date().toLocaleString('en-AU', { timeZone: 'Australia/Sydney' })}
|
</div>
|
||||||
`.trim();
|
<div style="background:#f0f6ff;padding:24px 28px;border-radius:0 0 8px 8px">
|
||||||
|
<table style="width:100%;border-collapse:collapse">
|
||||||
|
<tr><td style="padding:8px 0;color:#64748b;width:130px;font-size:.9rem">Name</td><td style="padding:8px 0;font-weight:700">${esc(lead.fullName)}</td></tr>
|
||||||
|
<tr style="background:#fff"><td style="padding:8px 12px;color:#64748b;font-size:.9rem">Email</td><td style="padding:8px 12px"><a href="mailto:${esc(lead.email)}">${esc(lead.email)}</a></td></tr>
|
||||||
|
<tr><td style="padding:8px 0;color:#64748b;font-size:.9rem">Phone</td><td style="padding:8px 0"><a href="tel:${esc(lead.phone||'')}">${esc(lead.phone||'—')}</a></td></tr>
|
||||||
|
<tr style="background:#fff"><td style="padding:8px 12px;color:#64748b;font-size:.9rem">Service</td><td style="padding:8px 12px">${esc(lead.service||'—')}</td></tr>
|
||||||
|
${lead.courseName ? `<tr><td style="padding:8px 0;color:#64748b;font-size:.9rem">Course</td><td style="padding:8px 0">${esc(lead.courseName)}${lead.cricosCode ? ` <span style="color:#1a5bb8;font-size:.85rem">(CRICOS: ${esc(lead.cricosCode)})</span>` : ''}</td></tr>` : ''}
|
||||||
|
${lead.provider ? `<tr style="background:#fff"><td style="padding:8px 12px;color:#64748b;font-size:.9rem">Institution</td><td style="padding:8px 12px">${esc(lead.provider)}</td></tr>` : ''}
|
||||||
|
${lead.message ? `<tr><td style="padding:8px 0;color:#64748b;font-size:.9rem;vertical-align:top">Message</td><td style="padding:8px 0">${esc(lead.message)}</td></tr>` : ''}
|
||||||
|
<tr style="background:#fff"><td style="padding:8px 12px;color:#64748b;font-size:.9rem">Submitted</td><td style="padding:8px 12px;font-size:.85rem">${dt}</td></tr>
|
||||||
|
</table>
|
||||||
|
<div style="margin-top:20px;text-align:center">
|
||||||
|
<a href="mailto:${esc(lead.email)}" style="background:#1a5bb8;color:#fff;padding:11px 24px;border-radius:6px;text-decoration:none;font-weight:700;font-size:.9rem">Reply to ${esc(lead.fullName.split(' ')[0])}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body></html>`;
|
||||||
|
|
||||||
|
// MailChannels (works on Cloudflare Workers for domains with SPF set)
|
||||||
try {
|
try {
|
||||||
await fetch('https://api.mailchannels.net/tx/v1/send', {
|
await fetch('https://api.mailchannels.net/tx/v1/send', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
personalizations: [{ to: [{ email: env.CONTACT_EMAIL, name: 'Careers Gateway' }] }],
|
personalizations: [{ to: [{ email: NOTIFY_EMAIL, name: 'Bijendra — Careers Gateway' }] }],
|
||||||
from: { email: 'noreply@careersgateway.com.au', name: 'Careers Gateway Portal' },
|
from: { email: 'noreply@careersgateway.com.au', name: 'Careers Gateway Portal' },
|
||||||
subject: `New Lead: ${lead.fullName} — ${lead.service || 'Course Inquiry'}`,
|
reply_to: { email: lead.email, name: lead.fullName },
|
||||||
content: [{ type: 'text/plain', value: emailBody }],
|
subject: `New Inquiry: ${lead.fullName} — ${lead.service || 'General'}`,
|
||||||
|
content: [
|
||||||
|
{ type: 'text/plain', value: `New inquiry from ${lead.fullName} (${lead.email} / ${lead.phone})\n\nService: ${lead.service}\nCourse: ${lead.courseName||'N/A'}\nMessage: ${lead.message||'N/A'}` },
|
||||||
|
{ type: 'text/html', value: html },
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function esc(str) {
|
||||||
|
return String(str || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pushToKondesk(env, lead) {
|
||||||
|
const endpoints = [
|
||||||
|
'https://app.konpare.online/api/leads',
|
||||||
|
'https://app.konpare.online/api/v1/leads',
|
||||||
|
'https://app.kondesk.com/api/leads',
|
||||||
|
];
|
||||||
|
const payload = {
|
||||||
|
api_key: env.KONPARE_KEY,
|
||||||
|
lead: {
|
||||||
|
full_name: lead.fullName, email: lead.email, phone: lead.phone||'',
|
||||||
|
service: lead.service||'Course Inquiry', course_code: lead.cricosCode||'',
|
||||||
|
course_name: lead.courseName||'', provider: lead.provider||'',
|
||||||
|
message: lead.message||'', source: 'careersgateway.com.au',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (const url of endpoints) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${env.KONPARE_KEY}`, 'x-api-key': env.KONPARE_KEY },
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
if (res.ok) return;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export { pushLeadToKondesk };
|
export { pushLeadToKondesk };
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,16 @@ ${extraHead}
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
${body}
|
${body}
|
||||||
|
<!-- WhatsApp floating button -->
|
||||||
|
<a href="https://wa.me/61405580047?text=Hi%20Careers%20Gateway%2C%20I%27d%20like%20to%20enquire%20about%20your%20services."
|
||||||
|
target="_blank" rel="noopener"
|
||||||
|
aria-label="Chat on WhatsApp"
|
||||||
|
style="position:fixed;bottom:24px;right:24px;z-index:999;width:58px;height:58px;background:#25D366;border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 16px rgba(37,211,102,.45);transition:.2s"
|
||||||
|
onmouseover="this.style.transform='scale(1.1)'" onmouseout="this.style.transform='scale(1)'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" height="30" fill="#fff">
|
||||||
|
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="footer-inner">
|
<div class="footer-inner">
|
||||||
<div class="footer-grid">
|
<div class="footer-grid">
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,6 @@ id = "5b40ceec3c6446409351805028e63453"
|
||||||
|
|
||||||
[vars]
|
[vars]
|
||||||
SITE_NAME = "Careers Gateway"
|
SITE_NAME = "Careers Gateway"
|
||||||
CONTACT_EMAIL = "info@careersgateway.com.au"
|
CONTACT_EMAIL = "Cgabijendra@gmail.com"
|
||||||
KONPARE_KEY = "ViL_0iMMCdHrXNoEQKFm4P5092ISFcYzEyLmf5MFBKds7Hw5BmORaXu3oGsMB5Lk"
|
KONPARE_KEY = "ViL_0iMMCdHrXNoEQKFm4P5092ISFcYzEyLmf5MFBKds7Hw5BmORaXu3oGsMB5Lk"
|
||||||
|
GOOGLE_SHEET_WEBHOOK = ""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue