diff --git a/lib/db.js b/lib/db.js
index b925b52c..8725f88c 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -68,3 +68,25 @@ export async function savePageView(website_id, session_id, url, referrer) {
}),
);
}
+
+export async function saveEvent(website_id, session_id, url, eventType, eventValue) {
+ return runQuery(
+ prisma.pageview.create({
+ data: {
+ website: {
+ connect: {
+ website_uuid: website_id,
+ },
+ },
+ session: {
+ connect: {
+ session_uuid: session_id,
+ },
+ },
+ url,
+ eventType,
+ eventValue,
+ },
+ }),
+ );
+}
diff --git a/lib/utils.js b/lib/utils.js
index ccf8c43d..c2730f70 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -91,6 +91,8 @@ export function parseCollectRequest(req) {
const {
url,
referrer,
+ eventType,
+ eventValue,
session: { website_id, session_id, time, hash: validationHash },
} = payload;
@@ -107,6 +109,8 @@ export function parseCollectRequest(req) {
session_id,
url,
referrer,
+ eventType,
+ eventValue,
};
}
}
diff --git a/pages/api/collect.js b/pages/api/collect.js
index 2f47cf9a..724191f8 100644
--- a/pages/api/collect.js
+++ b/pages/api/collect.js
@@ -1,5 +1,5 @@
import { parseCollectRequest } from 'lib/utils';
-import { savePageView } from 'lib/db';
+import { savePageView, saveEvent } from 'lib/db';
import { allowPost } from 'lib/middleware';
export default async (req, res) => {
@@ -8,12 +8,16 @@ export default async (req, res) => {
const values = parseCollectRequest(req);
if (values.success) {
- const { type, website_id, session_id, url, referrer } = values;
+ const { type, website_id, session_id, url, referrer, eventType, eventValue } = values;
if (type === 'pageview') {
await savePageView(website_id, session_id, url, referrer).catch(() => {
values.success = 0;
});
+ } else if (type === 'event') {
+ await saveEvent(website_id, session_id, url, eventType, eventValue).catch(() => {
+ values.success = 0;
+ });
}
}
diff --git a/pages/index.js b/pages/index.js
index e632bfd1..0bd3d0ac 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -14,6 +14,10 @@ export default function Home() {
123
+
+
);
}
diff --git a/public/umami.js b/public/umami.js
index 51691c4e..b4ab7334 100644
--- a/public/umami.js
+++ b/public/umami.js
@@ -1 +1 @@
-!function(){"use strict";function e(e){var n=this.constructor;return this.then((function(t){return n.resolve(e()).then((function(){return t}))}),(function(t){return n.resolve(e()).then((function(){return n.reject(t)}))}))}var n=setTimeout;function t(e){return Boolean(e&&void 0!==e.length)}function r(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],f(e,this)}function i(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn((function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null!==t){var r;try{r=t(e._value)}catch(e){return void s(n.promise,e)}u(n.promise,r)}else(1===e._state?u:s)(n.promise,e._value)}))):e._deferreds.push(n)}function u(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof o)return e._state=3,e._value=n,void c(e);if("function"==typeof t)return void f((r=t,i=n,function(){r.apply(i,arguments)}),e)}e._state=1,e._value=n,c(e)}catch(n){s(e,n)}var r,i}function s(e,n){e._state=2,e._value=n,c(e)}function c(e){2===e._state&&0===e._deferreds.length&&o._immediateFn((function(){e._handled||o._unhandledRejectionFn(e._value)}));for(var n=0,t=e._deferreds.length;n
fetch(url, {
method: 'post',
@@ -56,6 +60,29 @@ if (script) {
return success;
});
+ const trackEvent = (url, eventType, eventValue) =>
+ post(`${hostUrl}/api/collect`, {
+ type: 'event',
+ payload: { url, eventType, eventValue, session: getSession() },
+ }).then(({ success }) => {
+ if (!success) {
+ store.removeItem(sessionKey);
+ }
+ return success;
+ });
+
+ const elementToString = e => {
+ return JSON.stringify(
+ e.getAttributeNames().reduce(
+ (obj, val) => {
+ obj[val] = e.getAttribute(val);
+ return obj;
+ },
+ { tag: e.tagName.toLowerCase() },
+ ),
+ );
+ };
+
const execute = (url, referrer) => {
const data = getSessionData(url);
@@ -69,6 +96,8 @@ if (script) {
}
};
+ /* Handle push state */
+
const handlePush = (state, title, url) => {
currenrRef = currentUrl;
currentUrl = url;
@@ -87,6 +116,27 @@ if (script) {
history.pushState = hook('pushState', handlePush);
history.replaceState = hook('replaceState', handlePush);
+ /* Handle events */
+
+ document.querySelectorAll("[class*='umami--']").forEach(e => {
+ e.className.split(' ').forEach(c => {
+ console.log('class', c);
+ if (/^umami--/.test(c)) {
+ const [, event] = c.split('--');
+ console.log('event', event);
+ if (event) {
+ e.addEventListener(event, () => {
+ trackEvent(currentUrl, event, elementToString(e));
+ console.log('exec event', event, elementToString(e));
+ });
+ }
+ }
+ });
+ console.log('match', e);
+ });
+
+ /* Start */
+
execute(currentUrl, currenrRef);
}
}