Develop
This commit is contained in:
parent
a5a3dfb4dd
commit
49c0b3121a
3
.npmrc
3
.npmrc
@ -1 +1,4 @@
|
|||||||
node-options=--experimental-vm-modules --no-warnings
|
node-options=--experimental-vm-modules --no-warnings
|
||||||
|
|
||||||
|
@wit-lab-llc:registry=https://npm.pkg.github.com
|
||||||
|
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
||||||
15
index.html
15
index.html
@ -190,21 +190,6 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- Load NMI Collect.js -->
|
|
||||||
<script type="module">
|
|
||||||
import { createApi } from "/src/api/api.ts"
|
|
||||||
const api = createApi();
|
|
||||||
api.getPaymentConfig(null).then((paymentConfig) => {
|
|
||||||
const nmiPublicKey = paymentConfig?.data?.nmi?.publicKey;
|
|
||||||
|
|
||||||
const scriptElement = document.createElement("script");
|
|
||||||
scriptElement.src = "https://hms.transactiongateway.com/token/Collect.js";
|
|
||||||
scriptElement.setAttribute("data-tokenization-key", nmiPublicKey);
|
|
||||||
scriptElement.setAttribute("data-variant", "inline");
|
|
||||||
document.head.appendChild(scriptElement);
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<!-- Load NMI Collect.js -->
|
|
||||||
<!-- Klaviyo Metric -->
|
<!-- Klaviyo Metric -->
|
||||||
<script type="module">
|
<script type="module">
|
||||||
const klaviyoKeys = {
|
const klaviyoKeys = {
|
||||||
|
|||||||
54
package-lock.json
generated
54
package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"@smakss/react-scroll-direction": "^4.0.4",
|
"@smakss/react-scroll-direction": "^4.0.4",
|
||||||
"@unleash/proxy-client-react": "^4.5.2",
|
"@unleash/proxy-client-react": "^4.5.2",
|
||||||
|
"@wit-lab-llc/frontend-shared": "^1.0.4",
|
||||||
"apng-js": "^1.1.1",
|
"apng-js": "^1.1.1",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
"framer-motion": "^11.0.8",
|
"framer-motion": "^11.0.8",
|
||||||
@ -66,6 +67,28 @@
|
|||||||
"vite-plugin-svgr": "^4.2.0"
|
"vite-plugin-svgr": "^4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"../wit-frontend-shared": {
|
||||||
|
"name": "@wit-lab-llc/frontend-shared",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"dependencies": {
|
||||||
|
"@fingerprintjs/fingerprintjs": "^5.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.0.2",
|
||||||
|
"tsup": "^8.5.1",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
||||||
@ -1028,6 +1051,12 @@
|
|||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fingerprintjs/fingerprintjs": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-KbaeE/rk2WL8MfpRP6jTI4lSr42SJPjvkyrjP3QU6uUDkOMWWYC2Ts1sNSYcegHC8avzOoYTHBj+2fTqvZWQBA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@floating-ui/core": {
|
"node_modules/@floating-ui/core": {
|
||||||
"version": "1.6.4",
|
"version": "1.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz",
|
||||||
@ -2127,6 +2156,18 @@
|
|||||||
"vite": "^4.2.0"
|
"vite": "^4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@wit-lab-llc/frontend-shared": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://npm.pkg.github.com/download/@wit-lab-llc/frontend-shared/1.0.4/c342b071bc0716511d84bc3f3c9685aa7649ea5e",
|
||||||
|
"integrity": "sha512-9EZEpjWCdz+IP4RsgkVTPiUEKhm5LqnbgD/S/GJ07eG0Y10ulj3qXjDVXc7N9gURyZULshriDt350w6nhN7Z3w==",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"dependencies": {
|
||||||
|
"@fingerprintjs/fingerprintjs": "^5.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
@ -6238,6 +6279,11 @@
|
|||||||
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
|
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@fingerprintjs/fingerprintjs": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-KbaeE/rk2WL8MfpRP6jTI4lSr42SJPjvkyrjP3QU6uUDkOMWWYC2Ts1sNSYcegHC8avzOoYTHBj+2fTqvZWQBA=="
|
||||||
|
},
|
||||||
"@floating-ui/core": {
|
"@floating-ui/core": {
|
||||||
"version": "1.6.4",
|
"version": "1.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz",
|
||||||
@ -6903,6 +6949,14 @@
|
|||||||
"react-refresh": "^0.14.0"
|
"react-refresh": "^0.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@wit-lab-llc/frontend-shared": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://npm.pkg.github.com/download/@wit-lab-llc/frontend-shared/1.0.4/c342b071bc0716511d84bc3f3c9685aa7649ea5e",
|
||||||
|
"integrity": "sha512-9EZEpjWCdz+IP4RsgkVTPiUEKhm5LqnbgD/S/GJ07eG0Y10ulj3qXjDVXc7N9gURyZULshriDt350w6nhN7Z3w==",
|
||||||
|
"requires": {
|
||||||
|
"@fingerprintjs/fingerprintjs": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"abbrev": {
|
"abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
|||||||
@ -12,7 +12,9 @@
|
|||||||
"start:local": "vite --host --mode localhost",
|
"start:local": "vite --host --mode localhost",
|
||||||
"start:prod": "vite --host --mode production",
|
"start:prod": "vite --host --mode production",
|
||||||
"build:dev": "tsc && vite build --mode develop",
|
"build:dev": "tsc && vite build --mode develop",
|
||||||
"build:prod": "tsc && vite build --mode production"
|
"build:prod": "tsc && vite build --mode production",
|
||||||
|
"link:shared": "npm link @wit-lab-llc/frontend-shared",
|
||||||
|
"unlink:shared": "npm unlink @wit-lab-llc/frontend-shared && npm install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
@ -24,6 +26,7 @@
|
|||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"@smakss/react-scroll-direction": "^4.0.4",
|
"@smakss/react-scroll-direction": "^4.0.4",
|
||||||
"@unleash/proxy-client-react": "^4.5.2",
|
"@unleash/proxy-client-react": "^4.5.2",
|
||||||
|
"@wit-lab-llc/frontend-shared": "^1.0.4",
|
||||||
"apng-js": "^1.1.1",
|
"apng-js": "^1.1.1",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
"framer-motion": "^11.0.8",
|
"framer-motion": "^11.0.8",
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { ICreateAuthorizeUser } from "./User";
|
|||||||
import { ELocalesPlacement } from "@/locales";
|
import { ELocalesPlacement } from "@/locales";
|
||||||
import { Currency } from "@/components/PaymentTable/Price";
|
import { Currency } from "@/components/PaymentTable/Price";
|
||||||
import { PeriodType } from "@/hooks/translations";
|
import { PeriodType } from "@/hooks/translations";
|
||||||
|
import type { SessionFingerprintData, SessionFacebookData } from "@wit-lab-llc/frontend-shared";
|
||||||
|
|
||||||
export interface PayloadCreate {
|
export interface PayloadCreate {
|
||||||
feature: string, // Type: string
|
feature: string, // Type: string
|
||||||
@ -14,7 +15,13 @@ export interface PayloadCreate {
|
|||||||
sign: boolean, // Type: boolean
|
sign: boolean, // Type: boolean
|
||||||
signDate: string | undefined, // Type: string, ISO Date
|
signDate: string | undefined, // Type: string, ISO Date
|
||||||
utm: IUTM, // Type: { [key: string]: string } - Optional
|
utm: IUTM, // Type: { [key: string]: string } - Optional
|
||||||
domain: string // Type: string
|
anonymousId?: string,
|
||||||
|
query?: Record<string, string>,
|
||||||
|
landingQuery?: Record<string, string>,
|
||||||
|
lastActivityAt?: string,
|
||||||
|
domain: string, // Type: string
|
||||||
|
fingerprint?: SessionFingerprintData, // Fingerprint data from library
|
||||||
|
facebookData?: SessionFacebookData // Facebook data for Conversions API
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PayloadUpdate {
|
export interface PayloadUpdate {
|
||||||
@ -22,6 +29,10 @@ export interface PayloadUpdate {
|
|||||||
data: {
|
data: {
|
||||||
feature: string, // Type: string
|
feature: string, // Type: string
|
||||||
|
|
||||||
|
anonymousId?: string,
|
||||||
|
query?: Record<string, string>,
|
||||||
|
lastActivityAt?: string,
|
||||||
|
|
||||||
profile?: Partial<ICreateAuthorizeUser>;
|
profile?: Partial<ICreateAuthorizeUser>;
|
||||||
partner?: Partial<Exclude<ICreateAuthorizeUser, "relationship_status">>;
|
partner?: Partial<Exclude<ICreateAuthorizeUser, "relationship_status">>;
|
||||||
answers?: Partial<IAnswersSessionPalmistry | IAnswersSessionChats | IAnswersSessionCompatibilityV2 | IAnswersSessionCompatibilityV3 | IAnswersSessionCompatibilityV4>;
|
answers?: Partial<IAnswersSessionPalmistry | IAnswersSessionChats | IAnswersSessionCompatibilityV2 | IAnswersSessionCompatibilityV3 | IAnswersSessionCompatibilityV4>;
|
||||||
@ -160,7 +171,9 @@ export interface ResponseGetLocale {
|
|||||||
export interface ResponseGetPixels {
|
export interface ResponseGetPixels {
|
||||||
status: "success" | string,
|
status: "success" | string,
|
||||||
data: {
|
data: {
|
||||||
fb?: string[];
|
facebook_pixel?: string[];
|
||||||
|
google_analytics?: string[];
|
||||||
|
yandex_metrica?: string[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,33 @@ import { PayloadUpdate, ResponseCreate } from "@/api/resources/Session";
|
|||||||
import { ESourceAuthorization } from "@/api/resources/User";
|
import { ESourceAuthorization } from "@/api/resources/User";
|
||||||
import { getClientTimezone, language } from "@/locales";
|
import { getClientTimezone, language } from "@/locales";
|
||||||
import { actions, selectors } from "@/store";
|
import { actions, selectors } from "@/store";
|
||||||
import { useCallback, useMemo, useState } from "react"
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
FingerprintCollector,
|
||||||
|
FacebookCollector,
|
||||||
|
type SessionFingerprintData,
|
||||||
|
type SessionFacebookData,
|
||||||
|
getOrCreateAnonymousId,
|
||||||
|
} from "@wit-lab-llc/frontend-shared";
|
||||||
|
import { parseQueryParams } from "@/services/url";
|
||||||
|
|
||||||
|
let fingerprintCollectorInstance: FingerprintCollector | null = null;
|
||||||
|
let facebookCollectorInstance: FacebookCollector | null = null;
|
||||||
|
|
||||||
|
function getFingerprintCollector(): FingerprintCollector {
|
||||||
|
if (!fingerprintCollectorInstance) {
|
||||||
|
fingerprintCollectorInstance = new FingerprintCollector();
|
||||||
|
}
|
||||||
|
return fingerprintCollectorInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFacebookCollector(): FacebookCollector {
|
||||||
|
if (!facebookCollectorInstance) {
|
||||||
|
facebookCollectorInstance = new FacebookCollector();
|
||||||
|
}
|
||||||
|
return facebookCollectorInstance;
|
||||||
|
}
|
||||||
|
|
||||||
export const useSession = () => {
|
export const useSession = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -19,16 +43,119 @@ export const useSession = () => {
|
|||||||
const timezone = getClientTimezone();
|
const timezone = getClientTimezone();
|
||||||
|
|
||||||
const [isError, setIsError] = useState(false);
|
const [isError, setIsError] = useState(false);
|
||||||
|
const [fingerprintCollector] = useState(() => getFingerprintCollector());
|
||||||
|
const [facebookCollector] = useState(() => getFacebookCollector());
|
||||||
|
const dataCollectedRef = useRef(false);
|
||||||
|
|
||||||
|
const visitTtlMs = 30 * 60 * 1000;
|
||||||
|
|
||||||
|
const getVisitStorageKey = useCallback((source: ESourceAuthorization) => {
|
||||||
|
return `${source}_visit`;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const readVisit = useCallback((source: ESourceAuthorization) => {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(getVisitStorageKey(source));
|
||||||
|
if (!raw) return null;
|
||||||
|
return JSON.parse(raw) as {
|
||||||
|
sessionId: string;
|
||||||
|
startedAt: number;
|
||||||
|
lastActivityAt: number;
|
||||||
|
anonymousId?: string;
|
||||||
|
landingQuery?: Record<string, string>;
|
||||||
|
lastQuery?: Record<string, string>;
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, [getVisitStorageKey]);
|
||||||
|
|
||||||
|
const writeVisit = useCallback((source: ESourceAuthorization, visit: {
|
||||||
|
sessionId: string;
|
||||||
|
startedAt: number;
|
||||||
|
lastActivityAt: number;
|
||||||
|
anonymousId?: string;
|
||||||
|
landingQuery?: Record<string, string>;
|
||||||
|
lastQuery?: Record<string, string>;
|
||||||
|
}) => {
|
||||||
|
localStorage.setItem(getVisitStorageKey(source), JSON.stringify(visit));
|
||||||
|
localStorage.setItem(`${source}_sessionId`, visit.sessionId);
|
||||||
|
}, [getVisitStorageKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === "undefined" || dataCollectedRef.current) return;
|
||||||
|
dataCollectedRef.current = true;
|
||||||
|
|
||||||
|
Promise.all([
|
||||||
|
fingerprintCollector.collect().catch(() => null),
|
||||||
|
Promise.resolve(facebookCollector.collect()),
|
||||||
|
]).then(() => {
|
||||||
|
console.log("[useSession] Fingerprint and Facebook data collected");
|
||||||
|
});
|
||||||
|
}, [fingerprintCollector, facebookCollector]);
|
||||||
|
|
||||||
const createSession = useCallback(async (source: ESourceAuthorization): Promise<ResponseCreate> => {
|
const createSession = useCallback(async (source: ESourceAuthorization): Promise<ResponseCreate> => {
|
||||||
if (session[source]?.length) {
|
const nowMs = Date.now();
|
||||||
localStorage.setItem(`${source}_sessionId`, session[source]);
|
const existingVisit = readVisit(source);
|
||||||
return {
|
if (existingVisit && nowMs - existingVisit.lastActivityAt <= visitTtlMs) {
|
||||||
sessionId: session[source],
|
const nextQuery = parseQueryParams();
|
||||||
status: "old"
|
const nextAnonymousId = existingVisit.anonymousId ?? getOrCreateAnonymousId();
|
||||||
}
|
writeVisit(source, {
|
||||||
|
...existingVisit,
|
||||||
|
lastActivityAt: nowMs,
|
||||||
|
lastQuery: nextQuery,
|
||||||
|
anonymousId: nextAnonymousId,
|
||||||
|
});
|
||||||
|
dispatch(actions.session.update({ session: existingVisit.sessionId, source }));
|
||||||
|
localStorage.setItem(`${source}_sessionId`, existingVisit.sessionId);
|
||||||
|
return { sessionId: existingVisit.sessionId, status: "old" };
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
let fingerprint: SessionFingerprintData | undefined;
|
||||||
|
try {
|
||||||
|
const fpData = await fingerprintCollector.getOrCollect();
|
||||||
|
if (fpData) {
|
||||||
|
const payload = fingerprintCollector.toServerPayload();
|
||||||
|
fingerprint = {
|
||||||
|
visitorId: fpData.visitorId,
|
||||||
|
confidence: fpData.confidence,
|
||||||
|
collectedAt: fpData.collectedAt,
|
||||||
|
...payload,
|
||||||
|
} as SessionFingerprintData;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("[useSession] Failed to collect fingerprint:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
let facebookData: SessionFacebookData | undefined;
|
||||||
|
try {
|
||||||
|
const fbData = facebookCollector.getData() || facebookCollector.collect();
|
||||||
|
if (fbData) {
|
||||||
|
facebookData = {
|
||||||
|
fbp: fbData.fbp ?? undefined,
|
||||||
|
fbc: fbData.fbc ?? undefined,
|
||||||
|
fbclid: fbData.fbclid ?? undefined,
|
||||||
|
externalId: fingerprint?.visitorId,
|
||||||
|
landingPage: fbData.landingPage ?? undefined,
|
||||||
|
referrer: fbData.referrer,
|
||||||
|
clientUserAgent: fbData.userAgent,
|
||||||
|
eventSourceUrl: fbData.currentUrl,
|
||||||
|
browserLanguage: fbData.browserLanguage,
|
||||||
|
screenResolution: fbData.screenResolution,
|
||||||
|
viewportSize: fbData.viewportSize,
|
||||||
|
colorDepth: fbData.colorDepth,
|
||||||
|
devicePixelRatio: fbData.devicePixelRatio,
|
||||||
|
touchSupport: fbData.touchSupport,
|
||||||
|
cookiesEnabled: fbData.cookiesEnabled,
|
||||||
|
doNotTrack: fbData.doNotTrack,
|
||||||
|
collectedAt: fbData.collectedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("[useSession] Failed to collect Facebook data:", e);
|
||||||
|
}
|
||||||
|
|
||||||
const sessionParams = {
|
const sessionParams = {
|
||||||
feature,
|
feature,
|
||||||
locale: language,
|
locale: language,
|
||||||
@ -37,7 +164,13 @@ export const useSession = () => {
|
|||||||
sign: checked,
|
sign: checked,
|
||||||
signDate: dateOfCheck.length ? dateOfCheck : undefined,
|
signDate: dateOfCheck.length ? dateOfCheck : undefined,
|
||||||
utm,
|
utm,
|
||||||
domain: window.location.hostname
|
anonymousId: getOrCreateAnonymousId(),
|
||||||
|
query: parseQueryParams(),
|
||||||
|
landingQuery: parseQueryParams(),
|
||||||
|
lastActivityAt: new Date().toISOString(),
|
||||||
|
domain: window.location.hostname,
|
||||||
|
fingerprint,
|
||||||
|
facebookData,
|
||||||
};
|
};
|
||||||
console.log('Creating session with parameters:', sessionParams);
|
console.log('Creating session with parameters:', sessionParams);
|
||||||
const sessionFromServer = await api.createSession(sessionParams);
|
const sessionFromServer = await api.createSession(sessionParams);
|
||||||
@ -48,6 +181,15 @@ export const useSession = () => {
|
|||||||
source
|
source
|
||||||
}));
|
}));
|
||||||
localStorage.setItem(`${source}_sessionId`, sessionFromServer.sessionId);
|
localStorage.setItem(`${source}_sessionId`, sessionFromServer.sessionId);
|
||||||
|
const q = parseQueryParams();
|
||||||
|
writeVisit(source, {
|
||||||
|
sessionId: sessionFromServer.sessionId,
|
||||||
|
startedAt: Date.now(),
|
||||||
|
lastActivityAt: Date.now(),
|
||||||
|
anonymousId: sessionParams.anonymousId,
|
||||||
|
landingQuery: q,
|
||||||
|
lastQuery: q,
|
||||||
|
});
|
||||||
return sessionFromServer
|
return sessionFromServer
|
||||||
}
|
}
|
||||||
console.error('Session creation failed - invalid response:', sessionFromServer);
|
console.error('Session creation failed - invalid response:', sessionFromServer);
|
||||||
@ -64,7 +206,7 @@ export const useSession = () => {
|
|||||||
sessionId: ""
|
sessionId: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [api, checked, dateOfCheck, dispatch, feature, session, timezone, utm])
|
}, [api, checked, dateOfCheck, dispatch, feature, session, timezone, utm, fingerprintCollector, facebookCollector, readVisit, visitTtlMs, writeVisit])
|
||||||
|
|
||||||
const updateSession = useCallback(async (data: Omit<PayloadUpdate["data"], "feature">, source: ESourceAuthorization, sessionId?: string) => {
|
const updateSession = useCallback(async (data: Omit<PayloadUpdate["data"], "feature">, source: ESourceAuthorization, sessionId?: string) => {
|
||||||
try {
|
try {
|
||||||
@ -73,22 +215,39 @@ export const useSession = () => {
|
|||||||
sessionId: _sessionId,
|
sessionId: _sessionId,
|
||||||
data: {
|
data: {
|
||||||
feature,
|
feature,
|
||||||
|
anonymousId: getOrCreateAnonymousId(),
|
||||||
|
query: parseQueryParams(),
|
||||||
|
lastActivityAt: new Date().toISOString(),
|
||||||
...data
|
...data
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_sessionId) {
|
||||||
|
const nowMs = Date.now();
|
||||||
|
const existingVisit = readVisit(source);
|
||||||
|
if (existingVisit && existingVisit.sessionId === _sessionId) {
|
||||||
|
writeVisit(source, {
|
||||||
|
...existingVisit,
|
||||||
|
lastActivityAt: nowMs,
|
||||||
|
lastQuery: parseQueryParams(),
|
||||||
|
anonymousId: getOrCreateAnonymousId(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}, [api, feature, session])
|
}, [api, feature, session, readVisit, writeVisit])
|
||||||
|
|
||||||
const deleteSession = useCallback(async (source: ESourceAuthorization) => {
|
const deleteSession = useCallback(async (source: ESourceAuthorization) => {
|
||||||
localStorage.removeItem(`${source}_sessionId`);
|
localStorage.removeItem(`${source}_sessionId`);
|
||||||
|
localStorage.removeItem(getVisitStorageKey(source));
|
||||||
dispatch(actions.session.update({
|
dispatch(actions.session.update({
|
||||||
session: "",
|
session: "",
|
||||||
source
|
source
|
||||||
}))
|
}))
|
||||||
}, [dispatch])
|
}, [dispatch, getVisitStorageKey])
|
||||||
|
|
||||||
return useMemo(() => ({
|
return useMemo(() => ({
|
||||||
session,
|
session,
|
||||||
|
|||||||
11
src/init.tsx
11
src/init.tsx
@ -26,12 +26,19 @@ import { InitializationProvider } from "./initialization";
|
|||||||
import { getSourceByPathname } from "./utils/source.utils";
|
import { getSourceByPathname } from "./utils/source.utils";
|
||||||
import { parseQueryParams } from "./services/url";
|
import { parseQueryParams } from "./services/url";
|
||||||
import { actions } from "./store";
|
import { actions } from "./store";
|
||||||
|
import { initWitLib } from "@wit-lab-llc/frontend-shared";
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.js`;
|
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.js`;
|
||||||
|
|
||||||
const environments = import.meta.env;
|
const environments = import.meta.env;
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
|
// Initialize WIT shared library for fingerprint and facebook data collection
|
||||||
|
initWitLib({
|
||||||
|
baseUrl: environments.AURA_DAPI_HOST || '',
|
||||||
|
debug: environments.MODE !== 'production',
|
||||||
|
});
|
||||||
|
|
||||||
// Parse UTM parameters from URL at initialization
|
// Parse UTM parameters from URL at initialization
|
||||||
const utm = parseQueryParams();
|
const utm = parseQueryParams();
|
||||||
console.log('UTM parameters parsed at init:', utm);
|
console.log('UTM parameters parsed at init:', utm);
|
||||||
@ -105,11 +112,11 @@ const init = async () => {
|
|||||||
locale: getDefaultLocaleByLanguage(language),
|
locale: getDefaultLocaleByLanguage(language),
|
||||||
});
|
});
|
||||||
|
|
||||||
localStorage.setItem('fb_pixels', JSON.stringify(pixels?.data?.fb || []));
|
localStorage.setItem('fb_pixels', JSON.stringify(pixels?.data?.facebook_pixel || []));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{!!pixels?.data?.fb?.length && <HeadData pixels={pixels.data.fb} />}
|
{!!pixels?.data?.facebook_pixel?.length && <HeadData pixels={pixels.data.facebook_pixel} />}
|
||||||
<I18nextProvider i18n={i18nextInstance}>
|
<I18nextProvider i18n={i18nextInstance}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user