mirror of
https://github.com/qdrant/landing_page.git
synced 2026-09-28 23:48:31 +02:00
initial commit for segment introduction (#998)
* initial commit for segment introduction * conditionals to check for window.analytics
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import { getCookie, setCookie } from './helpers';
|
||||
import { loadSegment, handleConsent } from './segment-helpers';
|
||||
|
||||
(function () {
|
||||
window.cookit = function (options) {
|
||||
// SETTINGS
|
||||
@@ -56,32 +59,13 @@
|
||||
|
||||
// EVENT LISTENER (click)
|
||||
button.addEventListener('click', () => {
|
||||
if (!window.analytics) {
|
||||
loadSegment();
|
||||
handleConsent();
|
||||
}
|
||||
|
||||
banner.remove();
|
||||
setCookie('cookie-consent', 1, settings.lifetime);
|
||||
});
|
||||
|
||||
// GET COOKIE
|
||||
function getCookie(name) {
|
||||
const decodedCookie = decodeURIComponent(document.cookie);
|
||||
const ca = decodedCookie.split(';');
|
||||
name = name + '=';
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SET COOKIE
|
||||
function setCookie(name, value, days) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
const expires = 'expires=' + date.toUTCString();
|
||||
document.cookie = name + '=' + value + ';' + expires + ';path=/;Secure';
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -45,3 +45,34 @@ export function initGoToTopButton(selector) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// GET COOKIE
|
||||
export function getCookie(name) {
|
||||
const decodedCookie = decodeURIComponent(document.cookie);
|
||||
const ca = decodedCookie.split(';');
|
||||
name = name + "=";
|
||||
for(let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SET COOKIE
|
||||
export function setCookie(name, value, days) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
const expires = 'expires=' + date.toUTCString();
|
||||
document.cookie = name + '=' + value + ';' + expires + ';path=/;Secure';
|
||||
}
|
||||
|
||||
// Logging in Development Mode (localhost)
|
||||
export function devLog(str) {
|
||||
if (window.location.host.includes('localhost')) {
|
||||
console.log(str)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,18 @@
|
||||
import scrollHandler from './scroll-handler';
|
||||
import { XXL_BREAKPOINT } from './constants';
|
||||
import { initGoToTopButton } from './helpers';
|
||||
import { initGoToTopButton, getCookie } from './helpers';
|
||||
import { loadSegment, createSegmentStoredPage, tagAllAnchors } from './segment-helpers'
|
||||
|
||||
createSegmentStoredPage();
|
||||
|
||||
// on document ready
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
tagAllAnchors();
|
||||
|
||||
if (!window.analytics && getCookie('cookie-consent')) {
|
||||
loadSegment();
|
||||
}
|
||||
|
||||
// Header scroll
|
||||
const body = document.querySelector('body');
|
||||
const header = document.querySelector('.site-header');
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
import { getCookie, devLog } from './helpers';
|
||||
|
||||
const PAGES_SESSION_STORAGE_KEY = 'segmentPages';
|
||||
const INTERACTIONS_SESSION_STORAGE_KEY = 'segmentInteractions';
|
||||
const PAYLOAD_BOILERPLATE = {
|
||||
url: window.location.href,
|
||||
title: document.title,
|
||||
};
|
||||
|
||||
|
||||
/*******************/
|
||||
/* General helpers */
|
||||
/*******************/
|
||||
const storedPayload = () => {
|
||||
if (getCookie('cookie-consent')) {
|
||||
return PAYLOAD_BOILERPLATE;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
return {
|
||||
...PAYLOAD_BOILERPLATE,
|
||||
storedEvent: true,
|
||||
storedTimestamp: now.toISOString(),
|
||||
}
|
||||
};
|
||||
|
||||
const nameMapper = (url) => { // Mapping names based on pathname for Segment
|
||||
return url.includes('/blog/') ? 'Blog' : 'Marketing Site';
|
||||
};
|
||||
|
||||
|
||||
/***************/
|
||||
/* DOM helpers */
|
||||
/***************/
|
||||
const handleClickInteraction = (event) => {
|
||||
const payload = {
|
||||
...PAYLOAD_BOILERPLATE,
|
||||
location: event.target.getAttribute('data-metric-loc') ?? '',
|
||||
label: event.target.getAttribute('data-metric-label') ?? event.target.innerText,
|
||||
action: 'clicked'
|
||||
};
|
||||
|
||||
// If consented to tracking the track
|
||||
if(getCookie('cookie-consent')) {
|
||||
trackInteractionEvent(payload);
|
||||
|
||||
// If element can be clicked more than once (ie user remains on same page)
|
||||
if (!event.target.hasAttribute('data-metric-keep')) {
|
||||
event.target.removeEventListener('click', handleClickInteraction);
|
||||
}
|
||||
} else { // If no consent yet the store in sessionStorage in case of later consent
|
||||
createSegmentStoredInteraction(payload);
|
||||
}
|
||||
};
|
||||
|
||||
// Gather all <a> elements that have been tagged
|
||||
// for tracking via 'data-metric-loc' attribute
|
||||
export function tagAllAnchors() {
|
||||
const allMetricsAnchors= document.querySelectorAll('a[data-metric-loc]');
|
||||
|
||||
if (allMetricsAnchors) {
|
||||
allMetricsAnchors.forEach(anchor => {
|
||||
anchor.addEventListener('click', handleClickInteraction, false);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Segment CRUD */
|
||||
/****************/
|
||||
// Getters
|
||||
const getSegmentStoredPages = () => { // Get Page Entires
|
||||
return JSON.parse(sessionStorage.getItem(PAGES_SESSION_STORAGE_KEY) || '[]');
|
||||
};
|
||||
const getSegmentStoredInteractions = () => { // Get Interaction Entires
|
||||
return JSON.parse(sessionStorage.getItem(INTERACTIONS_SESSION_STORAGE_KEY) || '[]');
|
||||
};
|
||||
|
||||
// Deletions
|
||||
const removeSegmentStoredPages = () => { // Remove Page Entires
|
||||
sessionStorage.removeItem(PAGES_SESSION_STORAGE_KEY);
|
||||
};
|
||||
const removeSegmentStoredInteractions = () => { // Remove Interaction Entires
|
||||
sessionStorage.removeItem(INTERACTIONS_SESSION_STORAGE_KEY);
|
||||
};
|
||||
|
||||
// Create and Queue
|
||||
export function createSegmentStoredPage() { // Create and Queue Page Entry
|
||||
const payload = storedPayload();
|
||||
|
||||
const existingPages = JSON.parse(sessionStorage.getItem(PAGES_SESSION_STORAGE_KEY) || '[]');
|
||||
const updatedPages = [...existingPages, payload];
|
||||
sessionStorage.setItem(PAGES_SESSION_STORAGE_KEY, JSON.stringify(updatedPages));
|
||||
};
|
||||
|
||||
export function createSegmentStoredInteraction(payload) { // Create and Queue Interaction Entry
|
||||
const updatedPayload = {
|
||||
...payload,
|
||||
...storedPayload()
|
||||
};
|
||||
|
||||
const existingInteractions = JSON.parse(sessionStorage.getItem(INTERACTIONS_SESSION_STORAGE_KEY) || '[]');
|
||||
const updatedInteractions = [...existingInteractions, updatedPayload];
|
||||
sessionStorage.setItem(INTERACTIONS_SESSION_STORAGE_KEY, JSON.stringify(updatedInteractions));
|
||||
};
|
||||
|
||||
|
||||
/******************/
|
||||
/* Tracking Logic */
|
||||
/******************/
|
||||
const trackStoredPageViews = () => {
|
||||
const category = 'Qdrant.tech';
|
||||
|
||||
// Iterate over all stored page views
|
||||
getSegmentStoredPages().forEach(properties => {
|
||||
const name = nameMapper(properties.url);
|
||||
const originalTimestamp = properties.storedEvent ? properties.storedTimestamp : null;
|
||||
delete properties['storedTimestamp'];
|
||||
|
||||
if(window.analytics) {
|
||||
window.analytics.page(
|
||||
category,
|
||||
name,
|
||||
properties,
|
||||
originalTimestamp ? { timestamp: originalTimestamp } : null
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
removeSegmentStoredPages();
|
||||
}
|
||||
|
||||
const trackStoredInteractions = () => {
|
||||
// Iterate over all stored interactions
|
||||
getSegmentStoredInteractions().forEach(interactionPayload => {
|
||||
trackInteractionEvent(interactionPayload);
|
||||
});
|
||||
|
||||
removeSegmentStoredInteractions();
|
||||
}
|
||||
|
||||
const trackEvent = (name, properties = {}) => {
|
||||
const originalTimestamp = properties.storedEvent ? properties.storedTimestamp : null;
|
||||
delete properties['storedTimestamp'];
|
||||
|
||||
if(window.analytics) {
|
||||
window.analytics.track({
|
||||
event: name,
|
||||
properties
|
||||
},
|
||||
originalTimestamp ? { timestamp: originalTimestamp } : null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const trackInteractionEvent = (properties = {}) => {
|
||||
trackEvent(
|
||||
'interaction',
|
||||
properties
|
||||
)
|
||||
}
|
||||
|
||||
/***********/
|
||||
/* Consent */
|
||||
/***********/
|
||||
export function handleConsent() {
|
||||
trackEvent('Consented', PAYLOAD_BOILERPLATE)
|
||||
devLog('User consented...')
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* Loading Segment */
|
||||
/*******************/
|
||||
export function loadSegment() {
|
||||
const metaTag = document.querySelector(`meta[name="segment"]`);
|
||||
if (!metaTag) return; // Fail silently?
|
||||
|
||||
const writeKey = metaTag ? metaTag.getAttribute('content') : null;
|
||||
if (!writeKey) return; // Fail silently?
|
||||
|
||||
devLog('Loading Segment...');
|
||||
|
||||
// Segment snippet initialization
|
||||
var i = "analytics",
|
||||
analytics = window[i] = window[i] || [];
|
||||
|
||||
if (!analytics.initialize) {
|
||||
if (analytics.invoked) {
|
||||
window.console && console.error && console.error("Segment snippet included twice.");
|
||||
} else {
|
||||
analytics.invoked = true;
|
||||
analytics.methods = [
|
||||
"trackSubmit", "trackClick", "trackLink", "trackForm", "pageview", "identify", "reset", "group", "track",
|
||||
"ready", "alias", "debug", "page", "screen", "once", "off", "on", "addSourceMiddleware", "addIntegrationMiddleware",
|
||||
"setAnonymousId", "addDestinationMiddleware", "register"
|
||||
];
|
||||
|
||||
analytics.factory = function(e) {
|
||||
return function() {
|
||||
if (window[i].initialized) {
|
||||
return window[i][e].apply(window[i], arguments);
|
||||
}
|
||||
|
||||
var n = Array.prototype.slice.call(arguments);
|
||||
if (["track", "screen", "alias", "group", "page", "identify"].indexOf(e) > -1) {
|
||||
var c = document.querySelector("link[rel='canonical']");
|
||||
n.push({
|
||||
__t: "bpc",
|
||||
c: c && c.getAttribute("href") || void 0,
|
||||
p: location.pathname,
|
||||
u: location.href,
|
||||
s: location.search,
|
||||
t: document.title,
|
||||
r: document.referrer
|
||||
});
|
||||
}
|
||||
|
||||
n.unshift(e);
|
||||
analytics.push(n);
|
||||
return analytics;
|
||||
}
|
||||
};
|
||||
|
||||
for (var n = 0; n < analytics.methods.length; n++) {
|
||||
var key = analytics.methods[n];
|
||||
analytics[key] = analytics.factory(key);
|
||||
}
|
||||
|
||||
analytics.load = function(key, n) {
|
||||
var t = document.createElement("script");
|
||||
t.type = "text/javascript";
|
||||
t.async = true;
|
||||
t.setAttribute("data-global-segment-analytics-key", i);
|
||||
t.src = "https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";
|
||||
var r = document.getElementsByTagName("script")[0];
|
||||
r.parentNode.insertBefore(t, r);
|
||||
analytics._loadOptions = n;
|
||||
};
|
||||
|
||||
analytics._writeKey = writeKey;
|
||||
analytics.SNIPPET_VERSION = "5.2.0";
|
||||
analytics.load(writeKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Track any pages that may have been visited and stored in session storage
|
||||
trackStoredPageViews();
|
||||
trackStoredInteractions();
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
<meta name="msapplication-TileColor" content="#2b5797" />
|
||||
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="segment" content="{{ .Site.Params.segmentWriteKey }}" />
|
||||
|
||||
{{ if (eq .Params.type "external-link") }}
|
||||
<meta http-equiv="refresh" content="0; url={{ .Params.external_url }}" />
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<h1 class="hero__title">{{ .Params.title }}</h1>
|
||||
<p class="hero__subtitle">{{ .Params.subtitle }}</p>
|
||||
<div class="hero__buttons">
|
||||
<a href="{{ .Params.startFree.url }}" class="button button_contained button_lg"
|
||||
<a data-metric-loc="hero" href="{{ .Params.startFree.url }}" class="button button_contained button_lg"
|
||||
>{{ .Params.startFree.text }}</a
|
||||
>
|
||||
<a href="{{ .Params.learnMore.url }}" class="button button_outlined button_lg"
|
||||
<a data-metric-loc="hero" href="{{ .Params.learnMore.url }}" class="button button_outlined button_lg"
|
||||
>{{ .Params.learnMore.text }}</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
{{ if eq $section "documentation" }}
|
||||
{{ partial "theme-switch" . }}
|
||||
{{ end }}
|
||||
<a href="{{ .Params.logIn.url }}" class="menu-link mx-3">{{ .Params.logIn.text }}</a>
|
||||
<a href="{{ .Params.startFree.url }}" class="button button_contained button_sm">{{ .Params.startFree.text }}</a>
|
||||
<a data-metric-loc="nav" href="{{ .Params.logIn.url }}" class="menu-link mx-3">{{ .Params.logIn.text }}</a>
|
||||
<a data-metric-loc="nav" href="{{ .Params.startFree.url }}" class="button button_contained button_sm">{{ .Params.startFree.text }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div>
|
||||
<span class="top-banner__icon"> {{ .Params.icon | safeHTML }} </span>
|
||||
<span class="top-banner__text"> {{ .Params.text }} </span>
|
||||
<a class="link link_light link_sm" href="{{ .Params.link.url }}">{{ .Params.link.text }}</a>
|
||||
<a data-metric-loc="banner" data-metric-label="{{ .Params.text }} {{ .Params.link.text }}" class="link link_light link_sm" href="{{ .Params.link.url }}">{{ .Params.link.text }}</a>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user