Files
portal/app/resources/js/plugins/track.ts
T

51 lines
1.8 KiB
TypeScript

/**
* Свой учёт посетителей портала (spec 2026-07-13). Работает параллельно с Метрикой,
* её не заменяет и не трогает. Пишем только ИМЯ экрана — без содержимого (ПДн не уходят).
*/
const sentOnce = new Set<string>();
function send(event: string, extra: Record<string, unknown> = {}): void {
void fetch('/api/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
keepalive: true,
body: JSON.stringify({
event,
host: location.hostname,
path: location.pathname,
referrer: document.referrer || null,
...extra,
}),
}).catch(() => undefined);
}
/** Первый заход в портал + «человек шевельнулся». Идемпотентно. */
export function trackVisit(): void {
if (sentOnce.has('view')) return;
sentOnce.add('view');
send('view');
const events = ['scroll', 'touchstart', 'mousemove', 'keydown'];
const onFirst = () => {
if (!sentOnce.has('alive')) {
sentOnce.add('alive');
send('alive');
}
events.forEach((e) => window.removeEventListener(e, onFirst));
};
events.forEach((e) => window.addEventListener(e, onFirst, { once: true, passive: true }));
}
/** Открыт экран кабинета — только имя маршрута. */
export function trackScreen(screen: string): void {
send('portal_screen', { screen });
}
/** Открыт экран регистрации. */
export function trackRegisterOpen(): void {
if (sentOnce.has('register_open')) return;
sentOnce.add('register_open');
send('register_open');
}