From cb11c1dd018871bfb469209d6e48bcbb3be58972 Mon Sep 17 00:00:00 2001 From: David Joy Date: Mon, 11 Jan 2021 12:05:03 -0500 Subject: [PATCH] Further pages & resources naming and organization (#46) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixing package SCSS imports. They need tildas. This ensures webpack knows to look for them in the node_modules folder, and also enables webpack resolve aliases to function (which is the mechanism that module.config.js works on) * Renaming course-page-resources to pages-and-resources It’s all course stuff in the end. * Renaming CoursePageResources to PagesAndResources To match its parent directory and the page’s user-facing name. * Simplifying name of CoursePageConfigCard to PageCard Also moving into a sub-directory where we’ll put components for the “pages” part of the UI. * Remove data README from example app. * Moving discussion-tool-selector directory Adding it as a child of the pages-and-resources module. * Organizing SCSS. * Simplifying discussions module structure. - Combining “container” and discussion tool selector into DiscussionAppList. - Removing some sub-directories that feel a bit too granular. * Splitting out some sub-components from PagesAndResources. * Removing unnecessary scss extension on import. --- src/CourseAuthoringRoutes.jsx | 12 ++--- src/course-page-resources/data/.gitkeep | 0 src/course-page-resources/data/README.rst | 4 -- src/course-page-resources/index.js | 2 - .../DiscussionToolSelector.jsx | 51 ------------------- src/index.scss | 17 +++---- .../PagesAndResources.jsx} | 45 ++++------------ .../PagesAndResources.test.jsx} | 2 +- .../discussions/DiscussionAppCard.jsx} | 34 +++++++++---- .../discussions/DiscussionAppList.jsx} | 46 +++++++++++++---- .../discussions/DiscussionAppList.scss} | 0 .../discussions/DiscussionAppList.test.jsx} | 2 +- .../discussions}/FeaturesTable.jsx | 2 +- .../discussions}/messages.js | 0 src/pages-and-resources/index.js | 2 + .../index.scss | 2 + .../messages.js | 0 .../pages/PageCard.jsx} | 12 ++--- .../pages/PageCard.test.jsx} | 2 +- src/pages-and-resources/pages/PageGrid.jsx | 38 ++++++++++++++ .../resources/ResourcesList.jsx | 42 +++++++++++++++ 21 files changed, 173 insertions(+), 142 deletions(-) delete mode 100644 src/course-page-resources/data/.gitkeep delete mode 100644 src/course-page-resources/data/README.rst delete mode 100644 src/course-page-resources/index.js delete mode 100644 src/discussion-tool-selector/discussion-tool-selector/DiscussionToolSelector.jsx rename src/{course-page-resources/CoursePageResources.jsx => pages-and-resources/PagesAndResources.jsx} (58%) rename src/{course-page-resources/CoursePageResources.test.jsx => pages-and-resources/PagesAndResources.test.jsx} (60%) rename src/{discussion-tool-selector/discussion-tool-selector/discussion-tool-option/DiscussionToolOption.jsx => pages-and-resources/discussions/DiscussionAppCard.jsx} (68%) rename src/{discussion-tool-selector/DiscussionToolSelectorContainer.jsx => pages-and-resources/discussions/DiscussionAppList.jsx} (67%) rename src/{discussion-tool-selector/DiscussionToolSelector.scss => pages-and-resources/discussions/DiscussionAppList.scss} (100%) rename src/{course-page-resources/course-page/CoursePageConfigCard.test.jsx => pages-and-resources/discussions/DiscussionAppList.test.jsx} (60%) rename src/{discussion-tool-selector/discussion-tool-selector/features-table => pages-and-resources/discussions}/FeaturesTable.jsx (94%) rename src/{discussion-tool-selector => pages-and-resources/discussions}/messages.js (100%) create mode 100644 src/pages-and-resources/index.js rename src/{course-page-resources => pages-and-resources}/index.scss (52%) rename src/{course-page-resources => pages-and-resources}/messages.js (100%) rename src/{course-page-resources/course-page/CoursePageConfigCard.jsx => pages-and-resources/pages/PageCard.jsx} (87%) rename src/{discussion-tool-selector/DiscussionToolSelector.test.jsx => pages-and-resources/pages/PageCard.test.jsx} (68%) create mode 100644 src/pages-and-resources/pages/PageGrid.jsx create mode 100644 src/pages-and-resources/resources/ResourcesList.jsx diff --git a/src/CourseAuthoringRoutes.jsx b/src/CourseAuthoringRoutes.jsx index 9864a9aa5..cd031359b 100644 --- a/src/CourseAuthoringRoutes.jsx +++ b/src/CourseAuthoringRoutes.jsx @@ -4,9 +4,9 @@ import { Switch, useRouteMatch } from 'react-router'; import { PageRoute } from '@edx/frontend-platform/react'; import CourseAuthoringPage from './CourseAuthoringPage'; -import { CoursePageResources } from './course-page-resources'; +import { PagesAndResources } from './pages-and-resources'; import ProctoredExamSettings from './proctored-exam-settings/ProctoredExamSettings'; -import DiscussionToolSelectorContainer from './discussion-tool-selector/DiscussionToolSelectorContainer'; +import DiscussionAppList from './pages-and-resources/discussions/DiscussionAppList'; /** * As of this writing, these routes are mounted at a path prefixed with the following: @@ -28,11 +28,11 @@ export default function CourseAuthoringRoutes({ courseId }) { return ( - - + + - - + + diff --git a/src/course-page-resources/data/.gitkeep b/src/course-page-resources/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/course-page-resources/data/README.rst b/src/course-page-resources/data/README.rst deleted file mode 100644 index 9c829c858..000000000 --- a/src/course-page-resources/data/README.rst +++ /dev/null @@ -1,4 +0,0 @@ -data folder -=========== - -This folder is the home for non-component files, such as redux reducers, actions, selectors, API client services, etc. See `Feature-based Application Organization `_. for more detail. \ No newline at end of file diff --git a/src/course-page-resources/index.js b/src/course-page-resources/index.js deleted file mode 100644 index 480bbe631..000000000 --- a/src/course-page-resources/index.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -export { default as CoursePageResources } from './CoursePageResources'; diff --git a/src/discussion-tool-selector/discussion-tool-selector/DiscussionToolSelector.jsx b/src/discussion-tool-selector/discussion-tool-selector/DiscussionToolSelector.jsx deleted file mode 100644 index c058885c5..000000000 --- a/src/discussion-tool-selector/discussion-tool-selector/DiscussionToolSelector.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { Button, Container, Row } from '@edx/paragon'; -import PropTypes from 'prop-types'; -import DiscussionToolOption from './discussion-tool-option/DiscussionToolOption'; -import FeaturesTable from './features-table/FeaturesTable'; -import messages from '../messages'; - -function DiscussionToolSelector({ - intl, forums, featuresList, onSelectForum, selectedForumId, -}) { - return ( - -
{intl.formatMessage(messages.heading)}
- - - {forums.map(forum => ( - - ))} - - -
-

- {intl.formatMessage(messages.supportedFeatures)} -

- {selectedForumId && ( - - )} -
- - -
- ); -} - -DiscussionToolSelector.propTypes = { - intl: intlShape.isRequired, - forums: PropTypes.arrayOf(PropTypes.object).isRequired, - featuresList: PropTypes.arrayOf(PropTypes.object).isRequired, - onSelectForum: PropTypes.func.isRequired, - selectedForumId: PropTypes.string.isRequired, -}; - -export default injectIntl(DiscussionToolSelector); diff --git a/src/index.scss b/src/index.scss index 53da5cd71..a99e1e02c 100755 --- a/src/index.scss +++ b/src/index.scss @@ -1,14 +1,11 @@ -@import "@edx/brand/paragon/fonts"; -@import "@edx/brand/paragon/variables"; -@import "@edx/paragon/scss/core/core"; -@import "@edx/brand/paragon/overrides"; -@import './course-page-resources/index.scss'; +@import "~@edx/brand/paragon/fonts"; +@import "~@edx/brand/paragon/variables"; +@import "~@edx/paragon/scss/core/core"; +@import "~@edx/brand/paragon/overrides"; +@import "studio-header/header"; @import "~@edx/frontend-component-footer/dist/footer"; -@import "proctored-exam-settings/proctoredExamSettings.scss"; - -@import "discussion-tool-selector/DiscussionToolSelector.scss"; - -@import "studio-header/header.scss"; +@import "pages-and-resources/index"; +@import "proctored-exam-settings/proctoredExamSettings"; diff --git a/src/course-page-resources/CoursePageResources.jsx b/src/pages-and-resources/PagesAndResources.jsx similarity index 58% rename from src/course-page-resources/CoursePageResources.jsx rename to src/pages-and-resources/PagesAndResources.jsx index 51c1131c5..d6b086d92 100644 --- a/src/course-page-resources/CoursePageResources.jsx +++ b/src/pages-and-resources/PagesAndResources.jsx @@ -2,13 +2,13 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { AppContext } from '@edx/frontend-platform/react'; -import { Button } from '@edx/paragon'; -import CoursePageConfigCard from './course-page/CoursePageConfigCard'; import messages from './messages'; +import PageGrid from './pages/PageGrid'; +import ResourceList from './resources/ResourcesList'; // XXX this is just for testing and should be removed ASAP -const coursePages = [ +const pages = [ { id: 'cp-discussion', title: 'Discussion', @@ -65,55 +65,28 @@ const coursePages = [ }, ]; -function CoursePageResources({ courseId, intl }) { +function PagesAndResources({ courseId, intl }) { const { config } = useContext(AppContext); const lmsCourseURL = `${config.LMS_BASE_URL}/courses/${courseId}`; return (
-
+

