-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsite-config.js
More file actions
177 lines (174 loc) · 9.52 KB
/
Copy pathsite-config.js
File metadata and controls
177 lines (174 loc) · 9.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Site-wide config + GA4 event layer. TRIAL_READY default false until Himanshu/Abhishek confirm the trial form.
window.SITE_CONFIG = {
// ==== TRIAL CTA — ONE SWITCH ====
// Set TRIAL_URL to the real trial-signup URL and flip TRIAL_READY to true. That single change
// turns "Try Dalgo for Free" on in the nav (desktop + mobile drawer) and reveals the trial band
// on /product between the tour and the capability grid. Nothing else needs editing.
//
// Production trial signup. Swapped off the staging placeholder 15 Aug 2026 once
// insights.dalgo.org/free-trial went live (verified 200, a real Next.js signup page — it 404'd
// earlier the same day, before it shipped).
// Because this host IS in TRIAL_PROD_HOSTS, two things happen automatically: the rel="nofollow"
// that guarded the staging link disappears, and scripts/trial-guard.mjs reports OK instead of
// warning. Nothing else needs editing.
TRIAL_READY: true,
TRIAL_URL: 'https://insights.dalgo.org/free-trial',
// Hosts considered production for the trial CTA. Anything else is treated as non-production:
// the link gets rel="nofollow" and the build warns.
TRIAL_PROD_HOSTS: ['app.dalgo.org', 'insights.dalgo.org'],
GA4_ID: 'G-ZTDMFE4S5K', // live property (same ID as the current dalgo.org site), set 6 Aug 2026
// Single destination for every "Book Free Consultation" CTA — the pro-bono data
// consulting form (Stuti, 7 Aug 2026). Three different forms.gle URLs were in use
// before this; route every consultation CTA through window.consultCta() so they
// cannot diverge again.
CONSULT_FORM: 'https://forms.gle/6vpR5LKpV29zvyxK9',
// Featured resource in the nav Resources panel. Evergreen (no expiry): the Data Decoded
// newsletter, replacing the time-bound webinar card that had to be refreshed monthly.
FEATURED_RESOURCE: {
kicker: 'Newsletter',
title: 'Data Decoded with Dalgo',
blurb: 'One nonprofit data concept per edition, in plain language.',
img: 'assets/community-cards/data-decoded.webp?v=cffed030',
href: 'https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7470812385688276992',
cta: 'Subscribe'
},
// Site-wide announcement bar above the nav, plus a one-time home-page pop-up (EventPopup.jsx).
// Set to null to hide both once the event has passed.
EVENT_BANNER: {
tickerText: 'Data Decoded · 6 October · Bengaluru · One day data strategy session for nonprofits · Limited seats',
href: 'https://luma.com/uiwzzd76?utm_source=website',
cta: 'Register now',
popupEyebrow: 'Upcoming',
popupTitle: 'Data Decoded with Dalgo',
popupLines: ['A one day data strategy session for nonprofits', '6 October · Bengaluru']
}
};
// Returns the featured resource for the nav panel (null hides the Featured column).
window.featuredResource = function () {
var r = window.SITE_CONFIG.FEATURED_RESOURCE;
if (!r) return null;
var href = r.href + (r.href.indexOf('?') > -1 ? '&' : '?') + 'utm_source=website&utm_medium=nav_featured';
return Object.assign({}, r, { href: href });
};
// The trial CTA label lives here and nowhere else, so a rename is a one-line change — and the
// cta_click listener picks the new name up on its own, because it reads whatever text is on screen.
//
// ALWAYS returns an object, never null: Blueprint.jsx, DemoTour.jsx and SiteHero.jsx all
// dereference the result directly, so a null here would throw in three places. When the trial
// is not ready it falls back to Contact Us -> /contact, which keeps label and destination
// honest (BM-307).
window.trialCta = function () {
var c = window.SITE_CONFIG;
if (!(c.TRIAL_READY && c.TRIAL_URL)) return { label: 'Contact Us', href: '/contact', ext: false };
return { label: 'Try Dalgo for Free', href: c.TRIAL_URL, ext: true, nofollow: !window.trialUrlIsProd() };
};
// True when TRIAL_URL points at a real production host. While it points anywhere else (staging,
// a preview, localhost) the trial links carry rel="nofollow", so linking from production cannot
// hand crawlers a path into an un-noindexed staging site. Self-correcting: swap in the production
// URL and the nofollow disappears on its own.
window.trialUrlIsProd = function () {
var c = window.SITE_CONFIG;
if (!c.TRIAL_URL) return false;
try {
var h = new URL(c.TRIAL_URL).hostname;
return (c.TRIAL_PROD_HOSTS || []).indexOf(h) > -1;
} catch (e) { return false; }
};
// True only when there is a real trial destination to send someone to. Use this to decide
// whether a trial-specific CTA should exist at all (the /product band, the nav primary).
window.trialReady = function () {
var c = window.SITE_CONFIG;
return !!(c.TRIAL_READY && c.TRIAL_URL);
};
// Builds the rel attribute for a CTA descriptor from trialCta()/consultCta(). Keeps the
// noopener + conditional nofollow logic in one place instead of repeating it at every call site.
window.ctaRel = function (c) {
var parts = [];
if (c.ext) parts.push('noopener');
if (c.nofollow) parts.push('nofollow');
return parts.length ? parts.join(' ') : undefined;
};
// rel for a bare href, for call sites that only have a URL rather than a CTA descriptor
// (SiteHero builds its buttons from label + href). Without this the nofollow protection has
// holes: any component that renders the trial URL without going through trialCta() would emit
// a followable link into staging. Keep every trial-capable anchor on ctaRel or relForHref.
window.relForHref = function (href) {
var parts = [];
if (/^https?:/.test(href)) parts.push('noopener');
var c = window.SITE_CONFIG;
if (c.TRIAL_URL && href === c.TRIAL_URL && !window.trialUrlIsProd()) parts.push('nofollow');
return parts.length ? parts.join(' ') : undefined;
};
// Every "Book Free Consultation" CTA resolves through this — one destination, always external.
window.consultCta = function () {
return { label: 'Book Free Consultation', href: window.SITE_CONFIG.CONSULT_FORM, ext: true };
};
// GA4 bootstrap (no-op until GA4_ID is set).
(function () {
var id = window.SITE_CONFIG.GA4_ID;
window.dataLayer = window.dataLayer || [];
window.gtag = window.gtag || function () { window.dataLayer.push(arguments); };
if (id) {
var s = document.createElement('script'); s.async = true; s.src = 'https://www.googletagmanager.com/gtag/js?id=' + id; document.head.appendChild(s);
gtag('js', new Date()); gtag('config', id);
}
})();
// ===== cta_click — one event, names as parameters (BM-396) =====
// Before this, the ONLY gtag calls on the site were js + config: page_view fired and nothing
// else, so all 37 consultation buttons shared one forms.gle URL and were indistinguishable,
// and the 23 internal "Contact Us" links were not captured at all. Key events = 0.
//
// Scope is ACTION CTAs — the green (primary) and white (ghost) buttons, plus the Product
// dashboard/report links. Deliberately NOT tracked, because they are clicks rather than calls
// to action: nav links, nav dropdown items, the mobile drawer, footer columns and socials, the
// logo, support@dalgo.org, FAQ accordion toggles, story-carousel tabs and arrows, marquee dots,
// the tour scope tabs, and the capability pills. The last two are in-page toggles and are
// earmarked for a separate page_clicks event — not this one.
//
// The listener reads whatever text is on the button, so a copy change (e.g. the trial flow
// renaming CTAs to "Try Dalgo for Free") needs no code change here. What DOES break on a
// rename is any GA4 conversion keyed on a cta_name string — define those in the GA4 UI, where
// they can be edited without a deploy, not in here.
(function () {
var CTA = [
'.btn.btn-primary', '.btn.btn-ghost',
'.cmh-btn-primary', '.cmh-btn-ghost', '.cmh-btn-wa',
'.nurture-btn',
'.si-readall', '.vp-section-cta',
'.final-cta-btn', '.final-cta-btn-ghost',
'.pf-cta', '.co-probono-btn',
'.dsh-link', '.dsh-card a',
'.pricing-help-line a',
'.dtr-card-actions .btn',
'.evt-banner-cta', '.evt-popup-cta'
].join(',');
// Normalise to the label a human sees. Trailing glyphs are decorative and must go: several
// labels carry a literal arrow ("View All FAQs →") and .btn-primary::after appends another in
// CSS, so leaving them would split one CTA into two metrics that never reconcile.
function ctaName(el) {
var t = (el.textContent || '').replace(/\s+/g, ' ').trim().replace(/[\s→✓➜➡»>]+$/, '').trim();
if (!t) t = (el.getAttribute('aria-label') || '').trim();
if (!t) { var img = el.querySelector('img'); t = img ? (img.getAttribute('alt') || '').trim() : ''; }
return t.slice(0, 100); // GA4 caps parameter values at 100 chars
}
// Capture phase, so the event is recorded even if a handler downstream stops propagation or
// the browser starts unloading for an outbound link.
document.addEventListener('click', function (e) {
var t = e.target;
if (!t || typeof t.closest !== 'function') return;
var el = t.closest(CTA);
if (!el) return;
var name = ctaName(el);
if (!name) return; // never send an empty cta_name — an unnamed row is unusable in reports
var params = {
cta_name: name,
cta_destination: el.getAttribute('href') || '(button)'
};
// Optional: distinguishes CTAs that share a label/destination across placements, e.g. the
// event ticker vs. the home-page pop-up both say "Register now" and link to the same event.
var location = el.getAttribute('data-cta-location');
if (location) params.cta_location = location;
// TODO(BM-356): gate on Consent Mode v2 once it lands, defaulting to denied under DPDP.
window.gtag('event', 'cta_click', params);
}, true);
})();