Skip to content

Commit

Permalink
Improve analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
chadbrokaw committed Dec 12, 2024
1 parent ec3b950 commit 6ec2a35
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 16 deletions.
5 changes: 5 additions & 0 deletions app/assets/javascripts/account/AccountController.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ AccountController = (
$scope.passwordRegex = /^(?=.*[0-9])(?=.*[a-zA-Z])(.+){8,}$/
$scope.emailRegex = SharedService.emailRegex

$scope.logBackLinkClick = ->
path = window.location.pathname
listingId = path.split('/')[2]
AnalyticsService.trackApplicationStart(listingId || "", null, "Continue with application from save and exit")

$scope.accountForm = ->
# pick up which ever one is defined (the other will be undefined)
$scope.form.signIn ||
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.back-link-container.small-only-text-center ng-if="rememberedShortFormState"
a.back-link ui-sref="{{rememberedShortFormState}}"
a.back-link(ui-sref="{{rememberedShortFormState}}" ng-click="logBackLinkClick()")
span.ui-icon.ui-static.ui-medium.i-primary
svg
use xlink:href="#i-left"
Expand Down
3 changes: 3 additions & 0 deletions app/assets/javascripts/config/angularInitialize.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@
onConfirm: ->
# fires only if user clicks 'ok' to leave page
# reloads this stateChangeStart method with skipConfirm true
AnalyticsService.trackApplicationAbandon(ShortFormApplicationService.listing.listingID, null, "Leaving for " + toState.name)
$window.removeEventListener('unload', $rootScope.onUnload)

toParams.skipConfirm = true
$state.go(toState.name, toParams)
)
Expand Down
5 changes: 3 additions & 2 deletions app/assets/javascripts/config/angularRoutes.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,8 @@
]
application: [
# 'listing' is part of the params so that application waits for listing (above) to resolve
'$q', '$stateParams', '$state', 'ShortFormApplicationService', 'AccountService', 'AutosaveService', 'listing'
($q, $stateParams, $state, ShortFormApplicationService, AccountService, AutosaveService, listing) ->
'$q', '$stateParams', '$state', 'ShortFormApplicationService', 'AccountService', 'AutosaveService', 'AnalyticsService', 'listing'
($q, $stateParams, $state, ShortFormApplicationService, AccountService, AutosaveService, AnalyticsService, listing) ->
deferred = $q.defer()

# if the user just clicked the language switcher, don't reload the whole route
Expand All @@ -620,6 +620,7 @@

if ShortFormApplicationService.application.status == 'Submitted'
# send them to their review page if the application is already submitted
AnalyticsService.trackApplicationComplete(listing.Id, AccountService.loggedInUser?.id || null, "Application already submitted")
$state.go('dahlia.short-form-review', {id: ShortFormApplicationService.application.id})
else if ShortFormApplicationService.application.autofill == true
$state.go('dahlia.short-form-application.autofill-preview', {id: listing.Id, lang: $stateParams.lang})
Expand Down
41 changes: 29 additions & 12 deletions app/assets/javascripts/shared/AnalyticsService.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,32 @@ AnalyticsService = ($state) ->
Service = {}
Service.timer = {}

Service.resetProperties = {
label: undefined
event: undefined
event_timestamp: undefined
category: undefined
action: undefined
origin: undefined
reason: undefined
eventTimeout: undefined
fieldId: undefined
user_id: undefined
time_to_abandon: undefined
time_to_submit: undefined
listing_id: undefined
}

Service.trackEvent = (event, properties) ->
dataLayer = window.dataLayer || []
unless properties.label
combinedProperties = Object.assign({}, Service.resetProperties, properties)
unless combinedProperties.label
# by default, grab the end of the URL e.g. the "contact" from "/x/y/z/contact"
current_path = _.first(_.last($state.current.url.split('/')).split('?'))
properties.label = current_path
properties.event = event
properties.event_timestamp = Date.now()
dataLayer.push(properties)
combinedProperties.label = current_path
combinedProperties.event = event
combinedProperties.event_timestamp = Date.now()
dataLayer.push(combinedProperties)

# Tracks the current page as the user navigates
Service.trackCurrentPage = ->
Expand Down Expand Up @@ -69,19 +86,19 @@ AnalyticsService = ($state) ->
Service.trackEvent('Form Message', params)

Service.trackApplicationStart = (listingId, userId = null, origin = null) ->
params = { category: "Application", action: 'Application Start', user_id: userId, listing_id: listingId, origin: origin }
params = { user_id: userId, listing_id: listingId, origin: origin }
Service.createApplicationTimer(listingId)
Service.trackEvent('Analytics Message', params)
Service.trackEvent('Application_Start', params)

Service.trackApplicationComplete = (listingId, userId = null) ->
Service.trackApplicationComplete = (listingId, userId = null, reason = null) ->
time_to_submit = Service.getApplicationDuration(listingId)
params = { category: "Application", action: 'Application Complete', user_id: userId, listing_id: listingId, time_to_submit: time_to_submit }
Service.trackEvent('Analytics Message', params)
params = { user_id: userId, listing_id: listingId, time_to_submit: time_to_submit, reason: reason }
Service.trackEvent('Application_Complete', params)

Service.trackApplicationAbandon = (listingId, userId = null, reason = null) ->
time_to_abandon = Service.getApplicationDuration(listingId)
params = { category: "Application", action: 'Application Abandon', user_id: userId, listing_id: listingId, time_to_abandon: time_to_abandon, reason: reason }
Service.trackEvent('Analytics Message', params)
params = { user_id: userId, listing_id: listingId, time_to_abandon: time_to_abandon, reason: reason }
Service.trackEvent('Application_Abandon', params)

# Distinct from trackFormFieldError, this function is called when there is a validation error on the form
# For example, if the user has an income that is out of bounds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,19 @@ ShortFormApplicationController = (

$scope.resetAndReplaceApp = ShortFormApplicationService.resetAndReplaceApp

$scope.onUnload = (e) ->
# We want to track the user's actual exit after confirming that they want to leave the page
# Note that this is not perfect, as this will also capture application reloads which doesn't necessarily constitute an abandonment
AnalyticsService.trackApplicationAbandon($scope.listing.Id, AccountService.loggedInUser?.id || null, "Generic Exit")


$scope.atShortFormState = ->
ShortFormApplicationService.isShortFormPage($state.current)

if $scope.atShortFormState() && !$window.jasmine && !window.protractor
# don't add this onbeforeunload inside of jasmine tests
$window.addEventListener 'beforeunload', ShortFormApplicationService.onExit
$window.addEventListener 'unload', $scope.onUnload

$scope.submitForm = ->
form = $scope.form.applicationForm
Expand Down Expand Up @@ -887,7 +894,7 @@ ShortFormApplicationController = (
.then( ->
ShortFormNavigationService.isLoading(false)
ShortFormNavigationService.goToApplicationPage('dahlia.short-form-application.confirmation')
AnalyticsService.trackApplicationComplete($scope.listing.Id, AccountService.loggedInUser?.id || null,)
AnalyticsService.trackApplicationComplete($scope.listing.Id, AccountService.loggedInUser?.id || null)
).catch( ->
ShortFormNavigationService.isLoading(false)
)
Expand All @@ -902,7 +909,9 @@ ShortFormApplicationController = (
# if redirecting to the React my-applications page, disable the "Leave site?" popup
if $window.ACCOUNT_INFORMATION_PAGES_REACT is "true"
$window.removeEventListener('beforeunload', ShortFormApplicationService.onExit)
$window.removeEventListener('unload', $scope.onUnload)

AnalyticsService.trackApplicationAbandon($scope.listing.Id, AccountService.loggedInUser.id, 'Logged In Save and Finish Later')
# ShortFormNavigationService.isLoading(false) will happen after My Apps are loaded
# go to my applications without tracking Form Success
$scope.go('dahlia.my-applications', {skipConfirm: true})
Expand All @@ -911,6 +920,7 @@ ShortFormApplicationController = (
)
else
ShortFormNavigationService.isLoading(false)
AnalyticsService.trackApplicationAbandon($scope.listing.Id, null, 'Logged Out Save and Finish Later')
# go to Create Account without tracking Form Success
$scope.go('dahlia.short-form-application.create-account')

Expand Down Expand Up @@ -970,6 +980,7 @@ ShortFormApplicationController = (
if $scope.appIsSubmitted(previousApp)
# My Applications page is now in React, prevent the "Leave Site?" popup when redirecting
$window.removeEventListener('beforeunload', ShortFormApplicationService.onExit)
$window.removeEventListener('unload', $scope.onUnload)
doubleSubmit = !! $scope.appIsSubmitted($scope.application)
if $window.ACCOUNT_INFORMATION_PAGES_REACT is "true"
currentUrl = window.location.origin
Expand All @@ -982,6 +993,7 @@ ShortFormApplicationController = (
if doubleSubmit
# As we rebuilt the My Applications page in React we were not able to figure out a way to trigger the Double Submit Modal.
# We are leaving the code here both to document past behavior and to protect the application in case somehow the modal is triggered
AnalyticsService.trackApplicationAbandon($scope.listing.Id, AccountService.loggedInUser?.id || null, 'Double Submitted')
newUrl += "doubleSubmit=true"

window.location.href = newUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,9 @@ ShortFormApplicationService = (

# this will setup Service.application with the loaded data
Service.resetApplicationData(formattedApp)
if !_.isEmpty(data.application) && !_.isEmpty(Service.application) && Service.application.status.match(/draft/i) && Service.application.id
AnalyticsService.trackApplicationStart(data?.application?.listingID, data?.application?.primaryApplicant?.webAppID, 'Continue with these details')

# one last step, reconcile any uploaded files with your saved member + preference data
if !_.isEmpty(Service.application) && Service.application.status.match(/draft/i)
Service.refreshPreferences('all')
Expand Down

0 comments on commit 6ec2a35

Please sign in to comment.