feat(frontend): تحلیل رفتار با OpenPanel بهجای اجرای نمونهٔ دوم Umami
نمونهٔ OpenPanel موجود (stats.*) با یک پروژهٔ دوم برای این سایت استفاده میشود؛ VITE_OPENPANEL_URL/VITE_OPENPANEL_CLIENT_ID در زمان بیلد تزریق میشوند و در نبودشان همهچیز بیاثر است. API عمومی track() تغییر نکرده و مسیر Umami هم برای عقبنشینی دستنخورده مانده.
This commit is contained in:
@@ -1,17 +1,65 @@
|
||||
// لایهٔ نازک تحلیل رفتار (Umami) — اگر اسکریپت ردیاب بارگیری نشده باشد
|
||||
// (VITE_UMAMI_SRC خالی)، همهٔ فراخوانیها بیاثر و ارزاناند.
|
||||
// لایهٔ نازک تحلیل رفتار — OpenPanel.
|
||||
//
|
||||
// نمونهٔ OpenPanel از قبل روی این سرور بالا است (stats.bennu-api-bahrestan.ir) و
|
||||
// پروژهٔ ERP هم از همان استفاده میکند؛ بهجای اجرای یک ابزار تحلیل دوم (Umami)،
|
||||
// همین یک نمونه با یک «پروژهٔ» دوم برای این سایت به کار میرود.
|
||||
//
|
||||
// اگر VITE_OPENPANEL_URL و VITE_OPENPANEL_CLIENT_ID در زمان بیلد تنظیم نشده باشند،
|
||||
// همهٔ فراخوانیها بیاثر و ارزاناند (مثل حالت فعلی Umami).
|
||||
//
|
||||
// مسیر Umami دستنخورده مانده تا اگر اسکریپت قدیمی جایی فعال بود از کار نیفتد.
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
op?: (...args: unknown[]) => void
|
||||
umami?: { track: (event?: string, data?: Record<string, unknown>) => void }
|
||||
}
|
||||
}
|
||||
|
||||
/** رخداد سفارشی — نام رخداد در داشبورد Umami نمایش داده میشود. */
|
||||
export function track(event: string, data?: Record<string, unknown>) {
|
||||
const OP_URL = (import.meta.env?.VITE_OPENPANEL_URL as string | undefined)?.trim()
|
||||
const OP_CLIENT_ID = (import.meta.env?.VITE_OPENPANEL_CLIENT_ID as string | undefined)?.trim()
|
||||
const OP_SCRIPT_URL = (import.meta.env?.VITE_OPENPANEL_SCRIPT_URL as string | undefined)?.trim()
|
||||
|
||||
// شیم صف OpenPanel — تا رسیدن op1.js، فراخوانیها در صف میمانند و بعد تخلیه میشوند.
|
||||
function loadOpenPanelScript(src: string): void {
|
||||
if (document.querySelector('script[data-openpanel]')) return
|
||||
const shim = document.createElement('script')
|
||||
shim.textContent =
|
||||
'window.op=window.op||function(){var n=[];return new Proxy(function(){arguments.length&&n.push([].slice.call(arguments))},{get:function(t,r){return"q"===r?n:function(){n.push([r].concat([].slice.call(arguments)))}},has:function(t,r){return"q"===r}}) }();'
|
||||
document.head.appendChild(shim)
|
||||
const script = document.createElement('script')
|
||||
script.src = src
|
||||
script.async = true
|
||||
script.defer = true
|
||||
script.dataset.openpanel = '1'
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
/** یکبار در شروع اپ صدا زده میشود؛ بدون تنظیمات، هیچ کاری نمیکند. */
|
||||
export function initAnalytics(): void {
|
||||
if (!OP_URL || !OP_CLIENT_ID) return
|
||||
try {
|
||||
window.umami?.track(event, data)
|
||||
if (OP_SCRIPT_URL) loadOpenPanelScript(OP_SCRIPT_URL)
|
||||
window.op?.('init', {
|
||||
apiUrl: OP_URL,
|
||||
clientId: OP_CLIENT_ID,
|
||||
trackScreenViews: true, // بازدید صفحه → کدام صفحات دیده میشوند
|
||||
})
|
||||
} catch {
|
||||
// تحلیل رفتار هرگز نباید مسیر اصلی را بشکند
|
||||
}
|
||||
}
|
||||
|
||||
/** رخداد سفارشی — در داشبورد OpenPanel نمایش داده میشود. */
|
||||
export function track(event: string, data?: Record<string, unknown>) {
|
||||
try {
|
||||
window.op?.('track', event, data ?? {})
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
window.umami?.track(event, data)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ import "./index.css";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { App } from "./App";
|
||||
import { initAnalytics } from "./analytics";
|
||||
|
||||
initAnalytics();
|
||||
|
||||
const rootEl = document.getElementById("root");
|
||||
if (rootEl) {
|
||||
|
||||
Reference in New Issue
Block a user