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
@@ -52,6 +52,7 @@ describe("auth Tailwind components", () => {
expect(html).toContain("w-full");
expect(html).toContain("gap-md");
expect(html).toContain("Login");
expect(html).toContain('data-analytics-key="auth.email_login"');
});
it("renders EmailRegisterForm with Tailwind form layout", () => {
@@ -62,6 +63,7 @@ describe("auth Tailwind components", () => {
expect(html).toContain("w-full");
expect(html).toContain("gap-md");
expect(html).toContain("Register");
expect(html).toContain('data-analytics-key="auth.email_register"');
});
it("renders AuthBackground with Tailwind layout classes", () => {
@@ -128,6 +130,7 @@ describe("auth Tailwind components", () => {
);
expect(html).toContain("Login with Facebook");
expect(html).toContain('data-analytics-key="auth.facebook_login"');
expect(html).toContain("bg-auth-surface");
expect(html).toContain("enabled:hover:brightness-[0.97]");
expect(html).toContain("Other Sign In Options");
@@ -83,6 +83,9 @@ export function AuthEmailPanel({
<button
type="button"
data-analytics-key={
mode === "login" ? "auth.open_register" : "auth.open_email_login"
}
className="self-center border-0 bg-transparent pt-md text-(length:--responsive-body) text-auth-text-primary underline underline-offset-[3px] transition-opacity duration-150 hover:opacity-80"
onClick={() => setMode((m) => (m === "login" ? "register" : "login"))}
>
@@ -93,6 +96,8 @@ export function AuthEmailPanel({
<button
type="button"
data-analytics-key="auth.open_other_options"
data-analytics-label="Open other sign-in options"
className="self-center border-0 bg-transparent py-md text-(length:--responsive-body) text-auth-text-primary underline underline-offset-[3px] transition-opacity duration-150 hover:opacity-80"
onClick={() => setShowOptions(true)}
>
@@ -63,6 +63,8 @@ export function AuthFacebookPanel({
<button
type="button"
data-analytics-key="auth.facebook_login"
data-analytics-label="Facebook login"
className="mt-md inline-flex min-h-(--auth-field-height) w-full cursor-pointer items-center justify-center gap-md rounded-full border-0 bg-auth-surface px-lg text-(length:--responsive-body) font-semibold text-auth-text-primary shadow-[0_2px_6px_rgba(0,0,0,0.06)] transition-[filter,transform,opacity] duration-150 enabled:hover:brightness-[0.97] enabled:active:scale-98 disabled:cursor-not-allowed disabled:opacity-60"
onClick={() => handleFacebook()}
disabled={isLoading}
@@ -87,6 +89,8 @@ export function AuthFacebookPanel({
<button
type="button"
data-analytics-key="auth.open_other_options"
data-analytics-label="Open other sign-in options"
className="self-center border-0 bg-transparent py-md text-(length:--responsive-body) text-auth-text-primary underline underline-offset-[3px] transition-opacity duration-150 hover:opacity-80"
onClick={() => setShowOptions(true)}
>
@@ -52,6 +52,8 @@ export function AuthOtherOptionsDialog({
{mode === "email" ? (
<AuthSocialButton
data-analytics-key="auth.facebook_login"
data-analytics-label="Facebook login"
icon={<AuthProviderIcon provider="facebook" />}
onClick={() => {
onClose();
@@ -64,6 +66,8 @@ export function AuthOtherOptionsDialog({
{showNonProductionEmailOption ? (
<AuthSocialButton
data-analytics-key="auth.open_email_login"
data-analytics-label="Email login option"
icon={<MdEmail size={20} color="var(--color-auth-text-primary)" />}
onClick={() => {
onClose();
@@ -78,6 +82,8 @@ export function AuthOtherOptionsDialog({
<div className="w-full">{googleSlot}</div>
) : (
<AuthSocialButton
data-analytics-key="auth.google_login"
data-analytics-label="Google login"
icon={<AuthProviderIcon provider="google" />}
onClick={() => {
onClose();
+1 -1
View File
@@ -29,7 +29,7 @@ export function AuthPanel() {
return (
<div className="relative flex min-h-0 w-full flex-auto flex-col">
<BackButton onClick={handleBack} />
<BackButton onClick={handleBack} analyticsKey="auth.back" />
{state.authPanelMode === "facebook" ? (
<AuthFacebookPanel onSwitchToEmail={switchToEmail} />
+6 -1
View File
@@ -98,7 +98,12 @@ export function EmailLoginForm({
/>
{/* 优先级:本地校验错误 > 后端 globalError(两个互斥场景:本地校验未过时,UI 不会再有 globalError */}
<AuthErrorMessage message={validationError ?? globalError ?? null} />
<AuthPrimaryButton type="submit" isLoading={isLoading}>
<AuthPrimaryButton
type="submit"
isLoading={isLoading}
data-analytics-key="auth.email_login"
data-analytics-label="Email login"
>
Login
</AuthPrimaryButton>
</form>
@@ -147,7 +147,12 @@ export function EmailRegisterForm({
/>
{/* 优先级:本地校验错误 > 后端 globalError */}
<AuthErrorMessage message={validationError ?? globalError ?? null} />
<AuthPrimaryButton type="submit" isLoading={isLoading}>
<AuthPrimaryButton
type="submit"
isLoading={isLoading}
data-analytics-key="auth.email_register"
data-analytics-label="Email register"
>
Register
</AuthPrimaryButton>
</form>