utm
This commit is contained in:
parent
331b9d8547
commit
654e8899a8
@ -18,6 +18,8 @@ import { getFormattedPrice } from "@/shared/utils/price";
|
|||||||
import { formatPeriod, formatPeriodHyphen } from "@/shared/utils/period";
|
import { formatPeriod, formatPeriodHyphen } from "@/shared/utils/period";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { getTrackingCookiesForRedirect } from "@/shared/utils/cookies";
|
import { getTrackingCookiesForRedirect } from "@/shared/utils/cookies";
|
||||||
|
import { getClientSessionId } from "@/shared/session/sessionId";
|
||||||
|
import { getStateParamForRedirect } from "@/shared/utils/url";
|
||||||
|
|
||||||
interface SpecialOfferProps {
|
interface SpecialOfferProps {
|
||||||
funnel: FunnelDefinition;
|
funnel: FunnelDefinition;
|
||||||
@ -70,9 +72,25 @@ export function SpecialOfferTemplate({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIsLoadingRedirect(true);
|
setIsLoadingRedirect(true);
|
||||||
const redirectUrl = `${paymentUrl}?paywallId=${paywallId}&placementId=${placementId}&productId=${productId}&jwtToken=${token}&price=${(
|
|
||||||
|
// Build redirect URL with payment params
|
||||||
|
const baseParams = `paywallId=${paywallId}&placementId=${placementId}&productId=${productId}&jwtToken=${token}&price=${(
|
||||||
(trialPrice || 100) / 100
|
(trialPrice || 100) / 100
|
||||||
).toFixed(2)}¤cy=${currency}&${getTrackingCookiesForRedirect()}`;
|
).toFixed(2)}¤cy=${currency}`;
|
||||||
|
|
||||||
|
// Add sessionId
|
||||||
|
const sessionId = getClientSessionId();
|
||||||
|
const sessionParam = sessionId ? `&sessionId=${sessionId}` : "";
|
||||||
|
|
||||||
|
// Add state param with current UTM (base64 encoded JSON)
|
||||||
|
const stateParam = getStateParamForRedirect();
|
||||||
|
const stateStr = stateParam ? `&state=${stateParam}` : "";
|
||||||
|
|
||||||
|
// Add tracking cookies
|
||||||
|
const trackingCookies = getTrackingCookiesForRedirect();
|
||||||
|
const trackingStr = trackingCookies ? `&${trackingCookies}` : "";
|
||||||
|
|
||||||
|
const redirectUrl = `${paymentUrl}?${baseParams}${sessionParam}${stateStr}${trackingStr}`;
|
||||||
return window.location.replace(redirectUrl);
|
return window.location.replace(redirectUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,8 @@ import { getFormattedPrice } from "@/shared/utils/price";
|
|||||||
import { useClientToken } from "@/hooks/auth/useClientToken";
|
import { useClientToken } from "@/hooks/auth/useClientToken";
|
||||||
import { formatPeriod, formatPeriodHyphen } from "@/shared/utils/period";
|
import { formatPeriod, formatPeriodHyphen } from "@/shared/utils/period";
|
||||||
import { getTrackingCookiesForRedirect } from "@/shared/utils/cookies";
|
import { getTrackingCookiesForRedirect } from "@/shared/utils/cookies";
|
||||||
|
import { getClientSessionId } from "@/shared/session/sessionId";
|
||||||
|
import { getStateParamForRedirect } from "@/shared/utils/url";
|
||||||
|
|
||||||
interface TrialPaymentTemplateProps {
|
interface TrialPaymentTemplateProps {
|
||||||
funnel: FunnelDefinition;
|
funnel: FunnelDefinition;
|
||||||
@ -94,9 +96,25 @@ export function TrialPaymentTemplate({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoadingButtonIndex(buttonIndex);
|
setLoadingButtonIndex(buttonIndex);
|
||||||
const redirectUrl = `${paymentUrl}?paywallId=${paywallId}&placementId=${placementId}&productId=${productId}&jwtToken=${token}&price=${(
|
|
||||||
|
// Build redirect URL with payment params
|
||||||
|
const baseParams = `paywallId=${paywallId}&placementId=${placementId}&productId=${productId}&jwtToken=${token}&price=${(
|
||||||
(trialPrice || 100) / 100
|
(trialPrice || 100) / 100
|
||||||
).toFixed(2)}¤cy=${currency}&${getTrackingCookiesForRedirect()}`;
|
).toFixed(2)}¤cy=${currency}`;
|
||||||
|
|
||||||
|
// Add sessionId
|
||||||
|
const sessionId = getClientSessionId();
|
||||||
|
const sessionParam = sessionId ? `&sessionId=${sessionId}` : "";
|
||||||
|
|
||||||
|
// Add state param with current UTM (base64 encoded JSON)
|
||||||
|
const stateParam = getStateParamForRedirect();
|
||||||
|
const stateStr = stateParam ? `&state=${stateParam}` : "";
|
||||||
|
|
||||||
|
// Add tracking cookies
|
||||||
|
const trackingCookies = getTrackingCookiesForRedirect();
|
||||||
|
const trackingStr = trackingCookies ? `&${trackingCookies}` : "";
|
||||||
|
|
||||||
|
const redirectUrl = `${paymentUrl}?${baseParams}${sessionParam}${stateStr}${trackingStr}`;
|
||||||
return window.location.replace(redirectUrl);
|
return window.location.replace(redirectUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -112,7 +112,7 @@ function trackFacebookPixelEvent(
|
|||||||
// Map EnteredEmail to Lead for Facebook
|
// Map EnteredEmail to Lead for Facebook
|
||||||
const fbEvent = event === AnalyticsEvent.ENTERED_EMAIL ? AnalyticsEvent.LEAD : event;
|
const fbEvent = event === AnalyticsEvent.ENTERED_EMAIL ? AnalyticsEvent.LEAD : event;
|
||||||
|
|
||||||
window.fbq("track", fbEvent, options);
|
window.fbq?.("track", fbEvent, options);
|
||||||
console.log(`[FB] Event: ${fbEvent}`, options);
|
console.log(`[FB] Event: ${fbEvent}`, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,3 +17,81 @@ export const parseQueryParams = () => {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Params that should NOT be included in state (they are passed separately)
|
||||||
|
const EXCLUDED_STATE_PARAMS = [
|
||||||
|
"paywallId",
|
||||||
|
"placementId",
|
||||||
|
"productId",
|
||||||
|
"jwtToken",
|
||||||
|
"price",
|
||||||
|
"currency",
|
||||||
|
"fb_pixels",
|
||||||
|
"sessionId",
|
||||||
|
"state",
|
||||||
|
// Tracking cookies (passed separately)
|
||||||
|
"_fbc",
|
||||||
|
"_fbp",
|
||||||
|
"_ym_uid",
|
||||||
|
"_ym_d",
|
||||||
|
"_ym_isad",
|
||||||
|
"_ym_visorc",
|
||||||
|
"yandexuid",
|
||||||
|
"ymex",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current query params that should be passed between screens and to payment
|
||||||
|
* Includes ALL params except internal ones (productId, placementId, etc.)
|
||||||
|
* Works with utm_*, fbclid, gclid, and any other marketing params
|
||||||
|
*/
|
||||||
|
export const getCurrentQueryParams = (): Record<string, string> => {
|
||||||
|
if (typeof window === "undefined") return {};
|
||||||
|
|
||||||
|
const params = parseQueryParams();
|
||||||
|
const utmParams: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(params)) {
|
||||||
|
const isExcluded =
|
||||||
|
EXCLUDED_STATE_PARAMS.includes(key) ||
|
||||||
|
key.startsWith("_ga") ||
|
||||||
|
key.startsWith("_gid");
|
||||||
|
|
||||||
|
if (!isExcluded && value) {
|
||||||
|
utmParams[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return utmParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode params as base64 JSON for state parameter
|
||||||
|
* Uses URL-safe base64 encoding
|
||||||
|
*/
|
||||||
|
export const encodeStateParam = (params: Record<string, string>): string => {
|
||||||
|
if (Object.keys(params).length === 0) return "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const json = JSON.stringify(params);
|
||||||
|
// Use btoa for base64, replace unsafe chars for URL
|
||||||
|
const base64 = btoa(json)
|
||||||
|
.replace(/\+/g, "-")
|
||||||
|
.replace(/\//g, "_")
|
||||||
|
.replace(/=+$/, "");
|
||||||
|
return base64;
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get base64-encoded state parameter with current query params
|
||||||
|
*/
|
||||||
|
export const getStateParamForRedirect = (): string => {
|
||||||
|
const params = getCurrentQueryParams();
|
||||||
|
return encodeStateParam(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backward compatibility alias
|
||||||
|
export const getCurrentUtmParams = getCurrentQueryParams;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user