diff --git a/environments/.env.develop b/environments/.env.develop index b3a1374..767aa5a 100644 --- a/environments/.env.develop +++ b/environments/.env.develop @@ -6,4 +6,7 @@ AURA_PREFIX=api/v1 AURA_OPEN_AI_HOST=https://api.openai.com AURA_OPEN_AI_PREFIX=v1 AURA_YANDEX_COUNTER_NUMBER=95799066 -AURA_PERSONAL_VIDEO_TIME_LIMIT=180 \ No newline at end of file +AURA_PERSONAL_VIDEO_TIME_LIMIT=180 +AURA_GA_MEASUREMENT_ID=G-ECQDS5X0EH +AURA_UNLEASH_URL=https://unleash.admin.witapps.us/api/frontend +AURA_UNLEASH_CLIENT_KEY=*:development.7f714f98ed6e9128ae3c99906267292a4e34280d1a16becd2f0794b6 \ No newline at end of file diff --git a/environments/.env.production b/environments/.env.production index abb5667..7495b38 100644 --- a/environments/.env.production +++ b/environments/.env.production @@ -6,4 +6,7 @@ AURA_PREFIX=api/v1 AURA_OPEN_AI_HOST=https://api.openai.com AURA_OPEN_AI_PREFIX=v1 AURA_YANDEX_COUNTER_NUMBER=95799066 -AURA_PERSONAL_VIDEO_TIME_LIMIT=100 \ No newline at end of file +AURA_PERSONAL_VIDEO_TIME_LIMIT=100 +AURA_GA_MEASUREMENT_ID=G-4N17LL3BB5 +AURA_UNLEASH_URL=https://unleash.admin.witapps.us/api/frontend +AURA_UNLEASH_CLIENT_KEY=*:production.381ec8a37c977e928ff5ea8809fd943b7caff4232af6df8443903203 \ No newline at end of file diff --git a/index.html b/index.html index cf9ae09..fde9a0a 100755 --- a/index.html +++ b/index.html @@ -324,14 +324,14 @@ - +
diff --git a/package-lock.json b/package-lock.json index 1348350..1dd4a22 100755 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@smakss/react-scroll-direction": "^4.0.4", "@stripe/react-stripe-js": "^2.3.1", "@stripe/stripe-js": "^2.1.9", + "@unleash/proxy-client-react": "^4.5.2", "apng-js": "^1.1.1", "core-js": "^3.37.1", "framer-motion": "^11.0.8", @@ -41,6 +42,7 @@ "slick-carousel": "^1.8.1", "socket.io-client": "^4.8.1", "unique-names-generator": "^4.7.1", + "unleash-proxy-client": "^3.7.3", "yandex-metrica-ab-react": "^1.6.1" }, "devDependencies": { @@ -2112,6 +2114,17 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@unleash/proxy-client-react": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@unleash/proxy-client-react/-/proxy-client-react-4.5.2.tgz", + "integrity": "sha512-mxml+6+hH64qpTml768Suf955n5YttCZgmsw1TJYmUJ1pa+X+dBYvAM0Mdg8L+uUU7hz1xFrOeWtgtJRe+17eQ==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "unleash-proxy-client": "^3.7.3" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.0.tgz", @@ -5163,6 +5176,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -5259,6 +5277,15 @@ "node": ">=8" } }, + "node_modules/unleash-proxy-client": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/unleash-proxy-client/-/unleash-proxy-client-3.7.3.tgz", + "integrity": "sha512-Cd7ovrhAIpwveNFdtpzs7HO0WeArC2fbjIVGL2Cjza8bHD+jJ1JbSuy3tFuKvvUkbVKq/EGV0RgosEa/3UVLgg==", + "dependencies": { + "tiny-emitter": "^2.1.0", + "uuid": "^9.0.1" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -5312,6 +5339,18 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "optional": true }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "4.3.8", "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", @@ -6800,6 +6839,12 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@unleash/proxy-client-react": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@unleash/proxy-client-react/-/proxy-client-react-4.5.2.tgz", + "integrity": "sha512-mxml+6+hH64qpTml768Suf955n5YttCZgmsw1TJYmUJ1pa+X+dBYvAM0Mdg8L+uUU7hz1xFrOeWtgtJRe+17eQ==", + "requires": {} + }, "@vitejs/plugin-react": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.0.tgz", @@ -8995,6 +9040,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -9060,6 +9110,15 @@ "resolved": "https://registry.npmjs.org/unique-names-generator/-/unique-names-generator-4.7.1.tgz", "integrity": "sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow==" }, + "unleash-proxy-client": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/unleash-proxy-client/-/unleash-proxy-client-3.7.3.tgz", + "integrity": "sha512-Cd7ovrhAIpwveNFdtpzs7HO0WeArC2fbjIVGL2Cjza8bHD+jJ1JbSuy3tFuKvvUkbVKq/EGV0RgosEa/3UVLgg==", + "requires": { + "tiny-emitter": "^2.1.0", + "uuid": "^9.0.1" + } + }, "update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -9091,6 +9150,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "optional": true }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + }, "vite": { "version": "4.3.8", "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", diff --git a/package.json b/package.json index 36fa688..d14bbe6 100755 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@smakss/react-scroll-direction": "^4.0.4", "@stripe/react-stripe-js": "^2.3.1", "@stripe/stripe-js": "^2.1.9", + "@unleash/proxy-client-react": "^4.5.2", "apng-js": "^1.1.1", "core-js": "^3.37.1", "framer-motion": "^11.0.8", @@ -48,6 +49,7 @@ "slick-carousel": "^1.8.1", "socket.io-client": "^4.8.1", "unique-names-generator": "^4.7.1", + "unleash-proxy-client": "^3.7.3", "yandex-metrica-ab-react": "^1.6.1" }, "devDependencies": { diff --git a/src/api/api.ts b/src/api/api.ts index aaaac6f..624ef31 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -97,6 +97,7 @@ const api = { createSession: createMethod(Session.createRequest), updateSession: createMethod(Session.updateRequest), getLocaleTranslations: createMethod(Session.getLocaleRequest), + getPixels: createMethod(Session.getPixelsRequest), // Chats getChatsCategories: createMethod(ChatsCategories.getRequest), getChatMessages: createMethod(ChatMessages.getRequest), diff --git a/src/api/resources/Session.ts b/src/api/resources/Session.ts index 9c63001..c42d60a 100644 --- a/src/api/resources/Session.ts +++ b/src/api/resources/Session.ts @@ -122,6 +122,13 @@ export interface ResponseGetLocale { } } +export interface ResponseGetPixels { + status: "success" | string, + data: { + fb?: string[]; + } +} + export const createRequest = (data: PayloadCreate) => { const url = new URL(routes.server.createSession()); const body = JSON.stringify(data); @@ -155,4 +162,24 @@ export const getLocaleRequest = (data: PayloadGetLocale) => { body, headers: getBaseHeaders() }); +}; + +export interface PayloadGetPixels { + domain: string; + source: string; + locale: string; +} + +export const getPixelsRequest = ({ domain, source, locale }: PayloadGetPixels) => { + const url = new URL(routes.server.getPixels()); + const query = new URLSearchParams({ + domain, + source, + locale + }); + url.search = query.toString(); + return new Request(url, { + method: "GET", + headers: getBaseHeaders() + }); }; \ No newline at end of file diff --git a/src/api/utils.ts b/src/api/utils.ts index ec574b2..d647000 100644 --- a/src/api/utils.ts +++ b/src/api/utils.ts @@ -5,32 +5,12 @@ import { ApiError, buildUnknownError, } from "./errors"; -import { ESourceAuthorization } from "./resources/User"; +import { getSourceByPathname } from "@/utils/source.utils"; export function createMethod(createRequest: (payload: P) => Request) { return async (payload: P): Promise => { const request = createRequest(payload); - let source = ESourceAuthorization["aura.main.new"]; - - if (location.pathname.includes("/palmistry")) { - source = ESourceAuthorization["aura.palmistry"]; - } - - if (location.pathname.includes("/v1/palmistry")) { - source = ESourceAuthorization["aura.palmistry.new"]; - } - - if (location.pathname.includes("/chats")) { - source = ESourceAuthorization["aura.chats"]; - } - - if (location.pathname.includes("/v2/compatibility")) { - source = ESourceAuthorization["aura.compatibility.v2"]; - } - - if (location.pathname.includes("/v3/compatibility")) { - source = ESourceAuthorization["aura.compatibility.v3"]; - } + const source = getSourceByPathname() const sessionId = localStorage.getItem(`${source}_sessionId`); diff --git a/src/components/App/index.tsx b/src/components/App/index.tsx index 4c5b336..fa3c3b4 100755 --- a/src/components/App/index.tsx +++ b/src/components/App/index.tsx @@ -141,12 +141,18 @@ import { useScrollToTop } from "@/hooks/useScrollToTop"; import CompatibilityV2Routes from "@/routerComponents/Compatibility/v2"; import AnonymousRoutes from "@/routerComponents/Anonymous"; import CompatibilityV3Routes from "@/routerComponents/Compatibility/v3"; +import { useUnleashClient } from "@unleash/proxy-client-react"; +import { useSession } from "@/hooks/session/useSession"; +import { getSourceByPathname } from "@/utils/source.utils"; const isProduction = import.meta.env.MODE === "production"; +const gaMeasurementId = import.meta.env.AURA_GA_MEASUREMENT_ID; -if (isProduction) { - ReactGA.initialize("G-00S3ECJGSJ"); -} +// if (isProduction) { +ReactGA.initialize(gaMeasurementId); +// } else { +// ReactGA.initialize("G-ECQDS5X0EH"); +// } function App(): JSX.Element { const location = useLocation(); @@ -160,10 +166,34 @@ function App(): JSX.Element { // const api = useApi(); const dispatch = useDispatch(); const { user } = useAuth(); + const { session } = useSession(); const [searchParams] = useSearchParams(); // const jwtToken = searchParams.get("token"); const isForce = searchParams.get("force"); const subscriptionStatus = useSelector(selectors.selectStatus); + const unleashClient = useUnleashClient(); + const source = getSourceByPathname(); + + // update Unleash context + useEffect(() => { + if (!unleashClient) return; + if (user?.id) { + unleashClient.updateContext({ + userId: user?.id || undefined, + properties: { + source + } + }); + } + if (session?.[source]) { + unleashClient.updateContext({ + sessionId: session?.[source] || undefined, + properties: { + source + } + }); + } + }, [user, session, source, unleashClient]); // parse utm query useEffect(() => { diff --git a/src/components/CompatibilityV2/pages/Gender/index.tsx b/src/components/CompatibilityV2/pages/Gender/index.tsx index 9752826..46b0bf0 100644 --- a/src/components/CompatibilityV2/pages/Gender/index.tsx +++ b/src/components/CompatibilityV2/pages/Gender/index.tsx @@ -20,6 +20,7 @@ import { EGender, ESourceAuthorization } from "@/api/resources/User"; import AlreadyHaveAccount from "@/components/ui/AlreadyHaveAccount"; import Answer from "../../components/Answer"; import Loader, { LoaderColor } from "@/components/Loader"; +import { useUnleash } from "@/hooks/ab/unleash/useUnleash"; function GenderPage() { const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); @@ -38,7 +39,12 @@ function GenderPage() { }); const { flags, ready } = useMetricABFlags(); - const pageType = flags?.genderPageType?.[0] || "v2"; + + const { isReady, variant: genderPageType } = useUnleash({ + flag: "genderPageType" + }); + + const pageType = flags?.genderPageType?.[0] || genderPageType || "v2"; const genderButtonIcon = flags?.genderButtonIcon?.[0] || "hide"; const localGenders = genders.map((gender) => ({ @@ -76,6 +82,7 @@ function GenderPage() { metricService.userParams({ gender: genders.find((g) => g.id === gender)?.name, }); + const session = await createSession( ESourceAuthorization["aura.compatibility.v2"] ); @@ -103,7 +110,7 @@ function GenderPage() { } }, [gender, handleNext, isSelected, privacyPolicyChecked]); - if (!ready) return ; + if (!ready || !isReady) return ; switch (pageType) { case "v0": diff --git a/src/env.d.ts b/src/env.d.ts index e22e3a1..479c1ec 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -7,5 +7,8 @@ interface ImportMetaEnv { AURA_OPEN_AI_HOST: string, AURA_OPEN_AI_PREFIX: string, AURA_YANDEX_COUNTER_NUMBER: string, - AURA_PERSONAL_VIDEO_TIME_LIMIT: string + AURA_PERSONAL_VIDEO_TIME_LIMIT: string, + AURA_GA_MEASUREMENT_ID: string, + AURA_UNLEASH_URL: string, + AURA_UNLEASH_CLIENT_KEY: string, } \ No newline at end of file diff --git a/src/hooks/ab/unleash/useUnleash.ts b/src/hooks/ab/unleash/useUnleash.ts new file mode 100644 index 0000000..b020b56 --- /dev/null +++ b/src/hooks/ab/unleash/useUnleash.ts @@ -0,0 +1,47 @@ +import { useFlagsStatus, useUnleashClient, useVariant } from "@unleash/proxy-client-react"; +import { useEffect, useMemo } from "react"; + +interface IUseUnleashProps { + flag: string; +} + +export const useUnleash = ({ + flag +}: IUseUnleashProps) => { + const { flagsReady } = useFlagsStatus(); + const unleashClient = useUnleashClient(); + const abVariant = useVariant(flag); + // const isEnabled = useFlag(flag); + + const isReady = useMemo(() => { + return flagsReady ?? true; + }, [flagsReady]); + + const variant = useMemo(() => { + return abVariant?.payload?.value; + }, [abVariant]); + + useEffect(() => { + unleashClient.on("impression", (impressionEvent: any) => { + if ("enabled" in impressionEvent && impressionEvent.enabled) { + window.gtag?.("event", "experiment_impression", { + app_name: impressionEvent.context.appName, + feature: impressionEvent.featureName, + treatment: impressionEvent.variant, // in case we use a variant for the control treatment + }); + } + }); + + return () => { + unleashClient.off("impression"); + } + }, [unleashClient]); + + return useMemo(() => ({ + isReady, + variant + }), [ + isReady, + variant + ]) +}; \ No newline at end of file diff --git a/src/hooks/session/useSession.ts b/src/hooks/session/useSession.ts index e5ed7a7..11030b1 100644 --- a/src/hooks/session/useSession.ts +++ b/src/hooks/session/useSession.ts @@ -3,7 +3,7 @@ import { PayloadUpdate, ResponseCreate } from "@/api/resources/Session"; import { ESourceAuthorization } from "@/api/resources/User"; import { getClientTimezone, language } from "@/locales"; import { actions, selectors } from "@/store"; -import { useCallback, useMemo } from "react" +import { useCallback, useMemo, useState } from "react" import { useDispatch, useSelector } from "react-redux"; @@ -15,9 +15,11 @@ export const useSession = () => { const feature = useSelector(selectors.selectFeature) const { checked, dateOfCheck } = useSelector(selectors.selectPrivacyPolicy); const utm = useSelector(selectors.selectUTM); - + const timezone = getClientTimezone(); + const [isError, setIsError] = useState(false); + const createSession = useCallback(async (source: ESourceAuthorization): Promise => { if (session[source]?.length) return { sessionId: session[source], @@ -39,10 +41,16 @@ export const useSession = () => { source })); localStorage.setItem(`${source}_sessionId`, session.sessionId); + return session + } + setIsError(true); + return { + status: "error", + sessionId: "" } - return session } catch (error) { console.log(error) + setIsError(true); return { status: "error", sessionId: "" @@ -76,13 +84,15 @@ export const useSession = () => { return useMemo(() => ({ session, + isError, createSession, updateSession, deleteSession }), [ + session, + isError, createSession, deleteSession, - session, updateSession ]) } \ No newline at end of file diff --git a/src/init.tsx b/src/init.tsx index 1ce3652..50091d2 100755 --- a/src/init.tsx +++ b/src/init.tsx @@ -23,9 +23,7 @@ import { pdfjs } from "react-pdf"; import HeadData from "./utils/Helmet"; import Clarity from '@microsoft/clarity'; import { InitializationProvider } from "./initialization"; -import HeadDataPalmDomen from "./utils/HelmetPalm"; -import HeadDataCompatibilityDomen from "./utils/HelmetComp"; -import HeadDataCompatibilityDomen1 from "./utils/HelmetComp1"; +import { getSourceByPathname } from "./utils/source.utils"; pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.js`; @@ -89,12 +87,21 @@ const init = async () => { // }; // googleManager(); + const source = getSourceByPathname() + + const pixels = await api.getPixels({ + domain: window.location.hostname, + source, + locale: getDefaultLocaleByLanguage(language), + }); + return ( - {isProduction && window.location.hostname === "aura.witapps.us" && } + {!!pixels?.data?.fb?.length && } + {/* {isProduction && window.location.hostname === "aura.witapps.us" && } {isProduction && window.location.hostname === "aurastellar.us" && } {isProduction && window.location.hostname === "auraself.com" && } - {isProduction && window.location.hostname === "astralaura.us" && } + {isProduction && window.location.hostname === "astralaura.us" && } */} diff --git a/src/initialization/index.tsx b/src/initialization/index.tsx index 353c752..5025522 100644 --- a/src/initialization/index.tsx +++ b/src/initialization/index.tsx @@ -1,14 +1,28 @@ import { useApi } from "@/api"; +import { ESourceAuthorization } from "@/api/resources/User"; import { useAuth } from "@/auth/useAuth"; +import { useSession } from "@/hooks/session/useSession"; +import metricService from "@/services/metric/metricService"; import { actions } from "@/store"; +import { getSourceByPathname } from "@/utils/source.utils"; import { useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import { useLocation, useSearchParams } from "react-router-dom"; +import { FlagProvider } from '@unleash/proxy-client-react'; interface InitializationProviderProps { children: React.ReactNode; } +const availableSourcesForSession = [ + ESourceAuthorization["aura.palmistry"], + ESourceAuthorization["aura.palmistry.new"], + ESourceAuthorization["aura.chats"], + ESourceAuthorization["aura.compatibility.v2"], + ESourceAuthorization["aura.compatibility.v3"], + ESourceAuthorization["aura.test.payment"] +] + export function InitializationProvider({ children }: InitializationProviderProps) { const location = useLocation(); const [isInitialized, setIsInitialized] = useState(false); @@ -17,6 +31,25 @@ export function InitializationProvider({ children }: InitializationProviderProps const api = useApi(); const { signUp, logout, token, user } = useAuth(); const dispatch = useDispatch(); + const { isError: isErrorSession, session, createSession } = useSession() + const source = getSourceByPathname(); + + useEffect(() => { + const createSessionBySource = async () => { + if (!availableSourcesForSession.includes(source)) { + return; + } + const session = await createSession( + source + ); + if (session?.sessionId?.length) { + metricService.userParams({ + sessionId: session.sessionId, + }); + } + } + createSessionBySource(); + }, []) useEffect(() => { const initialize = async () => { @@ -67,9 +100,20 @@ export function InitializationProvider({ children }: InitializationProviderProps // eslint-disable-next-line react-hooks/exhaustive-deps }, [dispatch, api, token, location.pathname]); - if (!isInitialized) { + if (!isInitialized || (!session?.[source] && !isErrorSession)) { return null; } - return <>{children}; + const config = { + url: import.meta.env.AURA_UNLEASH_URL, // Your front-end API URL or the Unleash proxy's URL (https:///proxy) + clientKey: import.meta.env.AURA_UNLEASH_CLIENT_KEY, // A client-side API token OR one of your proxy's designated client keys (previously known as proxy secrets) + refreshInterval: 15, // How often (in seconds) the client should poll the proxy for updates + appName: 'aura', // The name of your application. It's only used for identifying your application + }; + + return <> + + {children} + + ; } \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index f296332..8436714 100755 --- a/src/routes.ts +++ b/src/routes.ts @@ -509,6 +509,7 @@ const routes = { createSession: () => [dApiHost, dApiPrefix, "session"].join("/"), updateSession: (id: string) => [dApiHost, dApiPrefix, "session", id].join("/"), getLocale: () => [dApiHost, dApiPrefix, "session", "locale"].join("/"), + getPixels: () => [dApiHost, dApiPrefix, "session", "pixels"].join("/"), // Chats getChatsCategories: () => [dApiHost, "chats", "categories"].join("/"), diff --git a/src/services/metric/metricService.ts b/src/services/metric/metricService.ts index b50044b..6f0ddb2 100644 --- a/src/services/metric/metricService.ts +++ b/src/services/metric/metricService.ts @@ -58,6 +58,12 @@ export enum EGoals { // FB LEAD = "Lead", PURCHASE = "Purchase", + + // Split + SPLIT_CHOOSE_GENDER = "SplitChooseGender", + + // Unleash + UNLEASH_CHOOSE_GENDER = "UnleashChooseGender", } export enum EFlags { @@ -68,7 +74,8 @@ export enum EFlags { export enum EMetrics { YANDEX = "Yandex", KLAVIYO = "Klaviyo", - FACEBOOK = "Facebook" + FACEBOOK = "Facebook", + GOOGLE_ANALYTICS = "GoogleAnalytics" } interface IUserParams { @@ -83,7 +90,7 @@ interface IUserParams { const environments = import.meta.env const metricCounterNumber = Number(environments.AURA_YANDEX_COUNTER_NUMBER) - +const gaMeasurementId = environments.AURA_GA_MEASUREMENT_ID const checkIsAvailableYandexMetric = () => { const isProduction = environments.MODE === "production"; if (!isProduction) { @@ -110,10 +117,35 @@ const checkIsAvailableYandexMetricAB = () => { return true } +const checkIsAvailableGoogleAnalytics = () => { + // const isProduction = environments.MODE === "production"; + // if (!isProduction) { + // console.log("ANALYTIC IS NOT WORKING: Not production") + // return false; + // }; + if (typeof window.gtag !== "function") { + console.error("Google Analytics not found") + return false + } + return true +} + const setUserID = (userId: string) => { - if (!checkIsAvailableYandexMetric()) return; - window.ym(metricCounterNumber, "setUserID", userId) - Clarity.identify(userId); + if (checkIsAvailableYandexMetric()) { + window.ym(metricCounterNumber, "setUserID", userId) + Clarity.identify(userId); + } + + // Google Analytics + if (checkIsAvailableGoogleAnalytics()) { + // window.gtag('set', 'user_properties', { + // user_id: userId + // }); + window.gtag('config', gaMeasurementId, { + user_id: userId + }); + } + if (!window.klaviyo) return console.error("Klaviyo.Metric not found"); window.klaviyo.push(['identify', userId]); } @@ -127,6 +159,20 @@ const userParams = (parameters: Partial) => { Clarity.setTag(key, String(value)); }); + // Google Analytics + if (checkIsAvailableGoogleAnalytics()) { + // const gaUserProperties = Object.entries(parameters).reduce((acc, [key, value]) => ({ + // ...acc, + // [key.toLowerCase()]: value + // }), {}); + + // window.gtag('set', 'user_properties', gaUserProperties); + window.gtag('config', gaMeasurementId, { + send_page_view: false, + ...parameters + }); + } + if (!window.klaviyo) return console.error("Klaviyo.Metric not found"); window.klaviyo.push(['identify', parameters]); } @@ -134,17 +180,34 @@ const userParams = (parameters: Partial) => { const reachGoal = (goal: EGoals, usingMetrics: EMetrics[], options?: unknown) => { console.log("goal: ", goal); const isProduction = environments.MODE === "production"; - if (!isProduction) return console.log("ANALYTIC IS NOT WORKING: Not production"); + // if (!isProduction) return console.log("ANALYTIC IS NOT WORKING: Not production"); if (usingMetrics.includes(EMetrics.YANDEX)) { if (typeof window.ym !== "function") { console.error("Yandex.Metric not found") - } else { + } else if (isProduction) { window.ym(metricCounterNumber, "reachGoal", goal) Clarity.event(goal); console.log("goalYM&Clarity: ", goal); } + if (!checkIsAvailableGoogleAnalytics()) { + console.error("Google Analytics not found") + } else { + const eventName = goal === EGoals.PAYMENT_SUCCESS ? "purchase" : goal; + window.gtag('event', eventName, options); + console.log("goalGA: ", goal); + } } + if (!isProduction) return console.log("ANALYTIC IS NOT WORKING: Not production"); + + // if (usingMetrics.includes(EMetrics.GOOGLE_ANALYTICS)) { + // if (typeof window.gtag !== "function") { + // console.error("Google Analytics not found") + // } else { + // window.gtag('event', goal, options); + // console.log("goalGA: ", goal); + // } + // } if (usingMetrics.includes(EMetrics.KLAVIYO)) { if (!window.klaviyo) { diff --git a/src/types.ts b/src/types.ts index 4e3dca3..aa96ae8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -35,5 +35,7 @@ declare global { fbq: any; // eslint-disable-next-line @typescript-eslint/no-explicit-any CollectJS: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + gtag: any; } } \ No newline at end of file diff --git a/src/utils/Helmet/index.tsx b/src/utils/Helmet/index.tsx index fb9cc66..234cb96 100644 --- a/src/utils/Helmet/index.tsx +++ b/src/utils/Helmet/index.tsx @@ -1,73 +1,15 @@ -import { getDefaultLocaleByLanguage, language } from "@/locales"; -import { chatsPrefix, compatibilityV2Prefix, palmistryV1Prefix } from "@/routes"; +import { language } from "@/locales"; import { Helmet } from "react-helmet"; -const routesPalmistry = [ - "/palmistry", - // routes.client.skipTrial(), - // routes.client.addConsultant(), - // routes.client.addGuides(), - palmistryV1Prefix -]; +interface IHeadDataProps { + pixels?: string[]; +} -const routesChats = [chatsPrefix]; +const HeadData = ({ + pixels +}: IHeadDataProps) => { -const routesCompatibility2 = [ - compatibilityV2Prefix -] - -const isRouteInclude = (url: string, routes: string[]) => { - for (const route of routes) { - if (url.includes(route)) { - return true; - } - } - return false; -}; - -const HeadData = () => { - const locale = getDefaultLocaleByLanguage(language); - const isPalmistry = isRouteInclude(window.location.pathname, routesPalmistry); - const isChats = isRouteInclude(window.location.pathname, routesChats); - const isCompatibility = isRouteInclude(window.location.pathname, routesCompatibility2); - - // Palmistry - const FBScriptPalmistry1 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '456294924152594'); -fbq('track', 'PageView');`; - - // const FBScriptPalmistry2 = `!function(f,b,e,v,n,t,s) - // {if(f.fbq)return;n=f.fbq=function(){n.callMethod? - // n.callMethod.apply(n,arguments):n.queue.push(arguments)}; - // if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; - // n.queue=[];t=b.createElement(e);t.async=!0; - // t.src=v;s=b.getElementsByTagName(e)[0]; - // s.parentNode.insertBefore(t,s)}(window, document,'script', - // 'https://connect.facebook.net/en_US/fbevents.js'); - // fbq('init', '1046770063554120'); - // fbq('track', 'PageView');`; - - const FBScriptPalmistry3 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '790043826570930'); -fbq('track', 'PageView');`; - - const FBScriptPalmistryES1 = ` + const FBScriptTemplate = (pixel: string) => ` !function(f,b,e,v,n,t,s) {if(f.fbq)return;n=f.fbq=function(){n.callMethod? n.callMethod.apply(n,arguments):n.queue.push(arguments)}; @@ -76,164 +18,14 @@ n.queue=[];t=b.createElement(e);t.async=!0; t.src=v;s=b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t,s)}(window, document,'script', 'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '1088618406337518'); -fbq('track', 'PageView');`; - - const FBScriptPalmistryES2 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '2126185901145571'); -fbq('track', 'PageView');`; - - const FBScriptPalmistryPT1 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '3936071523339830'); -fbq('track', 'PageView');`; - - const FBScriptPalmistryEN1 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '3771681503093940'); -fbq('track', 'PageView');`; - - const FBScriptPalmistryEN2 = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '3756105751317099'); -fbq('track', 'PageView');`; - - // Compatibility - const FBScriptCompatibility = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '1673216156929680'); -fbq('track', 'PageView');`; - - const FBScriptCompatibilityES = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '468790489561492'); -fbq('track', 'PageView');`; - - const FBScriptCompatibilityEN = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '1218510985903341'); -fbq('track', 'PageView');`; - - const FBScriptCompatibilityFR = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '923313529582091'); -fbq('track', 'PageView');`; - - // Chats - const FBScriptChatsEN = ` -!function(f,b,e,v,n,t,s) -{if(f.fbq)return;n=f.fbq=function(){n.callMethod? -n.callMethod.apply(n,arguments):n.queue.push(arguments)}; -if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; -n.queue=[];t=b.createElement(e);t.async=!0; -t.src=v;s=b.getElementsByTagName(e)[0]; -s.parentNode.insertBefore(t,s)}(window, document,'script', -'https://connect.facebook.net/en_US/fbevents.js'); -fbq('init', '1236760817439322'); +fbq('init', '${pixel}'); fbq('track', 'PageView');`; return ( - {/* Palmistry */} - {isPalmistry && } - {/* {isPalmistry && } */} - {isPalmistry && } - {isPalmistry && locale === "es" && ( - - )} - {isPalmistry && locale === "es-419" && ( - - )} - {isPalmistry && locale === "es" && ( - - )} - {isPalmistry && locale === "es-419" && ( - - )} - {isPalmistry && locale?.includes("pt") && ( - - )} - {isPalmistry && locale === "en" && ( - - )} - {isPalmistry && locale === "en" && ( - - )} - {/* Compatibility */} - {isCompatibility && ( - - )} - {isCompatibility && locale === "es" && ( - - )} - {isCompatibility && locale === "es-419" && ( - - )} - {isCompatibility && locale === "en" && ( - - )} - {isCompatibility && locale === "fr" && ( - - )} - {/* Chats */} - {isChats && locale === "en" && } + {pixels?.map((pixel) => ( + + ))} ); }; diff --git a/src/utils/source.utils.ts b/src/utils/source.utils.ts new file mode 100644 index 0000000..8914ee6 --- /dev/null +++ b/src/utils/source.utils.ts @@ -0,0 +1,30 @@ +import { ESourceAuthorization } from "@/api/resources/User"; +import { anonymousPrefix, chatsPrefix, compatibilityV2Prefix, compatibilityV3Prefix, palmistryV1Prefix } from "@/routes"; + +export const getSourceByPathname = (): ESourceAuthorization => { + if (location.pathname.includes(anonymousPrefix)) { + return ESourceAuthorization["aura.test.payment"]; + } + + if (location.pathname.includes(palmistryV1Prefix)) { + return ESourceAuthorization["aura.palmistry.new"]; + } + + if (location.pathname.includes("/palmistry")) { + return ESourceAuthorization["aura.palmistry"]; + } + + if (location.pathname.includes(chatsPrefix)) { + return ESourceAuthorization["aura.chats"]; + } + + if (location.pathname.includes(compatibilityV2Prefix)) { + return ESourceAuthorization["aura.compatibility.v2"]; + } + + if (location.pathname.includes(compatibilityV3Prefix)) { + return ESourceAuthorization["aura.compatibility.v3"]; + } + + return ESourceAuthorization["aura.main.new"]; +} \ No newline at end of file