From b3d33667d4862856a63673690bbb919ff852f02c Mon Sep 17 00:00:00 2001
From: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
Date: Mon, 30 Jan 2023 22:20:07 +0500
Subject: [PATCH] Updated frontend-build to v12 (#962)
* feat: rebase previous frontend-build upgrade
* chore: make welcome message to default to empty
---
.eslintrc.js | 6 +-
.../AccessExpirationAlert.jsx | 4 +-
.../AccessExpirationMasqueradeBanner.jsx | 4 +-
src/alerts/access-expiration-alert/hooks.js | 12 +--
.../ActiveEnterpriseAlert.jsx | 4 +-
src/alerts/active-enteprise-alert/hooks.js | 6 +-
.../course-start-alert/CourseStartAlert.jsx | 4 +-
.../CourseStartMasqueradeBanner.jsx | 4 +-
src/alerts/course-start-alert/hooks.js | 18 ++--
.../enrollment-alert/EnrollmentAlert.jsx | 4 +-
src/alerts/enrollment-alert/clickHook.js | 2 +-
src/alerts/enrollment-alert/hooks.js | 6 +-
.../AccountActivationAlert.jsx | 6 +-
.../logistration-alert/LogistrationAlert.jsx | 4 +-
src/course-home/data/api.js | 2 +-
src/course-home/dates-tab/DatesTab.jsx | 4 +-
src/course-home/dates-tab/timeline/Day.jsx | 6 +-
.../dates-tab/timeline/Timeline.jsx | 6 +-
.../discussion-tab/DiscussionTab.jsx | 4 +-
.../goal-unsubscribe/GoalUnsubscribe.jsx | 5 +-
.../goal-unsubscribe/ResultPage.jsx | 4 +-
src/course-home/live-tab/LiveTab.jsx | 4 +-
src/course-home/outline-tab/DateSummary.jsx | 8 +-
.../outline-tab/LmsHtmlFragment.jsx | 8 +-
src/course-home/outline-tab/OutlineTab.jsx | 4 +-
src/course-home/outline-tab/Section.jsx | 7 +-
src/course-home/outline-tab/SequenceLink.jsx | 6 +-
.../CertificateStatusAlert.jsx | 4 +-
.../alerts/certificate-status-alert/hooks.js | 7 +-
.../course-end-alert/CourseEndAlert.jsx | 4 +-
.../alerts/course-end-alert/hooks.js | 6 +-
.../PrivateCourseAlert.jsx | 4 +-
.../alerts/private-course-alert/hooks.js | 6 +-
.../ScheduledCotentAlert.jsx | 4 +-
.../alerts/scheduled-content-alert/hooks.js | 6 +-
.../outline-tab/widgets/CourseDates.jsx | 6 +-
.../outline-tab/widgets/CourseHandouts.jsx | 4 +-
.../outline-tab/widgets/CourseTools.jsx | 4 +-
.../outline-tab/widgets/FlagButton.jsx | 50 +++++-----
.../widgets/LearningGoalButton.jsx | 6 +-
.../widgets/ProctoringInfoPanel.jsx | 6 +-
.../widgets/StartOrResumeCourseCard.jsx | 5 +-
.../widgets/WeeklyLearningGoalCard.jsx | 11 ++-
.../outline-tab/widgets/WelcomeMessage.jsx | 13 +--
.../progress-tab/ProgressHeader.jsx | 4 +-
src/course-home/progress-tab/ProgressTab.jsx | 4 +-
.../certificate-status/CertificateStatus.jsx | 5 +-
.../CompleteDonutSegment.jsx | 8 +-
.../CompletionDonutChart.jsx | 4 +-
.../course-completion/CourseCompletion.jsx | 30 +++---
.../IncompleteDonutSegment.jsx | 8 +-
.../course-completion/LockedDonutSegment.jsx | 4 +-
.../credit-information/CreditInformation.jsx | 4 +-
.../grades/course-grade/CourseGrade.jsx | 4 +-
.../grades/course-grade/CourseGradeFooter.jsx | 4 +-
.../grades/course-grade/CourseGradeHeader.jsx | 4 +-
.../course-grade/CurrentGradeTooltip.jsx | 4 +-
.../grades/course-grade/GradeBar.jsx | 4 +-
.../grades/course-grade/GradeRangeTooltip.jsx | 4 +-
.../course-grade/PassingGradeTooltip.jsx | 4 +-
.../grades/detailed-grades/DetailedGrades.jsx | 4 +-
.../detailed-grades/DetailedGradesTable.jsx | 4 +-
.../detailed-grades/ProblemScoreDrawer.jsx | 4 +-
.../detailed-grades/SubsectionTitleCell.jsx | 4 +-
.../grade-summary/AssignmentTypeCell.jsx | 6 +-
.../DroppableAssignmentFootnote.jsx | 4 +-
.../grades/grade-summary/GradeSummary.jsx | 4 +-
.../grade-summary/GradeSummaryHeader.jsx | 4 +-
.../grade-summary/GradeSummaryTable.jsx | 39 ++++----
.../grade-summary/GradeSummaryTableFooter.jsx | 4 +-
.../related-links/RelatedLinks.jsx | 4 +-
.../ShiftDatesAlert.jsx | 8 +-
.../SuggestedScheduleHeader.jsx | 12 +--
.../UpgradeToCompleteAlert.jsx | 4 +-
.../UpgradeToShiftDatesAlert.jsx | 4 +-
src/course-tabs/CourseTabsNavigation.jsx | 42 ++++----
src/courseware/CoursewareContainer.test.jsx | 10 +-
.../CoursewareRedirectLandingPage.jsx | 4 +-
src/courseware/course/Course.jsx | 10 +-
src/courseware/course/CourseBreadcrumbs.jsx | 14 +--
src/courseware/course/JumpNavMenuItem.jsx | 8 +-
.../course/bookmark/BookmarkButton.jsx | 9 +-
.../course/bookmark/BookmarkFilledIcon.jsx | 6 +-
.../course/bookmark/BookmarkOutlineIcon.jsx | 6 +-
.../course/celebration/CelebrationModal.jsx | 7 +-
.../WeeklyGoalCelebrationModal.jsx | 7 +-
.../course/content-tools/ContentTools.jsx | 28 +++---
.../content-tools/ContentTools.test.jsx | 8 +-
.../course/course-exit/CatalogSuggestion.jsx | 4 +-
.../course/course-exit/CourseCelebration.jsx | 4 +-
.../course/course-exit/CourseExit.jsx | 4 +-
.../course/course-exit/CourseInProgress.jsx | 4 +-
.../course/course-exit/CourseNonPassing.jsx | 4 +-
.../course-exit/CourseRecommendations.jsx | 12 ++-
.../course/course-exit/DashboardFootnote.jsx | 4 +-
.../course/course-exit/Footnote.jsx | 18 ++--
.../course/course-exit/ProgramCompletion.jsx | 6 +-
.../course/course-exit/UpgradeFootnote.jsx | 4 +-
src/courseware/course/course-exit/index.js | 4 +-
src/courseware/course/course-exit/utils.js | 4 +-
.../course/course-license/CourseLicense.jsx | 6 +-
src/courseware/course/sequence/Sequence.jsx | 6 +-
.../course/sequence/Sequence.test.jsx | 27 +++---
.../course/sequence/SequenceContent.jsx | 6 +-
src/courseware/course/sequence/Unit.jsx | 6 +-
.../sequence/content-lock/ContentLock.jsx | 8 +-
.../hidden-after-due/HiddenAfterDue.jsx | 4 +-
.../course/sequence/honor-code/HonorCode.jsx | 4 +-
.../sequence/lock-paywall/LockPaywall.jsx | 6 +-
.../sequence-navigation/CompleteIcon.jsx | 6 +-
.../SequenceNavigation.jsx | 10 +-
.../SequenceNavigationDropdown.jsx | 62 ++++++------
.../SequenceNavigationTabs.jsx | 8 +-
.../sequence-navigation/UnitButton.jsx | 8 +-
.../sequence/sequence-navigation/UnitIcon.jsx | 6 +-
.../sequence-navigation/UnitNavigation.jsx | 10 +-
.../UnitNavigationEffortEstimate.jsx | 6 +-
src/courseware/course/share/ShareButton.jsx | 4 +-
src/courseware/course/sidebar/Sidebar.jsx | 4 +-
.../course/sidebar/SidebarContextProvider.jsx | 51 +++++-----
.../course/sidebar/SidebarTriggers.jsx | 4 +-
.../course/sidebar/common/SidebarBase.jsx | 7 +-
.../course/sidebar/common/TriggerBase.jsx | 28 +++---
.../discussions/DiscussionsSidebar.jsx | 4 +-
.../discussions/DiscussionsSidebar.test.jsx | 1 +
.../discussions/DiscussionsTrigger.jsx | 7 +-
.../discussions/DiscussionsTrigger.test.jsx | 18 +++-
.../notifications/NotificationIcon.jsx | 38 ++++----
.../notifications/NotificationTray.jsx | 5 +-
.../notifications/NotificationTray.test.jsx | 1 +
.../notifications/NotificationTrigger.jsx | 6 +-
.../NotificationTrigger.test.jsx | 18 +++-
src/courseware/social-share/SocialIcons.jsx | 6 +-
src/generic/CourseAccessErrorPage.jsx | 5 +-
src/generic/CourseAccessErrorPage.test.jsx | 4 +-
src/generic/notices/NoticesProvider.jsx | 1 +
src/generic/tabs/Tabs.jsx | 8 +-
.../tabs/useIndexOfLastVisibleChild.js | 1 +
.../upgrade-button/FormattedPricing.jsx | 4 +-
src/generic/upgrade-button/UpgradeButton.jsx | 4 +-
.../upgrade-button/UpgradeNowButton.jsx | 4 +-
.../UpgradeNotification.jsx | 95 +++++++++----------
src/generic/upsell-bullets/UpsellBullets.jsx | 24 +++--
src/generic/user-messages/Alert.jsx | 28 +++---
src/generic/user-messages/AlertList.jsx | 8 +-
.../user-messages/UserMessagesProvider.jsx | 14 ++-
src/generic/user-messages/hooks.js | 1 +
src/i18n/messages/es_419.json | 16 ++--
src/instructor-toolbar/InstructorToolbar.jsx | 7 +-
.../GenericTourFormattedMessages.jsx | 48 ++++------
src/product-tours/ProductTours.jsx | 15 +--
src/product-tours/ProductTours.test.jsx | 11 +--
.../LaunchCourseHomeTourButton.jsx | 5 +-
.../NewUserCourseHomeTourModal.jsx | 94 +++++++++---------
src/setupTest.js | 22 ++---
src/shared/effort-estimate/EffortEstimate.jsx | 4 +-
src/shared/links.jsx | 28 +++---
.../StreakCelebrationModal.jsx | 29 +++---
src/tab-page/LoadedTabPage.jsx | 6 +-
src/tab-page/LoadedTabPage.test.jsx | 16 +++-
src/tab-page/TabContainer.jsx | 7 +-
src/tab-page/TabContainer.test.jsx | 4 +-
src/tab-page/TabPage.jsx | 4 +-
src/tab-page/TabPage.test.jsx | 4 +-
164 files changed, 849 insertions(+), 800 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index 8b13869843..18330d5157 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,3 +1,4 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@edx/frontend-build');
const config = createConfig('eslint', {
@@ -5,14 +6,11 @@ const config = createConfig('eslint', {
// TODO: all these rules should be renabled/addressed. temporarily turned off to unblock a release.
'react-hooks/rules-of-hooks': 'off',
'react-hooks/exhaustive-deps': 'off',
- 'react/function-component-definition': 'off',
'import/no-extraneous-dependencies': 'off',
'no-restricted-exports': 'off',
'react/jsx-no-useless-fragment': 'off',
- 'react/jsx-no-bind': 'off',
'react/no-unknown-property': 'off',
- 'react/no-unstable-nested-components': 'off',
- 'react/jsx-no-constructed-context-values': 'off',
+ 'func-names': 'off',
},
});
diff --git a/src/alerts/access-expiration-alert/AccessExpirationAlert.jsx b/src/alerts/access-expiration-alert/AccessExpirationAlert.jsx
index 0f47df9154..9f71b6c823 100644
--- a/src/alerts/access-expiration-alert/AccessExpirationAlert.jsx
+++ b/src/alerts/access-expiration-alert/AccessExpirationAlert.jsx
@@ -8,7 +8,7 @@ import { Info } from '@edx/paragon/icons';
import messages from './messages';
-function AccessExpirationAlert({ intl, payload }) {
+const AccessExpirationAlert = ({ intl, payload }) => {
const {
accessExpiration,
courseId,
@@ -116,7 +116,7 @@ function AccessExpirationAlert({ intl, payload }) {
{deadlineMessage}
);
-}
+};
AccessExpirationAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/alerts/access-expiration-alert/AccessExpirationMasqueradeBanner.jsx b/src/alerts/access-expiration-alert/AccessExpirationMasqueradeBanner.jsx
index 2ad9b6d89e..c4266159a0 100644
--- a/src/alerts/access-expiration-alert/AccessExpirationMasqueradeBanner.jsx
+++ b/src/alerts/access-expiration-alert/AccessExpirationMasqueradeBanner.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage, FormattedDate } from '@edx/frontend-platform/i18n';
import { PageBanner } from '@edx/paragon';
-function AccessExpirationMasqueradeBanner({ payload }) {
+const AccessExpirationMasqueradeBanner = ({ payload }) => {
const {
expirationDate,
userTimezone,
@@ -27,7 +27,7 @@ function AccessExpirationMasqueradeBanner({ payload }) {
/>
);
-}
+};
AccessExpirationMasqueradeBanner.propTypes = {
payload: PropTypes.shape({
diff --git a/src/alerts/access-expiration-alert/hooks.js b/src/alerts/access-expiration-alert/hooks.js
index 3dfebc6968..2afdddd8fd 100644
--- a/src/alerts/access-expiration-alert/hooks.js
+++ b/src/alerts/access-expiration-alert/hooks.js
@@ -7,17 +7,17 @@ const AccessExpirationMasqueradeBanner = React.lazy(() => import('./AccessExpira
function useAccessExpirationAlert(accessExpiration, courseId, org, userTimezone, topic, analyticsPageName) {
const isVisible = accessExpiration && !accessExpiration.masqueradingExpiredCourse; // If it exists, show it.
- const payload = {
+ const payload = useMemo(() => ({
accessExpiration,
courseId,
org,
userTimezone,
analyticsPageName,
- };
+ }), [accessExpiration, analyticsPageName, courseId, org, userTimezone]);
useAlert(isVisible, {
code: 'clientAccessExpirationAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic,
});
@@ -34,14 +34,14 @@ export function useAccessExpirationMasqueradeBanner(courseId, tab) {
const isVisible = accessExpiration && accessExpiration.masqueradingExpiredCourse;
const expirationDate = accessExpiration && accessExpiration.expirationDate;
- const payload = {
+ const payload = useMemo(() => ({
expirationDate,
userTimezone,
- };
+ }), [expirationDate, userTimezone]);
useAlert(isVisible, {
code: 'clientAccessExpirationMasqueradeBanner',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'instructor-toolbar-alerts',
});
diff --git a/src/alerts/active-enteprise-alert/ActiveEnterpriseAlert.jsx b/src/alerts/active-enteprise-alert/ActiveEnterpriseAlert.jsx
index cb64f097b6..5e142e932f 100644
--- a/src/alerts/active-enteprise-alert/ActiveEnterpriseAlert.jsx
+++ b/src/alerts/active-enteprise-alert/ActiveEnterpriseAlert.jsx
@@ -7,7 +7,7 @@ import { WarningFilled } from '@edx/paragon/icons';
import { getConfig } from '@edx/frontend-platform';
import genericMessages from './messages';
-function ActiveEnterpriseAlert({ intl, payload }) {
+const ActiveEnterpriseAlert = ({ intl, payload }) => {
const { text, courseId } = payload;
const changeActiveEnterprise = (
);
-}
+};
ActiveEnterpriseAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/alerts/active-enteprise-alert/hooks.js b/src/alerts/active-enteprise-alert/hooks.js
index 7fcaf67320..5bf07ff604 100644
--- a/src/alerts/active-enteprise-alert/hooks.js
+++ b/src/alerts/active-enteprise-alert/hooks.js
@@ -12,16 +12,16 @@ export default function useActiveEnterpriseAlert(courseId) {
*/
const isVisible = courseAccess && !courseAccess.hasAccess && courseAccess.errorCode === 'incorrect_active_enterprise';
- const payload = {
+ const payload = useMemo(() => ({
text: courseAccess && courseAccess.userMessage,
courseId,
- };
+ }), [courseAccess, courseId]);
useAlert(isVisible, {
code: 'clientActiveEnterpriseAlert',
topic: 'outline',
dismissible: false,
type: ALERT_TYPES.ERROR,
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
});
return { clientActiveEnterpriseAlert: ActiveEnterpriseAlert };
diff --git a/src/alerts/course-start-alert/CourseStartAlert.jsx b/src/alerts/course-start-alert/CourseStartAlert.jsx
index bcd683671d..f24e328273 100644
--- a/src/alerts/course-start-alert/CourseStartAlert.jsx
+++ b/src/alerts/course-start-alert/CourseStartAlert.jsx
@@ -15,7 +15,7 @@ const DAY_SEC = 24 * 60 * 60; // in seconds
const DAY_MS = DAY_SEC * 1000; // in ms
const YEAR_SEC = 365 * DAY_SEC; // in seconds
-function CourseStartAlert({ payload }) {
+const CourseStartAlert = ({ payload }) => {
const {
courseId,
} = payload;
@@ -94,7 +94,7 @@ function CourseStartAlert({ payload }) {
/>
);
-}
+};
CourseStartAlert.propTypes = {
payload: PropTypes.shape({
diff --git a/src/alerts/course-start-alert/CourseStartMasqueradeBanner.jsx b/src/alerts/course-start-alert/CourseStartMasqueradeBanner.jsx
index ad85a07ecd..8df0d69503 100644
--- a/src/alerts/course-start-alert/CourseStartMasqueradeBanner.jsx
+++ b/src/alerts/course-start-alert/CourseStartMasqueradeBanner.jsx
@@ -5,7 +5,7 @@ import { PageBanner } from '@edx/paragon';
import { useModel } from '../../generic/model-store';
-function CourseStartMasqueradeBanner({ payload }) {
+const CourseStartMasqueradeBanner = ({ payload }) => {
const {
courseId,
} = payload;
@@ -33,7 +33,7 @@ function CourseStartMasqueradeBanner({ payload }) {
/>
);
-}
+};
CourseStartMasqueradeBanner.propTypes = {
payload: PropTypes.shape({
diff --git a/src/alerts/course-start-alert/hooks.js b/src/alerts/course-start-alert/hooks.js
index f8ab5676f4..0389aac86b 100644
--- a/src/alerts/course-start-alert/hooks.js
+++ b/src/alerts/course-start-alert/hooks.js
@@ -5,7 +5,7 @@ import { useModel } from '../../generic/model-store';
const CourseStartAlert = React.lazy(() => import('./CourseStartAlert'));
const CourseStartMasqueradeBanner = React.lazy(() => import('./CourseStartMasqueradeBanner'));
-function isStartDateInFuture(courseId) {
+function IsStartDateInFuture(courseId) {
const {
start,
} = useModel('courseHomeMeta', courseId);
@@ -20,15 +20,15 @@ function useCourseStartAlert(courseId) {
isEnrolled,
} = useModel('courseHomeMeta', courseId);
- const isVisible = isEnrolled && isStartDateInFuture(courseId);
+ const isVisible = isEnrolled && IsStartDateInFuture(courseId);
- const payload = {
+ const payload = useMemo(() => ({
courseId,
- };
+ }), [courseId]);
useAlert(isVisible, {
code: 'clientCourseStartAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline-course-alerts',
});
@@ -42,15 +42,15 @@ export function useCourseStartMasqueradeBanner(courseId, tab) {
isMasquerading,
} = useModel('courseHomeMeta', courseId);
- const isVisible = isMasquerading && tab === 'progress' && isStartDateInFuture(courseId);
+ const isVisible = isMasquerading && tab === 'progress' && IsStartDateInFuture(courseId);
- const payload = {
+ const payload = useMemo(() => ({
courseId,
- };
+ }), [courseId]);
useAlert(isVisible, {
code: 'clientCourseStartMasqueradeBanner',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'instructor-toolbar-alerts',
});
diff --git a/src/alerts/enrollment-alert/EnrollmentAlert.jsx b/src/alerts/enrollment-alert/EnrollmentAlert.jsx
index de659d728b..e8489e5fc5 100644
--- a/src/alerts/enrollment-alert/EnrollmentAlert.jsx
+++ b/src/alerts/enrollment-alert/EnrollmentAlert.jsx
@@ -11,7 +11,7 @@ import { useModel } from '../../generic/model-store';
import messages from './messages';
import useEnrollClickHandler from './clickHook';
-function EnrollmentAlert({ intl, payload }) {
+const EnrollmentAlert = ({ intl, payload }) => {
const {
canEnroll,
courseId,
@@ -55,7 +55,7 @@ function EnrollmentAlert({ intl, payload }) {
);
-}
+};
EnrollmentAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/alerts/enrollment-alert/clickHook.js b/src/alerts/enrollment-alert/clickHook.js
index 225e4fafdf..76ab52fc0f 100644
--- a/src/alerts/enrollment-alert/clickHook.js
+++ b/src/alerts/enrollment-alert/clickHook.js
@@ -27,7 +27,7 @@ function useEnrollClickHandler(courseId, orgId, successText) {
});
global.location.reload();
});
- }, [courseId]);
+ }, [addFlash, courseId, orgId, successText]);
return { enrollClickHandler, loading };
}
diff --git a/src/alerts/enrollment-alert/hooks.js b/src/alerts/enrollment-alert/hooks.js
index 03df8b616d..f3da187777 100644
--- a/src/alerts/enrollment-alert/hooks.js
+++ b/src/alerts/enrollment-alert/hooks.js
@@ -22,16 +22,16 @@ export function useEnrollmentAlert(courseId) {
* 3. the course is private.
*/
const isVisible = !enrolledUser && authenticatedUser !== null && privateOutline;
- const payload = {
+ const payload = useMemo(() => ({
canEnroll: outline && outline.enrollAlert ? outline.enrollAlert.canEnroll : false,
courseId,
extraText: outline && outline.enrollAlert ? outline.enrollAlert.extraText : '',
isStaff: course && course.isStaff,
- };
+ }), [course, courseId, outline]);
useAlert(isVisible, {
code: 'clientEnrollmentAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline',
});
diff --git a/src/alerts/logistration-alert/AccountActivationAlert.jsx b/src/alerts/logistration-alert/AccountActivationAlert.jsx
index dcdd06d7cb..8455e2dc3f 100644
--- a/src/alerts/logistration-alert/AccountActivationAlert.jsx
+++ b/src/alerts/logistration-alert/AccountActivationAlert.jsx
@@ -13,9 +13,9 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/
import { sendActivationEmail } from '../../courseware/data';
import messages from './messages';
-function AccountActivationAlert({
+const AccountActivationAlert = ({
intl,
-}) {
+}) => {
const [showModal, setShowModal] = useState(false);
const [showSpinner, setShowSpinner] = useState(false);
const [showCheck, setShowCheck] = useState(false);
@@ -123,7 +123,7 @@ function AccountActivationAlert({
{children()}
);
-}
+};
AccountActivationAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/alerts/logistration-alert/LogistrationAlert.jsx b/src/alerts/logistration-alert/LogistrationAlert.jsx
index be72180e53..5ab8ff6d31 100644
--- a/src/alerts/logistration-alert/LogistrationAlert.jsx
+++ b/src/alerts/logistration-alert/LogistrationAlert.jsx
@@ -7,7 +7,7 @@ import { WarningFilled } from '@edx/paragon/icons';
import genericMessages from '../../generic/messages';
-function LogistrationAlert({ intl }) {
+const LogistrationAlert = ({ intl }) => {
const signIn = (
);
-}
+};
LogistrationAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/data/api.js b/src/course-home/data/api.js
index eac84f1a98..3265d8a1c4 100644
--- a/src/course-home/data/api.js
+++ b/src/course-home/data/api.js
@@ -349,7 +349,7 @@ export async function getOutlineTabData(courseId) {
const timeOffsetMillis = getTimeOffsetMillis(headers && headers.date, requestTime, responseTime);
const userHasPassingGrade = data.user_has_passing_grade;
const verifiedMode = camelCaseObject(data.verified_mode);
- const welcomeMessageHtml = data.welcome_message_html;
+ const welcomeMessageHtml = data.welcome_message_html || '';
return {
accessExpiration,
diff --git a/src/course-home/dates-tab/DatesTab.jsx b/src/course-home/dates-tab/DatesTab.jsx
index 23e157cd6f..71b4389bc9 100644
--- a/src/course-home/dates-tab/DatesTab.jsx
+++ b/src/course-home/dates-tab/DatesTab.jsx
@@ -14,7 +14,7 @@ import ShiftDatesAlert from '../suggested-schedule-messaging/ShiftDatesAlert';
import UpgradeToCompleteAlert from '../suggested-schedule-messaging/UpgradeToCompleteAlert';
import UpgradeToShiftDatesAlert from '../suggested-schedule-messaging/UpgradeToShiftDatesAlert';
-function DatesTab({ intl }) {
+const DatesTab = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -57,7 +57,7 @@ function DatesTab({ intl }) {
>
);
-}
+};
DatesTab.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/dates-tab/timeline/Day.jsx b/src/course-home/dates-tab/timeline/Day.jsx
index ad89316594..125ce1ef0f 100644
--- a/src/course-home/dates-tab/timeline/Day.jsx
+++ b/src/course-home/dates-tab/timeline/Day.jsx
@@ -17,13 +17,13 @@ import { useModel } from '../../../generic/model-store';
import { getBadgeListAndColor } from './badgelist';
import { isLearnerAssignment } from '../utils';
-function Day({
+const Day = ({
date,
first,
intl,
items,
last,
-}) {
+}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -103,7 +103,7 @@ function Day({
);
-}
+};
Day.propTypes = {
date: PropTypes.objectOf(Date).isRequired,
diff --git a/src/course-home/dates-tab/timeline/Timeline.jsx b/src/course-home/dates-tab/timeline/Timeline.jsx
index e9f6868a97..09073d6fb7 100644
--- a/src/course-home/dates-tab/timeline/Timeline.jsx
+++ b/src/course-home/dates-tab/timeline/Timeline.jsx
@@ -6,7 +6,7 @@ import { useModel } from '../../../generic/model-store';
import Day from './Day';
import { daycmp, isLearnerAssignment } from '../utils';
-export default function Timeline() {
+const Timeline = () => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -67,4 +67,6 @@ export default function Timeline() {
))}
);
-}
+};
+
+export default Timeline;
diff --git a/src/course-home/discussion-tab/DiscussionTab.jsx b/src/course-home/discussion-tab/DiscussionTab.jsx
index d4d2d6e9a2..0bbae8be3c 100644
--- a/src/course-home/discussion-tab/DiscussionTab.jsx
+++ b/src/course-home/discussion-tab/DiscussionTab.jsx
@@ -6,7 +6,7 @@ import { generatePath, useHistory } from 'react-router';
import { useParams } from 'react-router-dom';
import { useIFrameHeight, useIFramePluginEvents } from '../../generic/hooks';
-function DiscussionTab() {
+const DiscussionTab = () => {
const { courseId } = useSelector(state => state.courseHome);
const { path } = useParams();
const [originalPath] = useState(path);
@@ -29,7 +29,7 @@ function DiscussionTab() {
title="discussion"
/>
);
-}
+};
DiscussionTab.propTypes = {};
diff --git a/src/course-home/goal-unsubscribe/GoalUnsubscribe.jsx b/src/course-home/goal-unsubscribe/GoalUnsubscribe.jsx
index 24fdddee7e..3a6922eed6 100644
--- a/src/course-home/goal-unsubscribe/GoalUnsubscribe.jsx
+++ b/src/course-home/goal-unsubscribe/GoalUnsubscribe.jsx
@@ -10,7 +10,7 @@ import { unsubscribeFromCourseGoal } from '../data/api';
import messages from './messages';
import ResultPage from './ResultPage';
-function GoalUnsubscribe({ intl }) {
+const GoalUnsubscribe = ({ intl }) => {
const { token } = useParams();
const [error, setError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
@@ -33,6 +33,7 @@ function GoalUnsubscribe({ intl }) {
// as visiting this page is allowed to be done anonymously and without the context of the course.
// The token can be used to connect a user and course, it will just require some post-processing
sendTrackEvent('edx.ui.lms.goal.unsubscribe', { token });
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // deps=[] to only run once
return (
@@ -48,7 +49,7 @@ function GoalUnsubscribe({ intl }) {
>
);
-}
+};
GoalUnsubscribe.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/goal-unsubscribe/ResultPage.jsx b/src/course-home/goal-unsubscribe/ResultPage.jsx
index edeadc05e1..ba6b36f627 100644
--- a/src/course-home/goal-unsubscribe/ResultPage.jsx
+++ b/src/course-home/goal-unsubscribe/ResultPage.jsx
@@ -6,7 +6,7 @@ import { Button, Hyperlink } from '@edx/paragon';
import messages from './messages';
import { ReactComponent as UnsubscribeIcon } from './unsubscribe.svg';
-function ResultPage({ courseTitle, error, intl }) {
+const ResultPage = ({ courseTitle, error, intl }) => {
const errorDescription = (
>
);
-}
+};
ResultPage.defaultProps = {
courseTitle: null,
diff --git a/src/course-home/live-tab/LiveTab.jsx b/src/course-home/live-tab/LiveTab.jsx
index 960d66e38e..05a470e038 100644
--- a/src/course-home/live-tab/LiveTab.jsx
+++ b/src/course-home/live-tab/LiveTab.jsx
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
-function LiveTab() {
+const LiveTab = () => {
const { courseId } = useSelector(state => state.courseHome);
const liveModel = useSelector(state => state.models.live);
useEffect(() => {
@@ -17,6 +17,6 @@ function LiveTab() {
dangerouslySetInnerHTML={{ __html: liveModel[courseId]?.iframe }}
/>
);
-}
+};
export default LiveTab;
diff --git a/src/course-home/outline-tab/DateSummary.jsx b/src/course-home/outline-tab/DateSummary.jsx
index abf5be05ed..edff43a7d2 100644
--- a/src/course-home/outline-tab/DateSummary.jsx
+++ b/src/course-home/outline-tab/DateSummary.jsx
@@ -9,10 +9,10 @@ import { useModel } from '../../generic/model-store';
import { isLearnerAssignment } from '../dates-tab/utils';
import './DateSummary.scss';
-export default function DateSummary({
+const DateSummary = ({
dateBlock,
userTimezone,
-}) {
+}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -75,7 +75,7 @@ export default function DateSummary({
);
-}
+};
DateSummary.propTypes = {
dateBlock: PropTypes.shape({
@@ -93,3 +93,5 @@ DateSummary.propTypes = {
DateSummary.defaultProps = {
userTimezone: null,
};
+
+export default DateSummary;
diff --git a/src/course-home/outline-tab/LmsHtmlFragment.jsx b/src/course-home/outline-tab/LmsHtmlFragment.jsx
index 0a525f25fa..191663554c 100644
--- a/src/course-home/outline-tab/LmsHtmlFragment.jsx
+++ b/src/course-home/outline-tab/LmsHtmlFragment.jsx
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
-export default function LmsHtmlFragment({
+const LmsHtmlFragment = ({
className,
html,
title,
...rest
-}) {
+}) => {
const wholePage = `
@@ -55,7 +55,7 @@ export default function LmsHtmlFragment({
{...rest}
/>
);
-}
+};
LmsHtmlFragment.defaultProps = {
className: '',
@@ -66,3 +66,5 @@ LmsHtmlFragment.propTypes = {
html: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
};
+
+export default LmsHtmlFragment;
diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index 1c75f73d20..072f0d04c6 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -29,7 +29,7 @@ import WelcomeMessage from './widgets/WelcomeMessage';
import ProctoringInfoPanel from './widgets/ProctoringInfoPanel';
import AccountActivationAlert from '../../alerts/logistration-alert/AccountActivationAlert';
-function OutlineTab({ intl }) {
+const OutlineTab = ({ intl }) => {
const {
courseId,
proctoringPanelStatus,
@@ -212,7 +212,7 @@ function OutlineTab({ intl }) {
>
);
-}
+};
OutlineTab.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/Section.jsx b/src/course-home/outline-tab/Section.jsx
index b50781267f..3de888a89a 100644
--- a/src/course-home/outline-tab/Section.jsx
+++ b/src/course-home/outline-tab/Section.jsx
@@ -12,13 +12,13 @@ import { useModel } from '../../generic/model-store';
import genericMessages from '../../generic/messages';
import messages from './messages';
-function Section({
+const Section = ({
courseId,
defaultOpen,
expand,
intl,
section,
-}) {
+}) => {
const {
complete,
sequenceIds,
@@ -38,6 +38,7 @@ function Section({
useEffect(() => {
setOpen(defaultOpen);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const sectionTitle = (
@@ -109,7 +110,7 @@ function Section({
);
-}
+};
Section.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/course-home/outline-tab/SequenceLink.jsx b/src/course-home/outline-tab/SequenceLink.jsx
index 794cdc2538..5a02c7f511 100644
--- a/src/course-home/outline-tab/SequenceLink.jsx
+++ b/src/course-home/outline-tab/SequenceLink.jsx
@@ -16,13 +16,13 @@ import EffortEstimate from '../../shared/effort-estimate';
import { useModel } from '../../generic/model-store';
import messages from './messages';
-function SequenceLink({
+const SequenceLink = ({
id,
intl,
courseId,
first,
sequence,
-}) {
+}) => {
const {
complete,
description,
@@ -98,7 +98,7 @@ function SequenceLink({
);
-}
+};
SequenceLink.propTypes = {
id: PropTypes.string.isRequired,
diff --git a/src/course-home/outline-tab/alerts/certificate-status-alert/CertificateStatusAlert.jsx b/src/course-home/outline-tab/alerts/certificate-status-alert/CertificateStatusAlert.jsx
index b650b36fc6..5b191cffcd 100644
--- a/src/course-home/outline-tab/alerts/certificate-status-alert/CertificateStatusAlert.jsx
+++ b/src/course-home/outline-tab/alerts/certificate-status-alert/CertificateStatusAlert.jsx
@@ -25,7 +25,7 @@ export const CERT_STATUS_TYPE = {
UNVERIFIED: 'unverified',
};
-function CertificateStatusAlert({ intl, payload }) {
+const CertificateStatusAlert = ({ intl, payload }) => {
const dispatch = useDispatch();
const {
certificateAvailableDate,
@@ -189,7 +189,7 @@ function CertificateStatusAlert({ intl, payload }) {
)}
);
-}
+};
CertificateStatusAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/alerts/certificate-status-alert/hooks.js b/src/course-home/outline-tab/alerts/certificate-status-alert/hooks.js
index 86445e3621..9cae4442f5 100644
--- a/src/course-home/outline-tab/alerts/certificate-status-alert/hooks.js
+++ b/src/course-home/outline-tab/alerts/certificate-status-alert/hooks.js
@@ -75,7 +75,7 @@ function useCertificateStatusAlert(courseId) {
&& hasEnded
&& !userHasPassingGrade
);
- const payload = {
+ const payload = useMemo(() => ({
certificateAvailableDate,
certURL,
certStatus,
@@ -85,11 +85,12 @@ function useCertificateStatusAlert(courseId) {
org,
notPassingCourseEnded,
tabs,
- };
+ }), [certStatus, certURL, certificateAvailableDate, courseId,
+ endBlock, notPassingCourseEnded, org, tabs, userTimezone]);
useAlert(isVisible || notPassingCourseEnded, {
code: 'clientCertificateStatusAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline-course-alerts',
});
diff --git a/src/course-home/outline-tab/alerts/course-end-alert/CourseEndAlert.jsx b/src/course-home/outline-tab/alerts/course-end-alert/CourseEndAlert.jsx
index 52287fb10b..f08e738055 100644
--- a/src/course-home/outline-tab/alerts/course-end-alert/CourseEndAlert.jsx
+++ b/src/course-home/outline-tab/alerts/course-end-alert/CourseEndAlert.jsx
@@ -13,7 +13,7 @@ const DAY_SEC = 24 * 60 * 60; // in seconds
const DAY_MS = DAY_SEC * 1000; // in ms
const YEAR_SEC = 365 * DAY_SEC; // in seconds
-function CourseEndAlert({ payload }) {
+const CourseEndAlert = ({ payload }) => {
const {
description,
endDate,
@@ -88,7 +88,7 @@ function CourseEndAlert({ payload }) {
{description}
);
-}
+};
CourseEndAlert.propTypes = {
payload: PropTypes.shape({
diff --git a/src/course-home/outline-tab/alerts/course-end-alert/hooks.js b/src/course-home/outline-tab/alerts/course-end-alert/hooks.js
index c39e6dadc6..147649ef44 100644
--- a/src/course-home/outline-tab/alerts/course-end-alert/hooks.js
+++ b/src/course-home/outline-tab/alerts/course-end-alert/hooks.js
@@ -23,15 +23,15 @@ export function useCourseEndAlert(courseId) {
const endDate = endBlock ? new Date(endBlock.date) : null;
const delta = endBlock ? endDate - new Date() : 0;
const isVisible = isEnrolled && endBlock && delta > 0 && delta < WARNING_PERIOD_MS;
- const payload = {
+ const payload = useMemo(() => ({
description: endBlock && endBlock.description,
endDate: endBlock && endBlock.date,
userTimezone,
- };
+ }), [endBlock, userTimezone]);
useAlert(isVisible, {
code: 'clientCourseEndAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline-course-alerts',
});
diff --git a/src/course-home/outline-tab/alerts/private-course-alert/PrivateCourseAlert.jsx b/src/course-home/outline-tab/alerts/private-course-alert/PrivateCourseAlert.jsx
index 19e07bea55..5c520d631e 100644
--- a/src/course-home/outline-tab/alerts/private-course-alert/PrivateCourseAlert.jsx
+++ b/src/course-home/outline-tab/alerts/private-course-alert/PrivateCourseAlert.jsx
@@ -14,7 +14,7 @@ import outlineMessages from '../../messages';
import useEnrollClickHandler from '../../../../alerts/enrollment-alert/clickHook';
import { useModel } from '../../../../generic/model-store';
-function PrivateCourseAlert({ intl, payload }) {
+const PrivateCourseAlert = ({ intl, payload }) => {
const {
anonymousUser,
canEnroll,
@@ -100,7 +100,7 @@ function PrivateCourseAlert({ intl, payload }) {
)}
);
-}
+};
PrivateCourseAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/alerts/private-course-alert/hooks.js b/src/course-home/outline-tab/alerts/private-course-alert/hooks.js
index ec5efc5c4a..c3e2b377dd 100644
--- a/src/course-home/outline-tab/alerts/private-course-alert/hooks.js
+++ b/src/course-home/outline-tab/alerts/private-course-alert/hooks.js
@@ -18,16 +18,16 @@ export function usePrivateCourseAlert(courseId) {
* 2. the user is authenticated.
* */
const isVisible = !enrolledUser && (privateOutline || authenticatedUser !== null);
- const payload = {
+ const payload = useMemo(() => ({
anonymousUser: authenticatedUser === null,
canEnroll: outline && outline.enrollAlert ? outline.enrollAlert.canEnroll : false,
courseId,
- };
+ }), [authenticatedUser, courseId, outline]);
useAlert(isVisible, {
code: 'clientPrivateCourseAlert',
dismissible: false,
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline-private-alerts',
type: ALERT_TYPES.WELCOME,
});
diff --git a/src/course-home/outline-tab/alerts/scheduled-content-alert/ScheduledCotentAlert.jsx b/src/course-home/outline-tab/alerts/scheduled-content-alert/ScheduledCotentAlert.jsx
index 4f0dddbc1a..fadb0a3e57 100644
--- a/src/course-home/outline-tab/alerts/scheduled-content-alert/ScheduledCotentAlert.jsx
+++ b/src/course-home/outline-tab/alerts/scheduled-content-alert/ScheduledCotentAlert.jsx
@@ -3,7 +3,7 @@ import { Alert, Button } from '@edx/paragon';
import React from 'react';
import PropTypes from 'prop-types';
-function ScheduledContentAlert({ payload }) {
+const ScheduledContentAlert = ({ payload }) => {
const {
datesTabLink,
} = payload;
@@ -38,7 +38,7 @@ function ScheduledContentAlert({ payload }) {
);
-}
+};
ScheduledContentAlert.propTypes = {
payload: PropTypes.shape({
diff --git a/src/course-home/outline-tab/alerts/scheduled-content-alert/hooks.js b/src/course-home/outline-tab/alerts/scheduled-content-alert/hooks.js
index fe29a22015..58e7d72501 100644
--- a/src/course-home/outline-tab/alerts/scheduled-content-alert/hooks.js
+++ b/src/course-home/outline-tab/alerts/scheduled-content-alert/hooks.js
@@ -20,12 +20,12 @@ const useScheduledContentAlert = (courseId) => {
&& !!Object.values(courses).find(course => course.hasScheduledContent === true)
);
const { isEnrolled } = useModel('courseHomeMeta', courseId);
- const payload = {
+ const payload = useMemo(() => ({
datesTabLink,
- };
+ }), [datesTabLink]);
useAlert(hasScheduledContent && isEnrolled, {
code: 'ScheduledContentAlert',
- payload: useMemo(() => payload, Object.values(payload).sort()),
+ payload,
topic: 'outline-course-alerts',
});
diff --git a/src/course-home/outline-tab/widgets/CourseDates.jsx b/src/course-home/outline-tab/widgets/CourseDates.jsx
index 5604e00a75..0db9e2e5a6 100644
--- a/src/course-home/outline-tab/widgets/CourseDates.jsx
+++ b/src/course-home/outline-tab/widgets/CourseDates.jsx
@@ -7,9 +7,9 @@ import DateSummary from '../DateSummary';
import messages from '../messages';
import { useModel } from '../../../generic/model-store';
-function CourseDates({
+const CourseDates = ({
intl,
-}) {
+}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -46,7 +46,7 @@ function CourseDates({
);
-}
+};
CourseDates.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/widgets/CourseHandouts.jsx b/src/course-home/outline-tab/widgets/CourseHandouts.jsx
index 7a07175c24..ac90adad8b 100644
--- a/src/course-home/outline-tab/widgets/CourseHandouts.jsx
+++ b/src/course-home/outline-tab/widgets/CourseHandouts.jsx
@@ -7,7 +7,7 @@ import LmsHtmlFragment from '../LmsHtmlFragment';
import messages from '../messages';
import { useModel } from '../../../generic/model-store';
-function CourseHandouts({ intl }) {
+const CourseHandouts = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -29,7 +29,7 @@ function CourseHandouts({ intl }) {
/>
);
-}
+};
CourseHandouts.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/widgets/CourseTools.jsx b/src/course-home/outline-tab/widgets/CourseTools.jsx
index 0847deac37..62ef499000 100644
--- a/src/course-home/outline-tab/widgets/CourseTools.jsx
+++ b/src/course-home/outline-tab/widgets/CourseTools.jsx
@@ -14,7 +14,7 @@ import messages from '../messages';
import { useModel } from '../../../generic/model-store';
import LaunchCourseHomeTourButton from '../../../product-tours/newUserCourseHomeTour/LaunchCourseHomeTourButton';
-function CourseTools({ intl }) {
+const CourseTools = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -79,7 +79,7 @@ function CourseTools({ intl }) {
);
-}
+};
CourseTools.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/widgets/FlagButton.jsx b/src/course-home/outline-tab/widgets/FlagButton.jsx
index 48375cb212..40848a2c40 100644
--- a/src/course-home/outline-tab/widgets/FlagButton.jsx
+++ b/src/course-home/outline-tab/widgets/FlagButton.jsx
@@ -2,37 +2,35 @@ import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
-function FlagButton({
+const FlagButton = ({
buttonIcon,
title,
text,
handleSelect,
isSelected,
-}) {
- return (
- handleSelect()}
- data-testid={`weekly-learning-goal-input-${title}`}
- >
-
- {buttonIcon}
-
-
- {title}
-
-
- {text}
-
-
- );
-}
+}) => (
+ handleSelect()}
+ data-testid={`weekly-learning-goal-input-${title}`}
+ >
+
+ {buttonIcon}
+
+
+ {title}
+
+
+ {text}
+
+
+);
FlagButton.propTypes = {
buttonIcon: PropTypes.element.isRequired,
diff --git a/src/course-home/outline-tab/widgets/LearningGoalButton.jsx b/src/course-home/outline-tab/widgets/LearningGoalButton.jsx
index 35f87ee024..c477ea9028 100644
--- a/src/course-home/outline-tab/widgets/LearningGoalButton.jsx
+++ b/src/course-home/outline-tab/widgets/LearningGoalButton.jsx
@@ -9,12 +9,12 @@ import { ReactComponent as FlagRegularIcon } from './flag_gray.svg';
import FlagButton from './FlagButton';
import messages from '../messages';
-function LearningGoalButton({
+const LearningGoalButton = ({
level,
isSelected,
handleSelect,
intl,
-}) {
+}) => {
const buttonDetails = {
casual: {
daysPerWeek: 1,
@@ -47,7 +47,7 @@ function LearningGoalButton({
isSelected={isSelected}
/>
);
-}
+};
LearningGoalButton.propTypes = {
level: PropTypes.string.isRequired,
diff --git a/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx b/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx
index 37d90bfe07..0159d66076 100644
--- a/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx
+++ b/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx
@@ -10,7 +10,7 @@ import { getProctoringInfoData } from '../../data/api';
import { fetchProctoringInfoResolved } from '../../data/slice';
import { useModel } from '../../../generic/model-store';
-function ProctoringInfoPanel({ intl }) {
+const ProctoringInfoPanel = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -128,6 +128,7 @@ function ProctoringInfoPanel({ intl }) {
.finally(() => {
dispatch(fetchProctoringInfoResolved());
});
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
let onboardingExamButton = null;
@@ -170,6 +171,7 @@ function ProctoringInfoPanel({ intl }) {
}
return (
+ // eslint-disable-next-line react/jsx-no-useless-fragment
<>
{ showInfoPanel && (
@@ -212,7 +214,7 @@ function ProctoringInfoPanel({ intl }) {
)}
>
);
-}
+};
ProctoringInfoPanel.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/widgets/StartOrResumeCourseCard.jsx b/src/course-home/outline-tab/widgets/StartOrResumeCourseCard.jsx
index a668cff427..5b1f033486 100644
--- a/src/course-home/outline-tab/widgets/StartOrResumeCourseCard.jsx
+++ b/src/course-home/outline-tab/widgets/StartOrResumeCourseCard.jsx
@@ -7,7 +7,7 @@ import { sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
import messages from '../messages';
import { useModel } from '../../../generic/model-store';
-function StartOrResumeCourseCard({ intl }) {
+const StartOrResumeCourseCard = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -56,10 +56,11 @@ function StartOrResumeCourseCard({ intl }) {
)}
/>
{/* Footer is needed for internal vertical spacing to work out. If you can remove, be my guest */}
+ {/* eslint-disable-next-line react/jsx-no-useless-fragment */}
<>>
);
-}
+};
StartOrResumeCourseCard.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx b/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx
index 1d8a0adfca..00def35b0e 100644
--- a/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx
+++ b/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx
@@ -15,11 +15,11 @@ import { saveWeeklyLearningGoal } from '../../data';
import { useModel } from '../../../generic/model-store';
import './FlagButton.scss';
-function WeeklyLearningGoalCard({
+const WeeklyLearningGoalCard = ({
daysPerWeek,
subscribedToReminders,
intl,
-}) {
+}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -36,7 +36,7 @@ function WeeklyLearningGoalCard({
const [isGetReminderSelected, setGetReminderSelected] = useState(subscribedToReminders);
const location = useLocation();
- function handleSelect(days, triggeredFromEmail = false) {
+ const handleSelect = (days, triggeredFromEmail = false) => {
// Set the subscription button if this is the first time selecting a goal
const selectReminders = daysPerWeekGoal === null ? true : isGetReminderSelected;
setGetReminderSelected(selectReminders);
@@ -54,7 +54,7 @@ function WeeklyLearningGoalCard({
sendTrackEvent('enrollment.email.clicked.setgoal', {});
}
}
- }
+ };
function handleSubscribeToReminders(event) {
const isGetReminderChecked = event.target.checked;
@@ -84,6 +84,7 @@ function WeeklyLearningGoalCard({
search: currentParams.toString(),
});
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [location.search]);
return (
@@ -146,7 +147,7 @@ function WeeklyLearningGoalCard({
)}
);
-}
+};
WeeklyLearningGoalCard.propTypes = {
daysPerWeek: PropTypes.number,
diff --git a/src/course-home/outline-tab/widgets/WelcomeMessage.jsx b/src/course-home/outline-tab/widgets/WelcomeMessage.jsx
index b2f93cab82..ed64b1b547 100644
--- a/src/course-home/outline-tab/widgets/WelcomeMessage.jsx
+++ b/src/course-home/outline-tab/widgets/WelcomeMessage.jsx
@@ -11,21 +11,22 @@ import messages from '../messages';
import { useModel } from '../../../generic/model-store';
import { dismissWelcomeMessage } from '../../data/thunks';
-function WelcomeMessage({ courseId, intl }) {
+const WelcomeMessage = ({ courseId, intl }) => {
const {
welcomeMessageHtml,
} = useModel('outline', courseId);
- if (!welcomeMessageHtml) {
- return null;
- }
-
const [display, setDisplay] = useState(true);
const shortWelcomeMessageHtml = truncate(welcomeMessageHtml, 100, { byWords: true, keepWhitespaces: true });
const messageCanBeShortened = shortWelcomeMessageHtml.length < welcomeMessageHtml.length;
const [showShortMessage, setShowShortMessage] = useState(messageCanBeShortened);
const dispatch = useDispatch();
+
+ if (!welcomeMessageHtml) {
+ return null;
+ }
+
return (
);
-}
+};
WelcomeMessage.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/course-home/progress-tab/ProgressHeader.jsx b/src/course-home/progress-tab/ProgressHeader.jsx
index ece2c81b46..40b31d56c7 100644
--- a/src/course-home/progress-tab/ProgressHeader.jsx
+++ b/src/course-home/progress-tab/ProgressHeader.jsx
@@ -9,7 +9,7 @@ import { useModel } from '../../generic/model-store';
import messages from './messages';
-function ProgressHeader({ intl }) {
+const ProgressHeader = ({ intl }) => {
const {
courseId,
targetUserId,
@@ -35,7 +35,7 @@ function ProgressHeader({ intl }) {
)}
);
-}
+};
ProgressHeader.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/ProgressTab.jsx b/src/course-home/progress-tab/ProgressTab.jsx
index 7954927aab..3413d3836f 100644
--- a/src/course-home/progress-tab/ProgressTab.jsx
+++ b/src/course-home/progress-tab/ProgressTab.jsx
@@ -12,7 +12,7 @@ import RelatedLinks from './related-links/RelatedLinks';
import { useModel } from '../../generic/model-store';
-function ProgressTab() {
+const ProgressTab = () => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -55,6 +55,6 @@ function ProgressTab() {
>
);
-}
+};
export default ProgressTab;
diff --git a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
index 5e187d433b..496feb4c62 100644
--- a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
+++ b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
@@ -14,7 +14,7 @@ import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../
import { requestCert } from '../../data/thunks';
import messages from './messages';
-function CertificateStatus({ intl }) {
+const CertificateStatus = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -206,6 +206,7 @@ function CertificateStatus({ intl }) {
grade_variant: gradeEventName,
certificate_status_variant: certEventName,
});
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!certCase) {
@@ -257,7 +258,7 @@ function CertificateStatus({ intl }) {
);
-}
+};
CertificateStatus.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx
index 2615b270d7..b604ddb87e 100644
--- a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx
+++ b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx
@@ -6,13 +6,13 @@ import { OverlayTrigger, Popover } from '@edx/paragon';
import messages from './messages';
-function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
+const CompleteDonutSegment = ({ completePercentage, intl, lockedPercentage }) => {
+ const [showCompletePopover, setShowCompletePopover] = useState(false);
+
if (!completePercentage) {
return null;
}
- const [showCompletePopover, setShowCompletePopover] = useState(false);
-
const completeSegmentOffset = (3.6 * completePercentage) / 8;
let completeTooltipDegree = completePercentage < 100 ? -completeSegmentOffset : 0;
@@ -78,7 +78,7 @@ function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
)}
);
-}
+};
CompleteDonutSegment.propTypes = {
completePercentage: PropTypes.number.isRequired,
diff --git a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
index fe62189f44..54b6caa9c6 100644
--- a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
+++ b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
@@ -10,7 +10,7 @@ import IncompleteDonutSegment from './IncompleteDonutSegment';
import LockedDonutSegment from './LockedDonutSegment';
import messages from './messages';
-function CompletionDonutChart({ intl }) {
+const CompletionDonutChart = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -60,7 +60,7 @@ function CompletionDonutChart({ intl }) {
>
);
-}
+};
CompletionDonutChart.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/course-completion/CourseCompletion.jsx b/src/course-home/progress-tab/course-completion/CourseCompletion.jsx
index 5b4abc227d..1fc7dfa946 100644
--- a/src/course-home/progress-tab/course-completion/CourseCompletion.jsx
+++ b/src/course-home/progress-tab/course-completion/CourseCompletion.jsx
@@ -4,23 +4,21 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import CompletionDonutChart from './CompletionDonutChart';
import messages from './messages';
-function CourseCompletion({ intl }) {
- return (
-
-
-
-
{intl.formatMessage(messages.courseCompletion)}
-
- {intl.formatMessage(messages.completionBody)}
-
-
-
-
-
+const CourseCompletion = ({ intl }) => (
+
+
+
+
{intl.formatMessage(messages.courseCompletion)}
+
+ {intl.formatMessage(messages.completionBody)}
+
-
- );
-}
+
+
+
+
+
+);
CourseCompletion.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx b/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx
index e1bcc3d7f1..9f2d16eb87 100644
--- a/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx
+++ b/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx
@@ -6,13 +6,13 @@ import { OverlayTrigger, Popover } from '@edx/paragon';
import messages from './messages';
-function IncompleteDonutSegment({ incompletePercentage, intl }) {
+const IncompleteDonutSegment = ({ incompletePercentage, intl }) => {
+ const [showIncompletePopover, setShowIncompletePopover] = useState(false);
+
if (!incompletePercentage) {
return null;
}
- const [showIncompletePopover, setShowIncompletePopover] = useState(false);
-
const incompleteSegmentOffset = (3.6 * incompletePercentage) / 16;
const incompleteTooltipDegree = incompletePercentage < 100 ? incompleteSegmentOffset : 0;
@@ -49,7 +49,7 @@ function IncompleteDonutSegment({ incompletePercentage, intl }) {
);
-}
+};
IncompleteDonutSegment.propTypes = {
incompletePercentage: PropTypes.number.isRequired,
diff --git a/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx b/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx
index 0ad8b02d04..9ab5b4de71 100644
--- a/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx
+++ b/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx
@@ -6,7 +6,7 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
-function LockedDonutSegment({ intl, lockedPercentage }) {
+const LockedDonutSegment = ({ intl, lockedPercentage }) => {
const [showLockedPopover, setShowLockedPopover] = useState(false);
if (!lockedPercentage) {
@@ -62,7 +62,7 @@ function LockedDonutSegment({ intl, lockedPercentage }) {
);
-}
+};
LockedDonutSegment.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/credit-information/CreditInformation.jsx b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
index 8683fb2c6f..24198be975 100644
--- a/src/course-home/progress-tab/credit-information/CreditInformation.jsx
+++ b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
@@ -10,7 +10,7 @@ import { DashboardLink } from '../../../shared/links';
import messages from './messages';
-function CreditInformation({ intl }) {
+const CreditInformation = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -106,7 +106,7 @@ function CreditInformation({ intl }) {
{requirements}
>
);
-}
+};
CreditInformation.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
index 2d2677e3a8..6aabdc08e6 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
@@ -11,7 +11,7 @@ import CreditInformation from '../../credit-information/CreditInformation';
import messages from '../messages';
-function CourseGrade({ intl }) {
+const CourseGrade = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -52,7 +52,7 @@ function CourseGrade({ intl }) {
);
-}
+};
CourseGrade.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
index 39443a0e50..7710de35fb 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
@@ -10,7 +10,7 @@ import { useModel } from '../../../../generic/model-store';
import GradeRangeTooltip from './GradeRangeTooltip';
import messages from '../messages';
-function CourseGradeFooter({ intl, passingGrade }) {
+const CourseGradeFooter = ({ intl, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -83,7 +83,7 @@ function CourseGradeFooter({ intl, passingGrade }) {
);
-}
+};
CourseGradeFooter.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
index 4a485b11ef..498788eea6 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
@@ -10,7 +10,7 @@ import { Button, Icon } from '@edx/paragon';
import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
-function CourseGradeHeader({ intl }) {
+const CourseGradeHeader = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -81,7 +81,7 @@ function CourseGradeHeader({ intl }) {
)}
);
-}
+};
CourseGradeHeader.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
index c778bb3778..2941dc662e 100644
--- a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
@@ -11,7 +11,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
-function CurrentGradeTooltip({ intl, tooltipClassName }) {
+const CurrentGradeTooltip = ({ intl, tooltipClassName }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -62,7 +62,7 @@ function CurrentGradeTooltip({ intl, tooltipClassName }) {
>
);
-}
+};
CurrentGradeTooltip.defaultProps = {
tooltipClassName: '',
diff --git a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
index a0f72eb3c0..3cbbe5b1c0 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
@@ -11,7 +11,7 @@ import PassingGradeTooltip from './PassingGradeTooltip';
import messages from '../messages';
-function GradeBar({ intl, passingGrade }) {
+const GradeBar = ({ intl, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -49,7 +49,7 @@ function GradeBar({ intl, passingGrade }) {
);
-}
+};
GradeBar.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
index e983d96232..760c6e3da4 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
@@ -11,7 +11,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
-function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) {
+const GradeRangeTooltip = ({ intl, iconButtonClassName, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -72,7 +72,7 @@ function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) {
/>
);
-}
+};
GradeRangeTooltip.defaultProps = {
iconButtonClassName: '',
diff --git a/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx
index 3b5cabe076..0c4eb0f740 100644
--- a/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx
@@ -8,7 +8,7 @@ import { OverlayTrigger, Popover } from '@edx/paragon';
import messages from '../messages';
-function PassingGradeTooltip({ intl, passingGrade, tooltipClassName }) {
+const PassingGradeTooltip = ({ intl, passingGrade, tooltipClassName }) => {
const isLocaleRtl = isRtl(getLocale());
let passingGradeDirection = passingGrade < 50 ? '' : '-';
@@ -47,7 +47,7 @@ function PassingGradeTooltip({ intl, passingGrade, tooltipClassName }) {
>
);
-}
+};
PassingGradeTooltip.defaultProps = {
tooltipClassName: '',
diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
index 62c0e1d5da..c7f2b1138a 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
@@ -12,7 +12,7 @@ import DetailedGradesTable from './DetailedGradesTable';
import messages from '../messages';
-function DetailedGrades({ intl }) {
+const DetailedGrades = ({ intl }) => {
const { administrator } = getAuthenticatedUser();
const {
courseId,
@@ -79,7 +79,7 @@ function DetailedGrades({ intl }) {
)}
);
-}
+};
DetailedGrades.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
index 0e34907098..8f84423a1e 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
@@ -10,7 +10,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
import SubsectionTitleCell from './SubsectionTitleCell';
-function DetailedGradesTable({ intl }) {
+const DetailedGradesTable = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -64,7 +64,7 @@ function DetailedGradesTable({ intl }) {
);
})
);
-}
+};
DetailedGradesTable.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx
index 7f64aa8f8c..855f3dfe46 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx
@@ -8,7 +8,7 @@ import {
import messages from '../messages';
-function ProblemScoreDrawer({ intl, problemScores, subsection }) {
+const ProblemScoreDrawer = ({ intl, problemScores, subsection }) => {
const isLocaleRtl = isRtl(getLocale());
return (
@@ -22,7 +22,7 @@ function ProblemScoreDrawer({ intl, problemScores, subsection }) {
);
-}
+};
ProblemScoreDrawer.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
index 0b086e30a9..e60d2be421 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
@@ -14,7 +14,7 @@ import messages from '../messages';
import { useModel } from '../../../../generic/model-store';
import ProblemScoreDrawer from './ProblemScoreDrawer';
-function SubsectionTitleCell({ intl, subsection }) {
+const SubsectionTitleCell = ({ intl, subsection }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -99,7 +99,7 @@ function SubsectionTitleCell({ intl, subsection }) {
);
-}
+};
SubsectionTitleCell.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
index 11633e2a8c..0a1218af5c 100644
--- a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
@@ -7,9 +7,9 @@ import { Icon } from '@edx/paragon';
import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
-function AssignmentTypeCell({
+const AssignmentTypeCell = ({
intl, assignmentType, footnoteMarker, footnoteId, locked,
-}) {
+}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -42,7 +42,7 @@ function AssignmentTypeCell({
);
-}
+};
AssignmentTypeCell.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
index 56d1a73944..14f6b2c337 100644
--- a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
@@ -7,7 +7,7 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/
import messages from '../messages';
import { useModel } from '../../../../generic/model-store';
-function DroppableAssignmentFootnote({ footnotes, intl }) {
+const DroppableAssignmentFootnote = ({ footnotes, intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -37,7 +37,7 @@ function DroppableAssignmentFootnote({ footnotes, intl }) {
>
);
-}
+};
DroppableAssignmentFootnote.propTypes = {
footnotes: PropTypes.arrayOf(PropTypes.shape({
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
index b937652cb4..e6c6b9ad02 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
@@ -5,7 +5,7 @@ import { useModel } from '../../../../generic/model-store';
import GradeSummaryHeader from './GradeSummaryHeader';
import GradeSummaryTable from './GradeSummaryTable';
-function GradeSummary() {
+const GradeSummary = () => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -28,6 +28,6 @@ function GradeSummary() {
);
-}
+};
export default GradeSummary;
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
index 230d205930..cff58e2f1c 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
@@ -11,7 +11,7 @@ import { Blocked, InfoOutline } from '@edx/paragon/icons';
import messages from '../messages';
import { useModel } from '../../../../generic/model-store';
-function GradeSummaryHeader({ intl, allOfSomeAssignmentTypeIsLocked }) {
+const GradeSummaryHeader = ({ intl, allOfSomeAssignmentTypeIsLocked }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -54,7 +54,7 @@ function GradeSummaryHeader({ intl, allOfSomeAssignmentTypeIsLocked }) {
)}
);
-}
+};
GradeSummaryHeader.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
index e9cf260c62..ae44d155a1 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
@@ -14,7 +14,7 @@ import GradeSummaryTableFooter from './GradeSummaryTableFooter';
import messages from '../messages';
-function GradeSummaryTable({ intl, setAllOfSomeAssignmentTypeIsLocked }) {
+const GradeSummaryTable = ({ intl, setAllOfSomeAssignmentTypeIsLocked }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -79,6 +79,16 @@ function GradeSummaryTable({ intl, setAllOfSomeAssignmentTypeIsLocked }) {
weightedGrade: { weightedGrade: `${(assignment.weightedGrade * 100).toFixed(0)}${isLocaleRtl ? '\u200f' : ''}%`, locked },
};
});
+ const getAssignmentTypeCell = (value) => (
+
+ );
+
+ const getCell = (locked, value) => {value} ;
return (
<>
@@ -89,45 +99,28 @@ function GradeSummaryTable({ intl, setAllOfSomeAssignmentTypeIsLocked }) {
{
Header: `${intl.formatMessage(messages.assignmentType)}`,
accessor: 'type',
- // eslint-disable-next-line react/prop-types
- Cell: ({ value }) => (
-
- ),
+ Cell: ({ value }) => getAssignmentTypeCell(value),
headerClassName: 'h5 mb-0',
},
{
Header: `${intl.formatMessage(messages.weight)}`,
accessor: 'weight',
headerClassName: 'justify-content-end h5 mb-0',
- // eslint-disable-next-line react/prop-types
- Cell: ({ value }) => (
- {value.weight} // eslint-disable-line react/prop-types
- ),
+ Cell: ({ value }) => getCell(value.locked, value.weight),
cellClassName: 'text-right small',
},
{
Header: `${intl.formatMessage(messages.grade)}`,
accessor: 'grade',
headerClassName: 'justify-content-end h5 mb-0',
- // eslint-disable-next-line react/prop-types
- Cell: ({ value }) => (
- {value.grade} // eslint-disable-line react/prop-types
- ),
+ Cell: ({ value }) => getCell(value.locked, value.grade),
cellClassName: 'text-right small',
},
{
Header: `${intl.formatMessage(messages.weightedGrade)}`,
accessor: 'weightedGrade',
headerClassName: 'justify-content-end h5 mb-0 text-right',
- // eslint-disable-next-line react/prop-types
- Cell: ({ value }) => (
- {value.weightedGrade} // eslint-disable-line react/prop-types
- ),
+ Cell: ({ value }) => getCell(value.locked, value.weightedGrade),
cellClassName: 'text-right font-weight-bold small',
},
]}
@@ -141,7 +134,7 @@ function GradeSummaryTable({ intl, setAllOfSomeAssignmentTypeIsLocked }) {
)}
>
);
-}
+};
GradeSummaryTable.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
index d30dde0e1d..a3d380e26c 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
@@ -9,7 +9,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
-function GradeSummaryTableFooter({ intl }) {
+const GradeSummaryTableFooter = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -34,7 +34,7 @@ function GradeSummaryTableFooter({ intl }) {
);
-}
+};
GradeSummaryTableFooter.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/progress-tab/related-links/RelatedLinks.jsx b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
index 2392e9e138..fe5e34181d 100644
--- a/src/course-home/progress-tab/related-links/RelatedLinks.jsx
+++ b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
@@ -9,7 +9,7 @@ import { Hyperlink } from '@edx/paragon';
import messages from './messages';
import { useModel } from '../../../generic/model-store';
-function RelatedLinks({ intl }) {
+const RelatedLinks = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -56,7 +56,7 @@ function RelatedLinks({ intl }) {
);
-}
+};
RelatedLinks.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/suggested-schedule-messaging/ShiftDatesAlert.jsx b/src/course-home/suggested-schedule-messaging/ShiftDatesAlert.jsx
index 37b918ffa9..e3e4450884 100644
--- a/src/course-home/suggested-schedule-messaging/ShiftDatesAlert.jsx
+++ b/src/course-home/suggested-schedule-messaging/ShiftDatesAlert.jsx
@@ -14,7 +14,7 @@ import { resetDeadlines } from '../data';
import { useModel } from '../../generic/model-store';
import messages from './messages';
-function ShiftDatesAlert({ fetch, intl, model }) {
+const ShiftDatesAlert = ({ fetch, intl, model }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -29,12 +29,12 @@ function ShiftDatesAlert({ fetch, intl, model }) {
missedGatedContent,
} = datesBannerInfo;
+ const dispatch = useDispatch();
+
if (!missedDeadlines || missedGatedContent || hasEnded) {
return null;
}
- const dispatch = useDispatch();
-
return (
@@ -55,7 +55,7 @@ function ShiftDatesAlert({ fetch, intl, model }) {
);
-}
+};
ShiftDatesAlert.propTypes = {
fetch: PropTypes.func.isRequired,
diff --git a/src/course-home/suggested-schedule-messaging/SuggestedScheduleHeader.jsx b/src/course-home/suggested-schedule-messaging/SuggestedScheduleHeader.jsx
index 2e9b1a7421..7953929c98 100644
--- a/src/course-home/suggested-schedule-messaging/SuggestedScheduleHeader.jsx
+++ b/src/course-home/suggested-schedule-messaging/SuggestedScheduleHeader.jsx
@@ -3,13 +3,11 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
-function SuggestedScheduleHeader({ intl }) {
- return (
-
- {intl.formatMessage(messages.suggestedSchedule)}
-
- );
-}
+const SuggestedScheduleHeader = ({ intl }) => (
+
+ {intl.formatMessage(messages.suggestedSchedule)}
+
+);
SuggestedScheduleHeader.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/suggested-schedule-messaging/UpgradeToCompleteAlert.jsx b/src/course-home/suggested-schedule-messaging/UpgradeToCompleteAlert.jsx
index d01c21d177..e2e73539b7 100644
--- a/src/course-home/suggested-schedule-messaging/UpgradeToCompleteAlert.jsx
+++ b/src/course-home/suggested-schedule-messaging/UpgradeToCompleteAlert.jsx
@@ -12,7 +12,7 @@ import {
import { useModel } from '../../generic/model-store';
import messages from './messages';
-function UpgradeToCompleteAlert({ intl, logUpgradeLinkClick }) {
+const UpgradeToCompleteAlert = ({ intl, logUpgradeLinkClick }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -55,7 +55,7 @@ function UpgradeToCompleteAlert({ intl, logUpgradeLinkClick }) {
);
-}
+};
UpgradeToCompleteAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-home/suggested-schedule-messaging/UpgradeToShiftDatesAlert.jsx b/src/course-home/suggested-schedule-messaging/UpgradeToShiftDatesAlert.jsx
index 70f818e503..1592d80125 100644
--- a/src/course-home/suggested-schedule-messaging/UpgradeToShiftDatesAlert.jsx
+++ b/src/course-home/suggested-schedule-messaging/UpgradeToShiftDatesAlert.jsx
@@ -13,7 +13,7 @@ import {
import { useModel } from '../../generic/model-store';
import messages from './messages';
-function UpgradeToShiftDatesAlert({ intl, logUpgradeLinkClick, model }) {
+const UpgradeToShiftDatesAlert = ({ intl, logUpgradeLinkClick, model }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -57,7 +57,7 @@ function UpgradeToShiftDatesAlert({ intl, logUpgradeLinkClick, model }) {
);
-}
+};
UpgradeToShiftDatesAlert.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/course-tabs/CourseTabsNavigation.jsx b/src/course-tabs/CourseTabsNavigation.jsx
index ec84ce0744..838a558ad6 100644
--- a/src/course-tabs/CourseTabsNavigation.jsx
+++ b/src/course-tabs/CourseTabsNavigation.jsx
@@ -6,30 +6,28 @@ import classNames from 'classnames';
import messages from './messages';
import Tabs from '../generic/tabs/Tabs';
-function CourseTabsNavigation({
+const CourseTabsNavigation = ({
activeTabSlug, className, tabs, intl,
-}) {
- return (
-
-
-
- {tabs.map(({ url, title, slug }) => (
-
- {title}
-
- ))}
-
-
+}) => (
+
+
+
+ {tabs.map(({ url, title, slug }) => (
+
+ {title}
+
+ ))}
+
- );
-}
+
+);
CourseTabsNavigation.propTypes = {
activeTabSlug: PropTypes.string,
diff --git a/src/courseware/CoursewareContainer.test.jsx b/src/courseware/CoursewareContainer.test.jsx
index 83e59262e6..7b02f611e3 100644
--- a/src/courseware/CoursewareContainer.test.jsx
+++ b/src/courseware/CoursewareContainer.test.jsx
@@ -24,15 +24,13 @@ import { buildOutlineFromBlocks } from './data/__factories__/learningSequencesOu
// to have been passed into the component. Separate tests can handle unit rendering, but this
// proves that the component is rendered and receives the correct props. We probably COULD render
// Unit.jsx and its iframe in this test, but it's already complex enough.
-function MockUnit({ courseId, id }) { // eslint-disable-line react/prop-types
- return (
-
Unit Contents {courseId} {id}
- );
-}
jest.mock(
'./course/sequence/Unit',
- () => MockUnit,
+ // eslint-disable-next-line react/prop-types
+ () => function ({ courseId, id }) {
+ return
Unit Contents {courseId} {id}
;
+ },
);
jest.mock('@edx/frontend-platform/analytics');
diff --git a/src/courseware/CoursewareRedirectLandingPage.jsx b/src/courseware/CoursewareRedirectLandingPage.jsx
index 5be31f90f3..0597a7b22b 100644
--- a/src/courseware/CoursewareRedirectLandingPage.jsx
+++ b/src/courseware/CoursewareRedirectLandingPage.jsx
@@ -7,7 +7,7 @@ import { PageRoute } from '@edx/frontend-platform/react';
import queryString from 'query-string';
import PageLoading from '../generic/PageLoading';
-export default () => {
+const CoursewareRedirectLandingPage = () => {
const { path } = useRouteMatch();
return (
@@ -50,3 +50,5 @@ export default () => {
);
};
+
+export default CoursewareRedirectLandingPage;
diff --git a/src/courseware/course/Course.jsx b/src/courseware/course/Course.jsx
index 480bf8a5cb..4bc56f1430 100644
--- a/src/courseware/course/Course.jsx
+++ b/src/courseware/course/Course.jsx
@@ -18,7 +18,7 @@ import SidebarTriggers from './sidebar/SidebarTriggers';
import { useModel } from '../../generic/model-store';
import { getSessionStorage, setSessionStorage } from '../../data/sessionStorage';
-function Course({
+const Course = ({
courseId,
sequenceId,
unitId,
@@ -26,7 +26,7 @@ function Course({
previousSequenceHandler,
unitNavigationHandler,
windowWidth,
-}) {
+}) => {
const course = useModel('coursewareMeta', courseId);
const {
celebrations,
@@ -109,7 +109,7 @@ function Course({
);
-}
+};
Course.propTypes = {
courseId: PropTypes.string,
@@ -127,7 +127,7 @@ Course.defaultProps = {
unitId: null,
};
-function CourseWrapper(props) {
+const CourseWrapper = (props) => {
// useWindowSize initially returns an undefined width intentionally at first.
// See https://www.joshwcomeau.com/react/the-perils-of-rehydration/ for why.
// But
has some tricky window-size-dependent, session-storage-setting logic and React would yell at us if
@@ -139,6 +139,6 @@ function CourseWrapper(props) {
}
return ;
-}
+};
export default CourseWrapper;
diff --git a/src/courseware/course/CourseBreadcrumbs.jsx b/src/courseware/course/CourseBreadcrumbs.jsx
index a90aff5f8c..0a1e73493d 100644
--- a/src/courseware/course/CourseBreadcrumbs.jsx
+++ b/src/courseware/course/CourseBreadcrumbs.jsx
@@ -10,9 +10,9 @@ import { Link } from 'react-router-dom';
import { useModel, useModels } from '../../generic/model-store';
import JumpNavMenuItem from './JumpNavMenuItem';
-function CourseBreadcrumb({
+const CourseBreadcrumb = ({
content, withSeparator, courseId, sequenceId, unitId, isStaff,
-}) {
+}) => {
const defaultContent = content.filter(destination => destination.default)[0] || { id: courseId, label: '', sequences: [] };
return (
<>
@@ -55,7 +55,7 @@ function CourseBreadcrumb({
>
);
-}
+};
CourseBreadcrumb.propTypes = {
content: PropTypes.arrayOf(
PropTypes.shape({
@@ -79,13 +79,13 @@ CourseBreadcrumb.defaultProps = {
isStaff: null,
};
-export default function CourseBreadcrumbs({
+const CourseBreadcrumbs = ({
courseId,
sectionId,
sequenceId,
unitId,
isStaff,
-}) {
+}) => {
const course = useModel('coursewareMeta', courseId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
@@ -151,7 +151,7 @@ export default function CourseBreadcrumbs({
);
-}
+};
CourseBreadcrumbs.propTypes = {
courseId: PropTypes.string.isRequired,
@@ -167,3 +167,5 @@ CourseBreadcrumbs.defaultProps = {
unitId: null,
isStaff: null,
};
+
+export default CourseBreadcrumbs;
diff --git a/src/courseware/course/JumpNavMenuItem.jsx b/src/courseware/course/JumpNavMenuItem.jsx
index 37077f29c8..4bfe74b3c4 100644
--- a/src/courseware/course/JumpNavMenuItem.jsx
+++ b/src/courseware/course/JumpNavMenuItem.jsx
@@ -8,14 +8,14 @@ import {
sendTrackEvent,
} from '@edx/frontend-platform/analytics';
-export default function JumpNavMenuItem({
+const JumpNavMenuItem = ({
title,
courseId,
currentSequence,
currentUnit,
sequences,
isDefault,
-}) {
+}) => {
function logEvent(targetUrl) {
const eventName = 'edx.ui.lms.jump_nav.selected';
const payload = {
@@ -48,7 +48,7 @@ export default function JumpNavMenuItem({
{title}
);
-}
+};
const sequenceShape = PropTypes.shape({
id: PropTypes.string.isRequired,
@@ -62,3 +62,5 @@ JumpNavMenuItem.propTypes = {
currentSequence: PropTypes.string.isRequired,
currentUnit: PropTypes.string.isRequired,
};
+
+export default JumpNavMenuItem;
diff --git a/src/courseware/course/bookmark/BookmarkButton.jsx b/src/courseware/course/bookmark/BookmarkButton.jsx
index 29e9d9ba8c..0f105a9160 100644
--- a/src/courseware/course/bookmark/BookmarkButton.jsx
+++ b/src/courseware/course/bookmark/BookmarkButton.jsx
@@ -23,9 +23,9 @@ const hasBookmarkLabel = (
/>
);
-export default function BookmarkButton({
+const BookmarkButton = ({
isBookmarked, isProcessing, unitId,
-}) {
+}) => {
const bookmarkState = isBookmarked ? 'bookmarked' : 'default';
const state = isProcessing ? `${bookmarkState}Processing` : bookmarkState;
@@ -36,6 +36,7 @@ export default function BookmarkButton({
} else {
dispatch(addBookmark(unitId));
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isBookmarked, unitId]);
return (
@@ -59,7 +60,7 @@ export default function BookmarkButton({
}}
/>
);
-}
+};
BookmarkButton.propTypes = {
unitId: PropTypes.string.isRequired,
@@ -70,3 +71,5 @@ BookmarkButton.propTypes = {
BookmarkButton.defaultProps = {
isBookmarked: false,
};
+
+export default BookmarkButton;
diff --git a/src/courseware/course/bookmark/BookmarkFilledIcon.jsx b/src/courseware/course/bookmark/BookmarkFilledIcon.jsx
index cb2a6614ee..af6efe730b 100644
--- a/src/courseware/course/bookmark/BookmarkFilledIcon.jsx
+++ b/src/courseware/course/bookmark/BookmarkFilledIcon.jsx
@@ -2,6 +2,6 @@ import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBookmark } from '@fortawesome/free-solid-svg-icons';
-export default function BookmarkFilledIcon(props) {
- return ;
-}
+const BookmarkFilledIcon = (props) => ;
+
+export default BookmarkFilledIcon;
diff --git a/src/courseware/course/bookmark/BookmarkOutlineIcon.jsx b/src/courseware/course/bookmark/BookmarkOutlineIcon.jsx
index eed786a69f..2153625754 100644
--- a/src/courseware/course/bookmark/BookmarkOutlineIcon.jsx
+++ b/src/courseware/course/bookmark/BookmarkOutlineIcon.jsx
@@ -2,6 +2,6 @@ import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBookmark } from '@fortawesome/free-regular-svg-icons';
-export default function BookmarkOutlineIcon(props) {
- return ;
-}
+const BookmarkOutlineIcon = (props) => ;
+
+export default BookmarkOutlineIcon;
diff --git a/src/courseware/course/celebration/CelebrationModal.jsx b/src/courseware/course/celebration/CelebrationModal.jsx
index 768bc1fe38..6b0f2e7e5d 100644
--- a/src/courseware/course/celebration/CelebrationModal.jsx
+++ b/src/courseware/course/celebration/CelebrationModal.jsx
@@ -16,9 +16,9 @@ import SocialIcons from '../../social-share/SocialIcons';
import { recordFirstSectionCelebration } from './utils';
import { useModel } from '../../../generic/model-store';
-function CelebrationModal({
+const CelebrationModal = ({
courseId, intl, isOpen, onClose, ...rest
-}) {
+}) => {
const { org } = useModel('courseHomeMeta', courseId);
const wideScreen = useWindowSize().width >= breakpoints.small.minWidth;
@@ -26,6 +26,7 @@ function CelebrationModal({
if (isOpen) {
recordFirstSectionCelebration(org, courseId);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
return (
@@ -59,7 +60,7 @@ function CelebrationModal({
>
);
-}
+};
CelebrationModal.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/courseware/course/celebration/WeeklyGoalCelebrationModal.jsx b/src/courseware/course/celebration/WeeklyGoalCelebrationModal.jsx
index 4d04f16149..19dafc964d 100644
--- a/src/courseware/course/celebration/WeeklyGoalCelebrationModal.jsx
+++ b/src/courseware/course/celebration/WeeklyGoalCelebrationModal.jsx
@@ -11,15 +11,16 @@ import messages from './messages';
import { recordWeeklyGoalCelebration } from './utils';
import { useModel } from '../../../generic/model-store';
-function WeeklyGoalCelebrationModal({
+const WeeklyGoalCelebrationModal = ({
courseId, daysPerWeek, intl, isOpen, onClose, ...rest
-}) {
+}) => {
const { org } = useModel('courseHomeMeta', courseId);
useEffect(() => {
if (isOpen) {
recordWeeklyGoalCelebration(org, courseId);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
return (
@@ -71,7 +72,7 @@ function WeeklyGoalCelebrationModal({
>
);
-}
+};
WeeklyGoalCelebrationModal.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/courseware/course/content-tools/ContentTools.jsx b/src/courseware/course/content-tools/ContentTools.jsx
index 095dc2ed6e..871bf62971 100644
--- a/src/courseware/course/content-tools/ContentTools.jsx
+++ b/src/courseware/course/content-tools/ContentTools.jsx
@@ -4,22 +4,20 @@ import PropTypes from 'prop-types';
import Calculator from './calculator';
import NotesVisibility from './notes-visibility';
-export default function ContentTools({
+const ContentTools = ({
course,
-}) {
- return (
-
-
- {course.showCalculator && (
-
- )}
- {course.notes.enabled && (
-
- )}
-
+}) => (
+
+
+ {course.showCalculator && (
+
+ )}
+ {course.notes.enabled && (
+
+ )}
- );
-}
+
+);
ContentTools.propTypes = {
course: PropTypes.shape({
@@ -29,3 +27,5 @@ ContentTools.propTypes = {
showCalculator: PropTypes.bool,
}).isRequired,
};
+
+export default ContentTools;
diff --git a/src/courseware/course/content-tools/ContentTools.test.jsx b/src/courseware/course/content-tools/ContentTools.test.jsx
index 08cadff99f..152acac862 100644
--- a/src/courseware/course/content-tools/ContentTools.test.jsx
+++ b/src/courseware/course/content-tools/ContentTools.test.jsx
@@ -2,8 +2,12 @@ import React from 'react';
import { initializeTestStore, render, screen } from '../../../setupTest';
import ContentTools from './ContentTools';
-jest.mock('./calculator/Calculator', () => () =>
);
-jest.mock('./notes-visibility/NotesVisibility', () => () =>
);
+jest.mock('./calculator/Calculator', () => function () {
+ return
;
+});
+jest.mock('./notes-visibility/NotesVisibility', () => function () {
+ return
;
+});
describe('Content Tools', () => {
const mockData = {
diff --git a/src/courseware/course/course-exit/CatalogSuggestion.jsx b/src/courseware/course/course-exit/CatalogSuggestion.jsx
index ededa14676..f0287d97bb 100644
--- a/src/courseware/course/course-exit/CatalogSuggestion.jsx
+++ b/src/courseware/course/course-exit/CatalogSuggestion.jsx
@@ -16,7 +16,7 @@ import { useModel } from '../../../generic/model-store';
import messages from './messages';
import { logClick } from './utils';
-function CatalogSuggestion({ intl, variant }) {
+const CatalogSuggestion = ({ intl, variant }) => {
const { courseId } = useSelector(state => state.courseware);
const { org } = useModel('courseHomeMeta', courseId);
const { administrator } = getAuthenticatedUser();
@@ -45,7 +45,7 @@ function CatalogSuggestion({ intl, variant }) {
);
-}
+};
CatalogSuggestion.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/CourseCelebration.jsx b/src/courseware/course/course-exit/CourseCelebration.jsx
index c9c5a2ba39..fd18b35259 100644
--- a/src/courseware/course/course-exit/CourseCelebration.jsx
+++ b/src/courseware/course/course-exit/CourseCelebration.jsx
@@ -36,7 +36,7 @@ import CourseRecommendations from './CourseRecommendations';
const LINKEDIN_BLUE = '#2867B2';
-function CourseCelebration({ intl }) {
+const CourseCelebration = ({ intl }) => {
const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth;
const { courseId } = useSelector(state => state.courseware);
const dispatch = useDispatch();
@@ -362,7 +362,7 @@ function CourseCelebration({ intl }) {
>
);
-}
+};
CourseCelebration.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/CourseExit.jsx b/src/courseware/course/course-exit/CourseExit.jsx
index 6bd80b857e..d6bff4084a 100644
--- a/src/courseware/course/course-exit/CourseExit.jsx
+++ b/src/courseware/course/course-exit/CourseExit.jsx
@@ -15,7 +15,7 @@ import { unsubscribeFromGoalReminders } from './data/thunks';
import { useModel } from '../../../generic/model-store';
-function CourseExit({ intl }) {
+const CourseExit = ({ intl }) => {
const { courseId } = useSelector(state => state.courseware);
const {
certificateData,
@@ -74,7 +74,7 @@ function CourseExit({ intl }) {
{body}
>
);
-}
+};
CourseExit.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/CourseInProgress.jsx b/src/courseware/course/course-exit/CourseInProgress.jsx
index 7c230d4f9e..a6b29096bd 100644
--- a/src/courseware/course/course-exit/CourseInProgress.jsx
+++ b/src/courseware/course/course-exit/CourseInProgress.jsx
@@ -14,7 +14,7 @@ import DashboardFootnote from './DashboardFootnote';
import messages from './messages';
import { logClick, logVisit } from './utils';
-function CourseInProgress({ intl }) {
+const CourseInProgress = ({ intl }) => {
const { courseId } = useSelector(state => state.courseware);
const {
org,
@@ -58,7 +58,7 @@ function CourseInProgress({ intl }) {
>
);
-}
+};
CourseInProgress.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/CourseNonPassing.jsx b/src/courseware/course/course-exit/CourseNonPassing.jsx
index a39d35bb8c..e63b9a704e 100644
--- a/src/courseware/course/course-exit/CourseNonPassing.jsx
+++ b/src/courseware/course/course-exit/CourseNonPassing.jsx
@@ -14,7 +14,7 @@ import DashboardFootnote from './DashboardFootnote';
import messages from './messages';
import { logClick, logVisit } from './utils';
-function CourseNonPassing({ intl }) {
+const CourseNonPassing = ({ intl }) => {
const { courseId } = useSelector(state => state.courseware);
const {
org,
@@ -58,7 +58,7 @@ function CourseNonPassing({ intl }) {
>
);
-}
+};
CourseNonPassing.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/CourseRecommendations.jsx b/src/courseware/course/course-exit/CourseRecommendations.jsx
index 53dff1b17c..d4cc344599 100644
--- a/src/courseware/course/course-exit/CourseRecommendations.jsx
+++ b/src/courseware/course/course-exit/CourseRecommendations.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/jsx-no-useless-fragment */
import React, { useEffect } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
@@ -55,7 +56,7 @@ const ListStyles = {
conjunction: 'conjunction',
};
-function CourseCard({
+const CourseCard = ({
original: {
title,
image,
@@ -64,7 +65,7 @@ function CourseCard({
onClick,
},
intl,
-}) {
+}) => {
const formatList = (items, style) => (
items.join(intl.formatMessage(
messages.listJoin,
@@ -112,7 +113,7 @@ function CourseCard({
);
-}
+};
CourseCard.propTypes = {
original: PropTypes.shape({
@@ -131,7 +132,7 @@ CourseCard.propTypes = {
const IntlCard = injectIntl(CourseCard);
-function CourseRecommendations({ intl, variant }) {
+const CourseRecommendations = ({ intl, variant }) => {
const { courseId, recommendationsStatus } = useSelector(state => ({ ...state.recommendations, ...state.courseware }));
const { recommendations } = useModel('coursewareMeta', courseId);
const { org, number } = useModel('courseHomeMeta', courseId);
@@ -142,6 +143,7 @@ function CourseRecommendations({ intl, variant }) {
useEffect(() => {
dispatch(fetchCourseRecommendations(courseKey, courseId));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch]);
const recommendationsLength = recommendations ? recommendations.length : 0;
@@ -200,7 +202,7 @@ function CourseRecommendations({ intl, variant }) {
);
-}
+};
CourseRecommendations.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/DashboardFootnote.jsx b/src/courseware/course/course-exit/DashboardFootnote.jsx
index 5a52542d0b..132d46fff7 100644
--- a/src/courseware/course/course-exit/DashboardFootnote.jsx
+++ b/src/courseware/course/course-exit/DashboardFootnote.jsx
@@ -16,7 +16,7 @@ import Footnote from './Footnote';
import messages from './messages';
import { logClick } from './utils';
-function DashboardFootnote({ intl, variant }) {
+const DashboardFootnote = ({ intl, variant }) => {
const { courseId } = useSelector(state => state.courseware);
const { org } = useModel('courseHomeMeta', courseId);
const { administrator } = getAuthenticatedUser();
@@ -45,7 +45,7 @@ function DashboardFootnote({ intl, variant }) {
)}
/>
);
-}
+};
DashboardFootnote.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/Footnote.jsx b/src/courseware/course/course-exit/Footnote.jsx
index b405edbe83..85317548ac 100644
--- a/src/courseware/course/course-exit/Footnote.jsx
+++ b/src/courseware/course/course-exit/Footnote.jsx
@@ -2,16 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-function Footnote({ icon, text }) {
- return (
-
- );
-}
+const Footnote = ({ icon, text }) => (
+
+);
Footnote.propTypes = {
icon: PropTypes.shape({}).isRequired,
diff --git a/src/courseware/course/course-exit/ProgramCompletion.jsx b/src/courseware/course/course-exit/ProgramCompletion.jsx
index 0114f65e89..f9e5635dad 100644
--- a/src/courseware/course/course-exit/ProgramCompletion.jsx
+++ b/src/courseware/course/course-exit/ProgramCompletion.jsx
@@ -19,13 +19,13 @@ import messages from './messages';
const programTypes = ['microbachelors', 'micromasters', 'professional-certificate', 'xseries'];
-function ProgramCompletion({
+const ProgramCompletion = ({
intl,
progress,
title,
type,
url,
-}) {
+}) => {
if (!programTypes.includes(type) || progress.notStarted !== 0 || progress.inProgress !== 0) {
return null;
}
@@ -95,7 +95,7 @@ function ProgramCompletion({
);
-}
+};
ProgramCompletion.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/course-exit/UpgradeFootnote.jsx b/src/courseware/course/course-exit/UpgradeFootnote.jsx
index d4173346cb..0f2cf72887 100644
--- a/src/courseware/course/course-exit/UpgradeFootnote.jsx
+++ b/src/courseware/course/course-exit/UpgradeFootnote.jsx
@@ -14,7 +14,7 @@ import { logClick } from './utils';
import messages from './messages';
import { useModel } from '../../../generic/model-store';
-function UpgradeFootnote({ deadline, href, intl }) {
+const UpgradeFootnote = ({ deadline, href, intl }) => {
const { courseId } = useSelector(state => state.courseware);
const { org } = useModel('courseHomeMeta', courseId);
const { administrator } = getAuthenticatedUser();
@@ -55,7 +55,7 @@ function UpgradeFootnote({ deadline, href, intl }) {
)}
/>
);
-}
+};
UpgradeFootnote.propTypes = {
deadline: PropTypes.instanceOf(Date).isRequired,
diff --git a/src/courseware/course/course-exit/index.js b/src/courseware/course/course-exit/index.js
index 2252238bbc..2f74d88a21 100644
--- a/src/courseware/course/course-exit/index.js
+++ b/src/courseware/course/course-exit/index.js
@@ -1,4 +1,4 @@
import CourseExit from './CourseExit';
-import { getCourseExitNavigation } from './utils';
+import { GetCourseExitNavigation } from './utils';
-export { CourseExit, getCourseExitNavigation };
+export { CourseExit, GetCourseExitNavigation };
diff --git a/src/courseware/course/course-exit/utils.js b/src/courseware/course/course-exit/utils.js
index 5da8356b4e..da1d353094 100644
--- a/src/courseware/course/course-exit/utils.js
+++ b/src/courseware/course/course-exit/utils.js
@@ -66,7 +66,7 @@ function getCourseExitMode(
}
// Returns null in order to render the default navigation text
-function getCourseExitNavigation(courseId, intl) {
+function GetCourseExitNavigation(courseId, intl) {
const {
certificateData,
hasScheduledContent,
@@ -133,7 +133,7 @@ const logVisit = (org, courseId, administrator, variant) => {
export {
COURSE_EXIT_MODES,
getCourseExitMode,
- getCourseExitNavigation,
+ GetCourseExitNavigation,
logClick,
logVisit,
};
diff --git a/src/courseware/course/course-license/CourseLicense.jsx b/src/courseware/course/course-license/CourseLicense.jsx
index 3d3cf5128a..870d7be48c 100644
--- a/src/courseware/course/course-license/CourseLicense.jsx
+++ b/src/courseware/course/course-license/CourseLicense.jsx
@@ -103,10 +103,10 @@ function parseLicense(license) {
return [licenseType, options, version];
}
-function CourseLicense({
+const CourseLicense = ({
license,
intl,
-}) {
+}) => {
const renderAllRightsReservedLicense = () => (
@@ -148,7 +148,7 @@ function CourseLicense({
)}
);
-}
+};
CourseLicense.propTypes = {
license: PropTypes.string,
diff --git a/src/courseware/course/sequence/Sequence.jsx b/src/courseware/course/sequence/Sequence.jsx
index 73738256e5..faa58c90c4 100644
--- a/src/courseware/course/sequence/Sequence.jsx
+++ b/src/courseware/course/sequence/Sequence.jsx
@@ -26,7 +26,7 @@ import HiddenAfterDue from './hidden-after-due';
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
import SequenceContent from './SequenceContent';
-function Sequence({
+const Sequence = ({
unitId,
sequenceId,
courseId,
@@ -34,7 +34,7 @@ function Sequence({
nextSequenceHandler,
previousSequenceHandler,
intl,
-}) {
+}) => {
const course = useModel('coursewareMeta', courseId);
const {
isStaff,
@@ -218,7 +218,7 @@ function Sequence({
{intl.formatMessage(messages.loadFailure)}
);
-}
+};
Sequence.propTypes = {
unitId: PropTypes.string,
diff --git a/src/courseware/course/sequence/Sequence.test.jsx b/src/courseware/course/sequence/Sequence.test.jsx
index 55d6513e0a..d771d97da5 100644
--- a/src/courseware/course/sequence/Sequence.test.jsx
+++ b/src/courseware/course/sequence/Sequence.test.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { Factory } from 'rosie';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { breakpoints } from '@edx/paragon';
@@ -381,27 +382,25 @@ describe('Sequence', () => {
});
});
+ const SidebarWrapper = ({ contextValue }) => (
+
+
+
+ );
+
+ SidebarWrapper.propTypes = {
+ contextValue: PropTypes.shape({}).isRequired,
+ };
+
describe('notification feature', () => {
it('renders notification tray in sequence', async () => {
- render(
- null }}
- >
-
- ,
- );
+ render( null }} />);
expect(await screen.findByText('Notifications')).toBeInTheDocument();
});
it('handles click on notification tray close button', async () => {
const toggleNotificationTray = jest.fn();
- render(
-
-
- ,
- );
+ render( );
const notificationCloseIconButton = await screen.findByRole('button', { name: /Close notification tray/i });
fireEvent.click(notificationCloseIconButton);
expect(toggleNotificationTray).toHaveBeenCalledTimes(1);
diff --git a/src/courseware/course/sequence/SequenceContent.jsx b/src/courseware/course/sequence/SequenceContent.jsx
index 9f78d59b49..35a9a27f9d 100644
--- a/src/courseware/course/sequence/SequenceContent.jsx
+++ b/src/courseware/course/sequence/SequenceContent.jsx
@@ -9,14 +9,14 @@ import Unit from './Unit';
const ContentLock = React.lazy(() => import('./content-lock'));
-function SequenceContent({
+const SequenceContent = ({
gated,
intl,
courseId,
sequenceId,
unitId,
unitLoadedHandler,
-}) {
+}) => {
const sequence = useModel('sequences', sequenceId);
// Go back to the top of the page whenever the unit or sequence changes.
@@ -61,7 +61,7 @@ function SequenceContent({
onLoaded={unitLoadedHandler}
/>
);
-}
+};
SequenceContent.propTypes = {
gated: PropTypes.bool.isRequired,
diff --git a/src/courseware/course/sequence/Unit.jsx b/src/courseware/course/sequence/Unit.jsx
index 41fe9d85d2..274bc68143 100644
--- a/src/courseware/course/sequence/Unit.jsx
+++ b/src/courseware/course/sequence/Unit.jsx
@@ -74,13 +74,13 @@ export function sendUrlHashToFrame(frame) {
}
}
-function Unit({
+const Unit = ({
courseId,
format,
onLoaded,
id,
intl,
-}) {
+}) => {
const { authenticatedUser } = useContext(AppContext);
const view = authenticatedUser ? 'student_view' : 'public_view';
let iframeUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}?show_title=0&show_bookmark_button=0&recheck_access=1&view=${view}`;
@@ -239,7 +239,7 @@ function Unit({
)}
);
-}
+};
Unit.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/courseware/course/sequence/content-lock/ContentLock.jsx b/src/courseware/course/sequence/content-lock/ContentLock.jsx
index 2ec0f00b69..26393fec0c 100644
--- a/src/courseware/course/sequence/content-lock/ContentLock.jsx
+++ b/src/courseware/course/sequence/content-lock/ContentLock.jsx
@@ -8,12 +8,12 @@ import { Button } from '@edx/paragon';
import messages from './messages';
-function ContentLock({
+const ContentLock = ({
intl, courseId, prereqSectionName, prereqId, sequenceTitle,
-}) {
+}) => {
const handleClick = useCallback(() => {
history.push(`/course/${courseId}/${prereqId}`);
- });
+ }, [courseId, prereqId]);
return (
<>
@@ -33,7 +33,7 @@ function ContentLock({
>
);
-}
+};
ContentLock.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string.isRequired,
diff --git a/src/courseware/course/sequence/hidden-after-due/HiddenAfterDue.jsx b/src/courseware/course/sequence/hidden-after-due/HiddenAfterDue.jsx
index 01f50b57bf..13f6d896c2 100644
--- a/src/courseware/course/sequence/hidden-after-due/HiddenAfterDue.jsx
+++ b/src/courseware/course/sequence/hidden-after-due/HiddenAfterDue.jsx
@@ -8,7 +8,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from './messages';
-function HiddenAfterDue({ courseId, intl }) {
+const HiddenAfterDue = ({ courseId, intl }) => {
const { tabs } = useModel('courseHomeMeta', courseId);
const progressTab = tabs.find(tab => tab.slug === 'progress');
@@ -42,7 +42,7 @@ function HiddenAfterDue({ courseId, intl }) {
);
-}
+};
HiddenAfterDue.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sequence/honor-code/HonorCode.jsx b/src/courseware/course/sequence/honor-code/HonorCode.jsx
index 4525482212..11e7d59468 100644
--- a/src/courseware/course/sequence/honor-code/HonorCode.jsx
+++ b/src/courseware/course/sequence/honor-code/HonorCode.jsx
@@ -10,7 +10,7 @@ import { useModel } from '../../../../generic/model-store';
import { saveIntegritySignature } from '../../../data';
import messages from './messages';
-function HonorCode({ intl, courseId }) {
+const HonorCode = ({ intl, courseId }) => {
const dispatch = useDispatch();
const {
isMasquerading,
@@ -63,7 +63,7 @@ function HonorCode({ intl, courseId }) {
);
-}
+};
HonorCode.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx b/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx
index b128eab3a2..90af888e20 100644
--- a/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx
+++ b/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx
@@ -19,10 +19,10 @@ import {
SupportMissionBullet,
} from '../../../../generic/upsell-bullets/UpsellBullets';
-function LockPaywall({
+const LockPaywall = ({
intl,
courseId,
-}) {
+}) => {
const { notificationTrayVisible } = useContext(SidebarContext);
const course = useModel('coursewareMeta', courseId);
const {
@@ -141,7 +141,7 @@ function LockPaywall({
);
-}
+};
LockPaywall.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string.isRequired,
diff --git a/src/courseware/course/sequence/sequence-navigation/CompleteIcon.jsx b/src/courseware/course/sequence/sequence-navigation/CompleteIcon.jsx
index bfddccdf0a..31dea65ef1 100644
--- a/src/courseware/course/sequence/sequence-navigation/CompleteIcon.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/CompleteIcon.jsx
@@ -2,6 +2,6 @@ import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
-export default function CompleteIcon(props) {
- return ;
-}
+const CompleteIcon = (props) => ;
+
+export default CompleteIcon;
diff --git a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx
index 0cc975c35d..76bbaf3ff6 100644
--- a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.jsx
@@ -11,7 +11,7 @@ import {
} from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
-import { getCourseExitNavigation } from '../../course-exit';
+import { GetCourseExitNavigation } from '../../course-exit';
import UnitButton from './UnitButton';
import SequenceNavigationTabs from './SequenceNavigationTabs';
import { useSequenceNavigationMetadata } from './hooks';
@@ -20,7 +20,7 @@ import { LOADED } from '../../../data/slice';
import messages from './messages';
-function SequenceNavigation({
+const SequenceNavigation = ({
intl,
unitId,
sequenceId,
@@ -29,7 +29,7 @@ function SequenceNavigation({
nextSequenceHandler,
previousSequenceHandler,
goToCourseExitPage,
-}) {
+}) => {
const sequence = useModel('sequences', sequenceId);
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
const {
@@ -64,7 +64,7 @@ function SequenceNavigation({
};
const renderNextButton = () => {
- const { exitActive, exitText } = getCourseExitNavigation(courseId, intl);
+ const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
const buttonOnClick = isLastUnit ? goToCourseExitPage : nextSequenceHandler;
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
const disabled = isLastUnit && !exitActive;
@@ -89,7 +89,7 @@ function SequenceNavigation({
);
-}
+};
SequenceNavigation.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sequence/sequence-navigation/SequenceNavigationDropdown.jsx b/src/courseware/course/sequence/sequence-navigation/SequenceNavigationDropdown.jsx
index e88017326f..8898ff3d8e 100644
--- a/src/courseware/course/sequence/sequence-navigation/SequenceNavigationDropdown.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/SequenceNavigationDropdown.jsx
@@ -5,42 +5,40 @@ import { FormattedMessage } from '@edx/frontend-platform/i18n';
import UnitButton from './UnitButton';
-export default function SequenceNavigationDropdown({
+const SequenceNavigationDropdown = ({
unitId,
onNavigate,
showCompletion,
unitIds,
-}) {
- return (
-
-
-
-
- {unitIds.map(buttonUnitId => (
-
- ))}
-
-
- );
-}
+ ))}
+
+
+);
SequenceNavigationDropdown.propTypes = {
unitId: PropTypes.string.isRequired,
@@ -48,3 +46,5 @@ SequenceNavigationDropdown.propTypes = {
showCompletion: PropTypes.bool.isRequired,
unitIds: PropTypes.arrayOf(PropTypes.string).isRequired,
};
+
+export default SequenceNavigationDropdown;
diff --git a/src/courseware/course/sequence/sequence-navigation/SequenceNavigationTabs.jsx b/src/courseware/course/sequence/sequence-navigation/SequenceNavigationTabs.jsx
index 6275548408..6e1e84d6c5 100644
--- a/src/courseware/course/sequence/sequence-navigation/SequenceNavigationTabs.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/SequenceNavigationTabs.jsx
@@ -5,9 +5,9 @@ import UnitButton from './UnitButton';
import SequenceNavigationDropdown from './SequenceNavigationDropdown';
import useIndexOfLastVisibleChild from '../../../../generic/tabs/useIndexOfLastVisibleChild';
-export default function SequenceNavigationTabs({
+const SequenceNavigationTabs = ({
unitIds, unitId, showCompletion, onNavigate,
-}) {
+}) => {
const [
indexOfLastVisibleChild,
containerRef,
@@ -43,7 +43,7 @@ export default function SequenceNavigationTabs({
)}
);
-}
+};
SequenceNavigationTabs.propTypes = {
unitId: PropTypes.string.isRequired,
@@ -51,3 +51,5 @@ SequenceNavigationTabs.propTypes = {
showCompletion: PropTypes.bool.isRequired,
unitIds: PropTypes.arrayOf(PropTypes.string).isRequired,
};
+
+export default SequenceNavigationTabs;
diff --git a/src/courseware/course/sequence/sequence-navigation/UnitButton.jsx b/src/courseware/course/sequence/sequence-navigation/UnitButton.jsx
index ed55e1a499..393a299bbe 100644
--- a/src/courseware/course/sequence/sequence-navigation/UnitButton.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/UnitButton.jsx
@@ -8,7 +8,7 @@ import UnitIcon from './UnitIcon';
import CompleteIcon from './CompleteIcon';
import BookmarkFilledIcon from '../../bookmark/BookmarkFilledIcon';
-function UnitButton({
+const UnitButton = ({
onClick,
title,
contentType,
@@ -19,10 +19,10 @@ function UnitButton({
unitId,
className,
showTitle,
-}) {
+}) => {
const handleClick = useCallback(() => {
onClick(unitId);
- });
+ }, [onClick, unitId]);
return (
);
-}
+};
UnitButton.propTypes = {
bookmarked: PropTypes.bool,
diff --git a/src/courseware/course/sequence/sequence-navigation/UnitIcon.jsx b/src/courseware/course/sequence/sequence-navigation/UnitIcon.jsx
index 27ade700bc..a0ea769ebf 100644
--- a/src/courseware/course/sequence/sequence-navigation/UnitIcon.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/UnitIcon.jsx
@@ -5,7 +5,7 @@ import {
faVideo, faBook, faEdit, faTasks, faLock,
} from '@fortawesome/free-solid-svg-icons';
-export default function UnitIcon({ type }) {
+const UnitIcon = ({ type }) => {
let icon = null;
switch (type) {
case 'video':
@@ -30,8 +30,10 @@ export default function UnitIcon({ type }) {
return (
);
-}
+};
UnitIcon.propTypes = {
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem', 'lock']).isRequired,
};
+
+export default UnitIcon;
diff --git a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx
index b6aa1ef819..75587248cd 100644
--- a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx
@@ -8,25 +8,25 @@ import {
} from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
-import { getCourseExitNavigation } from '../../course-exit';
+import { GetCourseExitNavigation } from '../../course-exit';
import UnitNavigationEffortEstimate from './UnitNavigationEffortEstimate';
import { useSequenceNavigationMetadata } from './hooks';
import messages from './messages';
-function UnitNavigation({
+const UnitNavigation = ({
intl,
sequenceId,
unitId,
onClickPrevious,
onClickNext,
goToCourseExitPage,
-}) {
+}) => {
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
const { courseId } = useSelector(state => state.courseware);
const renderNextButton = () => {
- const { exitActive, exitText } = getCourseExitNavigation(courseId, intl);
+ const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
const buttonOnClick = isLastUnit ? goToCourseExitPage : onClickNext;
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
const disabled = isLastUnit && !exitActive;
@@ -61,7 +61,7 @@ function UnitNavigation({
{renderNextButton()}
);
-}
+};
UnitNavigation.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sequence/sequence-navigation/UnitNavigationEffortEstimate.jsx b/src/courseware/course/sequence/sequence-navigation/UnitNavigationEffortEstimate.jsx
index a110a3846b..4c0c7098b9 100644
--- a/src/courseware/course/sequence/sequence-navigation/UnitNavigationEffortEstimate.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/UnitNavigationEffortEstimate.jsx
@@ -22,12 +22,12 @@ import messages from './messages';
* modulestore, which would allow us to revive the usefulness of this component again.
*/
-function UnitNavigationEffortEstimate({
+const UnitNavigationEffortEstimate = ({
children,
intl,
sequenceId,
unitId,
-}) {
+}) => {
const sequenceIds = useSelector(sequenceIdsSelector);
const sequenceIndex = sequenceIds.indexOf(sequenceId);
const nextSequenceId = sequenceIndex < sequenceIds.length - 1 ? sequenceIds[sequenceIndex + 1] : null;
@@ -55,7 +55,7 @@ function UnitNavigationEffortEstimate({
);
-}
+};
UnitNavigationEffortEstimate.propTypes = {
children: PropTypes.node,
diff --git a/src/courseware/course/share/ShareButton.jsx b/src/courseware/course/share/ShareButton.jsx
index 73473f3b0a..5304245d88 100644
--- a/src/courseware/course/share/ShareButton.jsx
+++ b/src/courseware/course/share/ShareButton.jsx
@@ -17,7 +17,7 @@ const ShareTwitterIcon = () => (
/>
);
-function ShareButton({ url }) {
+const ShareButton = ({ url }) => {
const { formatMessage } = useIntl();
const twitterUrl = stringifyUrl({
@@ -40,7 +40,7 @@ function ShareButton({ url }) {
{formatMessage(messages.shareButton)}
);
-}
+};
ShareButton.propTypes = {
url: PropTypes.string.isRequired,
diff --git a/src/courseware/course/sidebar/Sidebar.jsx b/src/courseware/course/sidebar/Sidebar.jsx
index efec70a1c4..7acfa5255d 100644
--- a/src/courseware/course/sidebar/Sidebar.jsx
+++ b/src/courseware/course/sidebar/Sidebar.jsx
@@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import SidebarContext from './SidebarContext';
import { SIDEBARS } from './sidebars';
-function Sidebar() {
+const Sidebar = () => {
const {
currentSidebar,
} = useContext(SidebarContext);
@@ -13,6 +13,6 @@ function Sidebar() {
return (
);
-}
+};
export default Sidebar;
diff --git a/src/courseware/course/sidebar/SidebarContextProvider.jsx b/src/courseware/course/sidebar/SidebarContextProvider.jsx
index 9159a1329b..a2cde920c5 100644
--- a/src/courseware/course/sidebar/SidebarContextProvider.jsx
+++ b/src/courseware/course/sidebar/SidebarContextProvider.jsx
@@ -1,6 +1,8 @@
import { breakpoints, useWindowSize } from '@edx/paragon';
import PropTypes from 'prop-types';
-import React, { useEffect, useState } from 'react';
+import React, {
+ useEffect, useState, useMemo, useCallback,
+} from 'react';
import { getLocalStorage, setLocalStorage } from '../../../data/localStorage';
import { getSessionStorage } from '../../../data/sessionStorage';
@@ -8,11 +10,11 @@ import { useModel } from '../../../generic/model-store';
import SidebarContext from './SidebarContext';
import { SIDEBARS } from './sidebars';
-export default function SidebarProvider({
+const SidebarProvider = ({
courseId,
unitId,
children,
-}) {
+}) => {
const { verifiedMode } = useModel('courseHomeMeta', courseId);
const shouldDisplayFullScreen = useWindowSize().width < breakpoints.large.minWidth;
const shouldDisplaySidebarOpen = useWindowSize().width > breakpoints.medium.minWidth;
@@ -29,37 +31,40 @@ export default function SidebarProvider({
if (verifiedMode && currentSidebar === null && initialSidebar) {
setCurrentSidebar(initialSidebar);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialSidebar, verifiedMode]);
- const onNotificationSeen = () => {
+ const onNotificationSeen = useCallback(() => {
setNotificationStatus('inactive');
setLocalStorage(`notificationStatus.${courseId}`, 'inactive');
- };
+ }, [courseId]);
- const toggleSidebar = (sidebarId) => {
+ const toggleSidebar = useCallback((sidebarId) => {
// Switch to new sidebar or hide the current sidebar
setCurrentSidebar(sidebarId === currentSidebar ? null : sidebarId);
- };
+ }, [currentSidebar]);
+
+ const contextValue = useMemo(() => ({
+ toggleSidebar,
+ onNotificationSeen,
+ setNotificationStatus,
+ currentSidebar,
+ notificationStatus,
+ upgradeNotificationCurrentState,
+ setUpgradeNotificationCurrentState,
+ shouldDisplaySidebarOpen,
+ shouldDisplayFullScreen,
+ courseId,
+ unitId,
+ }), [courseId, currentSidebar, notificationStatus, onNotificationSeen, shouldDisplayFullScreen,
+ shouldDisplaySidebarOpen, toggleSidebar, unitId, upgradeNotificationCurrentState]);
return (
-
+
{children}
);
-}
+};
SidebarProvider.propTypes = {
courseId: PropTypes.string.isRequired,
@@ -70,3 +75,5 @@ SidebarProvider.propTypes = {
SidebarProvider.defaultProps = {
children: null,
};
+
+export default SidebarProvider;
diff --git a/src/courseware/course/sidebar/SidebarTriggers.jsx b/src/courseware/course/sidebar/SidebarTriggers.jsx
index b578f41bb4..9ef7b724bb 100644
--- a/src/courseware/course/sidebar/SidebarTriggers.jsx
+++ b/src/courseware/course/sidebar/SidebarTriggers.jsx
@@ -3,7 +3,7 @@ import React, { useContext } from 'react';
import SidebarContext from './SidebarContext';
import { SIDEBAR_ORDER, SIDEBARS } from './sidebars';
-function SidebarTriggers() {
+const SidebarTriggers = () => {
const {
toggleSidebar,
currentSidebar,
@@ -25,7 +25,7 @@ function SidebarTriggers() {
})}
);
-}
+};
SidebarTriggers.propTypes = {};
diff --git a/src/courseware/course/sidebar/common/SidebarBase.jsx b/src/courseware/course/sidebar/common/SidebarBase.jsx
index 50d8ada988..a1c6651cc8 100644
--- a/src/courseware/course/sidebar/common/SidebarBase.jsx
+++ b/src/courseware/course/sidebar/common/SidebarBase.jsx
@@ -8,7 +8,7 @@ import { useEventListener } from '../../../../generic/hooks';
import messages from '../../messages';
import SidebarContext from '../SidebarContext';
-function SidebarBase({
+const SidebarBase = ({
intl,
title,
ariaLabel,
@@ -17,7 +17,7 @@ function SidebarBase({
children,
showTitleBar,
width,
-}) {
+}) => {
const {
toggleSidebar,
shouldDisplayFullScreen,
@@ -29,6 +29,7 @@ function SidebarBase({
if (type === 'learning.events.sidebar.close') {
toggleSidebar(null);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [sidebarId, toggleSidebar]);
useEventListener('message', receiveMessage);
@@ -82,7 +83,7 @@ function SidebarBase({
{children}
);
-}
+};
SidebarBase.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/common/TriggerBase.jsx b/src/courseware/course/sidebar/common/TriggerBase.jsx
index bf1e9b6432..16c2845041 100644
--- a/src/courseware/course/sidebar/common/TriggerBase.jsx
+++ b/src/courseware/course/sidebar/common/TriggerBase.jsx
@@ -2,24 +2,22 @@ import { injectIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import React from 'react';
-function SidebarTriggerBase({
+const SidebarTriggerBase = ({
onClick,
ariaLabel,
children,
-}) {
- return (
-
-
- {children}
-
-
- );
-}
+}) => (
+
+
+ {children}
+
+
+);
SidebarTriggerBase.propTypes = {
onClick: PropTypes.func.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.jsx b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.jsx
index 918a3a914c..c3dc90b1b2 100644
--- a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.jsx
+++ b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.jsx
@@ -10,7 +10,7 @@ import messages from './messages';
ensureConfig(['DISCUSSIONS_MFE_BASE_URL']);
-function DiscussionsSidebar({ intl }) {
+const DiscussionsSidebar = ({ intl }) => {
const {
unitId,
courseId,
@@ -37,7 +37,7 @@ function DiscussionsSidebar({ intl }) {
/>
);
-}
+};
DiscussionsSidebar.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.test.jsx b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.test.jsx
index 40c7032039..59c31b1cf7 100644
--- a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsSidebar.test.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/jsx-no-constructed-context-values */
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import MockAdapter from 'axios-mock-adapter';
diff --git a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.jsx b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.jsx
index 5f8dc4ab56..ef4b9944d7 100644
--- a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.jsx
+++ b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.jsx
@@ -14,10 +14,10 @@ import messages from './messages';
ensureConfig(['DISCUSSIONS_MFE_BASE_URL']);
export const ID = 'DISCUSSIONS';
-function DiscussionsTrigger({
+const DiscussionsTrigger = ({
intl,
onClick,
-}) {
+}) => {
const {
unitId,
courseId,
@@ -31,6 +31,7 @@ function DiscussionsTrigger({
if (baseUrl) {
dispatch(getCourseDiscussionTopics(courseId));
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [courseId, baseUrl]);
if (!topic?.id || !topic?.enabledInContext) {
@@ -42,7 +43,7 @@ function DiscussionsTrigger({
);
-}
+};
DiscussionsTrigger.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.test.jsx b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.test.jsx
index 18d4677d8d..f907cff99d 100644
--- a/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/discussions/DiscussionsTrigger.test.jsx
@@ -2,6 +2,7 @@ import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import MockAdapter from 'axios-mock-adapter';
import React from 'react';
+import PropTypes from 'prop-types';
import {
fireEvent, initializeMockApp, initializeTestStore, render, screen,
} from '../../../../../setupTest';
@@ -42,12 +43,19 @@ describe('Discussions Trigger', () => {
.reply(200, buildTopicsFromUnits(state.models.units));
});
+ const SidebarWrapper = ({ contextValue, onClick }) => (
+
+
+
+ );
+
+ SidebarWrapper.propTypes = {
+ contextValue: PropTypes.shape({}).isRequired,
+ onClick: PropTypes.func.isRequired,
+ };
+
function renderWithProvider(testData = {}, onClick = () => null) {
- const { container } = render(
-
-
- ,
- );
+ const { container } = render( );
return container;
}
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationIcon.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationIcon.jsx
index d8ea403038..d7fbc7d995 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationIcon.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationIcon.jsx
@@ -7,29 +7,27 @@ import React from 'react';
import messages from '../../../messages';
-function NotificationIcon({
+const NotificationIcon = ({
intl,
status,
notificationColor,
-}) {
- return (
- <>
-
- {status === 'active'
- ? (
-
- )
- : null}
- >
- );
-}
+}) => (
+ <>
+
+ {status === 'active'
+ ? (
+
+ )
+ : null}
+ >
+);
NotificationIcon.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
index bce9c899f8..3cef46a0ca 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
@@ -9,7 +9,7 @@ import SidebarBase from '../../common/SidebarBase';
import SidebarContext from '../../SidebarContext';
import NotificationTrigger, { ID } from './NotificationTrigger';
-function NotificationTray({ intl }) {
+const NotificationTray = ({ intl }) => {
const {
courseId,
onNotificationSeen,
@@ -34,6 +34,7 @@ function NotificationTray({ intl }) {
} = useModel('courseHomeMeta', courseId);
// After three seconds, update notificationSeen (to hide red dot)
+ // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => { setTimeout(onNotificationSeen, 3000); }, []);
return (
@@ -66,7 +67,7 @@ function NotificationTray({ intl }) {
);
-}
+};
NotificationTray.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
index 9028bdfb19..d7ba582e0c 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/jsx-no-constructed-context-values */
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { breakpoints } from '@edx/paragon';
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.jsx
index 73c667ba92..6819e06acc 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.jsx
@@ -11,10 +11,10 @@ import NotificationIcon from './NotificationIcon';
export const ID = 'NOTIFICATIONS';
-function NotificationTrigger({
+const NotificationTrigger = ({
intl,
onClick,
-}) {
+}) => {
const {
courseId,
notificationStatus,
@@ -61,7 +61,7 @@ function NotificationTrigger({
);
-}
+};
NotificationTrigger.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.test.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.test.jsx
index 92b86843e2..c6c264bec3 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTrigger.test.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import { Factory } from 'rosie';
import {
fireEvent, initializeTestStore, render, screen,
@@ -36,13 +37,20 @@ describe('Notification Trigger', () => {
setItemSpy.mockRestore();
});
+ const SidebarWrapper = ({ contextValue, onClick }) => (
+
+
+
+ );
+
+ SidebarWrapper.propTypes = {
+ contextValue: PropTypes.shape({}).isRequired,
+ onClick: PropTypes.func.isRequired,
+ };
+
function renderWithProvider(data, onClick = () => {
}) {
- const { container } = render(
-
-
- ,
- );
+ const { container } = render( );
return container;
}
diff --git a/src/courseware/social-share/SocialIcons.jsx b/src/courseware/social-share/SocialIcons.jsx
index 1752166c9f..6b6bfd29e7 100644
--- a/src/courseware/social-share/SocialIcons.jsx
+++ b/src/courseware/social-share/SocialIcons.jsx
@@ -19,7 +19,7 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import { useModel } from '../../generic/model-store';
-function SocialIcons({
+const SocialIcons = ({
analyticsId,
className,
courseId,
@@ -28,7 +28,7 @@ function SocialIcons({
hashtags,
intl,
socialMessage,
-}) {
+}) => {
const { marketingUrl } = useModel('coursewareMeta', courseId);
const {
@@ -104,7 +104,7 @@ function SocialIcons({
);
-}
+};
SocialIcons.defaultProps = {
analyticsId: '',
diff --git a/src/generic/CourseAccessErrorPage.jsx b/src/generic/CourseAccessErrorPage.jsx
index a88f72322d..3440382ff4 100644
--- a/src/generic/CourseAccessErrorPage.jsx
+++ b/src/generic/CourseAccessErrorPage.jsx
@@ -12,13 +12,14 @@ import { LOADED, LOADING } from '../course-home/data/slice';
import PageLoading from './PageLoading';
import messages from '../tab-page/messages';
-function CourseAccessErrorPage({ intl }) {
+const CourseAccessErrorPage = ({ intl }) => {
const { courseId } = useParams();
const dispatch = useDispatch();
const activeEnterpriseAlert = useActiveEnterpriseAlert(courseId);
useEffect(() => {
dispatch(fetchDiscussionTab(courseId));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [courseId]);
const {
@@ -54,7 +55,7 @@ function CourseAccessErrorPage({ intl }) {
>
);
-}
+};
CourseAccessErrorPage.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/generic/CourseAccessErrorPage.test.jsx b/src/generic/CourseAccessErrorPage.test.jsx
index 375466b13b..1361c391ea 100644
--- a/src/generic/CourseAccessErrorPage.test.jsx
+++ b/src/generic/CourseAccessErrorPage.test.jsx
@@ -11,7 +11,9 @@ jest.mock('react-redux', () => ({
useDispatch: () => mockDispatch,
useSelector: () => ({ courseStatus: mockCourseStatus }),
}));
-jest.mock('./PageLoading', () => () =>
);
+jest.mock('./PageLoading', () => function () {
+ return
;
+});
describe('CourseAccessErrorPage', () => {
let courseId;
diff --git a/src/generic/notices/NoticesProvider.jsx b/src/generic/notices/NoticesProvider.jsx
index e3066b7ce7..6e28f60d76 100644
--- a/src/generic/notices/NoticesProvider.jsx
+++ b/src/generic/notices/NoticesProvider.jsx
@@ -10,6 +10,7 @@ import { getNotices } from './api';
*/
const NoticesProvider = ({ children }) => {
const [isRedirected, setIsRedirected] = useState();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => {
if (getConfig().ENABLE_NOTICES) {
const data = await getNotices();
diff --git a/src/generic/tabs/Tabs.jsx b/src/generic/tabs/Tabs.jsx
index 86f08d26a3..b1a03488fc 100644
--- a/src/generic/tabs/Tabs.jsx
+++ b/src/generic/tabs/Tabs.jsx
@@ -6,7 +6,7 @@ import classNames from 'classnames';
import useIndexOfLastVisibleChild from './useIndexOfLastVisibleChild';
-export default function Tabs({ children, className, ...attrs }) {
+const Tabs = ({ children, className, ...attrs }) => {
const [
indexOfLastVisibleChild,
containerElementRef,
@@ -52,7 +52,7 @@ export default function Tabs({ children, className, ...attrs }) {
),
);
return wrappedChildren;
- }, [children, indexOfLastVisibleChild]);
+ }, [children, indexOfLastVisibleChild, invisibleStyle, overflowElementRef]);
return (
);
-}
+};
Tabs.propTypes = {
children: PropTypes.node,
@@ -74,3 +74,5 @@ Tabs.defaultProps = {
children: null,
className: undefined,
};
+
+export default Tabs;
diff --git a/src/generic/tabs/useIndexOfLastVisibleChild.js b/src/generic/tabs/useIndexOfLastVisibleChild.js
index de76589ad6..f538e12950 100644
--- a/src/generic/tabs/useIndexOfLastVisibleChild.js
+++ b/src/generic/tabs/useIndexOfLastVisibleChild.js
@@ -70,6 +70,7 @@ export default function useIndexOfLastVisibleChild() {
});
setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [windowSize, containerElementRef.current]);
return [indexOfLastVisibleChild, containerElementRef, invisibleStyle, overflowElementRef];
diff --git a/src/generic/upgrade-button/FormattedPricing.jsx b/src/generic/upgrade-button/FormattedPricing.jsx
index 960e9c44b3..2e676660d1 100644
--- a/src/generic/upgrade-button/FormattedPricing.jsx
+++ b/src/generic/upgrade-button/FormattedPricing.jsx
@@ -4,7 +4,7 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
-function FormattedPricing(props) {
+const FormattedPricing = (props) => {
const {
inline,
intl,
@@ -57,7 +57,7 @@ function FormattedPricing(props) {
>
);
-}
+};
FormattedPricing.defaultProps = {
inline: false,
diff --git a/src/generic/upgrade-button/UpgradeButton.jsx b/src/generic/upgrade-button/UpgradeButton.jsx
index dea6aa38f9..1e97094401 100644
--- a/src/generic/upgrade-button/UpgradeButton.jsx
+++ b/src/generic/upgrade-button/UpgradeButton.jsx
@@ -5,7 +5,7 @@ import { Button } from '@edx/paragon';
import FormattedPricing from './FormattedPricing';
-function UpgradeButton(props) {
+const UpgradeButton = (props) => {
const {
intl,
offer,
@@ -41,7 +41,7 @@ function UpgradeButton(props) {
);
-}
+};
UpgradeButton.defaultProps = {
offer: null,
diff --git a/src/generic/upgrade-button/UpgradeNowButton.jsx b/src/generic/upgrade-button/UpgradeNowButton.jsx
index 127e43709d..6d390235a5 100644
--- a/src/generic/upgrade-button/UpgradeNowButton.jsx
+++ b/src/generic/upgrade-button/UpgradeNowButton.jsx
@@ -5,7 +5,7 @@ import { Button } from '@edx/paragon';
import FormattedPricing from './FormattedPricing';
-function UpgradeNowButton(props) {
+const UpgradeNowButton = (props) => {
const {
intl,
offer,
@@ -39,7 +39,7 @@ function UpgradeNowButton(props) {
/>
);
-}
+};
UpgradeNowButton.defaultProps = {
offer: null,
diff --git a/src/generic/upgrade-notification/UpgradeNotification.jsx b/src/generic/upgrade-notification/UpgradeNotification.jsx
index 0ab756c2b8..c60f09b8d8 100644
--- a/src/generic/upgrade-notification/UpgradeNotification.jsx
+++ b/src/generic/upgrade-notification/UpgradeNotification.jsx
@@ -13,27 +13,23 @@ import {
SupportMissionBullet,
} from '../upsell-bullets/UpsellBullets';
-function UpsellNoFBECardContent() {
- return (
-
- );
-}
-
-function UpsellFBEFarAwayCardContent() {
- return (
-
- );
-}
-
-function UpsellFBESoonCardContent({ accessExpirationDate, timezoneFormatArgs }) {
+const UpsellNoFBECardContent = () => (
+
+);
+
+const UpsellFBEFarAwayCardContent = () => (
+
+);
+
+const UpsellFBESoonCardContent = ({ accessExpirationDate, timezoneFormatArgs }) => {
const includingAnyProgress = (
);
-}
+};
UpsellFBESoonCardContent.propTypes = {
accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired,
@@ -96,22 +92,20 @@ UpsellFBESoonCardContent.defaultProps = {
timezoneFormatArgs: {},
};
-function PastExpirationCardContent() {
- return (
-
- );
-}
+const PastExpirationCardContent = () => (
+
+);
-function ExpirationCountdown({
+const ExpirationCountdown = ({
courseId, hoursToExpiration, setupgradeNotificationCurrentState, type,
-}) {
+}) => {
let expirationText;
if (hoursToExpiration >= 24) { // More than 1 day left
// setupgradeNotificationCurrentState is available in NotificationTray (not course home)
@@ -179,7 +173,7 @@ function ExpirationCountdown({
);
}
return ({expirationText}
);
-}
+};
ExpirationCountdown.propTypes = {
courseId: PropTypes.string.isRequired,
@@ -192,9 +186,9 @@ ExpirationCountdown.defaultProps = {
type: null,
};
-function AccessExpirationDateBanner({
+const AccessExpirationDateBanner = ({
courseId, accessExpirationDate, timezoneFormatArgs, setupgradeNotificationCurrentState,
-}) {
+}) => {
if (setupgradeNotificationCurrentState) {
setupgradeNotificationCurrentState('accessDateView');
setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'accessDateView');
@@ -218,7 +212,7 @@ function AccessExpirationDateBanner({
/>
);
-}
+};
AccessExpirationDateBanner.propTypes = {
courseId: PropTypes.string.isRequired,
@@ -234,9 +228,9 @@ AccessExpirationDateBanner.defaultProps = {
setupgradeNotificationCurrentState: null,
};
-function PastExpirationDateBanner({
+const PastExpirationDateBanner = ({
courseId, accessExpirationDate, timezoneFormatArgs, setupgradeNotificationCurrentState,
-}) {
+}) => {
if (setupgradeNotificationCurrentState) {
setupgradeNotificationCurrentState('PastExpirationDate');
setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'PastExpirationDate');
@@ -260,7 +254,7 @@ function PastExpirationDateBanner({
/>
);
-}
+};
PastExpirationDateBanner.propTypes = {
courseId: PropTypes.string.isRequired,
@@ -276,7 +270,7 @@ PastExpirationDateBanner.defaultProps = {
setupgradeNotificationCurrentState: null,
};
-function UpgradeNotification({
+const UpgradeNotification = ({
accessExpiration,
contentTypeGatingEnabled,
marketingUrl,
@@ -289,17 +283,13 @@ function UpgradeNotification({
upsellPageName,
userTimezone,
verifiedMode,
-}) {
+}) => {
const dateNow = Date.now();
const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {};
const correctedTime = new Date(dateNow + timeOffsetMillis);
const accessExpirationDate = accessExpiration ? new Date(accessExpiration.expirationDate) : null;
const pastExpirationDeadline = accessExpiration ? new Date(dateNow) > accessExpirationDate : false;
- if (!verifiedMode) {
- return null;
- }
-
const eventProperties = {
org_key: org,
courserun_key: courseId,
@@ -316,8 +306,13 @@ function UpgradeNotification({
useEffect(() => {
sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.displayed', eventProperties);
sendTrackEvent('Promotion Viewed', promotionEventProperties);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
+ if (!verifiedMode) {
+ return null;
+ }
+
const logClick = () => {
sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.clicked', eventProperties);
sendTrackingLogEvent('edx.course.enrollment.upgrade.clicked', {
@@ -502,7 +497,7 @@ function UpgradeNotification({
);
-}
+};
UpgradeNotification.propTypes = {
courseId: PropTypes.string.isRequired,
diff --git a/src/generic/upsell-bullets/UpsellBullets.jsx b/src/generic/upsell-bullets/UpsellBullets.jsx
index 5557993e43..e631ebae02 100644
--- a/src/generic/upsell-bullets/UpsellBullets.jsx
+++ b/src/generic/upsell-bullets/UpsellBullets.jsx
@@ -4,14 +4,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
-function CheckmarkBullet() {
- return (
-
- );
-}
+const CheckmarkBullet = () => (
+
+);
// Must be child of a
-export function VerifiedCertBullet() {
+export const VerifiedCertBullet = () => {
const verifiedCertLink = (
);
-}
+};
// Must be child of a
-export function UnlockGradedBullet() {
+export const UnlockGradedBullet = () => {
const gradedAssignmentsInBoldText = (
);
-}
+};
// Must be child of a
-export function FullAccessBullet() {
+export const FullAccessBullet = () => {
const fullAccessInBoldText = (
);
-}
+};
// Must be child of a ,
+ }}
+ />
+
+
+
)}
- footerNode={(
-
-
- {intl.formatMessage(messages.skipForNow)}
-
-
- {intl.formatMessage(messages.beginTour)}
-
-
+ footerNode={(
+
+
+ {intl.formatMessage(messages.skipForNow)}
+
+
+ {intl.formatMessage(messages.beginTour)}
+
+
)}
- onClose={onDismiss}
- >
- {intl.formatMessage(messages.newUserModalBody, { siteName: getConfig().SITE_NAME })}
-
- );
-}
+ onClose={onDismiss}
+ >
+ {intl.formatMessage(messages.newUserModalBody, { siteName: getConfig().SITE_NAME })}
+
+);
NewUserCourseHomeTourModal.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/setupTest.js b/src/setupTest.js
index c706e943fe..955440b3de 100755
--- a/src/setupTest.js
+++ b/src/setupTest.js
@@ -168,18 +168,16 @@ function render(
...renderOptions
} = {},
) {
- function Wrapper({ children }) {
- return (
- // eslint-disable-next-line react/jsx-filename-extension
-
-
-
- {children}
-
-
-
- );
- }
+ const Wrapper = ({ children }) => (
+ // eslint-disable-next-line react/jsx-filename-extension
+
+
+
+ {children}
+
+
+
+ );
Wrapper.propTypes = {
children: PropTypes.node.isRequired,
diff --git a/src/shared/effort-estimate/EffortEstimate.jsx b/src/shared/effort-estimate/EffortEstimate.jsx
index 3a0fae4770..b747ff1f62 100644
--- a/src/shared/effort-estimate/EffortEstimate.jsx
+++ b/src/shared/effort-estimate/EffortEstimate.jsx
@@ -7,7 +7,7 @@ import messages from './messages';
// This component shows an effort estimate provided by the backend block data. Either time, activities, or both.
-function EffortEstimate(props) {
+const EffortEstimate = (props) => {
const {
block: {
effortActivities,
@@ -54,7 +54,7 @@ function EffortEstimate(props) {
{content}
);
-}
+};
EffortEstimate.defaultProps = {
className: null,
diff --git a/src/shared/links.jsx b/src/shared/links.jsx
index cabdcb7802..01713de8ec 100644
--- a/src/shared/links.jsx
+++ b/src/shared/links.jsx
@@ -6,23 +6,21 @@ import { Hyperlink } from '@edx/paragon';
import messages from '../courseware/course/course-exit/messages';
-function IntlDashboardLink({ intl }) {
- return (
-
- {intl.formatMessage(messages.dashboardLink)}
-
- );
-}
+const IntlDashboardLink = ({ intl }) => (
+
+ {intl.formatMessage(messages.dashboardLink)}
+
+);
IntlDashboardLink.propTypes = {
intl: intlShape.isRequired,
};
-function IntlIdVerificationSupportLink({ intl }) {
+const IntlIdVerificationSupportLink = ({ intl }) => {
if (!getConfig().SUPPORT_URL_ID_VERIFICATION) {
return null;
}
@@ -35,13 +33,13 @@ function IntlIdVerificationSupportLink({ intl }) {
{intl.formatMessage(messages.idVerificationSupportLink)}
);
-}
+};
IntlIdVerificationSupportLink.propTypes = {
intl: intlShape.isRequired,
};
-function IntlProfileLink({ intl }) {
+const IntlProfileLink = ({ intl }) => {
const { username } = getAuthenticatedUser();
return (
@@ -53,7 +51,7 @@ function IntlProfileLink({ intl }) {
{intl.formatMessage(messages.profileLink)}
);
-}
+};
IntlProfileLink.propTypes = {
intl: intlShape.isRequired,
diff --git a/src/shared/streak-celebration/StreakCelebrationModal.jsx b/src/shared/streak-celebration/StreakCelebrationModal.jsx
index a47ffa35df..febadc9f77 100644
--- a/src/shared/streak-celebration/StreakCelebrationModal.jsx
+++ b/src/shared/streak-celebration/StreakCelebrationModal.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/prop-types */
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
@@ -50,13 +51,17 @@ async function calculateVoucherDiscount(voucher, sku, username) {
.then(res => camelCaseObject(res));
}
-function StreakModal({
+const CloseText = ({ intl }) => (
+
+ {intl.formatMessage(messages.streakButton)}
+ . {intl.formatMessage(messages.streakButtonSrOnly)}
+
+);
+
+const StreakModal = ({
courseId, metadataModel, streakLengthToCelebrate, intl, isStreakCelebrationOpen,
closeStreakCelebration, streakDiscountCouponEnabled, verifiedMode, ...rest
-}) {
- if (!isStreakCelebrationOpen) {
- return null;
- }
+}) => {
const { org, celebrations, username } = useModel('courseHomeMeta', courseId);
const factoid = getRandomFactoid(intl, streakLengthToCelebrate);
// eslint-disable-next-line no-unused-vars
@@ -106,15 +111,11 @@ function StreakModal({
} else {
setDiscountPercent(0);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [streakDiscountCouponEnabled, username, verifiedMode]);
- function CloseText() {
- return (
-
- {intl.formatMessage(messages.streakButton)}
- . {intl.formatMessage(messages.streakButtonSrOnly)}
-
- );
+ if (!isStreakCelebrationOpen) {
+ return null;
}
let upgradeUrl;
@@ -230,12 +231,12 @@ function StreakModal({
>
)}
{ !queryingDiscount && !showOffer && (
-
+
)}
);
-}
+};
StreakModal.defaultProps = {
isStreakCelebrationOpen: false,
diff --git a/src/tab-page/LoadedTabPage.jsx b/src/tab-page/LoadedTabPage.jsx
index db31ca6d69..2ba3067d9e 100644
--- a/src/tab-page/LoadedTabPage.jsx
+++ b/src/tab-page/LoadedTabPage.jsx
@@ -15,13 +15,13 @@ import useLogistrationAlert from '../alerts/logistration-alert';
import ProductTours from '../product-tours/ProductTours';
-function LoadedTabPage({
+const LoadedTabPage = ({
activeTabSlug,
children,
courseId,
metadataModel,
unitId,
-}) {
+}) => {
const {
celebrations,
org,
@@ -85,7 +85,7 @@ function LoadedTabPage({
>
);
-}
+};
LoadedTabPage.propTypes = {
activeTabSlug: PropTypes.string.isRequired,
diff --git a/src/tab-page/LoadedTabPage.test.jsx b/src/tab-page/LoadedTabPage.test.jsx
index b4c3f9924b..ec521cca32 100644
--- a/src/tab-page/LoadedTabPage.test.jsx
+++ b/src/tab-page/LoadedTabPage.test.jsx
@@ -3,10 +3,18 @@ import { Factory } from 'rosie';
import { initializeTestStore, render, screen } from '../setupTest';
import LoadedTabPage from './LoadedTabPage';
-jest.mock('../course-tabs/CourseTabsNavigation', () => () =>
);
-jest.mock('../instructor-toolbar/InstructorToolbar', () => () =>
);
-jest.mock('../shared/streak-celebration/StreakCelebrationModal', () => () =>
);
-jest.mock('../product-tours/ProductTours', () => () =>
);
+jest.mock('../course-tabs/CourseTabsNavigation', () => function () {
+ return
;
+});
+jest.mock('../instructor-toolbar/InstructorToolbar', () => function () {
+ return
;
+});
+jest.mock('../shared/streak-celebration/StreakCelebrationModal', () => function () {
+ return
;
+});
+jest.mock('../product-tours/ProductTours', () => function () {
+ return
;
+});
describe('Loaded Tab Page', () => {
const mockData = { activeTabSlug: 'courseware', metadataModel: 'coursewareMeta' };
diff --git a/src/tab-page/TabContainer.jsx b/src/tab-page/TabContainer.jsx
index 4961d37d28..c5331f9fe8 100644
--- a/src/tab-page/TabContainer.jsx
+++ b/src/tab-page/TabContainer.jsx
@@ -6,7 +6,7 @@ import { OuterExamTimer } from '@edx/frontend-lib-special-exams';
import TabPage from './TabPage';
-export default function TabContainer(props) {
+const TabContainer = (props) => {
const {
children,
fetch,
@@ -19,6 +19,7 @@ export default function TabContainer(props) {
useEffect(() => {
// The courseId from the URL is the course we WANT to load.
dispatch(fetch(courseIdFromUrl));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [courseIdFromUrl]);
// The courseId from the store is the course we HAVE loaded. If the URL changes,
@@ -39,7 +40,7 @@ export default function TabContainer(props) {
{children}
);
-}
+};
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
@@ -47,3 +48,5 @@ TabContainer.propTypes = {
slice: PropTypes.string.isRequired,
tab: PropTypes.string.isRequired,
};
+
+export default TabContainer;
diff --git a/src/tab-page/TabContainer.test.jsx b/src/tab-page/TabContainer.test.jsx
index 3479d15e04..6052412947 100644
--- a/src/tab-page/TabContainer.test.jsx
+++ b/src/tab-page/TabContainer.test.jsx
@@ -10,7 +10,9 @@ jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatch,
}));
-jest.mock('./TabPage', () => () =>
);
+jest.mock('./TabPage', () => function () {
+ return
;
+});
describe('Tab Container', () => {
let courseId;
diff --git a/src/tab-page/TabPage.jsx b/src/tab-page/TabPage.jsx
index 24f1dd2542..5c2b692e11 100644
--- a/src/tab-page/TabPage.jsx
+++ b/src/tab-page/TabPage.jsx
@@ -17,7 +17,7 @@ import LoadedTabPage from './LoadedTabPage';
import { setCallToActionToast } from '../course-home/data/slice';
import LaunchCourseHomeTourButton from '../product-tours/newUserCourseHomeTour/LaunchCourseHomeTourButton';
-function TabPage({ intl, ...props }) {
+const TabPage = ({ intl, ...props }) => {
const {
activeTabSlug,
courseId,
@@ -95,7 +95,7 @@ function TabPage({ intl, ...props }) {
>
);
-}
+};
TabPage.defaultProps = {
courseId: null,
diff --git a/src/tab-page/TabPage.test.jsx b/src/tab-page/TabPage.test.jsx
index c6101077f3..2763b61794 100644
--- a/src/tab-page/TabPage.test.jsx
+++ b/src/tab-page/TabPage.test.jsx
@@ -10,7 +10,9 @@ import { executeThunk } from '../utils';
import * as thunks from '../course-home/data/thunks';
// We should not test `LoadedTabPage` page here, as `TabPage` is used only for passing `passthroughProps`.
-jest.mock('./LoadedTabPage', () => () =>
);
+jest.mock('./LoadedTabPage', () => function () {
+ return
;
+});
describe('Tab Page', () => {
const mockData = {