{intl.formatMessage(messages.heading)}

{intl.formatMessage(messages['viewLive.button'])}
-
-

- {intl.formatMessage(messages['pages.subheading'])} -

-
- {coursePages.map((coursePage) => ( -
- -
- ))} -
-
-
-

{intl.formatMessage(messages['resources.subheading'])}

-
-
{intl.formatMessage(messages['resources.custom.title'])}
-
- {intl.formatMessage(messages['resources.custom.description'])} -
-
- -
-
-
+ +
); } -CoursePageResources.propTypes = { +PagesAndResources.propTypes = { courseId: PropTypes.string.isRequired, intl: intlShape.isRequired, }; -export default injectIntl(CoursePageResources); +export default injectIntl(PagesAndResources); diff --git a/src/course-page-resources/CoursePageResources.test.jsx b/src/pages-and-resources/PagesAndResources.test.jsx similarity index 60% rename from src/course-page-resources/CoursePageResources.test.jsx rename to src/pages-and-resources/PagesAndResources.test.jsx index 82280d054..e68d14ebe 100644 --- a/src/course-page-resources/CoursePageResources.test.jsx +++ b/src/pages-and-resources/PagesAndResources.test.jsx @@ -1,4 +1,4 @@ -describe('coursepageresources', () => { +describe('PagesAndResources', () => { it('will pass because it is an example', () => { }); diff --git a/src/discussion-tool-selector/discussion-tool-selector/discussion-tool-option/DiscussionToolOption.jsx b/src/pages-and-resources/discussions/DiscussionAppCard.jsx similarity index 68% rename from src/discussion-tool-selector/discussion-tool-selector/discussion-tool-option/DiscussionToolOption.jsx rename to src/pages-and-resources/discussions/DiscussionAppCard.jsx index b21b76746..0e25d4c4c 100644 --- a/src/discussion-tool-selector/discussion-tool-selector/discussion-tool-option/DiscussionToolOption.jsx +++ b/src/pages-and-resources/discussions/DiscussionAppCard.jsx @@ -1,11 +1,13 @@ import React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { CheckBox, Image, Col } from '@edx/paragon'; +import { + Image, Col, Input, +} from '@edx/paragon'; import { faLock } from '@fortawesome/free-solid-svg-icons'; import PropTypes from 'prop-types'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import messages from '../../messages'; +import messages from './messages'; function DiscussionToolOption({ intl, forum, selected, onSelect, @@ -13,7 +15,7 @@ function DiscussionToolOption({ return (
-
+
+ {forum.isAvailable ? ( + + ) : ( + + + )} +
+ +
-
- {forum.isAvailable ? ( - - ) : ( - - )} -
+

{forum.description}
diff --git a/src/discussion-tool-selector/DiscussionToolSelectorContainer.jsx b/src/pages-and-resources/discussions/DiscussionAppList.jsx similarity index 67% rename from src/discussion-tool-selector/DiscussionToolSelectorContainer.jsx rename to src/pages-and-resources/discussions/DiscussionAppList.jsx index 225956225..37b104083 100644 --- a/src/discussion-tool-selector/DiscussionToolSelectorContainer.jsx +++ b/src/pages-and-resources/discussions/DiscussionAppList.jsx @@ -1,6 +1,10 @@ import React, { useState } from 'react'; + import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import DiscussionToolSelector from './discussion-tool-selector/DiscussionToolSelector'; +import { Button, Container, Row } from '@edx/paragon'; +import messages from './messages'; +import DiscussionAppCard from './DiscussionAppCard'; +import FeaturesTable from './FeaturesTable'; // XXX this is just for testing and should be removed ASAP const forums = [ @@ -40,7 +44,7 @@ const forums = [ const featuresList = ['LTI Integration', 'Discussion Page', 'Embedded Course Sections', 'Embedded Course Units', 'WCAG 2.1 Support']; -function DiscussionToolSelectorContainer({ intl }) { +function DiscussionAppList({ intl }) { const [selectedForumId, setSelectedForumId] = useState(null); const onSelectForum = (forumId) => { @@ -52,18 +56,38 @@ function DiscussionToolSelectorContainer({ intl }) { }; return ( - + +
{intl.formatMessage(messages.heading)}
+ + + {forums.map(forum => ( + + ))} + + +
+

+ {intl.formatMessage(messages.supportedFeatures)} +

+ {selectedForumId && ( + + )} +
+ + +
); } -DiscussionToolSelectorContainer.propTypes = { +DiscussionAppList.propTypes = { intl: intlShape.isRequired, }; -export default injectIntl(DiscussionToolSelectorContainer); +export default injectIntl(DiscussionAppList); diff --git a/src/discussion-tool-selector/DiscussionToolSelector.scss b/src/pages-and-resources/discussions/DiscussionAppList.scss similarity index 100% rename from src/discussion-tool-selector/DiscussionToolSelector.scss rename to src/pages-and-resources/discussions/DiscussionAppList.scss diff --git a/src/course-page-resources/course-page/CoursePageConfigCard.test.jsx b/src/pages-and-resources/discussions/DiscussionAppList.test.jsx similarity index 60% rename from src/course-page-resources/course-page/CoursePageConfigCard.test.jsx rename to src/pages-and-resources/discussions/DiscussionAppList.test.jsx index 379aaee02..f8961aa71 100644 --- a/src/course-page-resources/course-page/CoursePageConfigCard.test.jsx +++ b/src/pages-and-resources/discussions/DiscussionAppList.test.jsx @@ -1,4 +1,4 @@ -describe('CoursePageConfigCard', () => { +describe('DiscussionAppList', () => { it('will pass because it is an example', () => { }); diff --git a/src/discussion-tool-selector/discussion-tool-selector/features-table/FeaturesTable.jsx b/src/pages-and-resources/discussions/FeaturesTable.jsx similarity index 94% rename from src/discussion-tool-selector/discussion-tool-selector/features-table/FeaturesTable.jsx rename to src/pages-and-resources/discussions/FeaturesTable.jsx index 300825b9e..c101cf8db 100644 --- a/src/discussion-tool-selector/discussion-tool-selector/features-table/FeaturesTable.jsx +++ b/src/pages-and-resources/discussions/FeaturesTable.jsx @@ -34,5 +34,5 @@ export default function FeaturesTable({ forums, featuresList }) { FeaturesTable.propTypes = { forums: PropTypes.arrayOf(PropTypes.object).isRequired, - featuresList: PropTypes.arrayOf(PropTypes.object).isRequired, + featuresList: PropTypes.arrayOf(PropTypes.string).isRequired, }; diff --git a/src/discussion-tool-selector/messages.js b/src/pages-and-resources/discussions/messages.js similarity index 100% rename from src/discussion-tool-selector/messages.js rename to src/pages-and-resources/discussions/messages.js diff --git a/src/pages-and-resources/index.js b/src/pages-and-resources/index.js new file mode 100644 index 000000000..a9bf84cf6 --- /dev/null +++ b/src/pages-and-resources/index.js @@ -0,0 +1,2 @@ +/* eslint-disable import/prefer-default-export */ +export { default as PagesAndResources } from './PagesAndResources'; diff --git a/src/course-page-resources/index.scss b/src/pages-and-resources/index.scss similarity index 52% rename from src/course-page-resources/index.scss rename to src/pages-and-resources/index.scss index 8164e687a..6702bd929 100644 --- a/src/course-page-resources/index.scss +++ b/src/pages-and-resources/index.scss @@ -1,3 +1,5 @@ +@import "./discussions/DiscussionAppList"; + .course-page-config-card { flex-basis: 100%; } diff --git a/src/course-page-resources/messages.js b/src/pages-and-resources/messages.js similarity index 100% rename from src/course-page-resources/messages.js rename to src/pages-and-resources/messages.js diff --git a/src/course-page-resources/course-page/CoursePageConfigCard.jsx b/src/pages-and-resources/pages/PageCard.jsx similarity index 87% rename from src/course-page-resources/course-page/CoursePageConfigCard.jsx rename to src/pages-and-resources/pages/PageCard.jsx index 36e4b7b7e..18a70ed1d 100644 --- a/src/course-page-resources/course-page/CoursePageConfigCard.jsx +++ b/src/pages-and-resources/pages/PageCard.jsx @@ -9,7 +9,7 @@ import { faCog } from '@fortawesome/free-solid-svg-icons'; import messages from '../messages'; -const CoursePageShape = PropTypes.shape({ +const pageShape = PropTypes.shape({ id: PropTypes.string.isRequired, title: PropTypes.string.isRequired, description: PropTypes.string.isRequired, @@ -19,9 +19,7 @@ const CoursePageShape = PropTypes.shape({ showEnable: PropTypes.bool.isRequired, }); -export { CoursePageShape }; - -function CoursePageConfigCard({ intl, coursePage }) { +function PageCard({ intl, coursePage }) { const pageStatusMsgId = coursePage.isEnabled ? 'pageStatus.enabled' : 'pageStatus.disabled'; const componentClasses = classNames( 'course-page-config-card d-flex flex-column align-content-stretch', @@ -55,9 +53,9 @@ function CoursePageConfigCard({ intl, coursePage }) { ); } -CoursePageConfigCard.propTypes = { +PageCard.propTypes = { intl: intlShape.isRequired, - coursePage: CoursePageShape.isRequired, + coursePage: pageShape.isRequired, }; -export default injectIntl(CoursePageConfigCard); +export default injectIntl(PageCard); diff --git a/src/discussion-tool-selector/DiscussionToolSelector.test.jsx b/src/pages-and-resources/pages/PageCard.test.jsx similarity index 68% rename from src/discussion-tool-selector/DiscussionToolSelector.test.jsx rename to src/pages-and-resources/pages/PageCard.test.jsx index 3bad6f31d..86a7a009a 100644 --- a/src/discussion-tool-selector/DiscussionToolSelector.test.jsx +++ b/src/pages-and-resources/pages/PageCard.test.jsx @@ -1,4 +1,4 @@ -describe('example', () => { +describe('PageCard', () => { it('will pass because it is an example', () => { }); diff --git a/src/pages-and-resources/pages/PageGrid.jsx b/src/pages-and-resources/pages/PageGrid.jsx new file mode 100644 index 000000000..f7ef9c064 --- /dev/null +++ b/src/pages-and-resources/pages/PageGrid.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import PageCard from './PageCard'; + +import messages from '../messages'; + +function PageGrid({ intl, pages }) { + return ( +
+

+ {intl.formatMessage(messages['pages.subheading'])} +

+
+ {pages.map((page) => ( + + ))} +
+
+ ); +} + +const pageShape = PropTypes.shape({ + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + isEnabled: PropTypes.bool.isRequired, + showSettings: PropTypes.bool.isRequired, + showStatus: PropTypes.bool.isRequired, + showEnable: PropTypes.bool.isRequired, + description: PropTypes.string.isRequired, +}); + +PageGrid.propTypes = { + intl: intlShape.isRequired, + pages: PropTypes.arrayOf(pageShape).isRequired, +}; + +export default injectIntl(PageGrid); diff --git a/src/pages-and-resources/resources/ResourcesList.jsx b/src/pages-and-resources/resources/ResourcesList.jsx new file mode 100644 index 000000000..d212c3523 --- /dev/null +++ b/src/pages-and-resources/resources/ResourcesList.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { Button } from '@edx/paragon'; + +import messages from '../messages'; + +function ResourceList({ intl, resources }) { + return ( +
+

{intl.formatMessage(messages['resources.subheading'])}

+
+
{intl.formatMessage(messages['resources.custom.title'])}
+
+ {intl.formatMessage(messages['resources.custom.description'])} +
+
+ +
+
+ {resources} +
+ ); +} + +const resourcesShape = PropTypes.shape({ + id: PropTypes.string.isRequired, + // TODO: What is the shape of a resources model? +}); + +ResourceList.propTypes = { + resources: PropTypes.arrayOf(resourcesShape), + intl: intlShape.isRequired, +}; + +ResourceList.defaultProps = { + resources: [], +}; + +export default injectIntl(ResourceList);