Skip to content

Commit

Permalink
feat: global data state
Browse files Browse the repository at this point in the history
feat: global data state
  • Loading branch information
muselesscreator authored Oct 19, 2023
2 parents 2b35d47 + 3973cf2 commit 2e26524
Show file tree
Hide file tree
Showing 59 changed files with 2,029 additions and 2,022 deletions.
2,409 changes: 715 additions & 1,694 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
"url": "https://github.com/edx/frontend-app-ora/issues"
},
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
"@edx/brand": "npm:@edx/brand-edx.org@2.1.2",
"@edx/frontend-component-footer": "12.4.0",
"@edx/frontend-component-header": "4.7.1",
"@edx/frontend-platform": "5.6.0",
"@edx/paragon": "^20.20.0",
"@edx/frontend-platform": "5.6.1",
"@edx/paragon": "^21.5.3",
"@edx/react-unit-test-utils": "1.7.0",
"@edx/tinymce-language-selector": "1.1.0",
"@fortawesome/fontawesome-svg-core": "1.2.36",
Expand All @@ -54,6 +54,7 @@
"core-js": "3.32.2",
"filesize": "^8.0.6",
"jest-when": "^3.6.0",
"moment": "^2.29.4",
"pdfjs-dist": "^3.11.174",
"prop-types": "15.8.1",
"query-string": "^8.1.0",
Expand Down
39 changes: 13 additions & 26 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ const RouterRoot = () => {
<Route
path={route}
element={(
<PageDataProvider>
<AppContainer Component={Component} />
</PageDataProvider>
<AppContainer>
<Component />
</AppContainer>
)}
/>
);
const modalRoute = (route, Component, title) => (
<Route
path={route}
element={(
<PageDataProvider>
<ModalContainer {...{ title, Component }} />
</PageDataProvider>
<AppContainer>
<ModalContainer title={title}>
<Component />
</ModalContainer>
</AppContainer>
)}
/>
);
Expand All @@ -50,29 +52,14 @@ const RouterRoot = () => {
<Route path={routes.rootEmbed} element={<ErrorPage message={formatMessage(messages.error404Message)} />} />,
];
const baseRoutes = [
appRoute(routes.xblock, PeerAssessmentView),
appRoute(routes.peerAssessment, PeerAssessmentView),
appRoute(routes.selfAssessment, SelfAssessmentView),
appRoute(routes.studentTraining, StudentTrainingView),
appRoute(routes.submission, SubmissionView),
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.submission, SubmissionView, 'Your response'),
<Route path={routes.root} element={<ErrorPage message={formatMessage(messages.error404Message)} />} />,
];

const isConfigLoaded = useIsORAConfigLoaded();

if (!isConfigLoaded) {
return (
<div className="h-screen d-flex justify-content-center align-items-center">
<Spinner
animation="border"
variant="primary"
className="mr-3 spinner-md"
screenReaderText="loading"
/>
</div>
);
}

