@morphika/andami 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,6 @@ import { getSiteConfig } from "../../lib/config";
10
10
  import Navbar from "../../components/ui/Navbar";
11
11
  import CustomCursor from "../../components/ui/CustomCursor";
12
12
  import ScrollToTop from "../../components/ui/ScrollToTop";
13
- import PortfolioTracker from "../../components/ui/PortfolioTracker";
14
13
 
15
14
  // CPU Audit Fix 3: React cache() deduplicates within a render pass.
16
15
  const getSiteSettings = cache(async (): Promise<SiteSettings | null> => {
@@ -46,7 +45,6 @@ export default async function SiteLayout({
46
45
  <main className="flex-1">{children}</main>
47
46
  {cfg.features.customCursor && <CustomCursor />}
48
47
  <ScrollToTop />
49
- {cfg.features.portfolioTracking && <PortfolioTracker />}
50
48
  </div>
51
49
  </PageExitProvider>
52
50
  </NavAnimationProvider>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morphika/andami",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Visual Page Builder — core library. A reusable website builder with visual editing, CMS integration, and asset management.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,87 +0,0 @@
1
- "use client";
2
-
3
- /**
4
- * PortfolioTracker — Outreach & campaign visit tracking.
5
- *
6
- * Tracks two types of visits:
7
- * 1. Lead referrals: example.com/portfolio?r=AM92
8
- * 2. Custom channels: example.com/portfolio?c=discord
9
- *
10
- * Sends a POST to the Knock API on first load and on SPA route changes.
11
- * Uses sessionStorage to persist ref/channel across internal navigation.
12
- *
13
- * Configured via site.config.ts: tracking.knockApiUrl + tracking.sessionPrefix.
14
- * If knockApiUrl is empty, the component renders nothing.
15
- */
16
-
17
- import { useEffect, useRef } from "react";
18
- import { usePathname } from "next/navigation";
19
- import { getSiteConfig } from "../../lib/config";
20
-
21
- const cfg = getSiteConfig();
22
- const KNOCK_API_URL = cfg.tracking?.knockApiUrl ?? "";
23
- const REF_KEY = `${cfg.tracking?.sessionPrefix ?? "site"}_ref`;
24
- const CHANNEL_KEY = `${cfg.tracking?.sessionPrefix ?? "site"}_channel`;
25
-
26
- function sendVisit(
27
- page: string,
28
- ref: string | null,
29
- channel: string | null,
30
- ): void {
31
- if (!ref && !channel) return;
32
-
33
- const body: Record<string, string> = {
34
- page,
35
- timestamp: new Date().toISOString(),
36
- };
37
- if (ref) body.ref = ref;
38
- if (channel) body.channel = channel;
39
-
40
- fetch(KNOCK_API_URL, {
41
- method: "POST",
42
- headers: { "Content-Type": "application/json" },
43
- body: JSON.stringify(body),
44
- }).catch(() => {
45
- /* silent — tracking should never break the site */
46
- });
47
- }
48
-
49
- export default function PortfolioTracker() {
50
- const pathname = usePathname();
51
- const prevPathRef = useRef<string | null>(null);
52
- const enabled = !!KNOCK_API_URL;
53
-
54
- // Initial visit + capture URL params into sessionStorage
55
- useEffect(() => {
56
- if (!enabled) return;
57
-
58
- const params = new URLSearchParams(window.location.search);
59
- const ref = params.get("r") || params.get("ref");
60
- const channel = params.get("c");
61
-
62
- if (ref) sessionStorage.setItem(REF_KEY, ref);
63
- if (channel) sessionStorage.setItem(CHANNEL_KEY, channel);
64
-
65
- const storedRef = ref || sessionStorage.getItem(REF_KEY);
66
- const storedChannel = channel || sessionStorage.getItem(CHANNEL_KEY);
67
-
68
- if (storedRef || storedChannel) {
69
- sendVisit(window.location.pathname, storedRef, storedChannel);
70
- }
71
-
72
- prevPathRef.current = window.location.pathname;
73
- }, [enabled]); // eslint-disable-line react-hooks/exhaustive-deps
74
-
75
- // SPA route change tracking (Next.js App Router)
76
- useEffect(() => {
77
- if (!enabled) return;
78
- if (prevPathRef.current === null || pathname === prevPathRef.current) return;
79
- prevPathRef.current = pathname;
80
-
81
- const ref = sessionStorage.getItem(REF_KEY);
82
- const channel = sessionStorage.getItem(CHANNEL_KEY);
83
- sendVisit(pathname, ref, channel);
84
- }, [pathname, enabled]);
85
-
86
- return null;
87
- }