From 6674025bd4a606f02273d36cb5dc7e6a47741574 Mon Sep 17 00:00:00 2001 From: Maxwell Frank Date: Tue, 16 May 2023 17:13:22 +0000 Subject: [PATCH] fix: reduce event payload --- .../view-results/CarouselStack.jsx | 14 +++- .../view-results/ViewResults.jsx | 68 ++++++++++++------- .../view-results/test/ViewResults.test.jsx | 48 ++++++++++--- 3 files changed, 91 insertions(+), 39 deletions(-) diff --git a/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx b/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx index 77dff51..1b46a91 100644 --- a/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx +++ b/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx @@ -7,8 +7,12 @@ import messages from './messages'; const CarouselStack = ({ selectedRecommendations }) => { const { formatMessage } = useIntl(); - const { name: jobName, recommendations } = selectedRecommendations; + const { id: jobId, name: jobName, recommendations } = selectedRecommendations; const productTypeNames = Object.keys(recommendations); + const courseKeys = recommendations.course?.map(rec => ({ + title: rec.title, + courserun_key: rec.active_run_key, + })); const normalizeProductTypeName = (productType) => { // If the productType is more than one word (i.e. boot_camp) @@ -43,9 +47,13 @@ const CarouselStack = ({ selectedRecommendations }) => { app_name: 'skills_builder', category: 'skills_builder', page: 'skills_builder', - course_key: courseKey, + courserun_key: courseKey, product_type: productType, - selected_recommendations: selectedRecommendations, + selected_recommendations: { + job_id: jobId, + job_name: jobName, + courserun_keys: courseKeys, + }, }, ); }; diff --git a/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx b/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx index a33f9c1..2144352 100644 --- a/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx +++ b/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx @@ -1,5 +1,5 @@ import React, { - useCallback, useContext, useEffect, useState, + useContext, useEffect, useState, } from 'react'; import { Stack, Row, Alert, Spinner, @@ -58,9 +58,24 @@ const ViewResults = () => { })); setJobSkillsList(jobInfo); - setSelectedJobTitle(jobInfo[0].name); + setSelectedJobTitle(results[0].name); setProductRecommendations(results); setIsLoading(false); + sendTrackEvent('edx.skills_builder.recommendation.shown', { + app_name: 'skills_builder', + category: 'skills_builder', + page: 'skills_builder', + selected_recommendations: { + job_id: results[0].id, + job_name: results[0].name, + /* We extract the title and course key into an array of objects */ + courserun_keys: results[0].recommendations.course?.map(rec => ({ + title: rec.title, + courserun_key: rec.active_run_key, + })), + }, + is_default: true, + }); }; getRecommendations() .catch(() => { @@ -69,34 +84,37 @@ const ViewResults = () => { }); }, [careerInterests, jobSearchIndex, productSearchIndex]); - const sendRecommendationShownEvent = useCallback((selectedJobName, isDefault) => { - sendTrackEvent('edx.skills_builder.recommendation.shown', { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - selected_recommendations: productRecommendations.find(rec => rec.name === selectedJobName), - is_default: isDefault, - }); - }, [productRecommendations]); - useEffect(() => { - /* - This useEffect will fire when selectedJobTitle is changed - We initially setSelectedJobTitle when the recommendations are returned - We are sending an event with the is_default field set to true for the initial default selection - */ - const newlySelectedRecommendations = productRecommendations.find(rec => rec.name === selectedJobTitle); - if (!selectedRecommendations && newlySelectedRecommendations) { - sendRecommendationShownEvent(selectedJobTitle, true); - } - setSelectedRecommendations(newlySelectedRecommendations); - }, [productRecommendations, selectedJobTitle, selectedRecommendations, sendRecommendationShownEvent]); + setSelectedRecommendations(productRecommendations.find(rec => rec.name === selectedJobTitle)); + }, [productRecommendations, selectedJobTitle]); const handleJobTitleChange = (e) => { const { value } = e.target; setSelectedJobTitle(value); - // The is_default value will be set to false for any selections made by the user - sendRecommendationShownEvent(value, false); + const currentSelection = productRecommendations.find(rec => rec.name === value); + const { id: jobId, name: jobName, recommendations } = currentSelection; + const courseKeys = recommendations.course?.map(rec => ({ + title: rec.title, + courserun_key: rec.active_run_key, + })); + /* + The is_default value will be set to false for any selections made by the user. + This code is intentionally duplicated from the event that fires in the useEffect for fetching recommendations. + This proved less clunky than refactoring to make things DRY as we have to ensure the first call fires only once. + The previous implementation wrapped the event in an additional useEffect that was looping unnecessarily. + We have plans to refactor all of the event code as part of APER-2392, where we will revisit this approach. + */ + sendTrackEvent('edx.skills_builder.recommendation.shown', { + app_name: 'skills_builder', + category: 'skills_builder', + page: 'skills_builder', + selected_recommendations: { + job_id: jobId, + job_name: jobName, + courserun_keys: courseKeys, + }, + is_default: false, + }); }; if (fetchError) { diff --git a/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx b/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx index 3407fe5..d4df5fa 100644 --- a/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx +++ b/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx @@ -5,7 +5,6 @@ import { mergeConfig } from '@edx/frontend-platform'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { SkillsBuilderWrapperWithContext, contextValue } from '../../../test/setupSkillsBuilder'; import { getProductRecommendations } from '../../../utils/search'; -import { mockData } from '../../../test/__mocks__/jobSkills.mockData'; jest.mock('@edx/frontend-platform/analytics', () => ({ sendTrackEvent: jest.fn(), @@ -61,9 +60,18 @@ describe('view-results', () => { category: 'skills_builder', page: 'skills_builder', selected_recommendations: { - id: 0, - name: 'Prospector', - recommendations: { course: mockData.productRecommendations }, + job_id: 0, + job_name: 'Prospector', + courserun_keys: [ + { + title: 'Mining with the Mons', + courserun_key: 'MONS101', + }, + { + title: 'The Art of Warren Upkeep', + courserun_key: 'WAR101', + }, + ], }, is_default: true, }, @@ -86,9 +94,18 @@ describe('view-results', () => { category: 'skills_builder', page: 'skills_builder', selected_recommendations: { - id: 1, - name: 'Mirror Breaker', - recommendations: { course: mockData.productRecommendations }, + job_id: 1, + job_name: 'Mirror Breaker', + courserun_keys: [ + { + title: 'Mining with the Mons', + courserun_key: 'MONS101', + }, + { + title: 'The Art of Warren Upkeep', + courserun_key: 'WAR101', + }, + ], }, is_default: false, }, @@ -118,12 +135,21 @@ describe('view-results', () => { app_name: 'skills_builder', category: 'skills_builder', page: 'skills_builder', - course_key: 'MONS101', + courserun_key: 'MONS101', product_type: 'course', selected_recommendations: { - id: 0, - name: 'Prospector', - recommendations: { course: mockData.productRecommendations }, + job_id: 0, + job_name: 'Prospector', + courserun_keys: [ + { + title: 'Mining with the Mons', + courserun_key: 'MONS101', + }, + { + title: 'The Art of Warren Upkeep', + courserun_key: 'WAR101', + }, + ], }, }, );