From e3f5227cf20fdfb0a0bd54ef4d796181024cb40c Mon Sep 17 00:00:00 2001 From: Ethan Nguyen-Huu Date: Fri, 27 Feb 2026 01:06:52 -0800 Subject: [PATCH 1/2] add function for hover tracking + tested on contact cards --- .../components/ContactScrollSection.tsx | 19 ++++++++- app/hooks/TrackPage.ts | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/contact/components/ContactScrollSection.tsx b/app/contact/components/ContactScrollSection.tsx index 684bfa9..291954f 100644 --- a/app/contact/components/ContactScrollSection.tsx +++ b/app/contact/components/ContactScrollSection.tsx @@ -4,11 +4,26 @@ import { useState, useEffect, useRef } from "react"; import VendorInquiries from "@/app/contact/components/VendorInquiries"; import PressInquiries from "@/app/contact/components/PressInquiries"; import GeneralSupport from "@/app/contact/components/GeneralSupport"; +import { useTrackPage } from "@/app/hooks/TrackPage"; // Add cards into here if needed, ideally with the same visuals as the rest. const cards = [VendorInquiries, PressInquiries, GeneralSupport]; const scrollSensitivity = 0.00045; // Sensitivity (Higher = more Card switching per scroll) +function TrackedCard({ cardId, children }: { cardId: string; children: React.ReactNode }) +{ + const { onMouseEnter, onMouseLeave } = useTrackPage(cardId); + + return ( +
+ {children} +
+ ); +} +/** + * Hover tracking works best on single elements bc + * scroll-section has multiple cards in DOM. + */ export default function ContactScrollSection() { const containerRef = useRef(null); const [scrollIndex, setScrollIndex] = useState(0); @@ -56,7 +71,9 @@ export default function ContactScrollSection() { justifyContent: "center", alignItems: "center", }}> - + + + ))} diff --git a/app/hooks/TrackPage.ts b/app/hooks/TrackPage.ts index e69de29..1ff9a1c 100644 --- a/app/hooks/TrackPage.ts +++ b/app/hooks/TrackPage.ts @@ -0,0 +1,42 @@ +"use client"; +import { useRef } from "react"; + +export function useTrackPage(componentId: string, userId?: string) +{ + const hoverStart = useRef(null); + const hoveredAt = useRef(null); + + const onMouseEnter = () => + { + hoverStart.current = Date.now(); + hoveredAt.current = new Date().toISOString(); + }; + + const onMouseLeave = async () => + { + if (hoverStart.current === null) return; + + const durationMs = Date.now() - hoverStart.current; + hoverStart.current = null; + + await fetch("/api/track", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify( + { + event_type: "hover", + payload: + { + componentId, + durationMs, + hoveredAt: hoveredAt.current, + userId: userId ?? null, + }, + } + ), + } + ); + }; + return { onMouseEnter, onMouseLeave }; +} \ No newline at end of file From dfc9066776e903f7d5cc78af86bce02f56a7f23b Mon Sep 17 00:00:00 2001 From: Ethan Nguyen-Huu Date: Fri, 6 Mar 2026 22:47:30 -0800 Subject: [PATCH 2/2] Add minimum threshold for hover to POST --- app/hooks/TrackPage.ts | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/app/hooks/TrackPage.ts b/app/hooks/TrackPage.ts index 1ff9a1c..b67e32e 100644 --- a/app/hooks/TrackPage.ts +++ b/app/hooks/TrackPage.ts @@ -5,6 +5,7 @@ export function useTrackPage(componentId: string, userId?: string) { const hoverStart = useRef(null); const hoveredAt = useRef(null); + const thresholdMs = 5000; // Change to preference (Currently 5 seconds) const onMouseEnter = () => { @@ -19,24 +20,26 @@ export function useTrackPage(componentId: string, userId?: string) const durationMs = Date.now() - hoverStart.current; hoverStart.current = null; - await fetch("/api/track", - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify( - { - event_type: "hover", - payload: + if (durationMs > thresholdMs) { + await fetch("/api/track", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify( { - componentId, - durationMs, - hoveredAt: hoveredAt.current, - userId: userId ?? null, - }, - } - ), - } - ); + event_type: "hover", + payload: + { + componentId, + durationMs, + hoveredAt: hoveredAt.current, + userId: userId ?? null, + }, + } + ), + } + ); + } }; return { onMouseEnter, onMouseLeave }; } \ No newline at end of file