diff --git a/src/alerts/course-start-alert/CourseStartAlert.jsx b/src/alerts/course-start-alert/CourseStartAlert.jsx index 42f3a0184f..8c168d3909 100644 --- a/src/alerts/course-start-alert/CourseStartAlert.jsx +++ b/src/alerts/course-start-alert/CourseStartAlert.jsx @@ -40,7 +40,7 @@ const CourseStartAlert = ({ payload }) => { ); if (delta < DAY_MS) { return ( - + { } return ( - + ({ + useSelector: jest.fn(), +})); + +describe('LiveTab', () => { + afterEach(() => { + jest.clearAllMocks(); + document.body.innerHTML = ''; + }); + + it('renders iframe from liveModel using dangerouslySetInnerHTML', () => { + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '', + }, + }, + }, + })); + + render(); + + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe).toBeInTheDocument(); + expect(iframe.src).toBe('about:blank'); + }); + + it('adds classes to iframe after mount', () => { + document.body.innerHTML = ` +
+ +
+ `; + + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '', + }, + }, + }, + })); + + render(); + + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe.className).toContain('vh-100'); + expect(iframe.className).toContain('w-100'); + expect(iframe.className).toContain('border-0'); + }); + + it('does not throw if iframe is not found in DOM', () => { + useSelector.mockImplementation((selector) => selector({ + courseHome: { courseId: 'course-v1:test+id+2024' }, + models: { + live: { + 'course-v1:test+id+2024': { + iframe: '
No iframe here
', + }, + }, + }, + })); + + expect(() => render()).not.toThrow(); + const iframe = document.getElementById('lti-tab-embed'); + expect(iframe).toBeNull(); + }); +}); diff --git a/src/course-home/outline-tab/DateSummary.jsx b/src/course-home/outline-tab/DateSummary.jsx index edff43a7d2..ff3981b6dd 100644 --- a/src/course-home/outline-tab/DateSummary.jsx +++ b/src/course-home/outline-tab/DateSummary.jsx @@ -5,6 +5,8 @@ import { FormattedDate } from '@edx/frontend-platform/i18n'; import React from 'react'; import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { useWindowSize, breakpoints } from '@openedx/paragon'; import { useModel } from '../../generic/model-store'; import { isLearnerAssignment } from '../dates-tab/utils'; import './DateSummary.scss'; @@ -19,6 +21,7 @@ const DateSummary = ({ const { org, } = useModel('courseHomeMeta', courseId); + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; const linkedTitle = dateBlock.link && isLearnerAssignment(dateBlock); const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {}; @@ -35,7 +38,7 @@ const DateSummary = ({ }; return ( -
  • +
  • diff --git a/src/course-home/outline-tab/widgets/CourseDates.jsx b/src/course-home/outline-tab/widgets/CourseDates.jsx index 0db9e2e5a6..b255df08a9 100644 --- a/src/course-home/outline-tab/widgets/CourseDates.jsx +++ b/src/course-home/outline-tab/widgets/CourseDates.jsx @@ -1,5 +1,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; +import classNames from 'classnames'; +import { useWindowSize, breakpoints } from '@openedx/paragon'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; @@ -22,6 +24,7 @@ const CourseDates = ({ datesTabLink, }, } = useModel('outline', courseId); + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; if (courseDateBlocks.length === 0) { return null; @@ -40,7 +43,10 @@ const CourseDates = ({ /> ))} - + {intl.formatMessage(messages.allDates)}
    diff --git a/src/course-home/outline-tab/widgets/CourseHandouts.jsx b/src/course-home/outline-tab/widgets/CourseHandouts.jsx index ac90adad8b..e210f4b4e4 100644 --- a/src/course-home/outline-tab/widgets/CourseHandouts.jsx +++ b/src/course-home/outline-tab/widgets/CourseHandouts.jsx @@ -1,5 +1,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; +import { useWindowSize, breakpoints } from '@openedx/paragon'; +import classNames from 'classnames'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; @@ -14,6 +16,7 @@ const CourseHandouts = ({ intl }) => { const { handoutsHtml, } = useModel('outline', courseId); + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; if (!handoutsHtml) { return null; @@ -23,7 +26,7 @@ const CourseHandouts = ({ intl }) => {

    {intl.formatMessage(messages.handouts)}

    diff --git a/src/course-home/outline-tab/widgets/CourseTools.jsx b/src/course-home/outline-tab/widgets/CourseTools.jsx index 62ef499000..402ad871ba 100644 --- a/src/course-home/outline-tab/widgets/CourseTools.jsx +++ b/src/course-home/outline-tab/widgets/CourseTools.jsx @@ -9,6 +9,8 @@ import { faBookmark, faCertificate, faInfo, faCalendar, faStar, } from '@fortawesome/free-solid-svg-icons'; import { faNewspaper } from '@fortawesome/free-regular-svg-icons'; +import { useWindowSize, breakpoints } from '@openedx/paragon'; +import classNames from 'classnames'; import messages from '../messages'; import { useModel } from '../../../generic/model-store'; @@ -22,6 +24,7 @@ const CourseTools = ({ intl }) => { const { courseTools, } = useModel('outline', courseId); + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; if (courseTools.length === 0) { return null; @@ -66,14 +69,14 @@ const CourseTools = ({ intl }) => {

    {intl.formatMessage(messages.tools)}

    diff --git a/src/course-home/outline-tab/widgets/FlagButton.jsx b/src/course-home/outline-tab/widgets/FlagButton.jsx index 40848a2c40..7cfebbcb91 100644 --- a/src/course-home/outline-tab/widgets/FlagButton.jsx +++ b/src/course-home/outline-tab/widgets/FlagButton.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { useWindowSize, breakpoints } from '@openedx/paragon'; const FlagButton = ({ buttonIcon, @@ -8,29 +9,43 @@ const FlagButton = ({ text, handleSelect, isSelected, -}) => ( - -); +}) => { + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; + + return ( + + ); +}; FlagButton.propTypes = { buttonIcon: PropTypes.element.isRequired, diff --git a/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx b/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx index 1c1592193f..44532f8fff 100644 --- a/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx +++ b/src/course-home/outline-tab/widgets/WeeklyLearningGoalCard.jsx @@ -2,7 +2,10 @@ import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import PropTypes from 'prop-types'; -import { Form, Card, Icon } from '@openedx/paragon'; +import { + Form, Card, Icon, useWindowSize, breakpoints, +} from '@openedx/paragon'; +import classNames from 'classnames'; import { history } from '@edx/frontend-platform'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; @@ -23,6 +26,7 @@ const WeeklyLearningGoalCard = ({ const { courseId, } = useSelector(state => state.courseHome); + const wideScreen = useWindowSize().width >= breakpoints.medium.minWidth; const { isMasquerading, @@ -94,11 +98,11 @@ const WeeklyLearningGoalCard = ({ data-testid="weekly-learning-goal-card" > {intl.formatMessage(messages.setWeeklyGoal)}
    )} subtitle={intl.formatMessage(messages.setWeeklyGoalDetail)} /> - +
    handleSubscribeToReminders(event)} disabled={!daysPerWeekGoal} + className={classNames({ small: !wideScreen })} > - {intl.formatMessage(messages.setGoalReminder)} + {wideScreen + ? intl.formatMessage(messages.setGoalReminder) + : {intl.formatMessage(messages.setGoalReminder)}}
    {isGetReminderSelected && ( -
    +
    { const [showShortMessage, setShowShortMessage] = useState(messageCanBeShortened); const dispatch = useDispatch(); + const alertRef = useRef(null); if (!welcomeMessageHtml) { return null; } + useEffect(() => { + // TODO: Temporary solution due to a bug in the Paragon Alert component + // that prevents changing the button sizes. Delete after correction. + // Issue: https://github.com/openedx/paragon/issues/3205 + if (alertRef.current) { + const buttons = alertRef.current.querySelectorAll('button.btn-sm'); + buttons.forEach(btn => btn.classList.remove('btn-sm')); + } + }, [showShortMessage]); + return ( { diff --git a/src/generic/upgrade-notification/UpgradeNotification.jsx b/src/generic/upgrade-notification/UpgradeNotification.jsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/index.scss b/src/index.scss index f4ae867e15..e2a032dcba 100755 --- a/src/index.scss +++ b/src/index.scss @@ -446,12 +446,12 @@ .course-outline-tab .pgn__card { .pgn__card-header { display: block; - + .pgn__card-header-content { margin-top: 0; } } - + .pgn__card-header-actions { margin-left: 0; } @@ -472,6 +472,7 @@ @import "course-home/progress-tab/grades/course-grade/GradeBar.scss"; @import "courseware/course/course-exit/CourseRecommendations"; @import "product-tours/newUserCourseHomeTour/NewUserCourseHomeTourModal.scss"; +@import "alerts/course-start-alert/CourseStartAlert.scss"; @import "course-home/courseware-search/courseware-search.scss"; @import "course-tabs/course-tabs-navigation.scss"; @import "courseware/course/sidebar/common/SidebarBase.scss";