Some checks failed
Build and Deploy / build (push) Has been cancelled
- Add type-safe AnalyticsEvent union types - Create AnalyticsProvider interface for pluggable analytics backends - Implement OpenPanelProvider and RybbitProvider adapters - Create AnalyticsTracker that fans out events to all providers - Simplifies adding new analytics platforms in the future
147 lines
3.9 KiB
TypeScript
147 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import type { AnalyticsEvent, AnalyticsProvider, UserData } from "../core/types";
|
|
|
|
export class OpenPanelProvider implements AnalyticsProvider {
|
|
name = "OpenPanel";
|
|
private op: ReturnType<typeof import("@openpanel/nextjs").useOpenPanel>;
|
|
private isClient: boolean;
|
|
|
|
constructor(op: ReturnType<typeof import("@openpanel/nextjs").useOpenPanel>) {
|
|
this.op = op;
|
|
this.isClient = typeof window !== "undefined";
|
|
}
|
|
|
|
isAvailable(): boolean {
|
|
return this.isClient;
|
|
}
|
|
|
|
track(event: AnalyticsEvent): void {
|
|
if (!this.isAvailable()) return;
|
|
|
|
switch (event.type) {
|
|
case "product_viewed":
|
|
this.op.track("product_viewed", {
|
|
product_id: event.product.id,
|
|
product_name: event.product.name,
|
|
price: event.product.price,
|
|
currency: event.product.currency,
|
|
category: event.product.category,
|
|
});
|
|
break;
|
|
|
|
case "add_to_cart":
|
|
this.op.track("add_to_cart", {
|
|
product_id: event.product.id,
|
|
product_name: event.product.name,
|
|
price: event.product.price,
|
|
currency: event.product.currency,
|
|
quantity: event.product.quantity,
|
|
variant: event.product.variant,
|
|
});
|
|
break;
|
|
|
|
case "remove_from_cart":
|
|
this.op.track("remove_from_cart", {
|
|
product_id: event.product.id,
|
|
product_name: event.product.name,
|
|
quantity: event.product.quantity,
|
|
});
|
|
break;
|
|
|
|
case "cart_view":
|
|
this.op.track("cart_view", {
|
|
cart_total: event.cart.total,
|
|
currency: event.cart.currency,
|
|
item_count: event.cart.item_count,
|
|
});
|
|
break;
|
|
|
|
case "checkout_started":
|
|
this.op.track("checkout_started", {
|
|
cart_total: event.cart.total,
|
|
currency: event.cart.currency,
|
|
item_count: event.cart.item_count,
|
|
items: event.cart.items,
|
|
});
|
|
break;
|
|
|
|
case "checkout_step":
|
|
this.op.track("checkout_step", {
|
|
step: event.step,
|
|
...event.data,
|
|
});
|
|
break;
|
|
|
|
case "order_completed":
|
|
this.op.track("order_completed", {
|
|
order_id: event.order.order_id,
|
|
order_number: event.order.order_number,
|
|
total: event.order.total,
|
|
currency: event.order.currency,
|
|
item_count: event.order.item_count,
|
|
shipping_cost: event.order.shipping_cost,
|
|
coupon_code: event.order.coupon_code,
|
|
customer_email: event.order.customer_email,
|
|
payment_method: event.order.payment_method,
|
|
});
|
|
break;
|
|
|
|
case "search":
|
|
this.op.track("search", {
|
|
query: event.query,
|
|
results_count: event.results_count,
|
|
});
|
|
break;
|
|
|
|
case "external_link_click":
|
|
this.op.track("external_link_click", {
|
|
url: event.url,
|
|
label: event.label,
|
|
});
|
|
break;
|
|
|
|
case "wishlist_add":
|
|
this.op.track("wishlist_add", {
|
|
product_id: event.product.id,
|
|
product_name: event.product.name,
|
|
});
|
|
break;
|
|
|
|
case "user_login":
|
|
this.op.track("user_login", {
|
|
method: event.method,
|
|
});
|
|
break;
|
|
|
|
case "user_register":
|
|
this.op.track("user_register", {
|
|
method: event.method,
|
|
});
|
|
break;
|
|
|
|
case "newsletter_signup":
|
|
this.op.track("newsletter_signup", {
|
|
email: event.email,
|
|
source: event.source,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
identify(user: UserData): void {
|
|
if (!this.isAvailable()) return;
|
|
this.op.identify({
|
|
profileId: user.profileId,
|
|
firstName: user.firstName,
|
|
lastName: user.lastName,
|
|
email: user.email,
|
|
});
|
|
}
|
|
|
|
async revenue(amount: number, currency: string, properties?: Record<string, unknown>): Promise<void> {
|
|
if (!this.isAvailable()) return;
|
|
await this.op.revenue(amount, { currency, ...properties });
|
|
}
|
|
}
|