From 478815e4f77590562489c110d34e82fc5a463ee4 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Wed, 23 Oct 2024 14:16:32 -0400 Subject: [PATCH] add stats for onboarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have multiple ways to initiate onboarding: - scan QR in the app - paste from clipboard in the app - entering to a textbox in the app - launching a nrelopenpath:// link from an external app (browser, camera) We want to keep track of how often these methods are used, as well as how often they are successful. First I added the 'onboard' stat which represents an attempt to onboard. The reading has 'configUpdated' (to indicate whether the attempt was successful), and 'joinMethod' ('scan', 'paste', 'textbox', or 'external') I also added "open_qr_scanner" and "paste_token" events (no readings) because the user might open the QR scanner but not scan any QR codes. An 'onboard' stat would not be recorded, but we still want to know if the user clicked "Scan QR" Lastly, I added 'onboarding_state' as a more general stat for evaluating our onboarding process. We should be able to compare the timestamp at each reading to see how long users take at each stage of the onboarding process – as well as how long the entire onboarding process takes --- www/js/App.tsx | 7 +++++-- www/js/onboarding/WelcomePage.tsx | 9 ++++++--- www/js/onboarding/onboardingHelper.ts | 10 ++++++++-- www/js/plugin/clientStats.ts | 12 +++++++++++- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/www/js/App.tsx b/www/js/App.tsx index f671617d1..328e7ab29 100644 --- a/www/js/App.tsx +++ b/www/js/App.tsx @@ -16,13 +16,15 @@ import { initRemoteNotifyHandler } from './splash/remoteNotifyHandler'; // import { getUserCustomLabels } from './services/commHelper'; import AlertBar from './components/AlertBar'; import Main from './Main'; -import { joinWithTokenOrUrl } from './config/opcode'; +import { joinWithTokenOrUrl } from './config/dynamicConfig'; +import { addStatReading } from './plugin/clientStats'; export const AppContext = createContext({}); const CUSTOM_LABEL_KEYS_IN_DATABASE = ['mode', 'purpose']; type CustomLabelMap = { [k: string]: string[]; }; +type OnboardingJoinMethod = 'scan' | 'paste' | 'textbox' | 'external'; const App = () => { // will remain null while the onboarding state is still being determined @@ -39,8 +41,9 @@ const App = () => { // handleOpenURL function must be provided globally for cordova-plugin-customurlscheme // https://www.npmjs.com/package/cordova-plugin-customurlscheme - window['handleOpenURL'] = async (url: string) => { + window['handleOpenURL'] = async (url: string, joinMethod: OnboardingJoinMethod = 'external') => { const configUpdated = await joinWithTokenOrUrl(url); + addStatReading('onboard', { configUpdated, joinMethod }); if (configUpdated) { refreshOnboardingState(); } diff --git a/www/js/onboarding/WelcomePage.tsx b/www/js/onboarding/WelcomePage.tsx index 63366979b..2698df5d4 100644 --- a/www/js/onboarding/WelcomePage.tsx +++ b/www/js/onboarding/WelcomePage.tsx @@ -26,6 +26,7 @@ import { AppContext } from '../App'; import { displayError, logDebug, logWarn } from '../plugin/logger'; import { onboardingStyles } from './OnboardingStack'; import { AlertManager } from '../components/AlertBar'; +import { addStatReading } from '../plugin/clientStats'; let barcodeScannerIsOpen = false; @@ -41,6 +42,7 @@ const WelcomePage = () => { function scanCode() { if (barcodeScannerIsOpen) return; barcodeScannerIsOpen = true; + addStatReading('open_qr_scanner'); window['cordova'].plugins.barcodeScanner.scan( (result) => { barcodeScannerIsOpen = false; @@ -50,7 +52,7 @@ const WelcomePage = () => { AlertManager.addMessage({ text: 'No QR code found in scan. Please try again.' }); return; } - handleOpenURL(result.text); + handleOpenURL(result.text, 'scan'); }, (error) => { barcodeScannerIsOpen = false; @@ -61,11 +63,12 @@ const WelcomePage = () => { function pasteCode() { window['cordova'].plugins.clipboard.paste((clipboardContent: string) => { + addStatReading('paste_token'); try { if (!clipboardContent?.startsWith('nrelop_') && !clipboardContent?.includes('://')) { throw new Error('Clipboard content is not a valid token or URL'); } - handleOpenURL(clipboardContent); + handleOpenURL(clipboardContent, 'paste'); } catch (e) { logWarn(`Tried using clipboard content ${clipboardContent}: ${e}`); setPasteModalVis(true); @@ -138,7 +141,7 @@ const WelcomePage = () => {