Skip to content

Commit

Permalink
chore: add paragon messages (#530)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mashal-m authored and SundasNoreen committed Jul 21, 2023
1 parent 87ead24 commit 1487383
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 102 deletions.
3 changes: 2 additions & 1 deletion src/i18n/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { messages as footerMessages } from '@edx/frontend-component-footer';

import { messages as paragonMessages } from '@edx/paragon';
import arMessages from './messages/ar.json';
import frMessages from './messages/fr.json';
import es419Messages from './messages/es_419.json';
Expand Down Expand Up @@ -35,5 +35,6 @@ const appMessages = {

export default [
footerMessages,
paragonMessages,
appMessages,
];
87 changes: 50 additions & 37 deletions src/pages-and-resources/discussions/DiscussionsSettings.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,14 @@ describe('DiscussionsSettings', () => {

expect(queryByTestId(container, 'appConfigForm')).toBeInTheDocument();

userEvent.click(queryByText(container, appMessages.backButton.defaultMessage));
await act(async () => {
userEvent.click(queryByText(container, appMessages.backButton.defaultMessage));
});

expect(queryByTestId(container, 'appList')).toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
waitFor(() => {
expect(queryByTestId(container, 'appList')).toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
});
});

test('successfully closes the modal', async () => {
Expand Down Expand Up @@ -217,14 +221,16 @@ describe('DiscussionsSettings', () => {
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.getByRole('status'));

userEvent.click(getByRole(container, 'checkbox', { name: 'Select Discourse' }));
userEvent.click(getByRole(container, 'button', { name: 'Next' }));
await act(async () => userEvent.click(getByRole(container, 'checkbox', { name: 'Select Discourse' })));
await act(async () => userEvent.click(getByRole(container, 'button', { name: 'Next' })));

await findByRole(container, 'button', { name: 'Save' });
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'key');
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
userEvent.click(getByRole(container, 'button', { name: 'Save' }));
waitFor(async () => {
await findByRole(container, 'button', { name: 'Save' });
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Key' }), 'key');
userEvent.type(getByRole(container, 'textbox', { name: 'Consumer Secret' }), 'secret');
userEvent.type(getByRole(container, 'textbox', { name: 'Launch URL' }), 'http://example.test');
userEvent.click(getByRole(container, 'button', { name: 'Save' }));
});

await waitFor(() => expect(getByRole(container, 'dialog', { name: 'OK' })).toBeInTheDocument());
});
Expand Down Expand Up @@ -364,17 +370,18 @@ describe('DiscussionsSettings', () => {

userEvent.click(getByRole(container, 'button', { name: 'Save' }));

await waitFor(() => expect(axiosMock.history.post.length).toBe(1));

expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();
await waitFor(async () => {
expect(axiosMock.history.post.length).toBe(1);
expect(queryByTestId(container, 'appList')).not.toBeInTheDocument();
expect(queryByTestId(container, 'appConfigForm')).not.toBeInTheDocument();

// We don't technically leave the route in this case, though the modal is hidden.
expect(window.location.pathname).toEqual(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);
// We don't technically leave the route in this case, though the modal is hidden.
expect(window.location.pathname).toEqual(`/course/${courseId}/pages-and-resources/discussion/configure/piazza`);

const alert = await findByRole(container, 'alert');
expect(alert).toBeInTheDocument();
expect(alert.textContent).toEqual(expect.stringContaining('You are not authorized to view this page.'));
const alert = await findByRole(container, 'alert');
expect(alert).toBeInTheDocument();
expect(alert.textContent).toEqual(expect.stringContaining('You are not authorized to view this page.'));
});
});
});
});
Expand Down Expand Up @@ -421,17 +428,20 @@ describe.each([
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.getByRole('status'));

userEvent.click(queryByLabelText(container, 'Select Piazza'));
userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
await waitForElementToBeRemoved(screen.getByRole('status'));
await act(async () => userEvent.click(queryByLabelText(container, 'Select Piazza')));
await act(async () => userEvent.click(queryByText(container, messages.nextButton.defaultMessage)));

if (showLTIConfig) {
expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).toBeInTheDocument();
expect(queryByTestId(container, 'ltiConfigFields')).toBeInTheDocument();
} else {
expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).not.toBeInTheDocument();
expect(queryByTestId(container, 'ltiConfigFields')).not.toBeInTheDocument();
}
waitFor(async () => {
await waitForElementToBeRemoved(screen.getByRole('status'));

if (showLTIConfig) {
expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).toBeInTheDocument();
expect(queryByTestId(container, 'ltiConfigFields')).toBeInTheDocument();
} else {
expect(queryByText(container, ltiMessages.formInstructions.defaultMessage)).not.toBeInTheDocument();
expect(queryByTestId(container, 'ltiConfigFields')).not.toBeInTheDocument();
}
});
});
});

