Skip to content

Comments

LG-9848: Add analytics to onbeforeunload#8512

Merged
matthinz merged 16 commits intomainfrom
matthinz/9848-onbeforeunload-logging
Jun 2, 2023
Merged

LG-9848: Add analytics to onbeforeunload#8512
matthinz merged 16 commits intomainfrom
matthinz/9848-onbeforeunload-logging

Conversation

@matthinz
Copy link
Contributor

@matthinz matthinz commented May 30, 2023

🎫 Ticket

LG-9848

🛠 Summary of changes

Team Ada is considering removing some onbeforeunload prompts (the ones that say "If you navigate away from this page, your data may not be saved" or something to that effect) from the IdV flow on the grounds that they are annoying. But before we do that, we want actual data about how they are used and if they are doing their job.

  • How often do users encounter these prompts?
  • Do the prompts keep users on the page?

To that end, this PR refactors onbeforeunload code out into its own package and adds some analytics calls:

  • User prompted before navigation fires when the onbeforeunload event handler is called
  • User prompted before navigation and still on page fires at 5s, 15s, and 30s after to indicate the user stayed on the page

@matthinz matthinz force-pushed the matthinz/9848-onbeforeunload-logging branch from 7eef1d2 to 9aad622 Compare May 31, 2023 19:14
@matthinz matthinz force-pushed the matthinz/9848-onbeforeunload-logging branch from e47f560 to 0b84e23 Compare June 1, 2023 22:31
matthinz added 2 commits June 2, 2023 09:03
Sinon's useFakeTimers covers global.setTimeout (which is callable as plain `setTimeout(...)`, but does not cover `window.setTimeout`.
@matthinz matthinz marked this pull request as ready for review June 2, 2023 16:29
sandbox.clock.restore();
}

// useFakeTimers overrides global.setTimeout, etc. (callable as setTimeout()), but does not
Copy link
Contributor Author

Choose a reason for hiding this comment

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

FYI @aduth this is fun fallout from the setTimeout vs window.setTimeout issue. Sinon replaces global.setTimeout but NOT window.setTimeout. There is a config option to set the global it uses, but I think that would break any existing "bare" references to setTimeout.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha, this makes sense then 👍

Alternatively, I wonder what might happen if we changed the "window" setTimeout to point to the Node global in the test setup?

window.setTimeout = setTimeout;

Comment on lines +81 to +83
const cleanUp = this.cleanUpPromptOnNavigate ?? (() => {});
this.cleanUpPromptOnNavigate = undefined;
cleanUp();
Copy link
Contributor

Choose a reason for hiding this comment

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

personally I love the null-safe navigator for stuff like this but this is just style

Suggested change
const cleanUp = this.cleanUpPromptOnNavigate ?? (() => {});
this.cleanUpPromptOnNavigate = undefined;
cleanUp();
this.cleanUpPromptOnNavigate = undefined;
this.cleanUpPromptOnNavigate?.();

Copy link
Contributor

Choose a reason for hiding this comment

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

oh wait I just realized that we can't do this because we're clearing 🤦

Copy link
Contributor

@aduth aduth left a comment

Choose a reason for hiding this comment

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

LGTM 👍

Comment on lines +76 to +83
const isAlreadyBound = !!this.cleanUpPromptOnNavigate;

if (shouldPrompt && !isAlreadyBound) {
this.cleanUpPromptOnNavigate = promptOnNavigate();
} else if (!shouldPrompt && isAlreadyBound) {
const cleanUp = this.cleanUpPromptOnNavigate ?? (() => {});
this.cleanUpPromptOnNavigate = undefined;
cleanUp();
Copy link
Contributor

Choose a reason for hiding this comment

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

Kinda unfortunate that TypeScript isn't able to follow the type narrowing through the variable assignment. It could if we avoided the variable, but maybe that sacrifices readability too much?

Suggested change
const isAlreadyBound = !!this.cleanUpPromptOnNavigate;
if (shouldPrompt && !isAlreadyBound) {
this.cleanUpPromptOnNavigate = promptOnNavigate();
} else if (!shouldPrompt && isAlreadyBound) {
const cleanUp = this.cleanUpPromptOnNavigate ?? (() => {});
this.cleanUpPromptOnNavigate = undefined;
cleanUp();
if (shouldPrompt && !this.cleanUpPromptOnNavigate) {
this.cleanUpPromptOnNavigate = promptOnNavigate();
} else if (!shouldPrompt && this.cleanUpPromptOnNavigate) {
this.cleanUpPromptOnNavigate();
this.cleanUpPromptOnNavigate = undefined;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer the readability of isAlreadyBound but yeah I wish TS could deduce that cleanUpPromptOnNavigate is there when isAlreadyBound is true.


## Analytics

By default, `promptOnNavigate` will call `trackEvent` to log a `User prompted before navigation` event when the onbeforeunload handler is called. It will then log `User prompted before navigation and still on page` events at 5, 15, and 30 seconds after the onbeforeunload handler is called (the `seconds` property on the event will contain the number of seconds since the initial prompt).
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to confirm my understanding of the behavior: When I tested this, as long as the confirmation prompt was visible, there was no logging happening. It was only after I dismissed the confirmation prompt that it started logging the next events. Is that expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I don't think there's a good way for us to know when the prompt is dismissed. That was part of the motivation for doing the follow-up logging at intervals.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well it was more that nothing was logged while the prompt was visible. So as far as how it's described here:

It will then log User prompted before navigation and still on page events at 5, 15, and 30 seconds after the onbeforeunload handler is called

In reality it was more like:

It will then log User prompted before navigation and still on page events at 5, 15, and 30 seconds after the onbeforeunload handler dialog is dismissed

@matthinz matthinz merged commit bbb17ac into main Jun 2, 2023
@matthinz matthinz deleted the matthinz/9848-onbeforeunload-logging branch June 2, 2023 18:54
@solipet solipet mentioned this pull request Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants