diff --git a/src/data/api.js b/src/data/api.js index 7155dac0..499567a2 100644 --- a/src/data/api.js +++ b/src/data/api.js @@ -30,5 +30,15 @@ async function fetchLearningAssistantEnabled(courseId) { return data; } +async function fetchLearningAssistantChatHistory(courseId) { + const url = new URL(`${getConfig().CHAT_RESPONSE_URL}/${courseId}/history`); + + const { data } = await getAuthenticatedHttpClient().get(url.href); + return data; +} + export default fetchChatResponse; -export { fetchLearningAssistantEnabled }; +export { + fetchLearningAssistantEnabled, + fetchLearningAssistantChatHistory, +}; diff --git a/src/data/thunks.js b/src/data/thunks.js index b63d466a..d968d42d 100644 --- a/src/data/thunks.js +++ b/src/data/thunks.js @@ -2,7 +2,7 @@ import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import trackChatBotMessageOptimizely from '../utils/optimizelyExperiment'; -import fetchChatResponse, { fetchLearningAssistantEnabled } from './api'; +import fetchChatResponse, { fetchLearningAssistantChatHistory, fetchLearningAssistantEnabled } from './api'; import { setCurrentMessage, clearCurrentMessage, @@ -81,6 +81,36 @@ export function clearMessages() { }; } +export function fetchChatHistory(courseId) { + return async (dispatch) => { + dispatch(resetApiError()); + dispatch(setApiIsLoading(true)); + + try { + const rawMessageList = await fetchLearningAssistantChatHistory(courseId); + + if (rawMessageList.length) { + const messageList = rawMessageList + .filter(({ timestamp }) => timestamp) // Filter any message without timestamp + .toSorted((a, b) => (a.timestamp > b.timestamp ? 1 : -1)) // Sort by timestamp + .map(({ timestamp, ...msg }) => ({ + ...msg, + timestamp: new Date(timestamp), // Parse ISO time to Date() + })); + + dispatch(setMessageList({ messageList })); + + // If it has chat history, then we assume the user already aknowledged. + dispatch(setDisclosureAcknowledged(true)); + } + } catch (e) { + dispatch(setApiError()); + } + + dispatch(setApiIsLoading(false)); + }; +} + export function updateCurrentMessage(content) { return (dispatch) => { dispatch(setCurrentMessage({ currentMessage: content })); diff --git a/src/hooks/index.js b/src/hooks/index.js new file mode 100644 index 00000000..bfa4b76e --- /dev/null +++ b/src/hooks/index.js @@ -0,0 +1,2 @@ +/* eslint-disable import/prefer-default-export */ +export { useMessageHistory } from './message-history'; diff --git a/src/hooks/message-history.js b/src/hooks/message-history.js new file mode 100644 index 00000000..5da54779 --- /dev/null +++ b/src/hooks/message-history.js @@ -0,0 +1,15 @@ +/* eslint-disable import/prefer-default-export */ +import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { fetchChatHistory } from '../data/thunks'; + +export const useMessageHistory = (courseId) => { + const dispatch = useDispatch(); + const { isEnabled } = useSelector(state => state.learningAssistant); + + useEffect(() => { + if (!courseId || !isEnabled) { return; } + + dispatch(fetchChatHistory(courseId)); + }, [dispatch, isEnabled, courseId]); +}; diff --git a/src/widgets/Xpert.jsx b/src/widgets/Xpert.jsx index ade3b1e9..88ee461d 100644 --- a/src/widgets/Xpert.jsx +++ b/src/widgets/Xpert.jsx @@ -6,9 +6,11 @@ import { updateSidebarIsOpen, getIsEnabled } from '../data/thunks'; import ToggleXpert from '../components/ToggleXpertButton'; import Sidebar from '../components/Sidebar'; import { ExperimentsProvider } from '../experiments'; +import { useMessageHistory } from '../hooks'; const Xpert = ({ courseId, contentToolsEnabled, unitId }) => { const dispatch = useDispatch(); + useMessageHistory(courseId); const { isEnabled,