Expand Down Expand Up @@ -477,13 +487,16 @@ describe.each([
// content has been loaded - prior to proceeding with our expectations.
await waitForElementToBeRemoved(screen.getByRole('status'));

userEvent.click(queryByLabelText(container, 'Select Piazza'));
userEvent.click(queryByText(container, messages.nextButton.defaultMessage));
await waitForElementToBeRemoved(screen.getByRole('status'));
if (enablePIISharing) {
expect(queryByTestId(container, 'piiSharingFields')).toBeInTheDocument();
} else {
expect(queryByTestId(container, 'piiSharingFields')).not.toBeInTheDocument();
}
await act(async () => userEvent.click(queryByLabelText(container, 'Select Piazza')));
await act(async () => userEvent.click(queryByText(container, messages.nextButton.defaultMessage)));

waitFor(() => {
waitForElementToBeRemoved(screen.getByRole('status'));
if (enablePIISharing) {
expect(queryByTestId(container, 'piiSharingFields')).toBeInTheDocument();
} else {
expect(queryByTestId(container, 'piiSharingFields')).not.toBeInTheDocument();
}
});
});
});
95 changes: 89 additions & 6 deletions src/pages-and-resources/discussions/app-list/AppList.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, {
useCallback, useEffect, useMemo, useState, useContext,
} from 'react';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { CardGrid, Container, breakpoints } from '@edx/paragon';
import {
CardGrid, Container, breakpoints, Form, ActionRow, AlertModal, Button,
} from '@edx/paragon';
import { useDispatch, useSelector } from 'react-redux';
import Responsive from 'react-responsive';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
Expand All @@ -14,16 +18,25 @@ import messages from './messages';
import FeaturesTable from './FeaturesTable';
import AppListNextButton from './AppListNextButton';
import Loading from '../../../generic/Loading';
import useIsOnSmallScreen from '../data/hook';
import { saveProviderConfig, fetchDiscussionSettings } from '../data/thunks';
import { PagesAndResourcesContext } from '../../PagesAndResourcesProvider';
import { discussionRestriction } from '../data/constants';

