Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/au 1863 #1304

Merged
merged 7 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 58 additions & 46 deletions src/courseware/course/sequence/Sequence.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import HiddenAfterDue from './hidden-after-due';
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
import SequenceContent from './SequenceContent';
import FeedbackWidget from './Unit/feedback-widget';

const Sequence = ({
unitId,
Expand All @@ -37,7 +38,11 @@
previousSequenceHandler,
}) => {
const intl = useIntl();
const course = useModel('coursewareMeta', courseId);
const {
canAccessProctoredExams,
license,
wholeCourseTranslationEnabled,
} = useModel('coursewareMeta', courseId);
const {
isStaff,
originalUserIsStaff,
Expand All @@ -49,7 +54,8 @@
const shouldDisplayNotificationTriggerInSequence = useWindowSize().width < breakpoints.small.minWidth;
const enableNewSidebar = getConfig().ENABLE_NEW_SIDEBAR;

const handleNext = () => {
const handleNext = (position) => {
logEvent('edx.ui.lms.sequence.next_selected', position);
const nextIndex = sequence.unitIds.indexOf(unitId) + 1;
if (nextIndex < sequence.unitIds.length) {
const newUnitId = sequence.unitIds[nextIndex];
Expand All @@ -59,7 +65,8 @@
}
};

const handlePrevious = () => {
const handlePrevious = (position) => {
logEvent('edx.ui.lms.sequence.previous_selected', position);
const previousIndex = sequence.unitIds.indexOf(unitId) - 1;
if (previousIndex >= 0) {
const newUnitId = sequence.unitIds[previousIndex];
Expand Down Expand Up @@ -144,55 +151,60 @@
const gated = sequence && sequence.gatedContent !== undefined && sequence.gatedContent.gated;

const defaultContent = (
<div className="sequence-container d-inline-flex flex-row">
<div className={classNames('sequence w-100', { 'position-relative': shouldDisplayNotificationTriggerInSequence })}>
<SequenceNavigation
sequenceId={sequenceId}
unitId={unitId}
className="mb-4"
nextHandler={() => {
logEvent('edx.ui.lms.sequence.next_selected', 'top');
handleNext();
}}
onNavigate={(destinationUnitId) => {
logEvent('edx.ui.lms.sequence.tab_selected', 'top', destinationUnitId);
handleNavigate(destinationUnitId);
}}
previousHandler={() => {
logEvent('edx.ui.lms.sequence.previous_selected', 'top');
handlePrevious();
}}
/>
{shouldDisplayNotificationTriggerInSequence && (
enableNewSidebar === 'true' ? <NewSidebarTriggers /> : <SidebarTriggers />
)}

<div className="unit-container flex-grow-1">
<SequenceContent
courseId={courseId}
gated={gated}
sequenceId={sequenceId}
unitId={unitId}
unitLoadedHandler={handleUnitLoaded}
/>
{unitHasLoaded && (
<UnitNavigation
<>
<div className="sequence-container d-inline-flex flex-row">
<div className={classNames('sequence w-100', { 'position-relative': shouldDisplayNotificationTriggerInSequence })}>
<SequenceNavigation
sequenceId={sequenceId}
unitId={unitId}
onClickPrevious={() => {
logEvent('edx.ui.lms.sequence.previous_selected', 'bottom');
handlePrevious();
className="mb-4"
nextHandler={() => {
handleNext('top');
}}
onClickNext={() => {
logEvent('edx.ui.lms.sequence.next_selected', 'bottom');
handleNext();
onNavigate={(destinationUnitId) => {
logEvent('edx.ui.lms.sequence.tab_selected', 'top', destinationUnitId);
handleNavigate(destinationUnitId);
}}
previousHandler={() => {
handlePrevious('top');
}}
/>
{shouldDisplayNotificationTriggerInSequence && (
enableNewSidebar === 'true' ? <NewSidebarTriggers /> : <SidebarTriggers />
)}

<div className="unit-container flex-grow-1">
<SequenceContent
courseId={courseId}
gated={gated}
sequenceId={sequenceId}
unitId={unitId}
unitLoadedHandler={handleUnitLoaded}
/>
{unitHasLoaded && (
<UnitNavigation
sequenceId={sequenceId}
unitId={unitId}
onClickPrevious={() => {
handlePrevious('bottom');
}}
onClickNext={() => {
handleNext('bottom');
}}
/>
)}
</div>
</div>
{enableNewSidebar === 'true' ? <NewSidebar /> : <Sidebar />}
</div>
{enableNewSidebar === 'true' ? <NewSidebar /> : <Sidebar />}
</div>
{
wholeCourseTranslationEnabled && (
<div className="sequence-container d-inline-flex flex-row">

Check warning on line 202 in src/courseware/course/sequence/Sequence.jsx

View check run for this annotation

Codecov / codecov/patch

src/courseware/course/sequence/Sequence.jsx#L202

Added line #L202 was not covered by tests
<FeedbackWidget />
</div>
)
}
</>
);

if (sequenceStatus === 'loaded') {
Expand All @@ -203,11 +215,11 @@
courseId={courseId}
isStaff={isStaff}
originalUserIsStaff={originalUserIsStaff}
canAccessProctoredExams={course.canAccessProctoredExams}
canAccessProctoredExams={canAccessProctoredExams}
>
{defaultContent}
</SequenceExamWrapper>
<CourseLicense license={course.license || undefined} />
<CourseLicense license={license || undefined} />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<FeedbackWidget /> renders 1`] = `
<div
className="sequence w-100"
>
<div
className="ml-4 mr-2"
>
<ActionRow>
Rate this page translation
<Spacer />
<div>
<IconButton
alt="positive-feedback"
className="m-1"
iconAs="Icon"
id="positive-feedback-button"
onClick={[MockFunction sendFeedback]}
src="ThumbUpOutline"
variant="secondary"
/>
<IconButton
alt="negative-feedback"
className="mr-2"
iconAs="Icon"
id="negative-feedback-button"
onClick={[MockFunction sendFeedback]}
src="ThumbDownOffAlt"
variant="secondary"
/>
</div>
<div
className="mb-1 text-light action-row-divider"
>
|
</div>
<div>
<IconButton
alt="close-feedback"
className="ml-1 mr-2 float-right"
iconAs="Icon"
id="close-feedback-button"
onClick={[MockFunction closeFeedbackWidget]}
src="Close"
variant="secondary"
/>
</div>
</ActionRow>
</div>
</div>
`;
99 changes: 99 additions & 0 deletions src/courseware/course/sequence/Unit/feedback-widget/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { ActionRow, IconButton, Icon } from '@edx/paragon';
import { Close, ThumbUpOutline, ThumbDownOffAlt } from '@edx/paragon/icons';

import './index.scss';
import messages from './messages';
import useFeedbackWidget from './useFeedbackWidget';

const FeedbackWidget = ({
courseId,
languageCode,
unitId,
userId,
}) => {
const { formatMessage } = useIntl();
const {
closeFeedbackWidget,
sendFeedback,
showFeedbackWidget,
showGratitudeText,
} = useFeedbackWidget({
courseId,
languageCode,
unitId,
userId,
});
return (
(showFeedbackWidget || showGratitudeText) && (
<div className="sequence w-100">
{
showFeedbackWidget && (
<div className="ml-4 mr-2">
<ActionRow>
{formatMessage(messages.rateTranslationText)}
<ActionRow.Spacer />
<div>
<IconButton
src={ThumbUpOutline}
iconAs={Icon}
alt="positive-feedback"
onClick={sendFeedback}
variant="secondary"
className="m-1"
id="positive-feedback-button"
/>
<IconButton
src={ThumbDownOffAlt}
iconAs={Icon}
alt="negative-feedback"
onClick={sendFeedback}
variant="secondary"
className="mr-2"
id="negative-feedback-button"
/>
</div>
<div className="mb-1 text-light action-row-divider">
|
</div>
<div>
<IconButton
src={Close}
iconAs={Icon}
alt="close-feedback"
onClick={closeFeedbackWidget}
variant="secondary"
className="ml-1 mr-2 float-right"
id="close-feedback-button"
/>
</div>
</ActionRow>
</div>
)
}
{
showGratitudeText && (
<div className="ml-4 mr-4">

Check warning on line 78 in src/courseware/course/sequence/Unit/feedback-widget/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/courseware/course/sequence/Unit/feedback-widget/index.jsx#L78

Added line #L78 was not covered by tests
<ActionRow className="m-2 justify-content-center">
{formatMessage(messages.gratitudeText)}
</ActionRow>
</div>
)
}
</div>
)
);
};

FeedbackWidget.propTypes = {
courseId: PropTypes.string.isRequired,
languageCode: PropTypes.string.isRequired,
userId: PropTypes.string.isRequired,
unitId: PropTypes.string.isRequired,
};

FeedbackWidget.defaultProps = {};

export default FeedbackWidget;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.action-row-divider {
font-size: 31px;
font-weight: 100;
}
51 changes: 51 additions & 0 deletions src/courseware/course/sequence/Unit/feedback-widget/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { shallow } from '@edx/react-unit-test-utils';

import FeedbackWidget from './index';

jest.mock('@edx/paragon', () => jest.requireActual('@edx/react-unit-test-utils').mockComponents({
ActionRow: {
Spacer: 'Spacer',
},
IconButton: 'IconButton',
Icon: 'Icon',
}));
jest.mock('@edx/paragon/icons', () => ({
Close: 'Close',
ThumbUpOutline: 'ThumbUpOutline',
ThumbDownOffAlt: 'ThumbDownOffAlt',
}));
jest.mock('./useFeedbackWidget', () => () => ({
closeFeedbackWidget: jest.fn().mockName('closeFeedbackWidget'),
openFeedbackWidget: jest.fn().mockName('openFeedbackWidget'),
sendFeedback: jest.fn().mockName('sendFeedback'),
showFeedbackWidget: true,
showGratitudeText: false,
}));
jest.mock('@edx/frontend-platform/i18n', () => {
const i18n = jest.requireActual('@edx/frontend-platform/i18n');
const { formatMessage } = jest.requireActual('@edx/react-unit-test-utils');
// this provide consistent for the test on different platform/timezone
const formatDate = jest.fn(date => new Date(date).toISOString()).mockName('useIntl.formatDate');
return {
...i18n,
useIntl: jest.fn(() => ({
formatMessage,
formatDate,
})),
defineMessages: m => m,
FormattedMessage: () => 'FormattedMessage',
};
});

describe('<FeedbackWidget />', () => {
const props = {
courseId: 'course-v1:edX+DemoX+Demo_Course',
languageCode: 'es',
unitId: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@37b72b3915204b70acb00c55b604b563',
userId: '123',
};
it('renders', () => {
const wrapper = shallow(<FeedbackWidget {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
});
});
16 changes: 16 additions & 0 deletions src/courseware/course/sequence/Unit/feedback-widget/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
rateTranslationText: {
id: 'feedbackWidget.rateTranslationText',
defaultMessage: 'Rate this page translation',
description: 'Title for the feedback widget action row.',
},
gratitudeText: {
id: 'feedbackWidget.gratitudeText',
defaultMessage: 'Thank you! Your feedback matters.',
description: 'Title for secondary action row.',
},
});

export default messages;
Loading
Loading