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
@@ -0,0 +1,80 @@
export const PAYMENT_ANALYTICS_ENTRY_PARAM = "analytics_entry";
export const PAYMENT_ANALYTICS_REASON_PARAM = "analytics_reason";
export type PaymentAnalyticsTriggerReason =
| "daily_chat_limit"
| "private_topic_limit"
| "insufficient_credits"
| "sidebar_recharge"
| "vip_cta"
| "ad_landing"
| "manual_recharge"
| "unknown";
export type PaymentAnalyticsEntryPoint =
| "chat_input"
| "chat_unlock"
| "private_album_unlock"
| "private_room"
| "sidebar"
| "chat_offer_banner"
| "subscription_direct"
| "tip_page"
| "external_entry"
| "unknown";
export interface PaymentAnalyticsContext {
entryPoint: PaymentAnalyticsEntryPoint;
triggerReason: PaymentAnalyticsTriggerReason;
}
const ENTRY_POINTS = new Set<PaymentAnalyticsEntryPoint>([
"chat_input",
"chat_unlock",
"private_album_unlock",
"private_room",
"sidebar",
"chat_offer_banner",
"subscription_direct",
"tip_page",
"external_entry",
"unknown",
]);
const TRIGGER_REASONS = new Set<PaymentAnalyticsTriggerReason>([
"daily_chat_limit",
"private_topic_limit",
"insufficient_credits",
"sidebar_recharge",
"vip_cta",
"ad_landing",
"manual_recharge",
"unknown",
]);
export function getDefaultPaymentAnalyticsContext(
type: "vip" | "topup",
): PaymentAnalyticsContext {
return {
entryPoint: "subscription_direct",
triggerReason: type === "topup" ? "manual_recharge" : "vip_cta",
};
}
export function parsePaymentAnalyticsContext(input: {
entryPoint: string | null;
triggerReason: string | null;
subscriptionType: "vip" | "topup";
}): PaymentAnalyticsContext {
const fallback = getDefaultPaymentAnalyticsContext(input.subscriptionType);
return {
entryPoint: ENTRY_POINTS.has(input.entryPoint as PaymentAnalyticsEntryPoint)
? (input.entryPoint as PaymentAnalyticsEntryPoint)
: fallback.entryPoint,
triggerReason: TRIGGER_REASONS.has(
input.triggerReason as PaymentAnalyticsTriggerReason,
)
? (input.triggerReason as PaymentAnalyticsTriggerReason)
: fallback.triggerReason,
};
}