// =========================== // GOLD COAST RETIREMENT GUIDE // Google Apps Script Backend // =========================== // CONFIGURATION - UPDATE THESE VALUES const SHEET_ID = '1s1Xbfd6ymPYyrxjonX7WYbWnVaPwmogXrINSuZ6KLnw'; // Your Google Sheet ID const LEADS_SHEET = 'LEADS'; // Name of leads sheet const VILLAGES_SHEET = 'VILLAGE DATABASE'; // Name of village database sheet const LEAD_EMAIL = 'jacksonclarke@gcsr.com.au'; // Where to send lead notifications const SENDER_EMAIL = 'noreply@goldcoastretirementguide.com.au'; // From address (must be Gmail account or configured domain) // =========================== // MAIN FUNCTION - Handle form submission // =========================== function doPost(e) { try { const data = JSON.parse(e.postData.contents); // Validate required fields if (!data.fullName || !data.email || !data.phone) { return ContentService.createTextOutput(JSON.stringify({ success: false, message: 'Missing required fields' })).setMimeType(ContentService.MimeType.JSON); } // Get village database const villages = getVillageDatabase(); // Match quiz answers to villages const topMatches = matchVillages(data, villages); // Generate PDF report const pdfBlob = generatePDFReport(data, topMatches); // Send email to user with PDF sendUserEmail(data.email, data.fullName, pdfBlob); // Send notification to Clarkey sendLeadNotification(data, topMatches); // Log lead to Google Sheet logLead(data, topMatches); return ContentService.createTextOutput(JSON.stringify({ success: true, message: 'Your report has been sent to ' + data.email })).setMimeType(ContentService.MimeType.JSON); } catch (error) { Logger.log('Error in doPost: ' + error); return ContentService.createTextOutput(JSON.stringify({ success: false, message: 'Server error: ' + error.toString() })).setMimeType(ContentService.MimeType.JSON); } } // =========================== // Get village database from Google Sheet // =========================== function getVillageDatabase() { try { const ss = SpreadsheetApp.openById(SHEET_ID); const sheet = ss.getSheetByName(VILLAGES_SHEET); const data = sheet.getDataRange().getValues(); const villages = []; const headers = data[0]; // First row is headers for (let i = 1; i < data.length; i++) { if (!data[i][0]) continue; // Skip empty rows const village = {}; for (let j = 0; j < headers.length; j++) { village[headers[j]] = data[i][j]; } villages.push(village); } return villages; } catch (error) { Logger.log('Error getting villages: ' + error); return []; } } // =========================== // Match quiz answers to villages // =========================== function matchVillages(quizData, villages) { const matches = villages.map(village => { let score = 0; // Budget match (highest weight = 30 points) const villagePrice = parseFloat(village['Price Range'] || '0'); const userBudget = quizData.budget; if (userBudget === 'Not sure') { score += 15; // Partial credit } else if (userBudget.includes('Under') && villagePrice < 500) { score += 30; } else if (userBudget.includes('500k') && villagePrice >= 500 && villagePrice < 750) { score += 30; } else if (userBudget.includes('750k') && villagePrice >= 750 && villagePrice < 1000) { score += 30; } else if (userBudget.includes('Over') && villagePrice >= 1000) { score += 30; } else { score += 10; // Partial match } // Location match (25 points) const userLocations = quizData.locations || []; const villageLocation = village['Location/Suburb'] || ''; if (userLocations.length === 0 || userLocations.includes('No preference')) { score += 12; // Neutral } else if (userLocations.some(loc => villageLocation.includes(loc))) { score += 25; // Exact match } else if (userLocations.some(loc => isNearby(loc, villageLocation))) { score += 15; // Nearby } // Amenities match (25 points) const userAmenities = quizData.amenities || []; const villageAmenities = (village['Amenities'] || '').split(',').map(a => a.trim()); if (userAmenities.length > 0) { const amenityMatches = userAmenities.filter(ua => villageAmenities.some(va => va.toLowerCase().includes(ua.toLowerCase())) ).length; score += (amenityMatches / Math.max(userAmenities.length, 1)) * 25; } else { score += 12; // Neutral if no preference } // Wait time match (20 points - prefer shorter wait) const waitTime = parseInt(village['Wait Time (Months)'] || '0'); const userTimeline = quizData.timeline || 'Just exploring'; if (userTimeline === 'Immediately (within 3 months)' && waitTime <= 3) { score += 20; } else if (userTimeline === 'Soon (3-6 months)' && waitTime <= 6) { score += 20; } else if (waitTime <= 12) { score += 10; } else { score += 5; } return { village: village, score: score }; }); // Sort by score and return top 5 return matches .sort((a, b) => b.score - a.score) .slice(0, 5) .map(m => m.village); } // Helper function to check if locations are nearby function isNearby(userLoc, villageLoc) { const proximityMap = { 'Carrara': ['Clear Island Waters', 'Robina', 'Merrimac'], 'Robina': ['Carrara', 'Ashmore', 'Southport'], 'Ashmore': ['Robina', 'Southport', 'Arundel'], 'Southport': ['Broadbeach', 'Ashmore', 'Arundel'], 'Arundel': ['Ashmore', 'Southport'] }; const nearby = proximityMap[userLoc] || []; return nearby.some(loc => villageLoc.includes(loc)); } // =========================== // Generate PDF Report // =========================== function generatePDFReport(quizData, topVillages) { try { // Create a temporary Google Doc for PDF generation const doc = DocumentApp.create('Retirement Guide Report - ' + quizData.fullName); const body = doc.getBody(); // Add header const header = body.insertParagraph(0, 'GOLD COAST RETIREMENT VILLAGE GUIDE'); header.setFontSize(24); header.setFontFamily('Georgia'); header.setBold(true); header.setAlignment(DocumentApp.HorizontalAlignment.CENTER); const subtitle = body.insertParagraph(1, 'Your Personalised Recommendations'); subtitle.setFontSize(14); subtitle.setAlignment(DocumentApp.HorizontalAlignment.CENTER); body.insertParagraph(2, ''); // Add recipient info const intro = body.insertParagraph(3, 'Hello ' + quizData.fullName + ','); intro.setFontSize(12); const message = body.insertParagraph(4, 'Based on your answers about budget, location, lifestyle, and timeline, ' + 'we\'ve matched you with 5 retirement villages that best fit your preferences. ' + 'Below is your personalised report with detailed information about each recommendation.' ); message.setFontSize(11); body.insertParagraph(5, ''); // Add your preferences summary const prefTitle = body.insertParagraph(6, 'Your Preferences:'); prefTitle.setFontSize(12); prefTitle.setBold(true); const prefs = body.insertParagraph(7, 'Budget: ' + (quizData.budget || 'Not specified') + '\n' + 'Preferred Locations: ' + (quizData.locations.length > 0 ? quizData.locations.join(', ') : 'No preference') + '\n' + 'Timeline: ' + (quizData.timeline || 'Not specified') + '\n' + 'Lifestyle Priority: ' + (quizData.amenities.length > 0 ? quizData.amenities.join(', ') : 'Not specified') ); prefs.setFontSize(10); body.insertParagraph(8, ''); // Add village recommendations topVillages.forEach((village, index) => { const villageTitle = body.insertParagraph(9 + (index * 6), (index + 1) + '. ' + village['Village Name']); villageTitle.setFontSize(13); villageTitle.setBold(true); const villageOperator = body.insertParagraph(10 + (index * 6), 'Operator: ' + (village['Operator'] || 'N/A') + ' | Location: ' + (village['Location/Suburb'] || 'N/A') ); villageOperator.setFontSize(10); const villageDetails = body.insertParagraph(11 + (index * 6), 'Price Range: ' + (village['Price Range'] || 'N/A') + '\n' + 'Weekly Fees: ' + (village['Weekly Fees'] || 'N/A') + '\n' + 'Amenities: ' + (village['Amenities'] || 'N/A') + '\n' + 'Wait Time: ' + (village['Wait Time (Months)'] || 'N/A') + ' months' ); villageDetails.setFontSize(10); const villageContact = body.insertParagraph(12 + (index * 6), 'Contact: ' + (village['Phone'] || 'N/A') + '\n' + 'Website: ' + (village['Website'] || 'N/A') ); villageContact.setFontSize(10); body.insertParagraph(13 + (index * 6), ''); }); // Add next steps body.insertParagraph(39, ''); const stepsTitle = body.insertParagraph(40, 'Next Steps:'); stepsTitle.setFontSize(12); stepsTitle.setBold(true); const steps = body.insertParagraph(41, '1. Review the villages above\n' + '2. Visit the village websites or call for more information\n' + '3. Schedule tours at 2-3 villages that appeal to you\n' + '4. Ask questions about fees, care levels, and what\'s included\n' + '5. Visit in person and chat with residents' ); steps.setFontSize(10); body.insertParagraph(42, ''); const disclaimer = body.insertParagraph(43, 'Disclaimer: This is an educational guide only and not financial, investment, or legal advice. ' + 'All village information is accurate as of June 2026 but may change. ' + 'Always verify information directly with villages before making decisions.' ); disclaimer.setFontSize(9); disclaimer.setItalic(true); // Convert to PDF const pdfUrl = 'https://docs.google.com/document/d/' + doc.getId() + '/export?format=pdf'; const pdfBlob = UrlFetchApp.fetch(pdfUrl).getBlob(); // Delete temp document doc.setTrashed(true); return pdfBlob.setName('Retirement Village Report - ' + quizData.fullName + '.pdf'); } catch (error) { Logger.log('Error generating PDF: ' + error); // Return a blank blob if PDF generation fails return Utilities.newBlob('Report generation failed', 'text/plain'); } } // =========================== // Send email to user with PDF // =========================== function sendUserEmail(email, name, pdfBlob) { try { const subject = 'Your Personalised Gold Coast Retirement Village Report'; const body = 'Hi ' + name + ',\n\n' + 'Thank you for taking our retirement village quiz! ' + 'Attached is your personalised report with your top 5 matched villages based on your preferences.\n\n' + 'Next Steps:\n' + '1. Review the villages in your report\n' + '2. Visit their websites or call for tours\n' + '3. Schedule visits to see them in person\n' + '4. Ask lots of questions about costs, care levels, and lifestyle\n\n' + 'If you have any questions, feel free to reach out.\n\n' + 'Best wishes on your retirement journey,\n' + 'The Gold Coast Retirement Guide Team\n\n' + 'P.S. You can always browse all 30+ villages on our website at goldcoastretirementguide.com.au/villages.html'; GmailApp.sendEmail(email, subject, body, { attachments: [pdfBlob], name: 'Gold Coast Retirement Guide', replyTo: LEAD_EMAIL }); Logger.log('Email sent to ' + email); } catch (error) { Logger.log('Error sending user email: ' + error); } } // =========================== // Send lead notification to Clarkey // =========================== function sendLeadNotification(quizData, topVillages) { try { const subject = 'New Lead: ' + quizData.fullName; const body = 'New Quiz Submission:\n\n' + 'Name: ' + quizData.fullName + '\n' + 'Email: ' + quizData.email + '\n' + 'Phone: ' + quizData.phone + '\n' + 'Age Group: ' + quizData.ageGroup + '\n' + 'Budget: ' + quizData.budget + '\n' + 'Locations: ' + (quizData.locations.length > 0 ? quizData.locations.join(', ') : 'No preference') + '\n' + 'Timeline: ' + quizData.timeline + '\n\n' + 'Matched Villages:\n' + topVillages.map((v, i) => (i + 1) + '. ' + v['Village Name']).join('\n') + '\n\n' + 'Ready to call and follow up!'; GmailApp.sendEmail(LEAD_EMAIL, subject, body, { name: 'Gold Coast Retirement Guide' }); Logger.log('Lead notification sent to ' + LEAD_EMAIL); } catch (error) { Logger.log('Error sending lead notification: ' + error); } } // =========================== // Log lead to Google Sheet // =========================== function logLead(quizData, topVillages) { try { const ss = SpreadsheetApp.openById(SHEET_ID); const sheet = ss.getSheetByName(LEADS_SHEET); const now = new Date(); const row = [ '', // Lead ID (auto-increment or manual) quizData.fullName, quizData.email, quizData.phone, quizData.ageGroup, quizData.budget, quizData.locations.join('; '), quizData.amenities.join('; '), quizData.timeline, Utilities.formatDate(now, Session.getScriptTimeZone(), 'yyyy-MM-dd HH:mm'), 'Yes', // PDF Sent 'No', // Called '', // Call Date '', // Result/Notes topVillages[0] ? topVillages[0]['Village Name'] : '', topVillages[1] ? topVillages[1]['Village Name'] : '', topVillages[2] ? topVillages[2]['Village Name'] : '', topVillages[3] ? topVillages[3]['Village Name'] : '', topVillages[4] ? topVillages[4]['Village Name'] : '' ]; sheet.appendRow(row); Logger.log('Lead logged for ' + quizData.fullName); } catch (error) { Logger.log('Error logging lead: ' + error); } } // =========================== // Deploy endpoint // =========================== // 1. In Google Apps Script editor, click "Deploy" > "New Deployment" // 2. Select type: Web app // 3. Set "Execute as" to your account // 4. Set "Who has access" to "Anyone" // 5. Click Deploy // 6. Copy the deployment URL // 7. Paste into quiz.html js/main.js where it says "YOUR_GOOGLE_APPS_SCRIPT_URL_HERE"