Telemetry improvements (#2935)
* next-collect initial setup * naming changes * WIP * WIP: added cookie name * telemetry update * fixes * telemetry eventTypes fix * tmp jitsu config for testing * tmp jitsu key update (for tests) * deploy commit * cookieName fixes * telemetry credentials update * NextCollect updated to latest canary; added TELEMETRY_KEY to config * TELEMETRY_KEY fix removed browser_user_agent field from event * removed _middleware.ts for test deploy * _middleware.ts restored * next-collect version bump * yarn.lock fix * Added license consent property, set default telemetry endpoint * Switched to stable version of next-collect; restored LicenseProvider accidentally deleted during merge * Switched to stable version of next-collect; restored LicenseProvider accidentally deleted during merge * Updated to latest version of next-collect * - Updated to latest version of next-collect - Few improvements in event collection: isTeamBooking for all events, page_url for all events - Do not send second page event on re-render of /team/[slug] * Revert booking confirmed tracking * Applied prettier + fix lint Co-authored-by: Art Sk <kirsan007@gmail.com>
This commit is contained in:
1 parent
60d6c7be51
commit
456a4ba581
22 files changed
+186
-1344
No files matched your search
+2
-2
@@ -53,8 +53,8 @@ NEXTAUTH_SECRET=
|
||||
# Used for cross-domain cookie authentication
|
||||
NEXTAUTH_COOKIE_DOMAIN=.example.com
|
||||
|
||||
# Remove this var if you don't want Cal to collect anonymous usage
|
||||
NEXT_PUBLIC_TELEMETRY_KEY=js.2pvs2bbpqq1zxna97wcml.oi2jzirnbj1ev4tc57c5r
|
||||
# Remove those vars if you don't want Cal to collect anonymous usage
|
||||
TELEMETRY_KEY=s2s.2pvs2bbpqq1zxna97wcml.3jdhd69y09dzku3x243ive
|
||||
|
||||
# ApiKey for cronjobs
|
||||
CRON_API_KEY='0cc0e6c35519bba620c9360cfe3e68d0'
|
||||
|
||||
@@ -37,7 +37,6 @@ import classNames from "@lib/classNames";
|
||||
import { WEBAPP_URL } from "@lib/config/constants";
|
||||
import { shouldShowOnboarding } from "@lib/getting-started";
|
||||
import useMeQuery from "@lib/hooks/useMeQuery";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
|
||||
import { trpc } from "@lib/trpc";
|
||||
|
||||
import CustomBranding from "@components/CustomBranding";
|
||||
@@ -415,16 +414,8 @@ type LayoutProps = {
|
||||
};
|
||||
|
||||
export default function Shell(props: LayoutProps) {
|
||||
const router = useRouter();
|
||||
const { loading, session } = useRedirectToLoginIfUnauthenticated(props.isPublic);
|
||||
const { isRedirectingToOnboarding } = useRedirectToOnboardingIfNeeded();
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
useEffect(() => {
|
||||
telemetry.withJitsu((jitsu) => {
|
||||
return jitsu.track(telemetryEventTypes.pageView, collectPageParameters(router.asPath));
|
||||
});
|
||||
}, [telemetry, router.asPath]);
|
||||
|
||||
const query = useMeQuery();
|
||||
const user = query.data;
|
||||
|
||||
@@ -40,9 +40,7 @@ export default function SAMLLogin(props: Props) {
|
||||
event.preventDefault();
|
||||
|
||||
// track Google logins. Without personal data/payload
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(telemetryEventTypes.googleLogin, collectPageParameters())
|
||||
);
|
||||
telemetry.event(telemetryEventTypes.googleLogin, collectPageParameters());
|
||||
|
||||
if (!props.hostedCal) {
|
||||
await signIn("saml", {}, { tenant: props.samlTenantID, product: props.samlProductID });
|
||||
|
||||
@@ -78,9 +78,7 @@ export default function CancelBooking(props: Props) {
|
||||
reason: cancellationReason,
|
||||
};
|
||||
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(telemetryEventTypes.bookingCancelled, collectPageParameters())
|
||||
);
|
||||
telemetry.event(telemetryEventTypes.bookingCancelled, collectPageParameters());
|
||||
|
||||
const res = await fetch("/api/cancel", {
|
||||
body: JSON.stringify(payload),
|
||||
|
||||
@@ -143,12 +143,13 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
|
||||
useEffect(() => {
|
||||
handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true");
|
||||
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
top !== window ? telemetryEventTypes.embedView : telemetryEventTypes.pageView,
|
||||
if (top !== window) {
|
||||
//page_view will be collected automatically by _middleware.ts
|
||||
telemetry.event(
|
||||
telemetryEventTypes.embedView,
|
||||
collectPageParameters("/availability", { isTeamBooking: document.URL.includes("team/") })
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
}, [telemetry]);
|
||||
|
||||
const changeDate = useCallback(
|
||||
|
||||
@@ -107,12 +107,13 @@ const BookingPage = ({
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
useEffect(() => {
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
top !== window ? telemetryEventTypes.embedView : telemetryEventTypes.pageView,
|
||||
if (top !== window) {
|
||||
//page_view will be collected automatically by _middleware.ts
|
||||
telemetry.event(
|
||||
telemetryEventTypes.embedView,
|
||||
collectPageParameters("/book", { isTeamBooking: document.URL.includes("team/") })
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
@@ -332,13 +333,10 @@ const BookingPage = ({
|
||||
}
|
||||
|
||||
const bookEvent = (booking: BookingFormValues) => {
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
top !== window ? telemetryEventTypes.embedBookingConfirmed : telemetryEventTypes.bookingConfirmed,
|
||||
collectPageParameters("/book", { isTeamBooking: document.URL.includes("team/") })
|
||||
)
|
||||
telemetry.event(
|
||||
top !== window ? telemetryEventTypes.embedBookingConfirmed : telemetryEventTypes.bookingConfirmed,
|
||||
{ isTeamBooking: document.URL.includes("team/") }
|
||||
);
|
||||
|
||||
// "metadata" is a reserved key to allow for connecting external users without relying on the email address.
|
||||
// <...url>&metadata[user_id]=123 will be send as a custom input field as the hidden type.
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function SAMLConfiguration({
|
||||
const rawMetadata = samlConfigRef.current.value;
|
||||
|
||||
// track Google logins. Without personal data/payload
|
||||
telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.samlConfig, collectPageParameters()));
|
||||
telemetry.event(telemetryEventTypes.samlConfig, collectPageParameters());
|
||||
|
||||
mutation.mutate({
|
||||
encodedRawMetadata: Buffer.from(rawMetadata).toString("base64"),
|
||||
|
||||
@@ -7,7 +7,6 @@ import DynamicHelpscoutProvider from "@ee/lib/helpscout/providerDynamic";
|
||||
import DynamicIntercomProvider from "@ee/lib/intercom/providerDynamic";
|
||||
|
||||
import usePublicPage from "@lib/hooks/usePublicPage";
|
||||
import { createTelemetryClient, TelemetryProvider } from "@lib/telemetry";
|
||||
|
||||
import { trpc } from "./trpc";
|
||||
|
||||
@@ -51,17 +50,15 @@ const AppProviders = (props: AppPropsWithChildren) => {
|
||||
<CustomI18nextProvider {...props}>{props.children}</CustomI18nextProvider>
|
||||
</SessionProvider>
|
||||
);
|
||||
const telemetryClient = useMemo(createTelemetryClient, []);
|
||||
|
||||
if (isPublicPage) {
|
||||
return RemainingProviders;
|
||||
}
|
||||
|
||||
return (
|
||||
<TelemetryProvider value={telemetryClient}>
|
||||
{isPublicPage ? (
|
||||
RemainingProviders
|
||||
) : (
|
||||
<DynamicHelpscoutProvider>
|
||||
<DynamicIntercomProvider>{RemainingProviders}</DynamicIntercomProvider>
|
||||
</DynamicHelpscoutProvider>
|
||||
)}
|
||||
</TelemetryProvider>
|
||||
<DynamicHelpscoutProvider>
|
||||
<DynamicIntercomProvider>{RemainingProviders}</DynamicIntercomProvider>
|
||||
</DynamicHelpscoutProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+62
-86
@@ -1,17 +1,13 @@
|
||||
import { jitsuClient, JitsuClient } from "@jitsu/sdk-js";
|
||||
import React, { useContext } from "react";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { EventSinkOpts } from "next-collect";
|
||||
import { useCollector } from "next-collect/client";
|
||||
// it's ok to do this since we're importing only types which are harmless
|
||||
// eslint-disable-next-line @next/next/no-server-import-in-page
|
||||
import type { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var jitsu: JitsuClient | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of all event types that are being sent
|
||||
* to telemetry collection.
|
||||
*/
|
||||
export const telemetryEventTypes = {
|
||||
pageView: "page_view",
|
||||
apiCall: "api_call",
|
||||
bookingConfirmed: "booking_confirmed",
|
||||
bookingCancelled: "booking_cancelled",
|
||||
importSubmitted: "import_submitted",
|
||||
@@ -23,93 +19,73 @@ export const telemetryEventTypes = {
|
||||
embedBookingConfirmed: "embed_booking_confirmed",
|
||||
};
|
||||
|
||||
/**
|
||||
* Telemetry client
|
||||
*/
|
||||
export type TelemetryClient = {
|
||||
/**
|
||||
* Use it as: withJitsu((jitsu) => {return jitsu.track()}). If telemetry is disabled, the callback will ignored
|
||||
*
|
||||
* ATTENTION: always return the value of jitsu.track() or id() call. Otherwise unhandled rejection can happen,
|
||||
* which is handled in Next.js with a popup.
|
||||
*/
|
||||
withJitsu: (callback: (jitsu: JitsuClient) => void | Promise<void>) => void;
|
||||
};
|
||||
|
||||
const emptyClient: TelemetryClient = {
|
||||
withJitsu: () => {
|
||||
// empty
|
||||
},
|
||||
};
|
||||
|
||||
function useTelemetry(): TelemetryClient {
|
||||
return useContext(TelemetryContext);
|
||||
}
|
||||
|
||||
function isLocalhost(host: string) {
|
||||
return "localhost" === host || "127.0.0.1" === host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects page parameters and makes sure no sensitive data made it to telemetry
|
||||
* @param route current next.js route
|
||||
*/
|
||||
export function collectPageParameters(
|
||||
route?: string,
|
||||
extraData: Record<string, unknown> = {}
|
||||
): Record<string, unknown> {
|
||||
const host = document.location.hostname;
|
||||
const maskedHost = isLocalhost(host) ? "localhost" : "masked";
|
||||
//starts with ''
|
||||
const host = document.location.host;
|
||||
const docPath = route ?? "";
|
||||
return {
|
||||
page_url: route,
|
||||
page_title: "",
|
||||
source_ip: "",
|
||||
doc_encoding: document.characterSet,
|
||||
url: document.location.protocol + "//" + host + (docPath ?? ""),
|
||||
doc_host: maskedHost,
|
||||
doc_search: "",
|
||||
doc_path: docPath,
|
||||
referer: "",
|
||||
...extraData,
|
||||
};
|
||||
}
|
||||
|
||||
function createTelemetryClient(): TelemetryClient {
|
||||
if (process.env.NEXT_PUBLIC_TELEMETRY_KEY) {
|
||||
return {
|
||||
withJitsu: (callback) => {
|
||||
if (!process.env.NEXT_PUBLIC_TELEMETRY_KEY) {
|
||||
//telemetry is disabled
|
||||
return;
|
||||
}
|
||||
if (!window) {
|
||||
console.warn("Jitsu has been called during SSR, this scenario isn't supported yet");
|
||||
return;
|
||||
} else if (!window["jitsu"]) {
|
||||
window["jitsu"] = jitsuClient({
|
||||
log_level: "ERROR",
|
||||
tracking_host: "https://t.calendso.com",
|
||||
key: process.env.NEXT_PUBLIC_TELEMETRY_KEY,
|
||||
cookie_name: "__clnds",
|
||||
capture_3rd_party_cookies: false,
|
||||
});
|
||||
}
|
||||
const res = callback(window["jitsu"]);
|
||||
if (res && typeof res["catch"] === "function") {
|
||||
res.catch((e) => {
|
||||
console.debug("Unable to send telemetry event", e);
|
||||
});
|
||||
}
|
||||
export const nextCollectBasicSettings: EventSinkOpts = {
|
||||
drivers: [
|
||||
process.env.TELEMETRY_KEY && {
|
||||
type: "jitsu",
|
||||
opts: {
|
||||
key: process.env.TELEMETRY_KEY,
|
||||
server: "https://t.calendso.com",
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return emptyClient;
|
||||
}
|
||||
}
|
||||
},
|
||||
process.env.TELEMETRY_DEBUG && { type: "echo", opts: { disableColor: true } },
|
||||
],
|
||||
eventTypes: [
|
||||
{ "*.ttf": null },
|
||||
{ "*.webmanifest": null },
|
||||
{ "*.json": null },
|
||||
{ "*.svg": null },
|
||||
{ "*.map": null },
|
||||
{ "*.png": null },
|
||||
{ "*.gif": null },
|
||||
{ "/api/collect-events": null },
|
||||
{ "/api*": null },
|
||||
{ "/img*": null },
|
||||
{ "/favicon*": null },
|
||||
{ "/*": telemetryEventTypes.pageView },
|
||||
],
|
||||
};
|
||||
|
||||
const TelemetryContext = React.createContext<TelemetryClient>(emptyClient);
|
||||
export const extendEventData = (
|
||||
req: NextRequest | NextApiRequest,
|
||||
res: NextResponse | NextApiResponse,
|
||||
original: any
|
||||
) => {
|
||||
const onVercel =
|
||||
typeof req.headers?.get === "function"
|
||||
? !!req.headers.get("x-vercel-id")
|
||||
: !!(req.headers as any)?.["x-vercel-id"];
|
||||
const pageUrl = original?.page_url || (req as any)?.page?.name || undefined;
|
||||
return {
|
||||
title: "",
|
||||
ipAddress: "",
|
||||
queryString: "",
|
||||
page_url: pageUrl,
|
||||
licenseConsent: !!process.env.NEXT_PUBLIC_LICENSE_CONSENT,
|
||||
isTeamBooking:
|
||||
original?.isTeamBooking === undefined
|
||||
? pageUrl?.includes("team/") || undefined
|
||||
: original?.isTeamBooking,
|
||||
referrer: "",
|
||||
onVercel,
|
||||
isAuthorized:
|
||||
!!req.cookies["next-auth.session-token"] || !!req.cookies["__Secure-next-auth.session-token"],
|
||||
utc_time: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
|
||||
const TelemetryProvider = TelemetryContext.Provider;
|
||||
|
||||
export { TelemetryContext, TelemetryProvider, createTelemetryClient, useTelemetry };
|
||||
export const useTelemetry = useCollector;
|
||||
@@ -41,7 +41,6 @@
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@hookform/error-message": "^2.0.0",
|
||||
"@hookform/resolvers": "^2.8.9",
|
||||
"@jitsu/sdk-js": "^2.2.4",
|
||||
"@metamask/providers": "^8.1.1",
|
||||
"@next-auth/prisma-adapter": "^1.0.3",
|
||||
"@next/bundle-analyzer": "12.1.6",
|
||||
@@ -81,6 +80,7 @@
|
||||
"mime-types": "^2.1.35",
|
||||
"next": "^12.1.6",
|
||||
"next-auth": "^4.3.4",
|
||||
"next-collect": "^0.1.0",
|
||||
"next-i18next": "^11.0.0",
|
||||
"next-mdx-remote": "^4.0.3",
|
||||
"next-seo": "^4.26.0",
|
||||
|
||||
@@ -122,13 +122,12 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
useEffect(() => {
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
top !== window ? telemetryEventTypes.embedView : telemetryEventTypes.pageView,
|
||||
collectPageParameters("/[user]")
|
||||
)
|
||||
);
|
||||
}, [telemetry]);
|
||||
if (top !== window) {
|
||||
//page_view will be collected automatically by _middleware.ts
|
||||
telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/[user]"));
|
||||
}
|
||||
}, [telemetry, router.asPath]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Theme />
|
||||
|
||||
+20
-16
@@ -1,3 +1,4 @@
|
||||
import { EventCollectionProvider } from "next-collect/client";
|
||||
import { DefaultSeo } from "next-seo";
|
||||
import Head from "next/head";
|
||||
import superjson from "superjson";
|
||||
@@ -30,23 +31,26 @@ function MyApp(props: AppProps) {
|
||||
pageStatus = "500";
|
||||
}
|
||||
return (
|
||||
<ContractsProvider>
|
||||
<AppProviders {...props}>
|
||||
<DefaultSeo {...seoConfig.defaultNextSeo} />
|
||||
<I18nLanguageHandler />
|
||||
<Head>
|
||||
<script dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
</Head>
|
||||
{Component.requiresLicense ? (
|
||||
<LicenseRequired>
|
||||
<EventCollectionProvider options={{ apiPath: "/api/collect-events" }}>
|
||||
<ContractsProvider>
|
||||
<AppProviders {...props}>
|
||||
<DefaultSeo {...seoConfig.defaultNextSeo} />
|
||||
<I18nLanguageHandler />
|
||||
<Head>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
</Head>
|
||||
{Component.requiresLicense ? (
|
||||
<LicenseRequired>
|
||||
<Component {...pageProps} err={err} />
|
||||
</LicenseRequired>
|
||||
) : (
|
||||
<Component {...pageProps} err={err} />
|
||||
</LicenseRequired>
|
||||
) : (
|
||||
<Component {...pageProps} err={err} />
|
||||
)}
|
||||
</AppProviders>
|
||||
</ContractsProvider>
|
||||
)}
|
||||
</AppProviders>
|
||||
</ContractsProvider>
|
||||
</EventCollectionProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { collectEvents } from "next-collect/server";
|
||||
|
||||
import { extendEventData, nextCollectBasicSettings } from "@lib/telemetry";
|
||||
|
||||
export default collectEvents({
|
||||
...nextCollectBasicSettings,
|
||||
cookieName: "__clnds",
|
||||
extend: extendEventData,
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { nextEventsCollectApi } from "next-collect/server";
|
||||
|
||||
import { extendEventData, nextCollectBasicSettings } from "@lib/telemetry";
|
||||
|
||||
export default nextEventsCollectApi({
|
||||
...nextCollectBasicSettings,
|
||||
cookieName: "__clnds",
|
||||
extend: extendEventData,
|
||||
});
|
||||
@@ -107,7 +107,7 @@ export default function Login({
|
||||
className="space-y-6"
|
||||
handleSubmit={async (values) => {
|
||||
setErrorMessage(null);
|
||||
telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.login, collectPageParameters()));
|
||||
telemetry.event(telemetryEventTypes.login, collectPageParameters());
|
||||
const res = await signIn<"credentials">("credentials", {
|
||||
...values,
|
||||
callbackUrl,
|
||||
@@ -177,9 +177,7 @@ export default function Login({
|
||||
onClick={async (e) => {
|
||||
e.preventDefault();
|
||||
// track Google logins. Without personal data/payload
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(telemetryEventTypes.googleLogin, collectPageParameters())
|
||||
);
|
||||
telemetry.event(telemetryEventTypes.googleLogin, collectPageParameters());
|
||||
await signIn("google");
|
||||
}}>
|
||||
{t("signin_with_google")}
|
||||
|
||||
@@ -114,9 +114,7 @@ export default function Type(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
reason: cancellationReason,
|
||||
};
|
||||
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(telemetryEventTypes.bookingCancelled, collectPageParameters())
|
||||
);
|
||||
telemetry.event(telemetryEventTypes.bookingCancelled, collectPageParameters());
|
||||
|
||||
const res = await fetch("/api/cancel", {
|
||||
body: JSON.stringify(payload),
|
||||
|
||||
@@ -322,12 +322,10 @@ export default function Onboarding(props: inferSSRProps<typeof getServerSideProp
|
||||
className="flex"
|
||||
onSubmit={formMethods.handleSubmit(async (values) => {
|
||||
// track the number of imports. Without personal data/payload
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(telemetryEventTypes.importSubmitted, {
|
||||
...collectPageParameters(),
|
||||
selectedImport,
|
||||
})
|
||||
);
|
||||
telemetry.event(telemetryEventTypes.importSubmitted, {
|
||||
...collectPageParameters(),
|
||||
selectedImport,
|
||||
});
|
||||
setSubmitting(true);
|
||||
const response = await fetch(`/api/import/${selectedImport}`, {
|
||||
method: "POST",
|
||||
|
||||
@@ -179,12 +179,10 @@ export default function Success(props: SuccessProps) {
|
||||
const isCancelled = status === "CANCELLED" || status === "REJECTED";
|
||||
const telemetry = useTelemetry();
|
||||
useEffect(() => {
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
top !== window ? telemetryEventTypes.embedView : telemetryEventTypes.pageView,
|
||||
collectPageParameters("/success")
|
||||
)
|
||||
);
|
||||
if (top !== window) {
|
||||
//page_view will be collected automatically by _middleware.ts
|
||||
telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/success"));
|
||||
}
|
||||
}, [telemetry]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { UserPlan } from "@prisma/client";
|
||||
import classNames from "classnames";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
@@ -32,17 +33,15 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
useExposePlanGlobally("PRO");
|
||||
const isEmbed = useIsEmbed();
|
||||
const telemetry = useTelemetry();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
telemetry.withJitsu((jitsu) =>
|
||||
jitsu.track(
|
||||
telemetryEventTypes.pageView,
|
||||
collectPageParameters("/team/[slug]", {
|
||||
isTeamBooking: true,
|
||||
})
|
||||
)
|
||||
telemetry.event(
|
||||
telemetryEventTypes.pageView,
|
||||
collectPageParameters("/team/[slug]", { isTeamBooking: true })
|
||||
);
|
||||
}, [telemetry]);
|
||||
}, [telemetry, router.asPath]);
|
||||
|
||||
const eventTypes = (
|
||||
<ul className="space-y-3">
|
||||
{team.eventTypes.map((type) => (
|
||||
|
||||
Vendored
+1
-1
@@ -22,7 +22,7 @@ declare namespace NodeJS {
|
||||
/** @deprecated use `NEXT_PUBLIC_WEBSITE_URL` */
|
||||
readonly NEXT_PUBLIC_APP_URL: string | undefined;
|
||||
readonly NEXTAUTH_SECRET: string | undefined;
|
||||
readonly NEXT_PUBLIC_TELEMETRY_KEY: string | undefined;
|
||||
readonly TELEMETRY_KEY: string | undefined;
|
||||
readonly MS_GRAPH_CLIENT_ID: string | undefined;
|
||||
readonly MS_GRAPH_CLIENT_SECRET: string | undefined;
|
||||
readonly ZOOM_CLIENT_ID: string | undefined;
|
||||
|
||||
+1
-1
@@ -48,7 +48,6 @@
|
||||
"$NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE",
|
||||
"$NEXT_PUBLIC_STRIPE_PRO_PLAN_PRODUCT",
|
||||
"$NEXT_PUBLIC_STRIPE_PUBLIC_KEY",
|
||||
"$NEXT_PUBLIC_TELEMETRY_KEY",
|
||||
"$NEXT_PUBLIC_WEBAPP_URL",
|
||||
"$NEXT_PUBLIC_WEBSITE_URL",
|
||||
"$NEXT_PUBLIC_ZENDESK_KEY",
|
||||
@@ -66,6 +65,7 @@
|
||||
"$TANDEM_BASE_URL",
|
||||
"$TANDEM_CLIENT_ID",
|
||||
"$TANDEM_CLIENT_SECRET",
|
||||
"$TELEMETRY_KEY",
|
||||
"$ZOOM_CLIENT_ID",
|
||||
"$ZOOM_CLIENT_SECRET"
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user