return (
<Routes>
{embeddedRoutes}
Expand Down
23 changes: 17 additions & 6 deletions src/components/AppContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';

import ProgressBar from 'components/ProgressBar';

Check failure on line 4 in src/components/AppContainer.jsx

View workflow job for this annotation

GitHub Actions / test

'ProgressBar' is defined but never used

import { useIsPageDataLoaded, useIsORAConfigLoaded } from 'data/services/lms/hooks/selectors';

/* The purpose of this component is to wrap views with a header/footer for situations
* where we need to run non-embedded
*/

const AppContainer = ({ Component }) => (
<div className="bg-light-300">
<Component />
</div>
);
const AppContainer = ({ children }) => {
const isConfigLoaded = useIsORAConfigLoaded();
const isPageDataLoaded = useIsPageDataLoaded();
if (!isConfigLoaded || !isPageDataLoaded) {
return null;
}
return (
<div style={{ width: '100%' }}>
{children}
</div>
);
};
AppContainer.propTypes = {
Component: PropTypes.elementType.isRequired,
children: PropTypes.node.isRequired,
};

export default AppContainer;
6 changes: 0 additions & 6 deletions src/components/Assessment/EditableAssessment/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ const useEditableAssessmentData = () => {
submitRubricMutation.mutate(currentValue);
};

console.log({
criteria,
formFields,
onSubmit,
});

return {
criteria,
formFields,
Expand Down
1 change: 0 additions & 1 deletion src/components/BaseAssessmentView/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const BaseAssessmentView = ({
getValues,
}) => (
<AssessmentContextProvider>
<ProgressBar />
<div className="assessment-content-layout mr-auto ml-auto">
<div className="content-wrapper">
<Row className="flex-nowrap m-0">
Expand Down
48 changes: 25 additions & 23 deletions src/components/FileUpload/UploadConfirmModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import {
Form, FormLabel, ModalDialog, Button, ActionRow,
} from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import { useIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import messages from './messages';
import { useUploadConfirmModalHooks } from './hooks';

Expand Down Expand Up @@ -39,28 +39,30 @@ const UploadConfirmModal = ({
</ModalDialog.Header>

<ModalDialog.Body>
<div>
{file && (
<Form.Group>
<FormLabel>
<strong>
{formatMessage(messages.uploadFileDescriptionFieldLabel)}
</strong>
<span className="file-name-ellipsis">{file.name}</span>
</FormLabel>
<Form.Control
isInvalid={shouldShowError}
name="file-description"
onChange={onFileDescriptionChange}
/>
{shouldShowError && (
<Form.Control.Feedback type="invalid">
formatMessage(messages.fileDescriptionMissingError)
</Form.Control.Feedback>
)}
</Form.Group>
)}
</div>
<IntlProvider>
<div>
{file && (
<Form.Group>
<FormLabel>
<strong>
{formatMessage(messages.uploadFileDescriptionFieldLabel)}
</strong>
<span className="file-name-ellipsis">{file.name}</span>
</FormLabel>
<Form.Control
isInvalid={shouldShowError}
name="file-description"
onChange={onFileDescriptionChange}
/>
{shouldShowError && (
<Form.Control.Feedback type="invalid">
formatMessage(messages.fileDescriptionMissingError)
</Form.Control.Feedback>
)}
</Form.Group>
)}
</div>
</IntlProvider>
</ModalDialog.Body>
<ModalDialog.Footer>
<ActionRow>
Expand Down
26 changes: 10 additions & 16 deletions src/components/FileUpload/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const FileUpload = ({
} = useFileUploadHooks({
onFileUploaded,
});

return (
<div>
<h3>File Upload</h3>
Expand All @@ -46,8 +45,7 @@ const FileUpload = ({
itemCount={uploadedFiles.length}
data={uploadedFiles.map((file) => ({
...file,
size:
typeof file.size === 'number' ? filesize(file.size) : 'Unknown',
size: typeof file.size === 'number' ? filesize(file.size) : 'Unknown',
}))}
columns={[
{
Expand All @@ -72,19 +70,15 @@ const FileUpload = ({
</>
)}
{!isReadOnly && (
<>
<Dropzone
multiple
onProcessUpload={onProcessUpload}
progressVariant="bar"
/>
<UploadConfirmModal
open={isModalOpen}
file={uploadArgs.fileData?.getAll('file')[0]}
closeHandler={closeUploadModal}
uploadHandler={confirmUpload}
/>
</>
<Dropzone multiple onProcessUpload={onProcessUpload} progressVariant="bar" />
)}
{!isReadOnly && isModalOpen && (
<UploadConfirmModal
open={isModalOpen}
file={uploadArgs.fileData?.getAll('file')[0]}
closeHandler={closeUploadModal}
uploadHandler={confirmUpload}
/>
)}
</div>
);
Expand Down
28 changes: 28 additions & 0 deletions src/components/Instructions/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';

import { stepStates } from 'data/services/lms/constants';
import { useStepState } from 'data/services/lms/hooks/selectors';

import useInstructionsMessage from './useInstructionsMessage';

const Instructions = ({ step }) => {
const message = useInstructionsMessage(step);
const stepState = useStepState({ step });
if (stepState !== stepStates.inProgress) {
return null;
}
return (
<div>
<h2>Instructions</h2>
{message}
</div>
);
};
Instructions.defaultProps = {
step: null,
};
Instructions.propTypes = {
step: PropTypes.string,
};
export default Instructions;
33 changes: 33 additions & 0 deletions src/components/Instructions/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

import { stepNames } from 'data/services/lms/constants';

const messages = defineMessages({
[stepNames.submission]: {
defaultMessage: 'Submittion Instructions: TODO',
description: 'Submission step instructions',
id: 'frontend-app-ora.instructions.submisison',
},
[stepNames.studentTraining]: {
defaultMessage: 'Student Training Instructions: TODO',
description: 'StudentTraining step instructions',
id: 'frontend-app-ora.instructions.studentTraining',
},
[stepNames.self]: {
defaultMessage: 'Self Assessment Instructions: TODO',
description: 'Self Assessment step instructions',
id: 'frontend-app-ora.instructions.selfAssessment',
},
[stepNames.peer]: {
defaultMessage: 'Peer Assessment Instructions: TODO',
description: 'Peer Assessment step instructions',
id: 'frontend-app-ora.instructions.peerAssessment',
},
[stepNames.done]: {
defaultMessage: 'You have successfully completed this problem and received a {earned}/{possible}.',
description: 'Graded step instructions',
id: 'frontend-app-ora.instructions.done',
},
});

export default messages;
25 changes: 25 additions & 0 deletions src/components/Instructions/useInstructionsMessage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useIntl } from '@edx/frontend-platform/i18n';

import { useGlobalState } from 'data/services/lms/hooks/selectors';
import { stepNames, stepStates } from 'data/services/lms/constants';

import messages from './messages';

const useInstructionsMessage = (step = null) => {
const { formatMessage } = useIntl();
const {
activeStepName,
effectiveGrade,
stepState,
} = useGlobalState();
if (step || stepState !== stepStates.inProgress) {
return null;
}
const stepName = step || activeStepName;
if (stepName === stepNames.done) {
return formatMessage(messages[stepNames.done], effectiveGrade);
}
return formatMessage(messages[activeStepName]);
};

export default useInstructionsMessage;
11 changes: 7 additions & 4 deletions src/components/ModalContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,26 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FullscreenModal } from '@edx/paragon';

import ProgressBar from 'components/ProgressBar';

/* The purpose of this component is to wrap views with a header/footer for situations
* where we need to run non-embedded
*/

const ModalContainer = ({ Component, title }) => (
const ModalContainer = ({ title, children }) => (
<FullscreenModal
isOpen
onClose={null}
hasCloseButton={false}
title={title}
modalBodyClassName="content-body"
modalBodyClassName="content-body bg-light-300"
beforeBodyNode={<ProgressBar className="px-2" />}
>
<Component />
{children}
</FullscreenModal>
);
ModalContainer.propTypes = {
Component: PropTypes.elementType.isRequired,
children: PropTypes.node.isRequired,
title: PropTypes.string.isRequired,
};

Expand Down
Loading

0 comments on commit 2e26524

Please sign in to comment.