/* BBB Live Backend (Google Apps Script) – Expose web endpoint: doGet?token=…&leader= – onFormSubmit: process registrations, compute counts, create reward entries Sheets used: – “Recruits” columns: [A] id, [B] name, [C] phone, [D] leaderId/referrer, [E] timestamp – “Rewards” columns: [A] rewardId, [B] leaderId, [C] milestoneCount, [D] timestamp, [E] issued */const SHEET_RECRUITS = ‘Recruits’; const SHEET_REWARDS = ‘Rewards’;// Replace this with a token in Script Properties (see deploy steps) function getToken() { return PropertiesService.getScriptProperties().getProperty(‘API_TOKEN’) || ‘change-me’; }// Utility: generate unique id function uid() { return Utilities.getUuid(); }/** * doGet: return JSON for a leader or global summary * params: token (required), leader (optional) */ function doGet(e) { try { const params = e.parameter || {}; const token = params.token; if (!token || token !== getToken()) { return ContentService.createTextOutput(JSON.stringify({ error: ‘Unauthorized’ })) .setMimeType(ContentService.MimeType.JSON); }const ss = SpreadsheetApp.getActive(); const recruitsSheet = ss.getSheetByName(SHEET_RECRUITS); const rewardsSheet = ss.getSheetByName(SHEET_REWARDS);const recruits = recruitsSheet.getDataRange().getValues().slice(1); // skip header const rewards = rewardsSheet.getDataRange().getValues().slice(1);// Global totals const totalRecruits = recruits.length;// If leader param given, compute leader-specific stats (Tier1 + Tier2) if (params.leader) { const leaderId = params.leader;// Tier1: direct recruits whose leaderId == leaderId const tier1List = recruits.filter(r => String(r[3]) === String(leaderId)); const tier1Count = tier1List.length;// Tier2: recruits referred by tier1 members (i.e., recruits whose leaderId is any of tier1 member ids) // Assumption: each recruit’s own id is in column A; but tier1List rows are raw rows (id at index 0) const tier1Ids = tier1List.map(r => String(r[0])); const tier2List = recruits.filter(r => tier1Ids.indexOf(String(r[3])) !== -1); const tier2Count = tier2List.length;// Rewards for this leader const leaderRewards = rewards .filter(r => String(r[1]) === String(leaderId)) .map(r => ({ rewardId: r[0], milestone: r[2], timestamp: r[3], issued: r[4] }));const payload = { leader: leaderId, tier1Count: tier1Count, tier2Count: tier2Count, tier1Ids: tier1Ids.slice(0,50), // sample rewards: leaderRewards, totalRecruits: totalRecruits, timestamp: new Date().toISOString() };return ContentService.createTextOutput(JSON.stringify(payload)).setMimeType(ContentService.MimeType.JSON); }// If no leader param: return global summary const summary = { totalRecruits: totalRecruits, totalLeaders: Array.from(new Set(recruits.map(r => String(r[3])))).length, totalRewardsIssued: rewards.length, timestamp: new Date().toISOString() };return ContentService.createTextOutput(JSON.stringify(summary)).setMimeType(ContentService.MimeType.JSON);} catch (err) { return ContentService.createTextOutput(JSON.stringify({ error: err.message })).setMimeType(ContentService.MimeType.JSON); } }/** * onFormSubmit: bound to Google Form submission trigger * Expects form fields order: Name, Phone, LeaderId (referrer) */ function onFormSubmit(e) { try { const ss = SpreadsheetApp.getActive(); const recruitsSheet = ss.getSheetByName(SHEET_RECRUITS); const rewardsSheet = ss.getSheetByName(SHEET_REWARDS);// If using simple form -> e.values contains all answers const values = e.values; // array including timestamp as first item usually // Map fields depending on your form layout. Here’s an example mapping: // values example: [Timestamp, Name, Phone, LeaderId] const name = values[1] || ‘Unknown’; const phone = values[2] || ”; const leaderId = values[3] || ‘none’;// Create new recruit entry const newId = uid(); const ts = new Date(); recruitsSheet.appendRow([newId, name, phone, leaderId, ts]);// Update leader milestone: count how many recruits the leader has const recruitsData = recruitsSheet.getDataRange().getValues().slice(1); const leaderRecruits = recruitsData.filter(r => String(r[3]) === String(leaderId)); const leaderCount = leaderRecruits.length;// Milestone rule: every time leader reaches multiples of 5 recruits -> issue reward if not already issued for that milestone if (leaderCount >= 5) { const milestone = Math.floor(leaderCount / 5) * 5; // e.g., 5,10,15… // Check if reward already issued for this milestone const rewardsData = rewardsSheet.getDataRange().getValues().slice(1); const already = rewardsData.some(r => String(r[1]) === String(leaderId) && Number(r[2]) === milestone); if (!already) { const rewardId = uid(); rewardsSheet.appendRow([rewardId, leaderId, milestone, ts, ‘Yes’]); // Optionally: send email or call webhook to notify/claim reward // sendRewardNotification(leaderId, milestone); } }} catch (err) { Logger.log(‘onFormSubmit error: ‘ + err.message); } }/** * Optional: sendRewardNotification – example function to call an external webhook or email */ function sendRewardNotification(leaderId, milestone) { // Example: send an email (or integrate Twilio/WhatsApp API) const ss = SpreadsheetApp.getActive(); const recruitsSheet = ss.getSheetByName(SHEET_RECRUITS); // Find leader contact const recruits = recruitsSheet.getDataRange().getValues().slice(1); const leaderRow = recruits.find(r => String(r[0]) === String(leaderId)); const leaderEmail = leaderRow ? leaderRow[2] : null; // modify if email exists if (leaderEmail) { MailApp.sendEmail({ to: leaderEmail, subject: ‘BBB Reward Unlocked!’, body: `Congrats! You reached ${milestone} recruits. Claim your reward from the dashboard.` }); } }
Translate »
滚动至顶部