Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support join URLs to generate OPcodes on phone, Fix URL scheme, "Paste" improvements #1187

Merged
merged 9 commits into from
Oct 23, 2024

Conversation

JGreenlee
Copy link
Collaborator

@JGreenlee JGreenlee commented Oct 14, 2024

add opcode.ts, extracting functions from dynamicConfig and the join page

e-mission/e-mission-docs#1076
With the generation of OPcodes now occuring on the phone, several of the functions related to opcode generation will be moved from the join page to the phone.

I put these in a separate file "opcode.ts" which will also pull in several of the functions from dynamicConfig that are related to validating and parsing opcodes

While doing this, I adjusted the names of these functions to a unified convention, so let me describe where each one came from:

generateRandomString: from join page's _getRandomString
getStudyNameFromToken: from dynamicConfig's extractStudyName
getSubgroupFromToken: from dynamicConfig's extractSubgroup
getStudyNameFromUrl: from _getStudyName which was on both join page and dynamicConfig
generate
generateOpcodeFromUrl: from part of join page's validateAndGenerateToken

(For reference, here is the current version of the join page that some of these functions are sourced from: https://github.com/e-mission/nrel-openpath-join-page/blob/main/frontend/index.html#L515)

getTokenFromUrl and joinWithTokenOrUrl are new and help us handle 3 types of input: i) an actual token, ii) 'login_token' link that contains a token, and iii) 'join' link that gives parameters for a token to be generated on the phone


implement global 'handleOpenURL' function

In the current version of the app, QR codes have to be scanned from within the app; scanning the QR code from the device's camera or any other external app will not successfully launch openpath. This used to work and was the method we used before we made a lot of changes to the onboarding flow.

I found that the plugin relies on the existence of a global function (ie existing on the 'window' object).
If we just supply this, the app can handle any emission:// link (or nrelopenpath:// link for the NREL version of the app)

I'm also putting this function in the AppContext so it can be invoked in a "React"-friendly way downstream


WelcomePage: handle tokens, 'join' / 'login_token' URLs, autopaste

Now that reading URLs or tokens, generating a token (if applicable), and joining a study is handled by handleOpenURL (and the functions in opcode.ts it calls), we can use this on the WelcomePage.
Scanning or entering an opcode or URL on the WelcomePage should do the exact same thing as handling an emission:// link that was opened from some external location.

getCode and loginWithToken are not needed anymore, scanCode just needs to call handleOpenURL.

I saw an opportunity to make the "paste" flow easier by providing a shortcut; when "Paste code" is clicked the app will read the user's clipboard and try to join using that. Only if that fails will the paste modal need to be opened, as was the previous UX.
I used cordova-clipboard for this.


revert commenting out '10.0.2.2' downloadURL

I had this change locally and did not mean to commit it


better error handling in opcode.ts

-catch error that could be thrown from getTokenFromUrl
-pass return value of false on either of the catch blocks
-only show "proceeding with OPcode ..." if result from initByUser was true
-ability to pass style through to AlertBar; wordBreak: break-all so that long OPcodes will not be forced onto one line


use URL_SCHEME from package.json; simplify PopOpCode.tsx

Instead of hardcoding emission://, we can grab it from the package json. This way, the 'emission' string will only need to be changed in one place for other versions of the app.
And since QrCode.tsx is able to handle either URLs or plain tokens, we can also simplify PopOpCode to just accept the plain token and pass this through to QrCode.tsx


combine opcode.joinWithTokenOrUrl with dynamicConfig.initByUser

Looking at these 2 functions I realized they can be combined and error handling unified, so I combined these to make a new function using async/await syntax.

I chose to put the new function in dynamicConfig because this avoids a circular dependency at the module level (which is allowed but not tidy)
Now, dynamicConfig.ts imports from opcode.ts but opcode.ts no longer imports anything from dynamicConfig.ts.

Updated the tests for dynamicConfig to validate that the correct error messages are shown.


add tests for opcode.ts

Because joinWithTokenOrUrl in dynamicConfig.ts calls functions from opcode.ts and there are tests for that, most of opcode.ts is already covered. However, I am adding a few more dedicated tests to cover more scenarios.

e-mission/e-mission-docs#1076
With the generation of OPcodes now occuring on the phone, several of the functions related to opcode generation will be moved from the join page to the phone.

I put these in a separate file "opcode.ts" which will also pull in several of the functions from dynamicConfig that are related to validating and parsing opcodes

While doing this, I adjusted the names of these functions to a unified convention, so let me describe where each one came from:

generateRandomString: from join page's _getRandomString
getStudyNameFromToken: from dynamicConfig's extractStudyName
getSubgroupFromToken: from dynamicConfig's extractSubgroup
getStudyNameFromUrl: from _getStudyName which was on both join page and dynamicConfig
generate
generateOpcodeFromUrl: from part of join page's validateAndGenerateToken

