Commit d97544da authored by isstuev's avatar isstuev

traffic monitor

parent c8d6980b
...@@ -9,7 +9,7 @@ export interface GrowthBookFeatures { ...@@ -9,7 +9,7 @@ export interface GrowthBookFeatures {
test_value: string; test_value: string;
} }
export const growthBook = (() => { export const initGrowthBook = (uuid: string) => {
const feature = config.features.growthBook; const feature = config.features.growthBook;
if (!feature.isEnabled) { if (!feature.isEnabled) {
...@@ -21,7 +21,7 @@ export const growthBook = (() => { ...@@ -21,7 +21,7 @@ export const growthBook = (() => {
clientKey: feature.clientKey, clientKey: feature.clientKey,
enableDevMode: config.app.isDev, enableDevMode: config.app.isDev,
attributes: { attributes: {
id: mixpanel.getUuid(), id: uuid,
chain_id: config.chain.id, chain_id: config.chain.id,
}, },
trackingCallback: (experiment, result) => { trackingCallback: (experiment, result) => {
...@@ -37,7 +37,7 @@ export const growthBook = (() => { ...@@ -37,7 +37,7 @@ export const growthBook = (() => {
}); });
}, },
}); });
})(); };
function getStorageValue(): Array<unknown> | undefined { function getStorageValue(): Array<unknown> | undefined {
const item = window.localStorage.getItem(STORAGE_KEY); const item = window.localStorage.getItem(STORAGE_KEY);
......
...@@ -2,9 +2,10 @@ import React from 'react'; ...@@ -2,9 +2,10 @@ import React from 'react';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import { growthBook } from './init'; import { initGrowthBook } from './init';
export default function useLoadFeatures() { export default function useLoadFeatures(uuid: string) {
const growthBook = initGrowthBook(uuid);
React.useEffect(() => { React.useEffect(() => {
growthBook?.setAttributes({ growthBook?.setAttributes({
...growthBook.getAttributes(), ...growthBook.getAttributes(),
...@@ -13,5 +14,5 @@ export default function useLoadFeatures() { ...@@ -13,5 +14,5 @@ export default function useLoadFeatures() {
}); });
growthBook?.loadFeatures({ timeout: SECOND }); growthBook?.loadFeatures({ timeout: SECOND });
}, []); }, [ growthBook ]);
} }
import * as cookies from 'lib/cookies';
import * as growthBook from 'lib/growthbook/consts';
import isBrowser from 'lib/isBrowser';
export default function getUuid() {
const cookie = cookies.get(cookies.NAMES.UUID);
if (cookie) {
return cookie;
}
const uuid = crypto.randomUUID();
cookies.set(cookies.NAMES.UUID, uuid);
if (isBrowser()) {
window.localStorage.removeItem(growthBook.STORAGE_KEY);
}
return uuid;
}
import getPageType from './getPageType'; import getPageType from './getPageType';
import getUuid from './getUuid';
import logEvent from './logEvent'; import logEvent from './logEvent';
import reset from './reset'; import reset from './reset';
import useInit from './useInit'; import useInit from './useInit';
...@@ -12,7 +11,6 @@ export { ...@@ -12,7 +11,6 @@ export {
useLogPageView, useLogPageView,
logEvent, logEvent,
getPageType, getPageType,
getUuid,
userProfile, userProfile,
reset, reset,
}; };
...@@ -10,7 +10,6 @@ import * as cookies from 'lib/cookies'; ...@@ -10,7 +10,6 @@ import * as cookies from 'lib/cookies';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import getUuid from './getUuid';
import * as userProfile from './userProfile'; import * as userProfile from './userProfile';
export default function useMixpanelInit() { export default function useMixpanelInit() {
...@@ -30,7 +29,8 @@ export default function useMixpanelInit() { ...@@ -30,7 +29,8 @@ export default function useMixpanelInit() {
debug: Boolean(debugFlagQuery.current || debugFlagCookie), debug: Boolean(debugFlagQuery.current || debugFlagCookie),
}; };
const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN)); const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN));
const userId = getUuid();
const uuid = cookies.get(cookies.NAMES.UUID);
mixpanel.init(feature.projectToken, mixpanelConfig); mixpanel.init(feature.projectToken, mixpanelConfig);
mixpanel.register({ mixpanel.register({
...@@ -41,9 +41,9 @@ export default function useMixpanelInit() { ...@@ -41,9 +41,9 @@ export default function useMixpanelInit() {
'Viewport height': window.innerHeight, 'Viewport height': window.innerHeight,
Language: window.navigator.language, Language: window.navigator.language,
'Device type': capitalize(deviceType), 'Device type': capitalize(deviceType),
'User id': userId, 'User id': uuid,
}); });
mixpanel.identify(userId); mixpanel.identify(uuid);
userProfile.set({ userProfile.set({
'Device Type': capitalize(deviceType), 'Device Type': capitalize(deviceType),
...(isAuth ? { 'With Account': true } : {}), ...(isAuth ? { 'With Account': true } : {}),
...@@ -56,7 +56,7 @@ export default function useMixpanelInit() { ...@@ -56,7 +56,7 @@ export default function useMixpanelInit() {
if (debugFlagQuery.current && !debugFlagCookie) { if (debugFlagQuery.current && !debugFlagCookie) {
cookies.set(cookies.NAMES.MIXPANEL_DEBUG, 'true'); cookies.set(cookies.NAMES.MIXPANEL_DEBUG, 'true');
} }
}, []); }, [ ]);
return isInited; return isInited;
} }
...@@ -11,6 +11,7 @@ import * as metadata from 'lib/metadata'; ...@@ -11,6 +11,7 @@ import * as metadata from 'lib/metadata';
import * as mixpanel from 'lib/mixpanel'; import * as mixpanel from 'lib/mixpanel';
interface Props<Pathname extends Route['pathname']> { interface Props<Pathname extends Route['pathname']> {
uuid: string;
pathname: Pathname; pathname: Pathname;
children: React.ReactNode; children: React.ReactNode;
query?: PageProps<Pathname>['query']; query?: PageProps<Pathname>['query'];
......
...@@ -9,6 +9,7 @@ import config from 'configs/app'; ...@@ -9,6 +9,7 @@ import config from 'configs/app';
const rollupFeature = config.features.rollup; const rollupFeature = config.features.rollup;
const adBannerFeature = config.features.adsBanner; const adBannerFeature = config.features.adsBanner;
import isNeedProxy from 'lib/api/isNeedProxy'; import isNeedProxy from 'lib/api/isNeedProxy';
import * as cookies from 'lib/cookies';
import type * as metadata from 'lib/metadata'; import type * as metadata from 'lib/metadata';
export interface Props<Pathname extends Route['pathname'] = never> { export interface Props<Pathname extends Route['pathname'] = never> {
...@@ -19,9 +20,10 @@ export interface Props<Pathname extends Route['pathname'] = never> { ...@@ -19,9 +20,10 @@ export interface Props<Pathname extends Route['pathname'] = never> {
// if apiData is undefined, Next.js will complain that it is not serializable // if apiData is undefined, Next.js will complain that it is not serializable
// so we force it to be always present in the props but it can be null // so we force it to be always present in the props but it can be null
apiData: metadata.ApiData<Pathname> | null; apiData: metadata.ApiData<Pathname> | null;
uuid: string;
} }
export const base = async <Pathname extends Route['pathname'] = never>({ req, query }: GetServerSidePropsContext): export const base = async <Pathname extends Route['pathname'] = never>({ req, res, query }: GetServerSidePropsContext):
Promise<GetServerSidePropsResult<Props<Pathname>>> => { Promise<GetServerSidePropsResult<Props<Pathname>>> => {
const adBannerProvider = (() => { const adBannerProvider = (() => {
if (adBannerFeature.isEnabled) { if (adBannerFeature.isEnabled) {
...@@ -36,6 +38,36 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => { ...@@ -36,6 +38,36 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => {
return null; return null;
})(); })();
let uuid = cookies.getFromCookieString(req.headers.cookie || '', cookies.NAMES.UUID);
if (!uuid) {
uuid = crypto.randomUUID();
res.setHeader('Set-Cookie', `${ cookies.NAMES.UUID }=${ uuid }`);
}
const isTrackingDisabled = process.env.DISABLE_TRACKING === 'true';
if (!isTrackingDisabled) {
// log pageview
const hostname = req.headers.host;
const timestamp = new Date().toISOString();
const chainId = process.env.NEXT_PUBLIC_NETWORK_ID;
const chainName = process.env.NEXT_PUBLIC_NETWORK_NAME;
const publicRPC = process.env.NEXT_PUBLIC_NETWORK_RPC_URL;
fetch('https://monitor.blockscout.com/count', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
hostname,
timestamp,
chainId,
chainName,
publicRPC,
uuid,
}),
});
}
return { return {
props: { props: {
query, query,
...@@ -43,6 +75,7 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => { ...@@ -43,6 +75,7 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => {
referrer: req.headers.referer || '', referrer: req.headers.referer || '',
adBannerProvider: adBannerProvider, adBannerProvider: adBannerProvider,
apiData: null, apiData: null,
uuid,
}, },
}; };
}; };
......
...@@ -15,7 +15,7 @@ import { MarketplaceContextProvider } from 'lib/contexts/marketplace'; ...@@ -15,7 +15,7 @@ import { MarketplaceContextProvider } from 'lib/contexts/marketplace';
import { RewardsContextProvider } from 'lib/contexts/rewards'; import { RewardsContextProvider } from 'lib/contexts/rewards';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection'; import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
import { SettingsContextProvider } from 'lib/contexts/settings'; import { SettingsContextProvider } from 'lib/contexts/settings';
import { growthBook } from 'lib/growthbook/init'; import { initGrowthBook } from 'lib/growthbook/init';
import useLoadFeatures from 'lib/growthbook/useLoadFeatures'; import useLoadFeatures from 'lib/growthbook/useLoadFeatures';
import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation'; import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation';
import { clientConfig as rollbarConfig, Provider as RollbarProvider } from 'lib/rollbar'; import { clientConfig as rollbarConfig, Provider as RollbarProvider } from 'lib/rollbar';
...@@ -47,10 +47,10 @@ const ERROR_SCREEN_STYLES: ChakraProps = { ...@@ -47,10 +47,10 @@ const ERROR_SCREEN_STYLES: ChakraProps = {
}; };
function MyApp({ Component, pageProps }: AppPropsWithLayout) { function MyApp({ Component, pageProps }: AppPropsWithLayout) {
useLoadFeatures(pageProps.uuid);
useLoadFeatures();
useNotifyOnNavigation(); useNotifyOnNavigation();
const growthBook = initGrowthBook(pageProps.uuid);
const queryClient = useQueryClientConfig(); const queryClient = useQueryClientConfig();
const getLayout = Component.getLayout ?? ((page) => <Layout>{ page }</Layout>); const getLayout = Component.getLayout ?? ((page) => <Layout>{ page }</Layout>);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment