web: get rid of all telemetry & analytics code

This commit is contained in:
Abdullah Atta
2024-08-16 10:38:42 +05:00
committed by Abdullah Atta
parent 07cfd74506
commit 170b0aa49a
11 changed files with 1 additions and 374 deletions

View File

@@ -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);

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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);
}}
>

View File

@@ -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: <Note style={{ flexShrink: 0, width: 120, height: 120 }} />,
component: TrackingConsent
image: <Note style={{ flexShrink: 0, width: 120, height: 120 }} />
},
{
title: "Choose your style",
@@ -421,28 +419,6 @@ function ThemeSelector() {
);
}
function TrackingConsent() {
const [enableTelemetry, setEnableTelemetry] = usePersistentState(
"telemetry",
false
);
return (
<Label variant="text.subBody" my={4} sx={{ width: "80%" }}>
<Checkbox
checked={enableTelemetry}
onChange={(e) => {
setEnableTelemetry(e.target.checked);
}}
sx={{ width: 14 }}
/>
<Text>
Help improve Notesnook by sending completely anonymized product
analytics.
</Text>
</Label>
);
}
function CrossPlatform() {
return (
<Flex my={4} sx={{ alignItems: "center" }}>

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
import { Box, Text } from "@theme-ui/components";
import { ANALYTICS_EVENTS } from "../../../utils/analytics";
const events = Object.values(ANALYTICS_EVENTS);
export function TrackingDetails() {
return (
<table
style={{ tableLayout: "fixed", borderCollapse: "collapse" }}
cellPadding={0}
cellSpacing={0}
>
<thead>
<Box
as="tr"
sx={{
height: 30,
th: { borderBottom: "1px solid var(--separator)" }
}}
>
{[
{ id: "event-name", title: "Event name", width: "15%" },
{ id: "event-detail", title: "Detail", width: "50%" }
].map((column) =>
!column.title ? (
<th key={column.id} />
) : (
<Box
as="th"
key={column.id}
sx={{
width: column.width,
px: 1,
mb: 2,
textAlign: "left"
}}
>
<Text
variant="body"
sx={{ textAlign: "left", fontWeight: "normal" }}
>
{column.title}
</Text>
</Box>
)
)}
</Box>
</thead>
<tbody>
{events.map((event) => (
<tr key={event.name} style={{ height: 30 }}>
<Text
as="td"
sx={{ wordWrap: "break-word", maxWidth: 130 }}
variant="body"
>
{event.name}
</Text>
<Text as="td" variant="body">
{event.description}
</Text>
</tr>
))}
</tbody>
</table>
);
}

View File

@@ -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",

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}

View File

@@ -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<SettingStore> {
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<SettingStore> {
});
};
toggleTelemetry = () => {
const telemetry = this.get().telemetry;
this.set({ telemetry: !telemetry });
setTelemetry(!telemetry);
};
togglePrivacyMode = async () => {
const privacyMode = this.get().privacyMode;
this.set({ privacyMode: !privacyMode });

View File

@@ -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<UserStore> {
return db.user
.signup(form.email.toLowerCase(), form.password)
.then(() => {
trackEvent(ANALYTICS_EVENTS.accountCreated);
return this.init();
})
.finally(() => {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<string, unknown>;
};
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<string, unknown>) {
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<string, unknown>
) {
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();
});
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}

View File

@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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" }}