From 170b0aa49a548c7ad7c2d95615e4b5b02d1cb1e4 Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Fri, 16 Aug 2024 10:38:42 +0500 Subject: [PATCH] web: get rid of all telemetry & analytics code --- .../web/src/components/announcements/body.jsx | 2 - .../src/components/announcements/index.jsx | 2 - apps/web/src/dialogs/onboarding-dialog.tsx | 26 +-- .../settings/components/tracking-details.tsx | 85 --------- .../src/dialogs/settings/privacy-settings.ts | 23 --- apps/web/src/hooks/use-telemetry.ts | 31 ---- apps/web/src/stores/setting-store.ts | 8 - apps/web/src/stores/user-store.ts | 2 - apps/web/src/utils/analytics.ts | 163 ------------------ apps/web/src/utils/telemetry.ts | 31 ---- apps/web/src/views/email-confirmed.tsx | 2 - 11 files changed, 1 insertion(+), 374 deletions(-) delete mode 100644 apps/web/src/dialogs/settings/components/tracking-details.tsx delete mode 100644 apps/web/src/hooks/use-telemetry.ts delete mode 100644 apps/web/src/utils/analytics.ts delete mode 100644 apps/web/src/utils/telemetry.ts diff --git a/apps/web/src/components/announcements/body.jsx b/apps/web/src/components/announcements/body.jsx index 600a4c437..4c9dcff65 100644 --- a/apps/web/src/components/announcements/body.jsx +++ b/apps/web/src/components/announcements/body.jsx @@ -24,7 +24,6 @@ import { Image as RebassImage, Text as RebassText } from "@theme-ui/components"; -import { ANALYTICS_EVENTS, trackEvent } from "../../utils/analytics"; import { Sync, Notebook, @@ -284,7 +283,6 @@ function CalltoAction({ action, variant, sx, dismissAnnouncement }) { onClick={async () => { if (dismissAnnouncement) dismissAnnouncement(); DialogManager.closeAll(); - trackEvent(ANALYTICS_EVENTS.announcementCta, action); switch (action.type) { case "link": { const url = new URL(action.data); diff --git a/apps/web/src/components/announcements/index.jsx b/apps/web/src/components/announcements/index.jsx index 30502c146..25b2beb3a 100644 --- a/apps/web/src/components/announcements/index.jsx +++ b/apps/web/src/components/announcements/index.jsx @@ -19,7 +19,6 @@ along with this program. If not, see . import { Flex, Text } from "@theme-ui/components"; import { Cross } from "../icons"; -import { ANALYTICS_EVENTS, trackEvent } from "../../utils/analytics"; import AnnouncementBody from "./body"; import { useStore as useAnnouncementStore } from "../../stores/announcement-store"; import Notice from "../notice"; @@ -59,7 +58,6 @@ function Announcements() { }} title="Dismiss announcement" onClick={() => { - trackEvent(ANALYTICS_EVENTS.announcementDismissed, announcement); dismiss(announcement.id); }} > diff --git a/apps/web/src/dialogs/onboarding-dialog.tsx b/apps/web/src/dialogs/onboarding-dialog.tsx index 0140603ab..5189eddfa 100644 --- a/apps/web/src/dialogs/onboarding-dialog.tsx +++ b/apps/web/src/dialogs/onboarding-dialog.tsx @@ -37,7 +37,6 @@ import DarkUI from "../assets/dark1.png"; import GooglePlay from "../assets/play.png"; import AppleStore from "../assets/apple.png"; import { useStore as useThemeStore } from "../stores/theme-store"; -import { Checkbox, Label } from "@theme-ui/components"; import { Features } from "../components/announcements/body"; import { TaskManager } from "../common/task-manager"; import { db } from "../common/db"; @@ -64,8 +63,7 @@ const newUserSteps: Step[] = [ title: "Safe & encrypted notes", subtitle: "Write with freedom. Never compromise on privacy again.", buttonText: "Get started", - image: , - component: TrackingConsent + image: }, { title: "Choose your style", @@ -421,28 +419,6 @@ function ThemeSelector() { ); } -function TrackingConsent() { - const [enableTelemetry, setEnableTelemetry] = usePersistentState( - "telemetry", - false - ); - return ( - - ); -} - function CrossPlatform() { return ( diff --git a/apps/web/src/dialogs/settings/components/tracking-details.tsx b/apps/web/src/dialogs/settings/components/tracking-details.tsx deleted file mode 100644 index 690674a90..000000000 --- a/apps/web/src/dialogs/settings/components/tracking-details.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -import { Box, Text } from "@theme-ui/components"; -import { ANALYTICS_EVENTS } from "../../../utils/analytics"; - -const events = Object.values(ANALYTICS_EVENTS); -export function TrackingDetails() { - return ( - - - - {[ - { id: "event-name", title: "Event name", width: "15%" }, - { id: "event-detail", title: "Detail", width: "50%" } - ].map((column) => - !column.title ? ( - - - {events.map((event) => ( - - - {event.name} - - - {event.description} - - - ))} - -
- ) : ( - - - {column.title} - - - ) - )} - -
- ); -} diff --git a/apps/web/src/dialogs/settings/privacy-settings.ts b/apps/web/src/dialogs/settings/privacy-settings.ts index cd8b73715..8faf20001 100644 --- a/apps/web/src/dialogs/settings/privacy-settings.ts +++ b/apps/web/src/dialogs/settings/privacy-settings.ts @@ -24,7 +24,6 @@ import { getPlatform } from "../../utils/platform"; import { db } from "../../common/db"; import Config from "../../utils/config"; import { showToast } from "../../utils/toast"; -import { TrackingDetails } from "./components/tracking-details"; import { PromptDialog } from "../prompt"; export const PrivacySettings: SettingsGroup[] = [ @@ -33,26 +32,6 @@ export const PrivacySettings: SettingsGroup[] = [ section: "privacy", header: "General", settings: [ - { - key: "telemetry", - title: "Telemetry", - description: `Usage data & crash reports will be sent to us (no 3rd party involved) for analytics. All data is anonymous as mentioned in our privacy policy. - -What data is collected & when?`, - onStateChange: (listener) => - useSettingStore.subscribe((s) => s.telemetry, listener), - components: [ - { - type: "toggle", - isToggled: () => !!useSettingStore.getState().telemetry, - toggle: () => useSettingStore.getState().toggleTelemetry() - }, - { - type: "custom", - component: TrackingDetails - } - ] - }, { key: "marketing", title: "Marketing emails", @@ -136,8 +115,6 @@ This can sometimes bypass local ISP blockages on Notesnook traffic. Disable this title: "Custom CORS proxy", description: "CORS proxy is required to directly download images from within the Notesnook app. It allows Notesnook to bypass browser restrictions by using a proxy. You can set a custom self-hosted proxy URL to increase your privacy.", - onStateChange: (listener) => - useSettingStore.subscribe((s) => s.telemetry, listener), components: [ { type: "button", diff --git a/apps/web/src/hooks/use-telemetry.ts b/apps/web/src/hooks/use-telemetry.ts deleted file mode 100644 index ea304a179..000000000 --- a/apps/web/src/hooks/use-telemetry.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -import { useEffect, useState } from "react"; -import { isTelemetryEnabled, setTelemetry } from "../utils/telemetry"; - -export function useTelemetry() { - const [enabled, setEnabled] = useState(isTelemetryEnabled()); - - useEffect(() => { - setTelemetry(enabled); - }, [enabled]); - - return [enabled, setEnabled] as const; -} diff --git a/apps/web/src/stores/setting-store.ts b/apps/web/src/stores/setting-store.ts index 0966a8e15..011a7054b 100644 --- a/apps/web/src/stores/setting-store.ts +++ b/apps/web/src/stores/setting-store.ts @@ -24,7 +24,6 @@ import createStore from "../common/store"; import Config from "../utils/config"; import BaseStore from "./index"; import { useEditorStore } from "./editor-store"; -import { isTelemetryEnabled, setTelemetry } from "../utils/telemetry"; import { setDocumentTitle } from "../utils/dom"; import { TimeFormat } from "@notesnook/core/dist/utils/date"; import { Profile, TrashCleanupInterval } from "@notesnook/core"; @@ -49,7 +48,6 @@ class SettingStore extends BaseStore { privacyMode = false; customDns = true; hideNoteTitle = Config.get("hideNoteTitle", false); - telemetry = isTelemetryEnabled(); dateFormat = "DD-MM-YYYY"; timeFormat: TimeFormat = "12-hour"; titleFormat = "Note $date$ $time$"; @@ -177,12 +175,6 @@ class SettingStore extends BaseStore { }); }; - toggleTelemetry = () => { - const telemetry = this.get().telemetry; - this.set({ telemetry: !telemetry }); - setTelemetry(!telemetry); - }; - togglePrivacyMode = async () => { const privacyMode = this.get().privacyMode; this.set({ privacyMode: !privacyMode }); diff --git a/apps/web/src/stores/user-store.ts b/apps/web/src/stores/user-store.ts index 1eb224184..d365583d2 100644 --- a/apps/web/src/stores/user-store.ts +++ b/apps/web/src/stores/user-store.ts @@ -26,7 +26,6 @@ import Config from "../utils/config"; import { hashNavigate } from "../navigation"; import { isUserPremium } from "../hooks/use-is-user-premium"; import { SUBSCRIPTION_STATUS } from "../common/constants"; -import { ANALYTICS_EVENTS, trackEvent } from "../utils/analytics"; import { AuthenticatorType, User } from "@notesnook/core"; import { ConfirmDialog } from "../dialogs/confirm"; import { OnboardingDialog } from "../dialogs/onboarding-dialog"; @@ -148,7 +147,6 @@ class UserStore extends BaseStore { return db.user .signup(form.email.toLowerCase(), form.password) .then(() => { - trackEvent(ANALYTICS_EVENTS.accountCreated); return this.init(); }) .finally(() => { diff --git a/apps/web/src/utils/analytics.ts b/apps/web/src/utils/analytics.ts deleted file mode 100644 index 31819a950..000000000 --- a/apps/web/src/utils/analytics.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -import { getPlatform } from "./platform"; -import { isTelemetryEnabled } from "./telemetry"; -import { appVersion } from "./version"; - -type PageView = { - type: "pageview"; - referrer: string; - url?: string; -}; - -type Event = { - type: "event"; - event_name: string; - event_data: Record; -}; - -type TrackerEvent = { - name: string; - description: string; - type?: "event" | "view"; -}; - -export const ANALYTICS_EVENTS = { - version: { - name: "version", - description: "Sent on startup" - }, - checkoutStarted: { - name: "checkout:started", - description: "Sent when you start Paddle checkout." - }, - offerClaimed: { - name: "offer:claimed", - description: - "Sent when you start Paddle checkout with a coupon code applied." - }, - announcementDismissed: { - name: "announcement:dismissed", - description: "Sent when you dismiss an announcement." - }, - purchaseInitiated: { - name: "purchase:initiated", - description: - "Sent whenever the Premium dialog is shown to you. This can be voluntary or via accessing a premium feature." - }, - socialLink: { - name: "link:social", - description: - "Sent whenever you open Notesnook social media link from the email verified screen." - }, - announcementCta: { - name: "announcement:cta", - description: "Sent whenever you an announcement CTA is invoked." - }, - accountCreated: { - name: "/account/created", - description: "Sent when you create an account.", - type: "view" - } -} as const; - -const baseUrl = `https://analytics.streetwriters.co/api/collect`; - -async function trackUmamiView(url: string, referrer?: string) { - return collect({ - type: "pageview", - referrer: referrer || window.document.referrer, - url - }); -} - -function trackUmamiEvent(name: string, data: Record) { - return collect({ - type: "event", - event_name: name, - event_data: data - }); -} - -async function collect(event: PageView | Event) { - const { - screen: { width, height }, - navigator: { language }, - location: { hostname, pathname, search } - } = window; - - const screen = `${width}x${height}`; - const currentUrl = - (event.type === "pageview" && event.url) || `${pathname}${search}`; - - const body = { - payload: { - website: `f16c07d9-c77b-4781-bfbd-f58e95640002`, - hostname, - screen, - language, - url: currentUrl, - ...event - }, - type: event.type - }; - - try { - await fetch(baseUrl, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(body), - keepalive: true - }); - } catch (e) { - console.error(e); - } -} - -export function trackEvent( - event: TrackerEvent, - data?: Record -) { - if (!isTelemetryEnabled()) return; - if (event.type === "view") trackVisit(event.name); - else if (data) trackUmamiEvent(event.name, data); -} - -export function trackVisit(url = "/") { - if (!isTelemetryEnabled()) return; - - const platform = getPlatform(); - if (!platform) return; - - trackUmamiView(window.document.referrer); - if (url === "/") - trackEvent(ANALYTICS_EVENTS.version, { - version: appVersion.formatted, - platform - }); -} - -if (isTelemetryEnabled()) { - document.addEventListener("readystatechange", () => { - trackVisit(); - }); -} diff --git a/apps/web/src/utils/telemetry.ts b/apps/web/src/utils/telemetry.ts deleted file mode 100644 index 31920dbce..000000000 --- a/apps/web/src/utils/telemetry.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -This file is part of the Notesnook project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -import Config from "./config"; - -export function isTelemetryEnabled() { - // telemetry is always disabled in DEBUG/TEST mode - if (import.meta.env.DEV || IS_TESTING) return false; - - return Config.get("telemetry", false); -} - -export function setTelemetry(state: boolean) { - Config.set("telemetry", state); -} diff --git a/apps/web/src/views/email-confirmed.tsx b/apps/web/src/views/email-confirmed.tsx index 9e156e6f8..1ead42087 100644 --- a/apps/web/src/views/email-confirmed.tsx +++ b/apps/web/src/views/email-confirmed.tsx @@ -20,7 +20,6 @@ along with this program. If not, see . import "../app.css"; import { useEffect } from "react"; import { Flex, Text } from "@theme-ui/components"; -import { ANALYTICS_EVENTS, trackEvent } from "../utils/analytics"; import { useQueryParams } from "../navigation"; import { MailCheck, Discord, Twitter, Reddit } from "../components/icons"; @@ -152,7 +151,6 @@ function BlogPromoBanner() { title={account.title} onClick={() => { window.open(account.link, "_blank"); - trackEvent(ANALYTICS_EVENTS.socialLink, { link: account.link }); }} size={30} sx={{ mr: 1, cursor: "pointer" }}