const AppList = ({ intl }) => {
const dispatch = useDispatch();
const { courseId } = useContext(PagesAndResourcesContext);
const {
appIds, featureIds, status, activeAppId, selectedAppId,
appIds, featureIds, status, activeAppId, selectedAppId, enabled, postingRestrictions,
} = useSelector(state => state.discussions);

const [showDiscussionAlert, setShowDiscussionAlert] = useState(false);
const [discussionEnabled, setDiscussionEnabled] = useState(enabled);
const apps = useModels('apps', appIds);
const features = useModels('features', featureIds);
const isGlobalStaff = getAuthenticatedUser().administrator;
const ltiProvider = !['openedx', 'legacy'].includes(activeAppId);
const isOnSmallcreen = useIsOnSmallScreen();

const showOneEdxProvider = useMemo(() => apps.filter(app => (
activeAppId === 'openedx' ? app.id !== 'legacy' : app.id !== 'openedx'
Expand All @@ -42,8 +55,49 @@ const AppList = ({ intl }) => {
dispatch(updateValidationStatus({ hasError: false }));
}, [selectedAppId, activeAppId]);

useEffect(() => {
setDiscussionEnabled(enabled);
}, [enabled]);

useEffect(() => {
dispatch(fetchDiscussionSettings(courseId, selectedAppId));
}, [courseId, selectedAppId]);

const handleSelectApp = useCallback((appId) => {
dispatch(selectApp({ appId }));
}, []);

const updateSettings = useCallback((enabledDiscussion) => {
dispatch(saveProviderConfig(
courseId,
selectedAppId,
{
enabled: enabledDiscussion,
postingRestrictions:
enabledDiscussion ? postingRestrictions : discussionRestriction.ENABLED,
},
));
}, [courseId, selectedAppId, postingRestrictions, discussionEnabled]);

const handleClose = useCallback(() => {
setShowDiscussionAlert(false);
setDiscussionEnabled(enabled);
}, [enabled]);

const handleOk = useCallback(() => {
setShowDiscussionAlert(false);
setDiscussionEnabled(false);
updateSettings(false);
}, []);

const handleChange = useCallback((e) => {
const toggleVal = e.target.checked;

setShowDiscussionAlert(toggleVal);
setDiscussionEnabled(!toggleVal);
if (!toggleVal) {
updateSettings(toggleVal);
}
}, [selectedAppId]);

if (!selectedAppId || status === LOADING) {
Expand Down Expand Up @@ -72,16 +126,28 @@ const AppList = ({ intl }) => {

return (
<div className="my-sm-5 m-1" data-testid="appList">
<h3 className="my-sm-5 my-4">
{intl.formatMessage(messages.heading)}
</h3>
<div className={!isOnSmallcreen ? 'd-flex flex-row justify-content-between mt-4' : 'mt-2 mb-4'}>
<h3>
{intl.formatMessage(messages.heading)}
</h3>
<Form.Switch
floatLabelLeft
className="text-primary-500 d-flex flex-row align-items-center"
labelClassName="line-height-24"
onChange={handleChange}
checked={!discussionEnabled}
>
Hide discussion tab
</Form.Switch>
</div>
<CardGrid
columnSizes={{
xs: 12,
sm: 6,
lg: 4,
xl: 4,
}}
className="mt-4 my-sm-5"
>
{(isGlobalStaff || ltiProvider) ? showAppCard(apps) : showAppCard(showOneEdxProvider)}
</CardGrid>
Expand All @@ -96,6 +162,23 @@ const AppList = ({ intl }) => {
/>
</div>
</Responsive>
<AlertModal
title={intl.formatMessage(messages.hideDiscussionTabTitle)}
isOpen={showDiscussionAlert}
onClose={handleClose}
isBlocking
className="hide-discussion-modal"
footerNode={(
<ActionRow>
<Button variant="link" className="text-decoration-none bg-black" onClick={handleClose}>Cancel</Button>
<Button variant="primary" className="bg-primary-500 ml-1 rounded-0" onClick={handleOk}>OK</Button>
</ActionRow>
)}
>
<p className="bg-black">
{intl.formatMessage(messages.hideDiscussionTabMessage)}
</p>
</AlertModal>
</div>
);
};
Expand Down
31 changes: 30 additions & 1 deletion src/pages-and-resources/discussions/app-list/AppList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,39 @@
padding: 0 7px;
}

.line-height-24 {
line-height: 24px !important;
}

.hide-discussion-modal {
.pgn__modal-header {
padding-top: 24px;

h2 {
color: $primary-500;
line-height: 28px;
font-size: 22px;
}
}

.bg-black {
color: #000000;
}

.pgn__modal-footer {
padding-top: 8px;
padding-bottom: 24px;
}

button {
font-weight: 500;
}
}

.discussion-restriction {
.unselected-button {
&:hover {
background: #E9E6E4 !important;
background: #E9E6E4;
}
}

Expand Down
25 changes: 15 additions & 10 deletions src/pages-and-resources/discussions/app-list/AppList.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable react/jsx-no-constructed-context-values */
import React from 'react';
import {
render, screen, within, queryAllByRole,
render, screen, within, queryAllByRole, waitFor,
} from '@testing-library/react';
import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
Expand Down Expand Up @@ -70,35 +70,40 @@ describe('AppList', () => {
test('display a card for each available app', async () => {
renderComponent();
const appCount = store.getState().discussions.appIds.length;
expect(screen.queryAllByRole('radio')).toHaveLength(appCount);
waitFor(() => expect(screen.queryAllByRole('radio')).toHaveLength(appCount));
});

test('displays the FeaturesTable at desktop sizes', async () => {
renderComponent();
expect(screen.queryByRole('table')).toBeInTheDocument();
waitFor(() => expect(screen.queryByRole('table')).toBeInTheDocument());
});

test('hides the FeaturesTable at mobile sizes', async () => {
renderComponent(breakpoints.extraSmall.maxWidth);
expect(screen.queryByRole('table')).not.toBeInTheDocument();
waitFor(() => expect(screen.queryByRole('table')).not.toBeInTheDocument());
});

test('hides the FeaturesList at desktop sizes', async () => {
renderComponent();
expect(screen.queryByText(messages['supportedFeatureList-mobile-show'].defaultMessage)).not.toBeInTheDocument();
waitFor(() => expect(screen.queryByText(messages['supportedFeatureList-mobile-show'].defaultMessage))
.not.toBeInTheDocument());
});

test('displays the FeaturesList at mobile sizes', async () => {
renderComponent(breakpoints.extraSmall.maxWidth);
const appCount = store.getState().discussions.appIds.length;
expect(screen.queryAllByText(messages['supportedFeatureList-mobile-show'].defaultMessage)).toHaveLength(appCount);
waitFor(() => expect(screen.queryAllByText(messages['supportedFeatureList-mobile-show'].defaultMessage))
.toHaveLength(appCount));
});

test('selectApp is called when an app is clicked', async () => {
renderComponent();
userEvent.click(screen.getByLabelText('Select Piazza'));
const clickedCard = screen.getByRole('radio', { checked: true });
expect(within(clickedCard).queryByLabelText('Select Piazza')).toBeInTheDocument();

waitFor(() => {
userEvent.click(screen.getByLabelText('Select Piazza'));
const clickedCard = screen.getByRole('radio', { checked: true });
expect(within(clickedCard).queryByLabelText('Select Piazza')).toBeInTheDocument();
});
});
});

Expand All @@ -121,7 +126,7 @@ describe('AppList', () => {
test('does not display two edx providers card for non admin role', async () => {
renderComponent();
const appCount = store.getState().discussions.appIds.length;
expect(queryAllByRole(container, 'radio')).toHaveLength(appCount - 1);
waitFor(() => expect(queryAllByRole(container, 'radio')).toHaveLength(appCount - 1));
});
});
});
Loading

0 comments on commit 1487383

Please sign in to comment.