feat(analytics): add behavior and payment funnel tracking

This commit is contained in:
2026-07-14 16:54:13 +08:00
parent ca55723e48
commit 81d6489978
70 changed files with 1576 additions and 81 deletions
@@ -14,7 +14,12 @@ describe("shared Tailwind components", () => {
<BackButton onClick={() => undefined} variant="ghost" />,
);
const darkHtml = renderToStaticMarkup(
<BackButton href="/splash" variant="dark" ariaLabel="Back to home" />,
<BackButton
href="/splash"
variant="dark"
ariaLabel="Back to home"
analyticsKey="chat.back_to_home"
/>,
);
expect(linkHtml).toContain('href="/chat"');
@@ -27,6 +32,7 @@ describe("shared Tailwind components", () => {
expect(actionHtml).toContain("hover:opacity-70");
expect(darkHtml).toContain('href="/splash"');
expect(darkHtml).toContain('aria-label="Back to home"');
expect(darkHtml).toContain('data-analytics-key="chat.back_to_home"');
expect(darkHtml).toContain("bg-[rgba(13,11,20,0.7)]");
expect(darkHtml).toContain("text-white");
});
+11 -1
View File
@@ -6,6 +6,7 @@ import Link, { type LinkProps } from "next/link";
interface BackButtonBaseProps {
className?: string;
ariaLabel?: string;
analyticsKey?: string;
iconSize?: number;
variant?: "floating" | "soft" | "ghost" | "dark";
}
@@ -41,6 +42,7 @@ export function BackButton({
onClick,
className,
ariaLabel = "Back",
analyticsKey,
iconSize = 24,
variant = "floating",
}: BackButtonProps) {
@@ -57,7 +59,13 @@ export function BackButton({
if (href) {
return (
<Link href={href} className={buttonClassName} aria-label={ariaLabel}>
<Link
href={href}
className={buttonClassName}
aria-label={ariaLabel}
data-analytics-key={analyticsKey}
data-analytics-label={ariaLabel}
>
{icon}
</Link>
);
@@ -69,6 +77,8 @@ export function BackButton({
className={buttonClassName}
onClick={onClick}
aria-label={ariaLabel}
data-analytics-key={analyticsKey}
data-analytics-label={ariaLabel}
>
{icon}
</button>
@@ -101,5 +101,9 @@ describe("core Tailwind components", () => {
expect(privateRoomHtml).toMatch(
/<button[^>]*aria-current="page"[^>]*>.*?<span>Elio Private room<\/span>/,
);
expect(chatHtml).toContain('data-analytics-key="navigation.chat"');
expect(privateRoomHtml).toContain(
'data-analytics-key="navigation.private_room"',
);
});
});
@@ -24,6 +24,8 @@ export function AppBottomNav({
<nav className={getRootClass(variant)} aria-label="Primary navigation">
<button
type="button"
data-analytics-key="navigation.chat"
data-analytics-label="Chat navigation"
className={getButtonClass(activeItem === "chat")}
aria-current={activeItem === "chat" ? "page" : undefined}
onClick={onChatClick}
@@ -33,6 +35,8 @@ export function AppBottomNav({
</button>
<button
type="button"
data-analytics-key="navigation.private_room"
data-analytics-label="Private room navigation"
className={getButtonClass(activeItem === "privateRoom")}
aria-current={activeItem === "privateRoom" ? "page" : undefined}
onClick={onPrivateRoomClick}