diff --git a/src/pages-and-resources/discussions/AppCard.jsx b/src/pages-and-resources/discussions/AppCard.jsx index c272aa833..1a55915b6 100644 --- a/src/pages-and-resources/discussions/AppCard.jsx +++ b/src/pages-and-resources/discussions/AppCard.jsx @@ -3,20 +3,22 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Card, Input } from '@edx/paragon'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faLock } from '@fortawesome/free-solid-svg-icons'; import messages from './messages'; function AppCard({ app, onClick, intl, selected, }) { + const supportText = app.hasFullSupport + ? intl.formatMessage(messages.appFullSupport) + : intl.formatMessage(messages.appPartialSupport); + return ( { if (app.isAvailable) { onClick(app.id); } }} - onKeyPress={() => { if (app.isAvailable) { onClick(app.id); } }} + tabIndex="-1" + onClick={() => onClick(app.id)} + onKeyPress={() => onClick(app.id)} role="radio" aria-checked={selected} style={{ @@ -29,48 +31,28 @@ function AppCard({
- {app.isAvailable ? ( - - ) : ( - - )} +
- - {app.name} - {app.description} + + {intl.formatMessage(messages[`appName-${app.id}`])} + + {supportText} + {intl.formatMessage(messages[`appDescription-${app.id}`])} - - {app.supportLevel} -
); } AppCard.propTypes = { app: PropTypes.shape({ - description: PropTypes.string.isRequired, id: PropTypes.string.isRequired, - isAvailable: PropTypes.bool.isRequired, - logo: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - supportLevel: PropTypes.string.isRequired, + featureIds: PropTypes.arrayOf(PropTypes.string).isRequired, + hasFullSupport: PropTypes.bool.isRequired, }).isRequired, onClick: PropTypes.func.isRequired, selected: PropTypes.bool.isRequired, diff --git a/src/pages-and-resources/discussions/ConfigFormContainer.jsx b/src/pages-and-resources/discussions/ConfigFormContainer.jsx index 47fce44c3..cd117c9db 100644 --- a/src/pages-and-resources/discussions/ConfigFormContainer.jsx +++ b/src/pages-and-resources/discussions/ConfigFormContainer.jsx @@ -32,7 +32,7 @@ function ConfigFormContainer({ let form = null; - if (app.id === 'edx-discussions') { + if (app.id === 'legacy') { form = ( ({ - Header: app.name, + Header: intl.formatMessage(messages[`appName-${app.id}`]), accessor: app.id, })), ]} @@ -50,7 +52,10 @@ export default function FeaturesTable({ apps, features }) { ); } +export default injectIntl(FeaturesTable); + FeaturesTable.propTypes = { apps: PropTypes.arrayOf(PropTypes.object).isRequired, features: PropTypes.arrayOf(PropTypes.object).isRequired, + intl: intlShape.isRequired, }; diff --git a/src/pages-and-resources/discussions/data/api.js b/src/pages-and-resources/discussions/data/api.js index 644b4d40f..51c974033 100644 --- a/src/pages-and-resources/discussions/data/api.js +++ b/src/pages-and-resources/discussions/data/api.js @@ -1,3 +1,31 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +function normalizeApps(data) { + const apps = Object.entries(data.providers.available).map(([key, app]) => ({ + id: key, + featureIds: app.features, + hasFullSupport: app.features.length >= data.features.length, + })); + return { + courseId: data.context_key, + enabled: data.enabled, + features: data.features.map(id => ({ + id, + })), + appConfig: data.plugin_configuration, + activeAppId: data.providers.active, + apps, + }; +} + +export async function getApps(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(`${getConfig().LMS_BASE_URL}/discussions/api/v0/${courseId}`); + + return normalizeApps(data); +} + const legacyEdXDiscussions = { id: 'edx-discussions', name: 'edX Discussions', @@ -47,39 +75,6 @@ const yellowdigApp = { ], }; -export function getApps() { - return Promise.resolve({ - features: [ - { - id: 'lti', - name: 'LTI Integration', - }, - { - id: 'discussion-page', - name: 'Discussion Page', - }, - { - id: 'embedded-course-sections', - name: 'Embedded Course Sections', - }, - { - id: 'embedded-course-units', - name: 'Embedded Course Units', - }, - { - id: 'wcag-2.1', - name: 'WCAG 2.1 Support', - }, - ], - apps: [ - legacyEdXDiscussions, - piazzaApp, - yellowdigApp, - ], - activeAppId: 'piazza', - }); -} - export function getAppConfig(courseId, appId) { let app = null; switch (appId) { @@ -124,23 +119,18 @@ export function getAppConfig(courseId, appId) { features: [ { id: 'lti', - name: 'LTI Integration', }, { id: 'discussion-page', - name: 'Discussion Page', }, { id: 'embedded-course-sections', - name: 'Embedded Course Sections', }, { id: 'embedded-course-units', - name: 'Embedded Course Units', }, { id: 'wcag-2.1', - name: 'WCAG 2.1 Support', }, ], }); diff --git a/src/pages-and-resources/discussions/data/slice.js b/src/pages-and-resources/discussions/data/slice.js index 9bf00362c..88e8b5318 100644 --- a/src/pages-and-resources/discussions/data/slice.js +++ b/src/pages-and-resources/discussions/data/slice.js @@ -21,6 +21,7 @@ const slice = createSlice({ fetchAppsSuccess: (state, { payload }) => { state.appIds = payload.appIds; state.featureIds = payload.featureIds; + state.activeAppId = payload.activeAppId; }, fetchAppConfigSuccess: (state, { payload }) => { state.activeAppId = payload.activeAppId; diff --git a/src/pages-and-resources/discussions/data/thunks.js b/src/pages-and-resources/discussions/data/thunks.js index 1a5531b77..e578e55ec 100644 --- a/src/pages-and-resources/discussions/data/thunks.js +++ b/src/pages-and-resources/discussions/data/thunks.js @@ -21,11 +21,12 @@ export function fetchApps(courseId) { dispatch(updateStatus({ courseId, status: LOADING })); try { - const { apps, features } = await getApps(courseId); + const { apps, features, activeAppId } = await getApps(courseId); dispatch(addModels({ modelType: 'apps', models: apps })); dispatch(addModels({ modelType: 'features', models: features })); dispatch(fetchAppsSuccess({ + activeAppId, appIds: apps.map(app => app.id), featureIds: features.map(feature => feature.id), })); diff --git a/src/pages-and-resources/discussions/messages.js b/src/pages-and-resources/discussions/messages.js index 754d9071a..f3d027cbc 100644 --- a/src/pages-and-resources/discussions/messages.js +++ b/src/pages-and-resources/discussions/messages.js @@ -3,7 +3,7 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ heading: { id: 'authoring.discussions.heading', - defaultMessage: 'Which discussion tool would you like to use for this course?', + defaultMessage: 'Select a discussion tool for this course', }, supportedFeatures: { id: 'authoring.discussions.supportedFeatures', @@ -60,6 +60,60 @@ const messages = defineMessages({ defaultMessage: 'Select discussion tool', description: 'A label for the first step of a wizard where the user chooses a discussion tool to configure.', }, + appFullSupport: { + id: 'authoring.discussions.appFullSupport', + defaultMessage: 'Full support', + description: 'A label indicating that an app supports the full set of possible features for a discussions app.', + }, + appPartialSupport: { + id: 'authoring.discussions.appPartialSupport', + defaultMessage: 'Partial support', + description: 'A label indicating that an app only supports a subset of the possible features of a discussions app.', + }, + // Legacy + 'appName-legacy': { + id: 'authoring.discussions.appName-legacy', + defaultMessage: 'Legacy edX Discussions', + description: 'The name of the Legacy edX Discussions app.', + }, + 'appDescription-legacy': { + id: 'authoring.discussions.appDescription-legacy', + defaultMessage: 'Start conversations with other learners, ask questions, and interact with other learners in the course.', + description: 'A description of the Legacy edX Discussions app.', + }, + // Piazza + 'appName-piazza': { + id: 'authoring.discussions.appName-piazza', + defaultMessage: 'Piazza', + description: 'The name of the Piazza app.', + }, + 'appDescription-piazza': { + id: 'authoring.discussions.appDescription-piazza', + defaultMessage: 'Piazza is designed to connect students, TAs, and professors so every student can get the help they need when they need it.', + description: 'A description of the Piazza app.', + }, + + // Features + 'featureName-discussion-page': { + id: 'authoring.discussions.featureName-discussion-page', + defaultMessage: 'Discussion Page', + description: 'The name of a discussions feature.', + }, + 'featureName-embedded-course-sections': { + id: 'authoring.discussions.featureName-embedded-course-sections', + defaultMessage: 'Embedded Course Sections', + description: 'The name of a discussions feature.', + }, + 'featureName-lti': { + id: 'authoring.discussions.featureName-lti', + defaultMessage: 'LTI Integration', + description: 'The name of a discussions feature.', + }, + 'featureName-wcag-2.1': { + id: 'authoring.discussions.featureName-wcag-2.1', + defaultMessage: 'WCAG 2.1 Support', + description: 'The name of a discussions feature.', + }, }); export default messages;