fix: first section celebration
Fix the first section celebration modal showing logic. On Nutmeg+ it's shown only after the page reload or after going directly to the second section from the course home. Going through the course with the Next/Previous buttons has no effect (which worked on Maple). Notes: - the weekly goal has the same showing logic, but I assume that is correct behavior so no changes are added for it in this commit. - showing a celebration modal for the first section completion when going directly to the first unit of the second section seems to be a bug (reproduces on Maple too)
This commit is contained in:
committed by
leangseu-edx
parent
630d44a8cc
commit
cd430ebb5d
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
@@ -43,10 +43,8 @@ const Course = ({
|
|||||||
|
|
||||||
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
|
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
|
||||||
const [firstSectionCelebrationOpen, setFirstSectionCelebrationOpen] = useState(
|
const [firstSectionCelebrationOpen, setFirstSectionCelebrationOpen] = useState(false);
|
||||||
shouldCelebrateOnSectionLoad(courseId, sequenceId, celebrateFirstSection, dispatch, celebrations),
|
|
||||||
);
|
|
||||||
// If streakLengthToCelebrate is populated, that modal takes precedence. Wait til the next load to display
|
// If streakLengthToCelebrate is populated, that modal takes precedence. Wait til the next load to display
|
||||||
// the weekly goal celebration modal.
|
// the weekly goal celebration modal.
|
||||||
const [weeklyGoalCelebrationOpen, setWeeklyGoalCelebrationOpen] = useState(
|
const [weeklyGoalCelebrationOpen, setWeeklyGoalCelebrationOpen] = useState(
|
||||||
@@ -68,6 +66,17 @@ const Course = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
||||||
|
setFirstSectionCelebrationOpen(shouldCelebrateOnSectionLoad(
|
||||||
|
courseId,
|
||||||
|
sequenceId,
|
||||||
|
celebrateFirstSection,
|
||||||
|
dispatch,
|
||||||
|
celebrations,
|
||||||
|
));
|
||||||
|
}, [sequenceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarProvider courseId={courseId} unitId={unitId}>
|
<SidebarProvider courseId={courseId} unitId={unitId}>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
useWindowSize,
|
useWindowSize,
|
||||||
} from '@edx/paragon';
|
} from '@edx/paragon';
|
||||||
|
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
import ClapsMobile from './assets/claps_280x201.gif';
|
import ClapsMobile from './assets/claps_280x201.gif';
|
||||||
import ClapsTablet from './assets/claps_456x328.gif';
|
import ClapsTablet from './assets/claps_456x328.gif';
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
@@ -19,12 +20,13 @@ import { useModel } from '../../../generic/model-store';
|
|||||||
const CelebrationModal = ({
|
const CelebrationModal = ({
|
||||||
courseId, intl, isOpen, onClose, ...rest
|
courseId, intl, isOpen, onClose, ...rest
|
||||||
}) => {
|
}) => {
|
||||||
const { org } = useModel('courseHomeMeta', courseId);
|
const { org, celebrations } = useModel('courseHomeMeta', courseId);
|
||||||
|
const dispatch = useDispatch();
|
||||||
const wideScreen = useWindowSize().width >= breakpoints.small.minWidth;
|
const wideScreen = useWindowSize().width >= breakpoints.small.minWidth;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
recordFirstSectionCelebration(org, courseId);
|
recordFirstSectionCelebration(org, courseId, celebrations, dispatch);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|||||||
@@ -15,9 +15,20 @@ function handleNextSectionCelebration(sequenceId, nextSequenceId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordFirstSectionCelebration(org, courseId) {
|
function recordFirstSectionCelebration(org, courseId, celebrations, dispatch) {
|
||||||
// Tell the LMS
|
// Tell the LMS
|
||||||
postCelebrationComplete(courseId, { first_section: false });
|
postCelebrationComplete(courseId, { first_section: false });
|
||||||
|
// Update our local copy of course data from LMS
|
||||||
|
dispatch(updateModel({
|
||||||
|
modelType: 'courseHomeMeta',
|
||||||
|
model: {
|
||||||
|
id: courseId,
|
||||||
|
celebrations: {
|
||||||
|
...celebrations,
|
||||||
|
firstSection: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
// Tell our analytics
|
// Tell our analytics
|
||||||
const { administrator } = getAuthenticatedUser();
|
const { administrator } = getAuthenticatedUser();
|
||||||
|
|||||||
15
src/courseware/course/celebration/utils.test.jsx
Normal file
15
src/courseware/course/celebration/utils.test.jsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { recordFirstSectionCelebration } from './utils';
|
||||||
|
|
||||||
|
jest.mock('@edx/frontend-platform/analytics');
|
||||||
|
jest.mock('./data/api');
|
||||||
|
jest.mock('@edx/frontend-platform/auth', () => ({
|
||||||
|
getAuthenticatedUser: jest.fn(() => ({ administrator: 'admin' })),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('recordFirstSectionCelebration', () => {
|
||||||
|
it('updates the local copy of the course data from the LMS', async () => {
|
||||||
|
const dispatchMock = jest.fn();
|
||||||
|
recordFirstSectionCelebration('org', 'courseId', 'celebration', dispatchMock);
|
||||||
|
expect(dispatchMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user