From f1804de9059e72084687723ebe9751ce32e28a77 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 15:32:13 +0000 Subject: [PATCH 01/12] fix: save draft response hook --- src/data/services/lms/hooks/data.ts | 2 +- src/data/services/lms/urls.js | 2 +- src/hooks/app.js | 2 +- src/views/SubmissionView/hooks/useTextResponsesData.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/services/lms/hooks/data.ts b/src/data/services/lms/hooks/data.ts index 4a44f0ee..9f60e90c 100644 --- a/src/data/services/lms/hooks/data.ts +++ b/src/data/services/lms/hooks/data.ts @@ -85,7 +85,7 @@ export const usePageData = () => { } const url = (hasSubmitted || view === stepNames.xblock) ? `${pageDataUrl}` - : `${pageDataUrl}/${view}`; + : `${pageDataUrl}${view}`; console.log("page data real data"); return getAuthenticatedHttpClient().post(url, {}).then( ({ data }) => camelCaseObject(data) diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index dbe789db..aed4642d 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -25,7 +25,7 @@ export const usePageDataUrl = (step) => { if ( [stepNames.submission, stepNames.peer].includes(step) ) { return `${baseUrl}/get_learner_data/${step}`; } - return `${baseUrl}/get_learner_data`; + return `${baseUrl}/get_learner_data/`; }; export default StrictDict({ diff --git a/src/hooks/app.js b/src/hooks/app.js index 90a787f8..4ce0a075 100644 --- a/src/hooks/app.js +++ b/src/hooks/app.js @@ -34,7 +34,7 @@ export const { useDeleteFile, useDownloadFiles, useRefreshPageData, - useSaveResponse, + useSaveDraftResponse, useSubmitResponse, useUploadFiles, } = lmsActions; diff --git a/src/views/SubmissionView/hooks/useTextResponsesData.js b/src/views/SubmissionView/hooks/useTextResponsesData.js index 462a3552..c96d5034 100644 --- a/src/views/SubmissionView/hooks/useTextResponsesData.js +++ b/src/views/SubmissionView/hooks/useTextResponsesData.js @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; -import { useSaveResponse, useTextResponses } from 'hooks/app'; +import { useSaveDraftResponse, useTextResponses } from 'hooks/app'; import { MutationStatus } from 'constants'; export const stateKeys = StrictDict({ @@ -15,7 +15,7 @@ const useTextResponsesData = () => { const [isDirty, setIsDirty] = useKeyedState(stateKeys.isDirty, false); const [value, setValue] = useKeyedState(stateKeys.textResponses, textResponses); - const saveResponseMutation = useSaveResponse(); + const saveResponseMutation = useSaveDraftResponse(); const saveResponse = useCallback(() => { setIsDirty(false); From b470b2b1928c6648d466e6944c93f93e4bcf46e9 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 15:58:30 +0000 Subject: [PATCH 02/12] fix: auto-resize --- src/App.jsx | 24 ++++++++++++++++++++++++ src/index.jsx | 15 --------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 76f3b9ea..467de186 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,3 +1,4 @@ +import React from 'react'; import { Routes, Route } from 'react-router-dom'; import { AuthenticatedPageRoute, @@ -21,6 +22,29 @@ import messages from './messages'; import routes from './routes'; const RouterRoot = () => { + const { body } = document; + React.useEffect(() => { + const resizeEvent = () => { + const { clientHeight, scrollHeight, offsetHeight } = body; + console.log({ clientHeight, scrollHeight, offsetHeight }); + const height = body.clientHeight; + console.log({ body, scrollHeight: body.scrollHeight, height }); + console.log(document.referrer); + console.log({ resize: height }); + if (document.referrer !== '' && height !== 0) { + window.parent.postMessage( + { + type: 'ora-resize', + payload: { height }, + }, + document.referrer, + ); + } + }; + resizeEvent(); + window.addEventListener('resize', resizeEvent); + }, [body.scrollHeight]); + const { formatMessage } = useIntl(); // test diff --git a/src/index.jsx b/src/index.jsx index cc119158..58ac232b 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -50,18 +50,3 @@ subscribe(APP_INIT_ERROR, (error) => { initialize({ messages, }); - -const resizeEvent = () => { - const height = document.body.scrollHeight; - if (document.referrer !== '') { - window.parent.postMessage( - { - type: 'ora-resize', - payload: { height }, - }, - document.referrer, - ); - } -}; -window.onload = () => resizeEvent(); -window.onresize = () => resizeEvent(); From 1fc6b49d8c47d0191bd2505fa61bf0768f363b8e Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 16:53:14 +0000 Subject: [PATCH 03/12] fix: save draft behavior --- .../hooks/useActiveSubmissionConfig.js | 6 ++--- src/data/services/lms/api.ts | 17 ++++++------ src/data/services/lms/hooks/actions/index.ts | 16 ++++++++---- src/data/services/lms/urls.js | 5 ++++ src/hooks/app.js | 1 + .../hooks/useSubmissionViewData.js | 26 ++++++++++++++++--- .../hooks/useTextResponsesData.js | 10 ++++++- 7 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/components/ModalActions/hooks/useActiveSubmissionConfig.js b/src/components/ModalActions/hooks/useActiveSubmissionConfig.js index 394e10e5..e8b84fda 100644 --- a/src/components/ModalActions/hooks/useActiveSubmissionConfig.js +++ b/src/components/ModalActions/hooks/useActiveSubmissionConfig.js @@ -9,13 +9,13 @@ const useActiveSubmissionConfig = ({ formatMessage, }) => { const saveAndClose = React.useCallback( - () => (options.saveResponse ? options.saveResponse().then(closeModal) : null), + () => (options.finishLater ? options.finishLater().then(closeModal) : null), [options, closeModal], ); if (!options) { return null; } - const { submit, submitStatus, saveResponseStatus } = options; + const { submit, submitStatus, finishLaterStatus } = options; return { primary: { @@ -28,7 +28,7 @@ const useActiveSubmissionConfig = ({ }, secondary: { onClick: saveAndClose, - state: saveResponseStatus, + state: finishLaterStatus, labels: { [MutationStatus.idle]: formatMessage(messages.finishLater), [MutationStatus.loading]: formatMessage(messages.savingResponse), diff --git a/src/data/services/lms/api.ts b/src/data/services/lms/api.ts index f6f4909f..7e226d29 100644 --- a/src/data/services/lms/api.ts +++ b/src/data/services/lms/api.ts @@ -1,5 +1,7 @@ +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { queryKeys } from './constants'; import { AssessmentData } from './types'; +import * as urls from './urls'; export const submitAssessment = (data: AssessmentData) => { // TODO: submit rubric @@ -30,15 +32,12 @@ export const submitResponse = (data: any) => { return promise; }; -export const saveResponse = (data: any) => { - console.log({ save: data }); - // TODO: save response for later - return new Promise((resolve) => { - setTimeout(() => { - console.log('response saved'); - resolve(null); - }, 1000); - }); +export const useSaveDraft = () => { + const url = urls.useSaveDraftUrl(); + return (data: any) => { + console.log({ save: data }); + return getAuthenticatedHttpClient().post(url, { response: data }); + }; }; export const fakeProgress = async (requestConfig) => { diff --git a/src/data/services/lms/hooks/actions/index.ts b/src/data/services/lms/hooks/actions/index.ts index 44d01332..49c6e76d 100644 --- a/src/data/services/lms/hooks/actions/index.ts +++ b/src/data/services/lms/hooks/actions/index.ts @@ -51,17 +51,23 @@ export const useSubmitResponse = ({ onSuccess } = {}) => { }); }; -export const useSaveDraftResponse = ({ onSuccess } = {}) => { +export const useFinishLater = () => { // const queryClient = useQueryClient(); const testDataPath = useTestDataPath(); - - const apiFn = apiLog(api.saveResponse, 'saveDraftResponse'); - + const apiFn = api.useSaveDraft(); const mockFn = React.useCallback((data) => Promise.resolve(data), []); + return useMutation({ + mutationFn: apiLog(testDataPath ? mockFn : apiFn, 'savedDraftResponse'), + }); +}; +export const useSaveDraftResponse = () => { + // const queryClient = useQueryClient(); + const testDataPath = useTestDataPath(); + const apiFn = api.useSaveDraft(); + const mockFn = React.useCallback((data) => Promise.resolve(data), []); return useMutation({ mutationFn: apiLog(testDataPath ? mockFn : apiFn, 'savedDraftResponse'), - onSuccess, }); }; diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index aed4642d..aa1c79ca 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -10,6 +10,11 @@ const useBaseUrl = () => { return `${getConfig().LMS_BASE_URL}/courses/${courseId}/xblock/${xblockId}/handler`; }; +export const useSaveDraftUrl = () => { + const baseUrl = useBaseUrl(); + return `${baseUrl}/submission/draft`; +}; + export const useORAConfigUrl = () => { const baseUrl = useBaseUrl(); return `${baseUrl}/get_block_info`; diff --git a/src/hooks/app.js b/src/hooks/app.js index 4ce0a075..64b3aaf2 100644 --- a/src/hooks/app.js +++ b/src/hooks/app.js @@ -31,6 +31,7 @@ export const { } = lmsSelectors; export const { + useFinishLater, useDeleteFile, useDownloadFiles, useRefreshPageData, diff --git a/src/views/SubmissionView/hooks/useSubmissionViewData.js b/src/views/SubmissionView/hooks/useSubmissionViewData.js index acf41621..0683df9a 100644 --- a/src/views/SubmissionView/hooks/useSubmissionViewData.js +++ b/src/views/SubmissionView/hooks/useSubmissionViewData.js @@ -1,4 +1,6 @@ -import { useCallback } from 'react'; +import { useCallback, useEffect } from 'react'; + +import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; import { useGlobalState, @@ -12,7 +14,12 @@ import { stepStates, stepNames } from 'constants'; import useTextResponsesData from './useTextResponsesData'; import useUploadedFilesData from './useUploadedFilesData'; +const stateKeys = StrictDict({ + hasSavedDraft: 'hasSavedDraft', +}); + const useSubmissionViewData = () => { + const [hasSavedDraft, setHasSavedDraft] = useKeyedState(stateKeys.hasSavedDraft, false); const hasSubmitted = useHasSubmitted(); const setHasSubmitted = useSetHasSubmitted(); const submitResponseMutation = useSubmitResponse(); @@ -23,9 +30,10 @@ const useSubmissionViewData = () => { const { textResponses, onUpdateTextResponse, - isDraftSaved, saveResponse, saveResponseStatus, + finishLater, + finishLaterStatus, } = useTextResponsesData(); const { uploadedFiles, @@ -42,8 +50,20 @@ const useSubmissionViewData = () => { }); }, [setHasSubmitted, submitResponseMutation, textResponses, uploadedFiles]); + useEffect(() => { + const timer = setTimeout(() => { + saveResponse(); + if (!hasSavedDraft) { + setHasSavedDraft(true); + } + }, 5000); + return () => clearTimeout(timer); + }, [saveResponse]); + return { actionOptions: { + finishLater, + finishLaterStatus, saveResponse, saveResponseStatus, submit: submitResponseHandler, @@ -53,7 +73,7 @@ const useSubmissionViewData = () => { hasSubmitted, textResponses, onUpdateTextResponse, - isDraftSaved, + isDraftSaved: hasSavedDraft, uploadedFiles, onDeletedFile, onFileUploaded, diff --git a/src/views/SubmissionView/hooks/useTextResponsesData.js b/src/views/SubmissionView/hooks/useTextResponsesData.js index c96d5034..6b85046d 100644 --- a/src/views/SubmissionView/hooks/useTextResponsesData.js +++ b/src/views/SubmissionView/hooks/useTextResponsesData.js @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; -import { useSaveDraftResponse, useTextResponses } from 'hooks/app'; +import { useFinishLater, useSaveDraftResponse, useTextResponses } from 'hooks/app'; import { MutationStatus } from 'constants'; export const stateKeys = StrictDict({ @@ -16,12 +16,18 @@ const useTextResponsesData = () => { const [value, setValue] = useKeyedState(stateKeys.textResponses, textResponses); const saveResponseMutation = useSaveDraftResponse(); + const finishLaterMutation = useFinishLater(); const saveResponse = useCallback(() => { setIsDirty(false); return saveResponseMutation.mutateAsync({ textResponses: value }); }, [setIsDirty, saveResponseMutation, value]); + const finishLater = useCallback(() => { + setIsDirty(false); + return finishLaterMutation.mutateAsync({ textResponses: value }); + }, [setIsDirty, finishLaterMutation, value]); + const onChange = useCallback((index) => (textResponse) => { setValue(oldResponses => { const out = [...oldResponses]; @@ -37,6 +43,8 @@ const useTextResponsesData = () => { isDraftSaved: saveResponseMutation.status === MutationStatus.success && !isDirty, saveResponse, saveResponseStatus: saveResponseMutation.status, + finishLater, + finishLaterStatus: finishLaterMutation.status, }; }; From 173c1def27f4ccdedce7a1b48d1b795ba7e64887 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:03:45 +0000 Subject: [PATCH 04/12] fix: to self submission --- src/App.jsx | 32 +++++++++------ .../hooks/useFinishedStateActions.js | 1 + .../hooks/useModalActionConfig.js | 2 +- src/data/services/lms/api.ts | 39 +++++++------------ src/data/services/lms/hooks/actions/index.ts | 4 +- src/data/services/lms/hooks/data.ts | 16 +++++--- .../services/lms/hooks/selectors/oraConfig.ts | 2 +- src/data/services/lms/urls.js | 22 ++++------- src/hooks/actions/useStartStepAction.js | 4 +- src/hooks/modal.js | 18 ++++++++- .../hooks/useSubmissionViewData.js | 26 +++++++++---- 11 files changed, 93 insertions(+), 73 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 467de186..b69f39ce 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -16,27 +16,24 @@ import GradeView from 'views/GradeView'; import AppContainer from 'components/AppContainer'; import ModalContainer from 'components/ModalContainer'; +import { useRefreshPageData } from 'hooks/app'; +import { useRefreshUpstream } from 'hooks/modal'; import { useUpdateTestProgressKey } from 'hooks/test'; import messages from './messages'; import routes from './routes'; -const RouterRoot = () => { +const App = () => { const { body } = document; + const refreshPageData = useRefreshPageData(); + const refreshUpstream = useRefreshUpstream(); React.useEffect(() => { const resizeEvent = () => { - const { clientHeight, scrollHeight, offsetHeight } = body; - console.log({ clientHeight, scrollHeight, offsetHeight }); - const height = body.clientHeight; - console.log({ body, scrollHeight: body.scrollHeight, height }); - console.log(document.referrer); - console.log({ resize: height }); + // const { clientHeight, scrollHeight, offsetHeight } = body; + const height = body.scrollHeight; if (document.referrer !== '' && height !== 0) { window.parent.postMessage( - { - type: 'ora-resize', - payload: { height }, - }, + { type: 'ora-resize', payload: { height } }, document.referrer, ); } @@ -45,6 +42,17 @@ const RouterRoot = () => { window.addEventListener('resize', resizeEvent); }, [body.scrollHeight]); + React.useEffect(() => { + console.log("init refresh behavior"); + window.addEventListener('message', (event) => { + console.log({ event }); + if (event.data.type === 'ora-refresh') { + console.log("ORA Refresh"); + refreshPageData(); + } + }); + }, []); + const { formatMessage } = useIntl(); // test @@ -109,4 +117,4 @@ const RouterRoot = () => { ); }; -export default RouterRoot; +export default App; diff --git a/src/components/ModalActions/hooks/useFinishedStateActions.js b/src/components/ModalActions/hooks/useFinishedStateActions.js index f53de520..d9e17e77 100644 --- a/src/components/ModalActions/hooks/useFinishedStateActions.js +++ b/src/components/ModalActions/hooks/useFinishedStateActions.js @@ -66,6 +66,7 @@ const useFinishedStateActions = () => { } console.log("?"); // submission finished state + console.log({ startStepAction }); return { primary: startStepAction, secondary: finishLaterAction }; }; diff --git a/src/components/ModalActions/hooks/useModalActionConfig.js b/src/components/ModalActions/hooks/useModalActionConfig.js index 7f4e1e4a..27d5db02 100644 --- a/src/components/ModalActions/hooks/useModalActionConfig.js +++ b/src/components/ModalActions/hooks/useModalActionConfig.js @@ -19,7 +19,7 @@ const useModalActionConfig = ({ options }) => { const exitAction = useExitAction(); - // console.log({ useModalActionConfig: { step, globalState, hasSubmitted } }); + console.log({ useModalActionConfig: { step, globalState, hasSubmitted } }); // finished state if (hasSubmitted) { return finishedStateActions; diff --git a/src/data/services/lms/api.ts b/src/data/services/lms/api.ts index 7e226d29..a6f69fc3 100644 --- a/src/data/services/lms/api.ts +++ b/src/data/services/lms/api.ts @@ -1,35 +1,22 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; -import { queryKeys } from './constants'; +// import { queryKeys } from './constants'; import { AssessmentData } from './types'; import * as urls from './urls'; -export const submitAssessment = (data: AssessmentData) => { - // TODO: submit rubric - console.log({ submitAssessment: data }); - let resolvePromise; - const promise = new Promise((resolve) => { - resolvePromise = resolve; - }); - setTimeout(() => { - console.log('assessment submitted'); - resolvePromise(data); - console.log("Should have resolved"); - }, 1000); - return promise; +export const useSubmitAssessment = () => { + const url = urls.useSubmitAssessmentUrl(); + return (data: AssessmentData) => { + console.log({ submitAssessment: data }); + return getAuthenticatedHttpClient().post(url, data); + }; }; -export const submitResponse = (data: any) => { - console.log({ submitResponse: data }); - let resolvePromise; - const promise = new Promise((resolve) => { - resolvePromise = resolve; - }); - setTimeout(() => { - console.log('response submitted'); - resolvePromise(null); - console.log("Should have resolved"); - }, 1000); - return promise; +export const useSubmitResponse = () => { + const url = urls.useSubmitUrl(); + return (data: any) => { + console.log({ submitResponse: data }); + return getAuthenticatedHttpClient().post(url, { submission: data }); + }; }; export const useSaveDraft = () => { diff --git a/src/data/services/lms/hooks/actions/index.ts b/src/data/services/lms/hooks/actions/index.ts index 49c6e76d..78427dd1 100644 --- a/src/data/services/lms/hooks/actions/index.ts +++ b/src/data/services/lms/hooks/actions/index.ts @@ -22,7 +22,7 @@ const apiLog = (apiMethod, name) => (data) => apiMethod(data).then(response => { export const useSubmitAssessment = ({ onSuccess } = {}) => { const testDataPath = useTestDataPath(); - const apiFn = api.submitAssessment; + const apiFn = api.useSubmitAssessment(); const mockFn = React.useCallback((data) => Promise.resolve(data), []); return useMutation({ mutationFn: apiLog(testDataPath ? mockFn : apiFn, 'submittedAssessment'), @@ -43,7 +43,7 @@ export const useSubmitResponse = ({ onSuccess } = {}) => { queryClient.setQueryData([queryKeys.pageData], state); return Promise.resolve(state); }, [queryClient, step]); - const apiFn = api.submitAssessment; + const apiFn = api.useSubmitResponse(); return useMutation({ mutationFn: apiLog(testDataPath ? mockFn : apiFn, 'submittedResponse'), diff --git a/src/data/services/lms/hooks/data.ts b/src/data/services/lms/hooks/data.ts index 9f60e90c..558cef3f 100644 --- a/src/data/services/lms/hooks/data.ts +++ b/src/data/services/lms/hooks/data.ts @@ -84,13 +84,17 @@ export const usePageData = () => { return Promise.resolve(camelCaseObject(loadState({ view, progressKey }))); } const url = (hasSubmitted || view === stepNames.xblock) - ? `${pageDataUrl}` - : `${pageDataUrl}${view}`; + ? pageDataUrl() + : pageDataUrl(viewStep); console.log("page data real data"); - return getAuthenticatedHttpClient().post(url, {}).then( - ({ data }) => camelCaseObject(data) - ); - }, [testDataPath, view, progressKey, testProgressKey]); + console.log({ pageDataUrl: url }); + return getAuthenticatedHttpClient().post(url, {}) + .then(({ data }) => camelCaseObject(data)) + .then(data => { + console.log({ pageData: data }); + return data; + }); + }, [testDataPath, view, progressKey, testProgressKey, hasSubmitted]); return useQuery({ queryKey: [queryKeys.pageData, testDataPath], diff --git a/src/data/services/lms/hooks/selectors/oraConfig.ts b/src/data/services/lms/hooks/selectors/oraConfig.ts index 15bee7f8..81142209 100644 --- a/src/data/services/lms/hooks/selectors/oraConfig.ts +++ b/src/data/services/lms/hooks/selectors/oraConfig.ts @@ -53,7 +53,7 @@ export const useEmptyRubric = () => { return React.useMemo(() => ({ criteria: rubric.criteria.map((criterion) => ({ selectedOption: null, - feedback: criterion.feedbackEnabled ? '' : null, + feedback: '', })), overallFeedback: '', }), [rubric.criteria]); diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index aa1c79ca..8345ad0f 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -10,27 +10,21 @@ const useBaseUrl = () => { return `${getConfig().LMS_BASE_URL}/courses/${courseId}/xblock/${xblockId}/handler`; }; -export const useSaveDraftUrl = () => { - const baseUrl = useBaseUrl(); - return `${baseUrl}/submission/draft`; -}; - -export const useORAConfigUrl = () => { - const baseUrl = useBaseUrl(); - return `${baseUrl}/get_block_info`; -}; +export const useSaveDraftUrl = () => `${useBaseUrl()}/submission/draft`; +export const useSubmitUrl = () => `${useBaseUrl()}/submission/submit`; +export const useSubmitAssessmentUrl = () => `${useBaseUrl()}/assessment/submit`; +export const useORAConfigUrl = () => `${useBaseUrl()}/get_block_info`; export const useViewUrl = () => { const { xblockId, courseId } = useParams(); return ({ view }) => `${getConfig().BASE_URL}/${stepRoutes[view]}/${courseId}/${xblockId}`; }; -export const usePageDataUrl = (step) => { +export const usePageDataUrl = () => { const baseUrl = useBaseUrl(); - if ( [stepNames.submission, stepNames.peer].includes(step) ) { - return `${baseUrl}/get_learner_data/${step}`; - } - return `${baseUrl}/get_learner_data/`; + return (step) => (step + ? `${baseUrl}/get_learner_data/${step}` + : `${baseUrl}/get_learner_data/`); }; export default StrictDict({ diff --git a/src/hooks/actions/useStartStepAction.js b/src/hooks/actions/useStartStepAction.js index 7110f2eb..8a8487ef 100644 --- a/src/hooks/actions/useStartStepAction.js +++ b/src/hooks/actions/useStartStepAction.js @@ -23,10 +23,10 @@ const useStartStepAction = (viewStep) => { } const onClick = () => { - navigate(`/${stepRoutes[stepName]}/${courseId}/${xblockId}`); - refreshPageData(); setHasSubmitted(false); setShowValidation(false); + navigate(`/${stepRoutes[stepName]}/${courseId}/${xblockId}`); + refreshPageData(); }; const startMessages = { diff --git a/src/hooks/modal.js b/src/hooks/modal.js index 53332970..5b9e591f 100644 --- a/src/hooks/modal.js +++ b/src/hooks/modal.js @@ -2,10 +2,26 @@ import { useLocation } from 'react-router-dom'; import { useViewUrl } from 'data/services/lms/urls'; import { routeSteps } from 'constants'; +export const useRefreshUpstream = () => { + if (document.referrer !== '') { + const postMessage = (data) => window.parent.postMessage(data, process.env.BASE_URL); + return () => { + console.log("Send refresh upstream"); + postMessage({ type: 'ora-refresh' }); + }; + } + return () => { + console.log("refresh upstream"); + }; +}; + export const useCloseModal = () => { if (document.referrer !== '') { const postMessage = (data) => window.parent.postMessage(data, document.referrer); - return () => postMessage({ type: 'plugin.modal-close' }); + return () => { + postMessage({ type: 'ora-refresh' }); + postMessage({ type: 'plugin.modal-close' }); + }; } return () => { console.log("CLose Modal"); diff --git a/src/views/SubmissionView/hooks/useSubmissionViewData.js b/src/views/SubmissionView/hooks/useSubmissionViewData.js index 0683df9a..dd8769f5 100644 --- a/src/views/SubmissionView/hooks/useSubmissionViewData.js +++ b/src/views/SubmissionView/hooks/useSubmissionViewData.js @@ -8,7 +8,11 @@ import { useSubmitResponse, useSetHasSubmitted, useHasSubmitted, + useRefreshPageData, } from 'hooks/app'; +import { + useRefreshUpstream, +} from 'hooks/modal'; import { stepStates, stepNames } from 'constants'; import useTextResponsesData from './useTextResponsesData'; @@ -25,6 +29,8 @@ const useSubmissionViewData = () => { const submitResponseMutation = useSubmitResponse(); const rubricConfig = useRubricConfig(); const globalState = useGlobalState({ step: stepNames.submission }); + const refreshPageData = useRefreshPageData(); + const refreshUpstream = useRefreshUpstream(); const stepState = hasSubmitted ? stepStates.submitted : globalState.stepState; const { @@ -47,18 +53,22 @@ const useSubmissionViewData = () => { uploadedFiles, }).then(() => { setHasSubmitted(true); + refreshPageData(); + refreshUpstream(); }); }, [setHasSubmitted, submitResponseMutation, textResponses, uploadedFiles]); useEffect(() => { - const timer = setTimeout(() => { - saveResponse(); - if (!hasSavedDraft) { - setHasSavedDraft(true); - } - }, 5000); - return () => clearTimeout(timer); - }, [saveResponse]); + if (!hasSubmitted) { + const timer = setTimeout(() => { + saveResponse(); + if (!hasSavedDraft) { + setHasSavedDraft(true); + } + }, 5000); + return () => clearTimeout(timer); + } + }, [saveResponse, hasSubmitted]); return { actionOptions: { From 7b25fa96de41fa217a89acd99ebeafa9df985233 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:08:38 +0000 Subject: [PATCH 05/12] fix: self assessment submission --- src/data/redux/app/reducer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/redux/app/reducer.js b/src/data/redux/app/reducer.js index 26ca7890..3e45bb39 100644 --- a/src/data/redux/app/reducer.js +++ b/src/data/redux/app/reducer.js @@ -26,7 +26,7 @@ const app = createSlice({ reducers: { loadAssessment: (state, { payload }) => ({ ...state, - assessment: { ...initialState.assessment, submittedAssessment: payload }, + assessment: { ...initialState.assessment, submittedAssessment: payload.data }, }), setHasSubmitted: (state, { payload }) => ({ ...state, From 73886be04cd381f1280af955f82ff7452f2e3775 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:30:00 +0000 Subject: [PATCH 06/12] fix: staff step --- .../StatusAlert/useStatusAlertData.jsx | 6 + src/data/redux/app/reducer.js | 2 + src/data/redux/app/selectors/index.js | 2 + src/data/redux/hooks/app.js | 2 + src/data/services/lms/hooks/selectors.test.ts | 141 ------------------ src/hooks/app.js | 2 + src/hooks/assessment.js | 8 + .../hooks/useSubmissionViewData.js | 7 +- src/views/SubmissionView/index.jsx | 6 +- 9 files changed, 31 insertions(+), 145 deletions(-) delete mode 100644 src/data/services/lms/hooks/selectors.test.ts diff --git a/src/components/StatusAlert/useStatusAlertData.jsx b/src/components/StatusAlert/useStatusAlertData.jsx index 444f671b..6d84544e 100644 --- a/src/components/StatusAlert/useStatusAlertData.jsx +++ b/src/components/StatusAlert/useStatusAlertData.jsx @@ -141,6 +141,12 @@ const useStatusAlertData = ({ heading: messages.headings.peer.finished, })]; } + if (stepName === stepNames.staff) { + return [alertConfig({ + message: messages.alerts[activeStepName].staffAssessment, + heading: messages.headings[activeStepName].staffAssessment, + })]; + } return [alertConfig({ message: messages.alerts[stepName][stepState], heading: messages.headings[stepName][stepState], diff --git a/src/data/redux/app/reducer.js b/src/data/redux/app/reducer.js index 3e45bb39..df499464 100644 --- a/src/data/redux/app/reducer.js +++ b/src/data/redux/app/reducer.js @@ -7,6 +7,7 @@ const initialState = { submittedAssessment: null, showTrainingError: false, }, + response: [], formFields: { criteria: [], overallFeedback: '', @@ -28,6 +29,7 @@ const app = createSlice({ ...state, assessment: { ...initialState.assessment, submittedAssessment: payload.data }, }), + loadResponse: (state, { payload }) => ({ ...state, response: payload }), setHasSubmitted: (state, { payload }) => ({ ...state, hasSubmitted: payload, diff --git a/src/data/redux/app/selectors/index.js b/src/data/redux/app/selectors/index.js index 5824b0bd..69c4493c 100644 --- a/src/data/redux/app/selectors/index.js +++ b/src/data/redux/app/selectors/index.js @@ -12,6 +12,8 @@ const selectors = { formFieldsData(state).criteria[criterionIndex]?.selectedOption ), + response: createSelector(rootSelector, ({ response }) => response), + hasSubmitted: createSelector(rootSelector, ({ hasSubmitted }) => hasSubmitted), overallFeedback: (state) => formFieldsData(state).overallFeedback, diff --git a/src/data/redux/hooks/app.js b/src/data/redux/hooks/app.js index f0b71f24..aab07654 100644 --- a/src/data/redux/hooks/app.js +++ b/src/data/redux/hooks/app.js @@ -12,6 +12,7 @@ export const useHasSubmitted = () => useSelector(selectors.hasSubmitted); export const useShowValidation = () => useSelector(selectors.showValidation); export const useShowTrainingError = () => useSelector(selectors.showTrainingError); export const useOverallFeedbackValue = () => useSelector(selectors.overallFeedback); +export const useResponse = () => useSelector(selectors.response); /* special selectors */ export const useCriterionOption = criterionIndex => ( @@ -31,6 +32,7 @@ export const useSetShowTrainingError = () => useActionHook(actions.setShowTraini export const useSetFormFields = () => useActionHook(actions.setFormFields); export const useResetAssessment = () => useActionHook(actions.resetAssessment); export const useSetOverallFeedback = () => useActionHook(actions.setOverallFeedback); +export const useSetResponse = () => useActionHook(actions.setResponse); export const useSetCriterionFeedback = (criterionIndex) => { const dispatch = useDispatch(); diff --git a/src/data/services/lms/hooks/selectors.test.ts b/src/data/services/lms/hooks/selectors.test.ts deleted file mode 100644 index 0a9bb0f6..00000000 --- a/src/data/services/lms/hooks/selectors.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { when } from 'jest-when'; -import { keyStore } from '@edx/react-unit-test-utils'; - -import * as data from './data'; -import * as selectors from './selectors'; - -const statusData = { - isLoading: 'is-loading', - isFetching: 'is-fetching', - isInitialLoading: 'is-initial-loading', - status: 'status', - error: 'error', -}; - -const testValue = 'some-test-data'; - -const dataKeys = keyStore(data); -const selectorKeys = keyStore(selectors); - -const mockHook = (module, key, returnValue) => { - const spy = jest.spyOn(module, key); - when(spy).calledWith().mockReturnValueOnce(returnValue); -}; - -describe('lms data selector hooks', () => { - const mockORAConfig = (returnValue) => { - mockHook(data, dataKeys.useORAConfig, returnValue); - }; - const mockORAData = (returnValue) => { - mockHook(selectors, selectorKeys.useORAConfigData, returnValue); - }; - describe('ORA Config selectors', () => { - describe('useORAConfigDataStatus', () => { - it('returns status data from useORAConfig call', () => { - mockORAConfig({ - ...statusData, - other: 'field', - and: 'another one', - }); - expect(selectors.useORAConfigDataStatus()).toEqual(statusData); - }); - }); - describe('useIsORAConfigLoaded', () => { - it('returns true if ORAConfig.status is "success"', () => { - mockORAConfig({ ...statusData, status: 'success' }); - expect(selectors.useIsORAConfigLoaded()).toEqual(true); - }); - it('returns false if ORAConfig.status is not "success"', () => { - mockORAConfig({ ...statusData, status: 'random' }); - expect(selectors.useIsORAConfigLoaded()).toEqual(false); - }); - }); - describe('useORAConfigData', () => { - it('returns data from ORAConfig', () => { - mockORAConfig({ ...statusData, data: testValue }); - expect(selectors.useORAConfigData()).toEqual(testValue); - }); - }); - describe('useSubmissionConfig', () => { - it('returns submissionConfig from ORAConfigData', () => { - mockORAData({ submissionConfig: testValue }); - expect(selectors.useSubmissionConfig()).toEqual(testValue); - }); - }); - describe('useAssessmentStepConfig', () => { - it('returns assessmentSteps from ORAConfigData', () => { - mockORAData({ assessmentSteps: testValue }); - expect(selectors.useAssessmentStepConfig()).toEqual(testValue); - }); - }); - describe('useRubricConfig', () => { - it('returns rubric from ORAConfigData', () => { - mockORAData({ rubric: testValue }); - expect(selectors.useRubricConfig()).toEqual(testValue); - }); - }); - describe('useLeaderboardConfig', () => { - it('returns rubric from ORAConfigData', () => { - mockORAData({ leaderboardConfig: testValue }); - expect(selectors.useLeaderboardConfig()).toEqual(testValue); - }); - }); - }); - describe('Page Data selectors', () => { - const mockPageDataQuery = (returnValue) => { - mockHook(data, dataKeys.usePageData, returnValue); - }; - const mockPageData = (returnValue) => { - mockHook(selectors, selectorKeys.usePageData, returnValue); - }; - describe('usePageDataStatus', () => { - it('returns status data from useORAConfig call', () => { - mockPageDataQuery({ - ...statusData, - other: 'field', - and: 'another one', - }); - expect(selectors.usePageDataStatus()).toEqual(statusData); - }); - }); - describe('useIsPageDataLoaded', () => { - it('returns true if PageData.status is "success"', () => { - mockPageDataQuery({ ...statusData, status: 'success' }); - expect(selectors.useIsPageDataLoaded()).toEqual(true); - }); - it('returns false if PageData.status is not "success"', () => { - mockPageDataQuery({ ...statusData, status: 'random' }); - expect(selectors.useIsPageDataLoaded()).toEqual(false); - }); - }); - describe('usePageData', () => { - it('returns data from PageData query', () => { - mockPageDataQuery({ ...statusData, data: testValue }); - expect(selectors.usePageData()).toEqual(testValue); - }); - }); - describe('useSubmissionTeamInfo', () => { - it('returns submission team info from PageData', () => { - mockPageData({ submission: { teamInfo: testValue } }); - expect(selectors.useSubmissionTeamInfo()).toEqual(testValue); - }); - }); - describe('useSubmissionStatus', () => { - it('returns hasCancelled, hasReceivedGraded, and hasSubmitted', () => { - const submissionStatus = { - hasCancelled: 'has-cancelled', - hasReceivedGrade: 'has-received-grade', - hasSubmitted: 'has-submitted', - }; - mockPageData({ submission: { ...submissionStatus, other: 'fields' } }); - expect(selectors.useSubmissionStatus()).toEqual(submissionStatus); - }); - }); - describe('useSubmissionResponse', () => { - it('returns submission response from PageData', () => { - mockPageData({ submission: { response: testValue } }); - expect(selectors.useSubmissionResponse()).toEqual(testValue); - }) - }); - }); -}); diff --git a/src/hooks/app.js b/src/hooks/app.js index 64b3aaf2..3c41c58f 100644 --- a/src/hooks/app.js +++ b/src/hooks/app.js @@ -6,6 +6,8 @@ export const { useHasSubmitted, useSetHasSubmitted, useSetShowTrainingError, + useResponse, + useSetResponse, } = reduxHooks; export const { diff --git a/src/hooks/assessment.js b/src/hooks/assessment.js index 9dd94cc9..bacac0ce 100644 --- a/src/hooks/assessment.js +++ b/src/hooks/assessment.js @@ -72,6 +72,12 @@ export const useCheckTrainingSelection = () => { export const useInitializeAssessment = () => { const emptyRubric = lmsSelectors.useEmptyRubric(); const setFormFields = reduxHooks.useSetFormFields(); + const setResponse = reduxHooks.useSetResponse(); + const response = lmsSelectors.useResponseData(); + React.useEffect(() => { + setResponse(response); + }, []); + return React.useCallback(() => { setFormFields(emptyRubric); }, []); @@ -135,6 +141,8 @@ export const useResetAssessment = () => { export const { useHasSubmitted, + useResponse, + useSetResponse, useSetHasSubmitted, useSetShowValidation, useShowValidation, diff --git a/src/views/SubmissionView/hooks/useSubmissionViewData.js b/src/views/SubmissionView/hooks/useSubmissionViewData.js index dd8769f5..29eb5066 100644 --- a/src/views/SubmissionView/hooks/useSubmissionViewData.js +++ b/src/views/SubmissionView/hooks/useSubmissionViewData.js @@ -9,6 +9,7 @@ import { useSetHasSubmitted, useHasSubmitted, useRefreshPageData, + useSetResponse, } from 'hooks/app'; import { useRefreshUpstream, @@ -30,6 +31,8 @@ const useSubmissionViewData = () => { const rubricConfig = useRubricConfig(); const globalState = useGlobalState({ step: stepNames.submission }); const refreshPageData = useRefreshPageData(); + const setResponse = useSetResponse(); + const response = useResponse(); const refreshUpstream = useRefreshUpstream(); const stepState = hasSubmitted ? stepStates.submitted : globalState.stepState; @@ -53,6 +56,7 @@ const useSubmissionViewData = () => { uploadedFiles, }).then(() => { setHasSubmitted(true); + setResponse({ textResponses, uploadedFiles }); refreshPageData(); refreshUpstream(); }); @@ -80,11 +84,10 @@ const useSubmissionViewData = () => { submitStatus: submitResponseMutation.status, hasSubmitted, }, + response, hasSubmitted, - textResponses, onUpdateTextResponse, isDraftSaved: hasSavedDraft, - uploadedFiles, onDeletedFile, onFileUploaded, showRubric: rubricConfig.showDuringResponse, diff --git a/src/views/SubmissionView/index.jsx b/src/views/SubmissionView/index.jsx index 54ecbcec..168cbfb0 100644 --- a/src/views/SubmissionView/index.jsx +++ b/src/views/SubmissionView/index.jsx @@ -24,10 +24,12 @@ export const SubmissionView = () => { const { actionOptions, showRubric, - textResponses, + response: { + textResponses, + uploadedFiles, + }, onUpdateTextResponse, isDraftSaved, - uploadedFiles, onDeletedFile, onFileUploaded, isReadOnly, From 5273a48994dbd3d6fb8bd77f75a4a00a4401014e Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:36:06 +0000 Subject: [PATCH 07/12] fix: response persists through submission --- src/data/redux/hooks/app.js | 2 +- src/views/AssessmentView/PeerAssessmentView/index.jsx | 4 ++-- src/views/AssessmentView/SelfAssessmentView/index.jsx | 4 ++-- src/views/AssessmentView/StudentTrainingView/index.jsx | 4 ++-- src/views/SubmissionView/hooks/useSubmissionViewData.js | 7 +++++-- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/data/redux/hooks/app.js b/src/data/redux/hooks/app.js index aab07654..c2522e7c 100644 --- a/src/data/redux/hooks/app.js +++ b/src/data/redux/hooks/app.js @@ -32,7 +32,7 @@ export const useSetShowTrainingError = () => useActionHook(actions.setShowTraini export const useSetFormFields = () => useActionHook(actions.setFormFields); export const useResetAssessment = () => useActionHook(actions.resetAssessment); export const useSetOverallFeedback = () => useActionHook(actions.setOverallFeedback); -export const useSetResponse = () => useActionHook(actions.setResponse); +export const useSetResponse = () => useActionHook(actions.loadResponse); export const useSetCriterionFeedback = (criterionIndex) => { const dispatch = useDispatch(); diff --git a/src/views/AssessmentView/PeerAssessmentView/index.jsx b/src/views/AssessmentView/PeerAssessmentView/index.jsx index 16f661fb..a07c4b15 100644 --- a/src/views/AssessmentView/PeerAssessmentView/index.jsx +++ b/src/views/AssessmentView/PeerAssessmentView/index.jsx @@ -4,7 +4,7 @@ import React from 'react'; import { useIsORAConfigLoaded, usePrompts, - useResponseData, + useResponse, } from 'hooks/app'; import Prompt from 'components/Prompt'; @@ -14,7 +14,7 @@ import BaseAssessmentView from '../BaseAssessmentView'; export const PeerAssessmentView = () => { const prompts = usePrompts(); - const response = useResponseData(); + const response = useResponse(); if (!useIsORAConfigLoaded()) { return null; } diff --git a/src/views/AssessmentView/SelfAssessmentView/index.jsx b/src/views/AssessmentView/SelfAssessmentView/index.jsx index f476b367..d509883d 100644 --- a/src/views/AssessmentView/SelfAssessmentView/index.jsx +++ b/src/views/AssessmentView/SelfAssessmentView/index.jsx @@ -3,7 +3,7 @@ import React from 'react'; import { useIsORAConfigLoaded, usePrompts, - useResponseData, + useResponse, } from 'hooks/app'; import FileUpload from 'components/FileUpload'; @@ -15,7 +15,7 @@ import BaseAssessmentView from '../BaseAssessmentView'; export const SelfAssessmentView = () => { const prompts = usePrompts(); - const response = useResponseData(); + const response = useResponse(); if (!useIsORAConfigLoaded()) { return null; } diff --git a/src/views/AssessmentView/StudentTrainingView/index.jsx b/src/views/AssessmentView/StudentTrainingView/index.jsx index 8992c083..6a2b230f 100644 --- a/src/views/AssessmentView/StudentTrainingView/index.jsx +++ b/src/views/AssessmentView/StudentTrainingView/index.jsx @@ -3,7 +3,7 @@ import React from 'react'; import { useIsORAConfigLoaded, usePrompts, - useResponseData, + useResponse, } from 'hooks/app'; import Prompt from 'components/Prompt'; @@ -15,7 +15,7 @@ import BaseAssessmentView from '../BaseAssessmentView'; export const StudentTrainingView = () => { const prompts = usePrompts(); - const response = useResponseData(); + const response = useResponse(); console.log("StudentTrainingView"); if (!useIsORAConfigLoaded()) { return null; diff --git a/src/views/SubmissionView/hooks/useSubmissionViewData.js b/src/views/SubmissionView/hooks/useSubmissionViewData.js index 29eb5066..cbe1ab64 100644 --- a/src/views/SubmissionView/hooks/useSubmissionViewData.js +++ b/src/views/SubmissionView/hooks/useSubmissionViewData.js @@ -10,6 +10,7 @@ import { useHasSubmitted, useRefreshPageData, useSetResponse, + useResponse, } from 'hooks/app'; import { useRefreshUpstream, @@ -55,8 +56,8 @@ const useSubmissionViewData = () => { textResponses, uploadedFiles, }).then(() => { - setHasSubmitted(true); setResponse({ textResponses, uploadedFiles }); + setHasSubmitted(true); refreshPageData(); refreshUpstream(); }); @@ -84,7 +85,9 @@ const useSubmissionViewData = () => { submitStatus: submitResponseMutation.status, hasSubmitted, }, - response, + response: hasSubmitted + ? response + : { textResponses, uploadedFiles }, hasSubmitted, onUpdateTextResponse, isDraftSaved: hasSavedDraft, From 1ed5122eb0a9002e20c4ab6de5ef31f052d442ed Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:46:15 +0000 Subject: [PATCH 08/12] fix: progress bar revisit limitations --- src/components/ProgressBar/hooks.js | 1 + src/components/ProgressBar/index.jsx | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/ProgressBar/hooks.js b/src/components/ProgressBar/hooks.js index b72eff07..4aa12f0e 100644 --- a/src/components/ProgressBar/hooks.js +++ b/src/components/ProgressBar/hooks.js @@ -20,6 +20,7 @@ export const useProgressStepData = ({ step, canRevisit = false }) => { || (stepState === stepStates.inProgress) || (canRevisit && stepState === stepStates.done) ); + console.log({ step, viewStep, stepState, canRevisit, isEnabled }); return { href, isEnabled, diff --git a/src/components/ProgressBar/index.jsx b/src/components/ProgressBar/index.jsx index db5c8122..eaed274b 100644 --- a/src/components/ProgressBar/index.jsx +++ b/src/components/ProgressBar/index.jsx @@ -50,20 +50,20 @@ export const ProgressBar = ({ className }) => { return null; } - const stepEl = (curStep) => - stepLabels[curStep] ? ( + const stepEl = (curStep) => stepLabels[curStep] + ? ( ) : null; return ( - -
+ +
{stepOrders.map(stepEl)}
From 72ab34c9c63208d4bbda24b7d07543a8127abc50 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 20:59:00 +0000 Subject: [PATCH 09/12] chore: add get_peer url --- src/data/services/lms/urls.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index 8345ad0f..154400cc 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -14,6 +14,7 @@ export const useSaveDraftUrl = () => `${useBaseUrl()}/submission/draft`; export const useSubmitUrl = () => `${useBaseUrl()}/submission/submit`; export const useSubmitAssessmentUrl = () => `${useBaseUrl()}/assessment/submit`; export const useORAConfigUrl = () => `${useBaseUrl()}/get_block_info`; +export const useGetPeerUrl = () => `${useBaseUrl()}/assessment/get_peer`; export const useViewUrl = () => { const { xblockId, courseId } = useParams(); From a9b86f6071daa7de6bd34833365e1ab8fa8b935f Mon Sep 17 00:00:00 2001 From: Leangseu Kim Date: Thu, 16 Nov 2023 16:07:25 -0500 Subject: [PATCH 10/12] chore: update finish later button message --- src/components/ModalActions/hooks/useActiveSubmissionConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ModalActions/hooks/useActiveSubmissionConfig.js b/src/components/ModalActions/hooks/useActiveSubmissionConfig.js index e8b84fda..b1c21dba 100644 --- a/src/components/ModalActions/hooks/useActiveSubmissionConfig.js +++ b/src/components/ModalActions/hooks/useActiveSubmissionConfig.js @@ -30,7 +30,7 @@ const useActiveSubmissionConfig = ({ onClick: saveAndClose, state: finishLaterStatus, labels: { - [MutationStatus.idle]: formatMessage(messages.finishLater), + default: formatMessage(messages.finishLater), [MutationStatus.loading]: formatMessage(messages.savingResponse), }, }, From 9d4720a08c5a4b6c802f34f8588b2300d95943bf Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Thu, 16 Nov 2023 21:08:31 +0000 Subject: [PATCH 11/12] fix: progress grade value --- src/components/ProgressBar/ProgressStep.jsx | 3 ++- src/components/StatusAlert/messages.js | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ProgressBar/ProgressStep.jsx b/src/components/ProgressBar/ProgressStep.jsx index 39a23a2c..edf04f25 100644 --- a/src/components/ProgressBar/ProgressStep.jsx +++ b/src/components/ProgressBar/ProgressStep.jsx @@ -39,6 +39,7 @@ const ProgressStep = ({ let iconSrc = stepIcons[step]; let subLabel = null; let colorClass = null; + console.log({ myGrade }); if (isPastDue) { colorClass = 'text-danger-500'; iconSrc = Error; @@ -46,7 +47,7 @@ const ProgressStep = ({ } else if (isComplete) { iconSrc = CheckCircle; if (step === stepNames.done && myGrade) { - subLabel = `${myGrade.earned} / ${myGrade.possible}`; + subLabel = `${myGrade.stepScore.earned} / ${myGrade.stepScore.possible}`; } } return ( diff --git a/src/components/StatusAlert/messages.js b/src/components/StatusAlert/messages.js index 7b47b396..24b0327d 100644 --- a/src/components/StatusAlert/messages.js +++ b/src/components/StatusAlert/messages.js @@ -272,4 +272,3 @@ export default { }, ...messages, }; - From 2c62661039202955c997cae7bce14e81e8f7b3da Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Fri, 17 Nov 2023 05:14:05 +0000 Subject: [PATCH 12/12] feat: pet er fixes --- src/App.jsx | 17 ++--- src/components/FileUpload/hooks.js | 18 ++--- src/components/FileUpload/index.jsx | 9 +-- .../hooks/useModalActionConfig.js | 4 +- src/components/PageDataProvider.jsx | 9 --- src/components/ProgressBar/ProgressStep.jsx | 1 - src/components/ProgressBar/hooks.js | 1 - src/components/Rubric/Rubric.scss | 3 +- src/components/Rubric/index.jsx | 7 +- .../StatusAlert/useStatusAlertData.jsx | 10 +++ .../StepProgressIndicator/index.jsx | 2 - src/data/redux/app/reducer.js | 2 +- src/data/services/lms/api.ts | 24 +++++++ src/data/services/lms/hooks/actions/files.ts | 65 +++++++++---------- src/data/services/lms/hooks/actions/index.ts | 2 +- src/data/services/lms/hooks/data.ts | 4 +- .../services/lms/hooks/selectors/index.ts | 2 +- .../services/lms/hooks/selectors/pageData.ts | 12 +++- src/data/services/lms/urls.js | 3 + src/hooks/actions/useStartStepAction.js | 5 +- src/hooks/modal.js | 4 +- src/hooks/test.js | 2 +- .../PeerAssessmentView/index.jsx | 10 +-- src/views/AssessmentView/index.jsx | 33 ++++++++++ src/views/AssessmentView/useAssessmentData.js | 43 ++++++++++++ .../hooks/useSubmissionViewData.js | 1 + .../hooks/useUploadedFilesData.js | 1 + 27 files changed, 205 insertions(+), 89 deletions(-) delete mode 100644 src/components/PageDataProvider.jsx create mode 100644 src/views/AssessmentView/index.jsx create mode 100644 src/views/AssessmentView/useAssessmentData.js diff --git a/src/App.jsx b/src/App.jsx index b69f39ce..9a3d2f00 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -6,9 +6,7 @@ import { } from '@edx/frontend-platform/react'; import { useIntl } from '@edx/frontend-platform/i18n'; -import PeerAssessmentView from 'views/AssessmentView/PeerAssessmentView'; -import SelfAssessmentView from 'views/AssessmentView/SelfAssessmentView'; -import StudentTrainingView from 'views/AssessmentView/StudentTrainingView'; +import AssessmentView from 'views/AssessmentView'; import SubmissionView from 'views/SubmissionView'; import XBlockView from 'views/XBlockView'; import GradeView from 'views/GradeView'; @@ -24,6 +22,7 @@ import messages from './messages'; import routes from './routes'; const App = () => { + /* const { body } = document; const refreshPageData = useRefreshPageData(); const refreshUpstream = useRefreshUpstream(); @@ -43,15 +42,13 @@ const App = () => { }, [body.scrollHeight]); React.useEffect(() => { - console.log("init refresh behavior"); window.addEventListener('message', (event) => { - console.log({ event }); - if (event.data.type === 'ora-refresh') { - console.log("ORA Refresh"); + if (event.data.type === 'plugin.modal-close') { refreshPageData(); } }); }, []); + */ const { formatMessage } = useIntl(); @@ -101,9 +98,9 @@ const App = () => { */ const baseRoutes = [ appRoute(routes.xblock, XBlockView), - modalRoute(routes.peerAssessment, PeerAssessmentView, 'Assess your peers'), - modalRoute(routes.selfAssessment, SelfAssessmentView, 'Assess yourself'), - modalRoute(routes.studentTraining, StudentTrainingView, 'Practice grading'), + modalRoute(routes.peerAssessment, AssessmentView, 'Assess your peers'), + modalRoute(routes.selfAssessment, AssessmentView, 'Assess yourself'), + modalRoute(routes.studentTraining, AssessmentView, 'Practice grading'), modalRoute(routes.submission, SubmissionView, 'Your response'), modalRoute(routes.graded, GradeView, 'My Grade'), } />, diff --git a/src/components/FileUpload/hooks.js b/src/components/FileUpload/hooks.js index 29203c81..9c06adb4 100644 --- a/src/components/FileUpload/hooks.js +++ b/src/components/FileUpload/hooks.js @@ -15,16 +15,14 @@ export const useUploadConfirmModalHooks = ({ closeHandler, uploadHandler, }) => { - const [description, setDescription] = useKeyedState( - stateKeys.description, - '' - ); + const [description, setDescription] = useKeyedState(stateKeys.description, ''); const [shouldShowError, setShouldShowError] = useKeyedState( stateKeys.shouldShowError, - false + false, ); const confirmUploadClickHandler = () => { + console.log({ confirmUploadClick: { description } }); if (description !== '') { uploadHandler(file, description); } else { @@ -54,13 +52,15 @@ export const useFileUploadHooks = ({ onFileUploaded }) => { const [uploadArgs, setUploadArgs] = useKeyedState(stateKeys.uploadArgs, {}); const [isModalOpen, setIsModalOpen] = useKeyedState( stateKeys.isModalOpen, - false + false, ); - const confirmUpload = useCallback(async () => { + const confirmUpload = useCallback(async (file, description) => { + console.log({ confirmUpload: { file, description } }); setIsModalOpen(false); if (onFileUploaded) { - await onFileUploaded(uploadArgs); + console.log({ uploadArgs }); + await onFileUploaded({ ...uploadArgs, description }); } setUploadArgs({}); }, [uploadArgs, onFileUploaded, setIsModalOpen, setUploadArgs]); @@ -75,7 +75,7 @@ export const useFileUploadHooks = ({ onFileUploaded }) => { setIsModalOpen(true); setUploadArgs({ fileData, handleError, requestConfig }); }, - [setIsModalOpen, setUploadArgs] + [setIsModalOpen, setUploadArgs], ); return { diff --git a/src/components/FileUpload/index.jsx b/src/components/FileUpload/index.jsx index e5e4196a..5113dda9 100644 --- a/src/components/FileUpload/index.jsx +++ b/src/components/FileUpload/index.jsx @@ -7,7 +7,9 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { nullMethod } from 'utils'; import { useFileUploadEnabled } from 'hooks/app'; +import { useViewStep } from 'hooks/routing'; import FilePreview from 'components/FilePreview'; +import { stepNames } from 'constants'; import UploadConfirmModal from './UploadConfirmModal'; import ActionCell from './ActionCell'; @@ -35,11 +37,10 @@ const FileUpload = ({ isModalOpen, onProcessUpload, uploadArgs, - } = useFileUploadHooks({ - onFileUploaded, - }); + } = useFileUploadHooks({ onFileUploaded }); + const viewStep = useViewStep(); - if ( !useFileUploadEnabled() ) { + if (!useFileUploadEnabled() || viewStep === stepNames.studentTraining) { return null; } diff --git a/src/components/ModalActions/hooks/useModalActionConfig.js b/src/components/ModalActions/hooks/useModalActionConfig.js index 27d5db02..68b9216f 100644 --- a/src/components/ModalActions/hooks/useModalActionConfig.js +++ b/src/components/ModalActions/hooks/useModalActionConfig.js @@ -19,9 +19,11 @@ const useModalActionConfig = ({ options }) => { const exitAction = useExitAction(); - console.log({ useModalActionConfig: { step, globalState, hasSubmitted } }); // finished state if (hasSubmitted) { + if (globalState.activeStepState !== stepStates.inProgress) { + return { primary: exitAction }; + } return finishedStateActions; } diff --git a/src/components/PageDataProvider.jsx b/src/components/PageDataProvider.jsx deleted file mode 100644 index b684ecca..00000000 --- a/src/components/PageDataProvider.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { useIsPageDataLoaded } from 'hooks/app'; - -const PageDataProvider = ({ children }) => (useIsPageDataLoaded() ? children : null); -PageDataProvider.propTypes = { children: PropTypes.node.isRequired }; - -export default PageDataProvider; diff --git a/src/components/ProgressBar/ProgressStep.jsx b/src/components/ProgressBar/ProgressStep.jsx index edf04f25..2370dd81 100644 --- a/src/components/ProgressBar/ProgressStep.jsx +++ b/src/components/ProgressBar/ProgressStep.jsx @@ -39,7 +39,6 @@ const ProgressStep = ({ let iconSrc = stepIcons[step]; let subLabel = null; let colorClass = null; - console.log({ myGrade }); if (isPastDue) { colorClass = 'text-danger-500'; iconSrc = Error; diff --git a/src/components/ProgressBar/hooks.js b/src/components/ProgressBar/hooks.js index 4aa12f0e..b72eff07 100644 --- a/src/components/ProgressBar/hooks.js +++ b/src/components/ProgressBar/hooks.js @@ -20,7 +20,6 @@ export const useProgressStepData = ({ step, canRevisit = false }) => { || (stepState === stepStates.inProgress) || (canRevisit && stepState === stepStates.done) ); - console.log({ step, viewStep, stepState, canRevisit, isEnabled }); return { href, isEnabled, diff --git a/src/components/Rubric/Rubric.scss b/src/components/Rubric/Rubric.scss index 87077ca9..18c47605 100644 --- a/src/components/Rubric/Rubric.scss +++ b/src/components/Rubric/Rubric.scss @@ -61,7 +61,8 @@ } .rubric-body { - overflow-y: scroll; + overflow-y: hide; + padding: map-get($spacers, 3); } .rubric-footer { diff --git a/src/components/Rubric/index.jsx b/src/components/Rubric/index.jsx index d244e789..f58c8a9d 100644 --- a/src/components/Rubric/index.jsx +++ b/src/components/Rubric/index.jsx @@ -23,13 +23,14 @@ export const Rubric = ({ isCollapsible }) => { return ( {formatMessage(messages.rubric)}} - className='rubric-card' + className="rubric-card" + defaultOpen > - + {!isCollapsible && ( <>

{formatMessage(messages.rubric)}

-
+
)} {criteria.map((criterion) => ( diff --git a/src/components/StatusAlert/useStatusAlertData.jsx b/src/components/StatusAlert/useStatusAlertData.jsx index 6d84544e..36e726ae 100644 --- a/src/components/StatusAlert/useStatusAlertData.jsx +++ b/src/components/StatusAlert/useStatusAlertData.jsx @@ -52,6 +52,7 @@ const useStatusAlertData = ({ const { formatMessage } = useIntl(); const { activeStepName, + activeStepState, cancellationInfo, stepState, } = useGlobalState({ step }); @@ -102,6 +103,15 @@ const useStatusAlertData = ({ heading: messages.headings[viewStep].submitted, ...alertTypes.success, })); + if (activeStepState !== stepStates.inProgress) { + out.push(alertConfig({ + message: messages.alerts[activeStepName][activeStepState], + heading: messages.headings[activeStepName][activeStepState], + actions: [ + , + ], + })); + } if (activeStepName === stepNames.staff) { out.push(alertConfig({ message: messages.alerts[activeStepName].staffAssessment, diff --git a/src/components/StepProgressIndicator/index.jsx b/src/components/StepProgressIndicator/index.jsx index d1789713..d20a55b4 100644 --- a/src/components/StepProgressIndicator/index.jsx +++ b/src/components/StepProgressIndicator/index.jsx @@ -20,14 +20,12 @@ import messages from './messages'; import './index.scss'; const StepProgressIndicator = ({ step }) => { - console.log("Step Progress Indicator"); const { formatMessage } = useIntl(); const configInfo = useAssessmentStepConfig(); const stepInfo = useStepInfo(); const globalState = useGlobalState(); const hasSubmitted = useHasSubmitted(); const { activeStepName } = globalState; - console.log({ globalState, stepInfo }); const loadNextAction = useLoadNextAction(); if (![stepNames.peer, stepNames.studentTraining].includes(step)) { return null; diff --git a/src/data/redux/app/reducer.js b/src/data/redux/app/reducer.js index df499464..3bbec275 100644 --- a/src/data/redux/app/reducer.js +++ b/src/data/redux/app/reducer.js @@ -7,7 +7,7 @@ const initialState = { submittedAssessment: null, showTrainingError: false, }, - response: [], + response: null, formFields: { criteria: [], overallFeedback: '', diff --git a/src/data/services/lms/api.ts b/src/data/services/lms/api.ts index a6f69fc3..860e8dec 100644 --- a/src/data/services/lms/api.ts +++ b/src/data/services/lms/api.ts @@ -27,6 +27,30 @@ export const useSaveDraft = () => { }; }; +export const useAddFile = () => { + const url = urls.useAddFileUrl(); + const responseUrl = urls.useUploadResponseUrl(); + return (data: any, description: string) => { + const { post } = getAuthenticatedHttpClient(); + const file = { + fileDescription: description, + fileName: data.name, + fileSize: data.size, + contentType: data.type, + }; + console.log({ addFile: { data, description, file } }); + return post(url, file) + .then(response => post(responseUrl, { fileIndex: response.data.fileIndex, success: true })) + }; +}; + +export const useDeleteFile = () => { + const url = urls.useDeleteFileUrl(); + return (fileIndex) => { + return getAuthenticatedHttpClient().post(url, { fileIndex }); + }; +}; + export const fakeProgress = async (requestConfig) => { for (let i = 0; i <= 50; i++) { // eslint-disable-next-line no-await-in-loop, no-promise-executor-return diff --git a/src/data/services/lms/hooks/actions/files.ts b/src/data/services/lms/hooks/actions/files.ts index 6c655afe..307194eb 100644 --- a/src/data/services/lms/hooks/actions/files.ts +++ b/src/data/services/lms/hooks/actions/files.ts @@ -1,7 +1,13 @@ import * as zip from '@zip.js/zip.js'; import FileSaver from 'file-saver'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform'; +import { useMutation } from '@tanstack/react-query'; + import { queryKeys } from 'constants'; +import * as api from 'data/services/lms/api'; +import { useTestDataPath } from 'hooks/test'; + import fakeData from '../../fakeData'; import { UploadedFile } from '../../types'; @@ -99,43 +105,36 @@ export const downloadBlobs = async (files: UploadedFile[]) => { return { blobs, files }; }; -export const useUploadFiles = () => - useCreateMutationAction(async (data: any) => { +export const useUploadFiles = () => { + const testDataPath = useTestDataPath(); + const addFile = api.useAddFile(); + const apiFn = (data) => { + const { fileData, requestConfig, description } = data; + const file = fileData.getAll('file')[0]; + console.log({ file }); + return addFile(file, description); + }; + const mockFn = (data, description) => { const { fileData, requestConfig } = data; - const files = fileData.getAll('file'); - // TODO: upload files - /* - * const addFileResponse = await post(`{xblock_id}/handler/file/add`, file); - * const uploadResponse = await(post(response.fileUrl, file)); - * post(`${xblock_id}/handler/download_url', (response)); - */ - await fakeProgress(requestConfig); - return Promise.resolve(); + return fakeProgress(requestConfig); + }; + return useMutation({ + mutationFn: testDataPath ? mockFn : apiFn, }); +}; -export const useDeleteFile = () => - useCreateMutationAction(async (fileIndex, queryClient) => { - await new Promise((resolve) => - setTimeout(() => { - fakeData.pageData.shapes.emptySubmission.submission.response = { - ...fakeData.pageData.shapes.emptySubmission.submission.response, - uploaded_files: [ - ...fakeData.pageData.shapes.emptySubmission.submission.response.uploaded_files.filter( - (_, index) => index !== fileIndex - ), - ], - } as any; - resolve(null); - }, 1000) - ); - - console.log("invalidate pageData"); - queryClient.invalidateQueries([queryKeys.pageData, false]); - return Promise.resolve( - fakeData.pageData.shapes.emptySubmission.submission.response - .uploaded_files - ); +export const useDeleteFile = () => { + const testDataPath = useTestDataPath(); + const deleteFile = api.useDeleteFile(); + const apiFn = (index) => { + console.log({ deleteFile: index }); + return deleteFile(index); + }; + const mockFn = (data) => Promise.resolve(data); + return useMutation({ + mutationFn: testDataPath ? mockFn : apiFn, }); +}; export const useDownloadFiles = () => useCreateMutationAction( diff --git a/src/data/services/lms/hooks/actions/index.ts b/src/data/services/lms/hooks/actions/index.ts index 78427dd1..4ab01fe9 100644 --- a/src/data/services/lms/hooks/actions/index.ts +++ b/src/data/services/lms/hooks/actions/index.ts @@ -73,5 +73,5 @@ export const useSaveDraftResponse = () => { export const useRefreshPageData = () => { const queryClient = useQueryClient(); - return () => queryClient.invalidateQueries({ queryKey: queryKeys.pageData }); + return () => queryClient.invalidateQueries({ queryKey: [queryKeys.pageData] }); }; diff --git a/src/data/services/lms/hooks/data.ts b/src/data/services/lms/hooks/data.ts index 558cef3f..d112beec 100644 --- a/src/data/services/lms/hooks/data.ts +++ b/src/data/services/lms/hooks/data.ts @@ -55,6 +55,7 @@ export const useORAConfig = (): types.QueryData => { ({ data }) => camelCaseObject(data) ); }, + staleTime: Infinity, }); }; @@ -78,7 +79,6 @@ export const usePageData = () => { const progressKey = testProgressKey || params.progressKey || defaultViewProgressKeys[viewKey]; const queryFn = React.useCallback(() => { - console.log({ testDataPath }); if (testDataPath) { console.log("page data fake data"); return Promise.resolve(camelCaseObject(loadState({ view, progressKey }))); @@ -86,6 +86,7 @@ export const usePageData = () => { const url = (hasSubmitted || view === stepNames.xblock) ? pageDataUrl() : pageDataUrl(viewStep); + console.log({ url, hasSubmitted, view }); console.log("page data real data"); console.log({ pageDataUrl: url }); return getAuthenticatedHttpClient().post(url, {}) @@ -99,6 +100,7 @@ export const usePageData = () => { return useQuery({ queryKey: [queryKeys.pageData, testDataPath], queryFn, + staleTime: Infinity, }); }; diff --git a/src/data/services/lms/hooks/selectors/index.ts b/src/data/services/lms/hooks/selectors/index.ts index 5e55fd40..5add47fc 100644 --- a/src/data/services/lms/hooks/selectors/index.ts +++ b/src/data/services/lms/hooks/selectors/index.ts @@ -44,7 +44,7 @@ export const useStepState = ({ step = null } = {}) => { return hasReceivedFinalGrade ? stepStates.done : stepStates.notAvailable; } - if (stepName === stepNames.peer && stepInfo?.peer?.isWaitingForSubmissions) { + if (activeStepName === stepNames.peer && stepInfo?.peer?.isWaitingForSubmissions) { return stepStates.waiting; } // For Assessment steps diff --git a/src/data/services/lms/hooks/selectors/pageData.ts b/src/data/services/lms/hooks/selectors/pageData.ts index c551d1f7..7f3959cc 100644 --- a/src/data/services/lms/hooks/selectors/pageData.ts +++ b/src/data/services/lms/hooks/selectors/pageData.ts @@ -13,14 +13,20 @@ export const usePageDataStatus = () => { return { isLoading: queryStatus.isLoading, isFetching: queryStatus.isFetching, + isRefetching: queryStatus.isRefetching, isInitialLoading: queryStatus.isInitialLoading, + isStale: queryStatus.isStale, status: queryStatus.status, error: queryStatus.error, }; }; -export const useIsPageDataLoaded = (): boolean => ( - data.usePageData().status === 'success' -); +export const useIsPageDataLoaded = (): boolean => { + const pageData = data.usePageData(); + console.log({ rawPageData: pageData }); + const { isRefetching, isStale, status } = pageData; + console.log({ isStale, isRefetching }); + return status === 'success' && !isRefetching; +}; export const usePageData = (): types.PageData => { const pageData = data.usePageData()?.data; if (process.env.NODE_ENV === 'development') { diff --git a/src/data/services/lms/urls.js b/src/data/services/lms/urls.js index 154400cc..a446c3fd 100644 --- a/src/data/services/lms/urls.js +++ b/src/data/services/lms/urls.js @@ -15,6 +15,9 @@ export const useSubmitUrl = () => `${useBaseUrl()}/submission/submit`; export const useSubmitAssessmentUrl = () => `${useBaseUrl()}/assessment/submit`; export const useORAConfigUrl = () => `${useBaseUrl()}/get_block_info`; export const useGetPeerUrl = () => `${useBaseUrl()}/assessment/get_peer`; +export const useAddFileUrl = () => `${useBaseUrl()}/file/add`; +export const useUploadResponseUrl = () => `${useBaseUrl()}/file/upload_response`; +export const useDeleteFileUrl = () => `${useBaseUrl()}/file/delete`; export const useViewUrl = () => { const { xblockId, courseId } = useParams(); diff --git a/src/hooks/actions/useStartStepAction.js b/src/hooks/actions/useStartStepAction.js index 8a8487ef..63cf5f1b 100644 --- a/src/hooks/actions/useStartStepAction.js +++ b/src/hooks/actions/useStartStepAction.js @@ -3,7 +3,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import { useIntl } from '@edx/frontend-platform/i18n'; import { stepNames, stepRoutes } from 'constants'; -import { useRefreshPageData, useActiveStepName } from 'hooks/app'; +import { useRefreshPageData, useActiveStepName, useSetResponse } from 'hooks/app'; import { useSetHasSubmitted, useSetShowValidation } from 'hooks/assessment'; import messages from './messages'; @@ -14,6 +14,7 @@ const useStartStepAction = (viewStep) => { const refreshPageData = useRefreshPageData(); const setHasSubmitted = useSetHasSubmitted(); const setShowValidation = useSetShowValidation(); + const setResponse = useSetResponse(); const stepName = useActiveStepName(); @@ -23,8 +24,10 @@ const useStartStepAction = (viewStep) => { } const onClick = () => { + console.log("Load next page"); setHasSubmitted(false); setShowValidation(false); + setResponse(null); navigate(`/${stepRoutes[stepName]}/${courseId}/${xblockId}`); refreshPageData(); }; diff --git a/src/hooks/modal.js b/src/hooks/modal.js index 5b9e591f..7fb35148 100644 --- a/src/hooks/modal.js +++ b/src/hooks/modal.js @@ -17,7 +17,7 @@ export const useRefreshUpstream = () => { export const useCloseModal = () => { if (document.referrer !== '') { - const postMessage = (data) => window.parent.postMessage(data, document.referrer); + const postMessage = (data) => window.parent.postMessage(data, '*'); return () => { postMessage({ type: 'ora-refresh' }); postMessage({ type: 'plugin.modal-close' }); @@ -29,7 +29,7 @@ export const useCloseModal = () => { }; export const useOpenModal = () => { - const postMessage = (data) => window.parent.postMessage(data, document.referrer); + const postMessage = (data) => window.parent.postMessage(data, '*'); const viewUrl = useViewUrl(); return ({ view, title }) => { postMessage({ diff --git a/src/hooks/test.js b/src/hooks/test.js index d07a8906..379eebe6 100644 --- a/src/hooks/test.js +++ b/src/hooks/test.js @@ -69,7 +69,7 @@ export const useUpdateTestProgressKey = () => { testDataPath, ]); React.useEffect(() => { - if (!testDirty) { + if (testDataPath && !testDirty) { console.log({ testDirty, testProgressKey }); queryClient.invalidateQueries({ queryKey: [queryKeys.pageData] }); console.log("invalidated"); diff --git a/src/views/AssessmentView/PeerAssessmentView/index.jsx b/src/views/AssessmentView/PeerAssessmentView/index.jsx index a07c4b15..ea3ca4b6 100644 --- a/src/views/AssessmentView/PeerAssessmentView/index.jsx +++ b/src/views/AssessmentView/PeerAssessmentView/index.jsx @@ -1,23 +1,25 @@ import React from 'react'; - import { useIsORAConfigLoaded, usePrompts, useResponse, + useSetResponse, + useResponseData, } from 'hooks/app'; import Prompt from 'components/Prompt'; import TextResponse from 'components/TextResponse'; import FileUpload from 'components/FileUpload'; import BaseAssessmentView from '../BaseAssessmentView'; +import useAssessmentData from './useAssessmentData'; export const PeerAssessmentView = () => { - const prompts = usePrompts(); - const response = useResponse(); - if (!useIsORAConfigLoaded()) { + const { prompts, response, isLoaded } = useAssessmentData(); + if (!isLoaded || !response) { return null; } + return ( {}}>
diff --git a/src/views/AssessmentView/index.jsx b/src/views/AssessmentView/index.jsx new file mode 100644 index 00000000..ff40ee38 --- /dev/null +++ b/src/views/AssessmentView/index.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import Prompt from 'components/Prompt'; +import TextResponse from 'components/TextResponse'; +import FileUpload from 'components/FileUpload'; + +import BaseAssessmentView from './BaseAssessmentView'; +import useAssessmentData from './useAssessmentData'; + +export const AssessmentView = () => { + const { prompts, response, isLoaded } = useAssessmentData(); + if (!isLoaded || !response) { + return null; + } + + return ( + {}}> +
+ {React.Children.toArray( + prompts.map((prompt, index) => ( +
+ + +
+ )), + )} + +
+
+ ); +}; + +export default AssessmentView; diff --git a/src/views/AssessmentView/useAssessmentData.js b/src/views/AssessmentView/useAssessmentData.js new file mode 100644 index 00000000..17cf1822 --- /dev/null +++ b/src/views/AssessmentView/useAssessmentData.js @@ -0,0 +1,43 @@ +import React from 'react'; +import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; +import { + useIsORAConfigLoaded, + useIsPageDataLoaded, + usePageDataStatus, + usePrompts, + useResponse, + useSetResponse, + useResponseData, +} from 'hooks/app'; + +const stateKeys = StrictDict({ + initialized: 'initialized', +}); + +const useAssessmentData = () => { + const [initialized, setInitialized] = useKeyedState(stateKeys.initialized, false); + const prompts = usePrompts(); + const response = useResponse(); + const responseData = useResponseData(); + const setResponse = useSetResponse(); + const isLoaded = useIsORAConfigLoaded(); + const isPageDataLoaded = useIsPageDataLoaded(); + console.log({ pageDataStatus: usePageDataStatus() }); + React.useEffect(() => { + console.log("useAssessmentView useEffect"); + if (!initialized && isLoaded && isPageDataLoaded) { + setResponse(responseData); + setInitialized(true); + } + if (initialized && responseData && response !== responseData) { + setResponse(responseData); + } + }, [responseData, initialized]); + return { + isLoaded, + response, + prompts, + }; +}; + +export default useAssessmentData; diff --git a/src/views/SubmissionView/hooks/useSubmissionViewData.js b/src/views/SubmissionView/hooks/useSubmissionViewData.js index cbe1ab64..b1248a1e 100644 --- a/src/views/SubmissionView/hooks/useSubmissionViewData.js +++ b/src/views/SubmissionView/hooks/useSubmissionViewData.js @@ -56,6 +56,7 @@ const useSubmissionViewData = () => { textResponses, uploadedFiles, }).then(() => { + console.log("submitResponseMutation.then"); setResponse({ textResponses, uploadedFiles }); setHasSubmitted(true); refreshPageData(); diff --git a/src/views/SubmissionView/hooks/useUploadedFilesData.js b/src/views/SubmissionView/hooks/useUploadedFilesData.js index cde4fce0..163362c2 100644 --- a/src/views/SubmissionView/hooks/useUploadedFilesData.js +++ b/src/views/SubmissionView/hooks/useUploadedFilesData.js @@ -22,6 +22,7 @@ const useUploadedFilesData = () => { ); const onFileUploaded = useCallback(async (data) => { + console.log({ onFileUploaded: { data } }); // const { fileData, queryClient } = data; const uploadResponse = await uploadFilesMutation.mutateAsync(data); if (uploadResponse) {