From 7bb5ac814a8aae0640f010337eefc6bb160dc0c9 Mon Sep 17 00:00:00 2001 From: Mike Heneghan Date: Mon, 8 Jan 2024 16:10:57 +0000 Subject: [PATCH] refactor: try to reduce nesting with guard clauses - As per: https://github.com/theopensystemslab/planx-new/pull/2597#discussion_r1441607544 - Reduce nesting by refactoring to use guard clauses - Abstract commonly used guard clause into it's own function. --- .../FlowEditor/lib/analyticsProvider.tsx | 366 +++++++++--------- 1 file changed, 184 insertions(+), 182 deletions(-) diff --git a/editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx b/editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx index 4b379e0b25..a4f1608bd1 100644 --- a/editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/lib/analyticsProvider.tsx @@ -106,21 +106,22 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({ const previousBreadcrumbs = usePrevious(breadcrumbs); const trackVisibilityChange = () => { - if (lastVisibleNodeAnalyticsLogId && shouldTrackAnalytics) { - if (document.visibilityState === "hidden") { + skipUpdateIfNotTracking(); + switch (document.visibilityState) { + case "hidden": send( `${ process.env.REACT_APP_API_URL - }/analytics/log-user-exit?analyticsLogId=${lastVisibleNodeAnalyticsLogId.toString()}`, + }/analytics/log-user-exit?analyticsLogId=${lastVisibleNodeAnalyticsLogId?.toString()}`, ); - } - if (document.visibilityState === "visible") { + break; + case "visible": send( `${ process.env.REACT_APP_API_URL }/analytics/log-user-resume?analyticsLogId=${lastVisibleNodeAnalyticsLogId?.toString()}`, ); - } + break; } }; @@ -136,7 +137,8 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({ useEffect(onVisibilityChange, []); useEffect(() => { - if (shouldTrackAnalytics && analyticsId) trackBreadcrumbChanges(); + if (!shouldTrackAnalytics || !analyticsId) return; + trackBreadcrumbChanges(); }, [breadcrumbs]); return ( @@ -282,174 +284,176 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({ }); } + function skipUpdateIfNotTracking() { + if (!shouldTrackAnalytics || !lastVisibleNodeAnalyticsLogId) { + return; + } + } + async function trackHelpClick(metadata?: HelpClickMetadata) { - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - await publicClient.mutate({ - mutation: gql` - mutation UpdateHasClickedHelp($id: bigint!, $metadata: jsonb = {}) { - update_analytics_logs_by_pk( - pk_columns: { id: $id } - _set: { has_clicked_help: true } - _append: { metadata: $metadata } - ) { - id - } + skipUpdateIfNotTracking(); + await publicClient.mutate({ + mutation: gql` + mutation UpdateHasClickedHelp($id: bigint!, $metadata: jsonb = {}) { + update_analytics_logs_by_pk( + pk_columns: { id: $id } + _set: { has_clicked_help: true } + _append: { metadata: $metadata } + ) { + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - metadata, - }, - }); - } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + metadata, + }, + }); } async function trackNextStepsLinkClick(metadata?: SelectedUrlsMetadata) { - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - await publicClient.mutate({ - mutation: gql` - mutation UpdateHasClickNextStepsLink( - $id: bigint! - $metadata: jsonb = {} + skipUpdateIfNotTracking(); + await publicClient.mutate({ + mutation: gql` + mutation UpdateHasClickNextStepsLink( + $id: bigint! + $metadata: jsonb = {} + ) { + update_analytics_logs_by_pk( + pk_columns: { id: $id } + _append: { metadata: $metadata } ) { - update_analytics_logs_by_pk( - pk_columns: { id: $id } - _append: { metadata: $metadata } - ) { - id - } + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - metadata, - }, - }); - } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + metadata, + }, + }); } async function trackFlowDirectionChange( flowDirection: AnalyticsLogDirection, ) { - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - await publicClient.mutate({ - mutation: gql` - mutation UpdateFlowDirection($id: bigint!, $flow_direction: String) { - update_analytics_logs_by_pk( - pk_columns: { id: $id } - _set: { flow_direction: $flow_direction } - ) { - id - } + skipUpdateIfNotTracking(); + await publicClient.mutate({ + mutation: gql` + mutation UpdateFlowDirection($id: bigint!, $flow_direction: String) { + update_analytics_logs_by_pk( + pk_columns: { id: $id } + _set: { flow_direction: $flow_direction } + ) { + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - flow_direction: flowDirection, - }, - }); - } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + flow_direction: flowDirection, + }, + }); } async function trackBackwardsNavigationByNodeId( nodeId: string, initiator: BackwardsNavigationInitiatorType, ) { + skipUpdateIfNotTracking(); + const targetNodeMetadata = getTitleAndTypeFromFlow(nodeId); const metadata: Record = {}; metadata[`${initiator}`] = targetNodeMetadata; - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - await publicClient.mutate({ - mutation: gql` - mutation UpdateHaInitiatedBackwardsNavigation( - $id: bigint! - $metadata: jsonb = {} + await publicClient.mutate({ + mutation: gql` + mutation UpdateHaInitiatedBackwardsNavigation( + $id: bigint! + $metadata: jsonb = {} + ) { + update_analytics_logs_by_pk( + pk_columns: { id: $id } + _append: { metadata: $metadata } ) { - update_analytics_logs_by_pk( - pk_columns: { id: $id } - _append: { metadata: $metadata } - ) { - id - } + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - metadata, - }, - }); - } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + metadata, + }, + }); } async function createAnalytics(type: AnalyticsType) { - if (shouldTrackAnalytics) { - const userAgent = Bowser.parse(window.navigator.userAgent); - const referrer = document.referrer || null; - - const response = await publicClient.mutate({ - mutation: gql` - mutation InsertNewAnalytics( - $type: String - $flow_id: uuid - $user_agent: jsonb - $referrer: String - ) { - insert_analytics_one( - object: { - type: $type - flow_id: $flow_id - user_agent: $user_agent - referrer: $referrer - } - ) { - id + if (!shouldTrackAnalytics) return; + const userAgent = Bowser.parse(window.navigator.userAgent); + const referrer = document.referrer || null; + + const response = await publicClient.mutate({ + mutation: gql` + mutation InsertNewAnalytics( + $type: String + $flow_id: uuid + $user_agent: jsonb + $referrer: String + ) { + insert_analytics_one( + object: { + type: $type + flow_id: $flow_id + user_agent: $user_agent + referrer: $referrer } + ) { + id } - `, - variables: { - type, - flow_id: flowId, - user_agent: userAgent, - referrer, - }, - }); - const id = response.data.insert_analytics_one.id; - setAnalyticsId(id); - const currentNodeId = currentCard()?.id; - if (currentNodeId) track(currentNodeId, type, id); - } + } + `, + variables: { + type, + flow_id: flowId, + user_agent: userAgent, + referrer, + }, + }); + const id = response.data.insert_analytics_one.id; + setAnalyticsId(id); + const currentNodeId = currentCard()?.id; + if (currentNodeId) track(currentNodeId, type, id); } async function updateLastVisibleNodeLogWithAllowListAnswers(nodeId: string) { - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - const allowListAnswers = getAllowListAnswers(nodeId); - if (allowListAnswers) { - await publicClient.mutate({ - mutation: gql` - mutation UpdateAllowListAnswers( - $id: bigint! - $allow_list_answers: jsonb - $node_id: String! - ) { - update_analytics_logs( - where: { id: { _eq: $id }, node_id: { _eq: $node_id } } - _set: { allow_list_answers: $allow_list_answers } - ) { - returning { - id - } - } + skipUpdateIfNotTracking(); + + const allowListAnswers = getAllowListAnswers(nodeId); + if (!allowListAnswers) return; + + await publicClient.mutate({ + mutation: gql` + mutation UpdateAllowListAnswers( + $id: bigint! + $allow_list_answers: jsonb + $node_id: String! + ) { + update_analytics_logs( + where: { id: { _eq: $id }, node_id: { _eq: $node_id } } + _set: { allow_list_answers: $allow_list_answers } + ) { + returning { + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - allow_list_answers: allowListAnswers, - node_id: nodeId, - }, - }); - } - } + } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + allow_list_answers: allowListAnswers, + node_id: nodeId, + }, + }); } function getAllowListAnswers(nodeId: string) { @@ -499,24 +503,23 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({ * Capture user input errors caught by ErrorWrapper component */ async function trackInputErrors(error: string) { - if (shouldTrackAnalytics && lastVisibleNodeAnalyticsLogId) { - await publicClient.mutate({ - mutation: gql` - mutation TrackInputErrors($id: bigint!, $error: jsonb) { - update_analytics_logs_by_pk( - pk_columns: { id: $id } - _append: { input_errors: $error } - ) { - id - } + skipUpdateIfNotTracking(); + await publicClient.mutate({ + mutation: gql` + mutation TrackInputErrors($id: bigint!, $error: jsonb) { + update_analytics_logs_by_pk( + pk_columns: { id: $id } + _append: { input_errors: $error } + ) { + id } - `, - variables: { - id: lastVisibleNodeAnalyticsLogId, - error, - }, - }); - } + } + `, + variables: { + id: lastVisibleNodeAnalyticsLogId, + error, + }, + }); } function extractNodeTitle(node: Store.node) { @@ -528,38 +531,37 @@ export const AnalyticsProvider: React.FC<{ children: React.ReactNode }> = ({ } function determineLogDirection() { - if (previousBreadcrumbs) { - const curLength = Object.keys(breadcrumbs).length; - const prevLength = Object.keys(previousBreadcrumbs).length; - if (curLength > prevLength) return "forwards"; - if (curLength < prevLength) return "backwards"; - } + if (!previousBreadcrumbs) return; + + const curLength = Object.keys(breadcrumbs).length; + const prevLength = Object.keys(previousBreadcrumbs).length; + if (curLength > prevLength) return "forwards"; + if (curLength < prevLength) return "backwards"; } function findUpdatedBreadcrumbKeys(): string[] | undefined { - if (previousBreadcrumbs) { - const currentKeys = Object.keys(breadcrumbs); - const previousKeys = Object.keys(previousBreadcrumbs); + if (!previousBreadcrumbs) return; - const updatedBreadcrumbKeys = currentKeys.filter( - (breadcrumb) => !previousKeys.includes(breadcrumb), - ); - return updatedBreadcrumbKeys; - } + const currentKeys = Object.keys(breadcrumbs); + const previousKeys = Object.keys(previousBreadcrumbs); + const updatedBreadcrumbKeys = currentKeys.filter( + (breadcrumb) => !previousKeys.includes(breadcrumb), + ); + return updatedBreadcrumbKeys; } function trackBreadcrumbChanges() { const updatedBreadcrumbKeys = findUpdatedBreadcrumbKeys(); - if (updatedBreadcrumbKeys) { - updatedBreadcrumbKeys.forEach((breadcrumbKey) => { - const breadcrumb = breadcrumbs[breadcrumbKey]; - if (breadcrumb.auto) { - track(breadcrumbKey); - } else { - updateLastVisibleNodeLogWithAllowListAnswers(breadcrumbKey); - } - }); - } + if (!updatedBreadcrumbKeys) return; + + updatedBreadcrumbKeys.forEach((breadcrumbKey) => { + const breadcrumb = breadcrumbs[breadcrumbKey]; + if (breadcrumb.auto) { + track(breadcrumbKey); + } else { + updateLastVisibleNodeLogWithAllowListAnswers(breadcrumbKey); + } + }); } };