Bläddra i källkod

feat: implement unique visitor tracking cookie

unknown 2 månader sedan
förälder
incheckning
e56b9d447b
2 ändrade filer med 57 tillägg och 0 borttagningar
  1. 53 0
      src/lib/tracking.ts
  2. 4 0
      src/main.ts

+ 53 - 0
src/lib/tracking.ts

@@ -0,0 +1,53 @@
+/**
+ * Visitor Tracking Service
+ * Sets a unique persistent cookie to identify visitors across sessions
+ */
+
+const VISITOR_COOKIE_NAME = 'r3d_visitor_id';
+const COOKIE_EXPIRY_DAYS = 365;
+
+export function initVisitorTracking() {
+  // 1. Check if we already have a visitor ID
+  const existingId = getCookie(VISITOR_COOKIE_NAME);
+  if (existingId) return existingId;
+
+  // 2. Generate new unique ID
+  const newId = generateUniqueId();
+
+  // 3. Set the cookie
+  setCookie(VISITOR_COOKIE_NAME, newId, COOKIE_EXPIRY_DAYS);
+  
+  return newId;
+}
+
+export function getVisitorId(): string | null {
+  return getCookie(VISITOR_COOKIE_NAME);
+}
+
+function generateUniqueId(): string {
+  // Use crypto.randomUUID if available, fallback to random string
+  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
+    return crypto.randomUUID();
+  }
+  return Math.random().toString(36).substring(2, 15) + 
+         Math.random().toString(36).substring(2, 15);
+}
+
+function setCookie(name: string, value: string, days: number) {
+  const date = new Date();
+  date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
+  const expires = "expires=" + date.toUTCString();
+  // SameSite=Lax is good for tracking but reasonably secure
+  document.cookie = `${name}=${value};${expires};path=/;SameSite=Lax`;
+}
+
+function getCookie(name: string): string | null {
+  const nameEQ = name + "=";
+  const ca = document.cookie.split(';');
+  for (let i = 0; i < ca.length; i++) {
+    let c = ca[i];
+    while (c.charAt(0) === ' ') c = c.substring(1, c.length);
+    if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
+  }
+  return null;
+}

+ 4 - 0
src/main.ts

@@ -5,6 +5,7 @@ import App from "./App.vue";
 import { createHead } from "@unhead/vue/client";
 import router from "./router";
 import i18n from "./i18n";
+import { initVisitorTracking } from "@/lib/tracking";
 import "./index.css";
 
 // Handle dynamic import failures (assets deleted after deploy)
@@ -15,6 +16,9 @@ window.addEventListener('vite:preloadError', () => {
 
 const app = createApp(App);
 
+// Initialize visitor tracking
+initVisitorTracking();
+
 app.use(createPinia());
 app.use(createHead());