(For reference, here is the current version of the join page that some of these functions are sourced from: https://github.com/e-mission/nrel-openpath-join-page/blob/main/frontend/index.html#L515)

getTokenFromUrl and joinWithTokenOrUrl are new and help us handle 3 types of input: i) an actual token, ii) 'login_token' link that contains a token, and iii) 'join' link that gives parameters for a token to be generated on the phone
In the current version of the app, QR codes have to be scanned from within the app; scanning the QR code from the device's camera or any other external app will not successfully launch openpath. This used to work and was the method we used before we made a lot of changes to the onboarding flow.

I found that the plugin relies on the existence of a global function (ie existing on the 'window' object).
If we just supply this, the app can handle any emission:// link (or nrelopenpath:// link for the NREL version of the app)

I'm also putting this function in the AppContext so it can be invoked in a "React"-friendly way downstream
Now that reading URLs or tokens, generating a token (if applicable), and joining a study is handled by handleOpenURL (and the functions in opcode.ts it calls), we can use this on the WelcomePage.
Scanning or entering an opcode or URL on the WelcomePage should do the exact same thing as handling an emission:// link that was opened from some external location.

getCode and loginWithToken are not needed anymore, scanCode just needs to call handleOpenURL.

I saw an opportunity to make the "paste" flow easier by providing a shortcut; when "Paste code" is clicked the app will read the user's clipboard and try to join using that. Only if that fails will the paste modal need to be opened, as was the previous UX.
I used cordova-clipboard for this.
I had this change locally and did not mean to commit it
-catch error that could be thrown from getTokenFromUrl
-pass return value of false on either of the catch blocks
-only show "proceeding with OPcode ..." if result from initByUser was true
-ability to pass style through to AlertBar; wordBreak: break-all so that long OPcodes will not be forced onto one line
@JGreenlee JGreenlee changed the title Onboarding redesign oct2024 Support join URLs to generate OPcodes on phone, Fix URL scheme, "Paste" improvements Oct 14, 2024
Instead of hardcoding `emission://`, we can grab it from the package json. This way, the 'emission' string will only need to be changed in one place for other versions of the app.
And since QrCode.tsx is able to handle either URLs or plain tokens, we can also simplify PopOpCode to just accept the plain token and pass this through to QrCode.tsx
Looking at these 2 functions I realized they can be combined and error handling unified, so I combined these to make a new function using async/await syntax.

I chose to put the new function in dynamicConfig because this avoids a circular dependency at the module level (which is allowed but not tidy)
Now, `dynamicConfig.ts` imports from `opcode.ts` but `opcode.ts` no longer imports anything from `dynamicConfig.ts`.

Updated the tests for dynamicConfig to validate that the correct error messages are shown.
Because joinWithTokenOrUrl in dynamicConfig.ts calls functions from opcode.ts and there are tests for that, most of opcode.ts is already covered. However, I am adding a few more dedicated tests to cover more scenarios.
@JGreenlee JGreenlee marked this pull request as ready for review October 17, 2024 16:21
Copy link

codecov bot commented Oct 17, 2024

Codecov Report

Attention: Patch coverage is 70.47619% with 31 lines in your changes missing coverage. Please review.

Project coverage is 29.98%. Comparing base (d4986e9) to head (ee85fb0).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
www/js/onboarding/WelcomePage.tsx 0.00% 18 Missing ⚠️
www/js/App.tsx 0.00% 5 Missing ⚠️
www/js/config/dynamicConfig.ts 80.00% 3 Missing ⚠️
www/js/components/QrCode.tsx 0.00% 2 Missing ⚠️
www/js/control/PopOpCode.tsx 0.00% 2 Missing ⚠️
www/js/config/opcode.ts 98.41% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1187      +/-   ##
==========================================
+ Coverage   29.41%   29.98%   +0.56%     
==========================================
  Files         122      123       +1     
  Lines        4919     4933      +14     
  Branches     1125     1091      -34     
==========================================
+ Hits         1447     1479      +32     
+ Misses       3470     3454      -16     
+ Partials        2        0       -2     
Flag Coverage Δ
unit 29.98% <70.47%> (+0.56%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
www/js/components/AlertBar.tsx 6.25% <ø> (ø)
www/js/control/ProfileSettings.tsx 0.00% <ø> (ø)
www/js/config/opcode.ts 98.41% <98.41%> (ø)
www/js/components/QrCode.tsx 0.00% <0.00%> (ø)
www/js/control/PopOpCode.tsx 0.00% <0.00%> (ø)
www/js/config/dynamicConfig.ts 86.79% <80.00%> (+1.47%) ⬆️
www/js/App.tsx 0.00% <0.00%> (ø)
www/js/onboarding/WelcomePage.tsx 0.00% <0.00%> (ø)

... and 2 files with indirect coverage changes

@shankari
Copy link
Contributor

@JGreenlee can we add some stats to see how people actually provide us with the opcode - launch via URL or scan from app? That will help us smooth the onboarding flow further.

Copy link
Contributor

@shankari shankari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with merging this once we add the stats

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
Copy link
Contributor

@shankari shankari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@shankari shankari merged commit ccc7aef into e-mission:master Oct 23, 2024
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Tasks completed
Development

Successfully merging this pull request may close these issues.

2 participants