mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-23 19:49:56 +01:00
web: get rid of all telemetry & analytics code
This commit is contained in:
committed by
Abdullah Atta
parent
07cfd74506
commit
170b0aa49a
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -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" }}>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 });
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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" }}
|
||||
|
||||
Reference in New Issue
Block a user