diff --git a/src/components/Sidebar/index.jsx b/src/components/Sidebar/index.jsx index 2d47f297..203b7d23 100644 --- a/src/components/Sidebar/index.jsx +++ b/src/components/Sidebar/index.jsx @@ -2,6 +2,7 @@ import React, { useRef, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; +import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import { Button, Icon, @@ -9,6 +10,7 @@ import { } from '@openedx/paragon'; import { Close } from '@openedx/paragon/icons'; +import { usePromptExperiment } from '../../utils/optimizelyExperiment'; import APIError from '../APIError'; import ChatBox from '../ChatBox'; import Disclosure from '../Disclosure'; @@ -31,6 +33,8 @@ const Sidebar = ({ } = useSelector(state => state.learningAssistant); const chatboxContainerRef = useRef(null); const dispatch = useDispatch(); + const { userId } = getAuthenticatedUser(); + const [ variationKey, experimentName ] = usePromptExperiment(userId); // this use effect is intended to scroll to the bottom of the chat window, in the case // that a message is larger than the chat window height. @@ -80,6 +84,7 @@ const Sidebar = ({ dispatch(clearMessages()); sendTrackEvent('edx.ui.lms.learning_assistant.clear', { course_id: courseId, + ...(variationKey ? { experiment_name: experimentName, variation_key: variationKey } : {}), }); }; diff --git a/src/components/ToggleXpertButton/index.jsx b/src/components/ToggleXpertButton/index.jsx index 6041c9bc..f32d49f2 100644 --- a/src/components/ToggleXpertButton/index.jsx +++ b/src/components/ToggleXpertButton/index.jsx @@ -12,6 +12,7 @@ import { } from '@openedx/paragon'; import { Close } from '@openedx/paragon/icons'; +import { usePromptExperiment } from '../../utils/optimizelyExperiment'; import { ReactComponent as XpertLogo } from '../../assets/xpert-logo.svg'; import './index.scss'; @@ -25,6 +26,7 @@ const ToggleXpert = ({ const [isModalOpen, setIsModalOpen] = useState(true); const [target, setTarget] = useState(null); const { userId } = getAuthenticatedUser(); + const [ variationKey, experimentName ] = usePromptExperiment(userId); const handleClick = (event) => { // log event if the tool is opened @@ -35,6 +37,7 @@ const ToggleXpert = ({ course_id: courseId, user_id: userId, source: event.target.id === 'toggle-button' ? 'toggle' : 'cta', + ...(variationKey ? { experiment_name: experimentName, variation_key: variationKey } : {}), }, ); } @@ -51,6 +54,7 @@ const ToggleXpert = ({ localStorage.setItem('dismissedLearningAssistantCallToAction', 'true'); sendTrackEvent('edx.ui.lms.learning_assistant.dismiss_action_message', { course_id: courseId, + ...(variationKey ? { experiment_name: experimentName, variation_key: variationKey } : {}), }); }; @@ -63,6 +67,7 @@ const ToggleXpert = ({ course_id: courseId, user_id: userId, source: 'product-tour', + ...(variationKey ? { experiment_name: experimentName, variation_key: variationKey } : {}), }, ); }; @@ -78,7 +83,7 @@ const ToggleXpert = ({ (!isOpen && (
diff --git a/src/data/api.js b/src/data/api.js index ec10b41e..c2b89335 100644 --- a/src/data/api.js +++ b/src/data/api.js @@ -1,5 +1,6 @@ import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; -import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import { usePromptExperiment, trackChatBotMessageOptimizely } from '../utils/optimizelyExperiment' async function fetchChatResponse(courseId, messageList, unitId) { const payload = messageList.map((message) => ({ @@ -7,15 +8,24 @@ async function fetchChatResponse(courseId, messageList, unitId) { content: message?.content, })); + const { userId } = getAuthenticatedUser(); + const [ variationKey ] = usePromptExperiment(userId); + let queryParams = { unitId }; + + if (variationKey) { + queryParams.responseVariation = variationKey + trackChatBotMessageOptimizely(userId) + } + queryParams = snakeCaseObject(queryParams); let queryString = new URLSearchParams(queryParams); queryString = queryString.toString(); const url = new URL(`${getConfig().CHAT_RESPONSE_URL}/${courseId}?${queryString}`); - const { data } = await getAuthenticatedHttpClient().post(url.href, payload); + return data; } diff --git a/src/data/thunks.js b/src/data/thunks.js index bdc0a7f4..20c67f3e 100644 --- a/src/data/thunks.js +++ b/src/data/thunks.js @@ -1,5 +1,7 @@ import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; + +import { usePromptExperiment } from '../utils/optimizelyExperiment'; import fetchChatResponse, { fetchLearningAssistantEnabled } from './api'; import { setCurrentMessage, @@ -33,6 +35,8 @@ export function addChatMessage(role, content, courseId) { dispatch(resetApiError()); const { userId } = getAuthenticatedUser(); + const [ variationKey, experimentName ] = usePromptExperiment(userId); + sendTrackEvent('edx.ui.lms.learning_assistant.message', { id: conversationId, course_id: courseId, @@ -40,6 +44,7 @@ export function addChatMessage(role, content, courseId) { timestamp: message.timestamp, role: message.role, content: message.content, + ...(variationKey ? { experiment_name: experimentName, variation_key: variationKey } : {}), }); }; } diff --git a/src/utils/optimizelyExperiment.js b/src/utils/optimizelyExperiment.js index 1d192303..d907f968 100644 --- a/src/utils/optimizelyExperiment.js +++ b/src/utils/optimizelyExperiment.js @@ -1,3 +1,4 @@ +import { useDecision } from '@optimizely/react-sdk' import optimizelyInstance from '../data/optimizely'; const PRODUCT_TOUR_EXP_KEY = 'la_product_tour'; @@ -11,6 +12,17 @@ const activateProductTourExperiment = (userId) => { return variant === PRODUCT_TOUR_EXP_VARIATION; }; +const PROMPT_EXPERIMENT_FLAG = '_cosmo__xpert_gpt_4_0_prompt' +const PROMPT_EXPERIMENT_KEY = 'updated_prompt' + +const usePromptExperiment = (userId) => { + const [{ enabled, variationKey }] = useDecision(PROMPT_EXPERIMENT_FLAG, { autoUpdate: true }, { id: userId }) + + const active = enabled && variationKey === PROMPT_EXPERIMENT_KEY + + return active ? [variationKey, PROMPT_EXPERIMENT_FLAG] : [] +} + const trackChatBotLaunchOptimizely = (userId, userAttributes = {}) => { optimizelyInstance.track('learning_assistant_chat_click', userId, userAttributes); }; @@ -23,4 +35,5 @@ export { activateProductTourExperiment, trackChatBotLaunchOptimizely, trackChatBotMessageOptimizely, + usePromptExperiment, };