Compare commits
1 Commits
2u/main
...
schen/upse
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb0f48f08 |
2
.env
2
.env
@@ -41,4 +41,4 @@ ACCOUNT_PROFILE_URL=''
|
|||||||
ENABLE_NOTICES=''
|
ENABLE_NOTICES=''
|
||||||
CAREER_LINK_URL=''
|
CAREER_LINK_URL=''
|
||||||
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
||||||
EXPERIMENT_08_23_VAN_PAINTED_DOOR=true
|
EXPERIMENT_08_23_VAN_PAINTED_DOOR='true'
|
||||||
|
|||||||
@@ -48,3 +48,4 @@ ACCOUNT_PROFILE_URL='http://localhost:1995'
|
|||||||
ENABLE_NOTICES=''
|
ENABLE_NOTICES=''
|
||||||
CAREER_LINK_URL=''
|
CAREER_LINK_URL=''
|
||||||
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
OPTIMIZELY_FULL_STACK_SDK_KEY=''
|
||||||
|
EXPERIMENT_08_23_VAN_PAINTED_DOOR=true
|
||||||
|
|||||||
29
src/containers/CertificatePreviewModal/hooks.js
Normal file
29
src/containers/CertificatePreviewModal/hooks.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
|
import { reduxHooks } from 'hooks';
|
||||||
|
import messages from './messages';
|
||||||
|
|
||||||
|
export const useCertificatePreviewData = () => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
const selectedCardId = reduxHooks.useCertificatePreviewData().cardId;
|
||||||
|
|
||||||
|
const { courseId } = reduxHooks.useCardCourseRunData(selectedCardId) || {};
|
||||||
|
|
||||||
|
const courseTitle = courseId;
|
||||||
|
const header = formatMessage(messages.previewTitle, { courseTitle });
|
||||||
|
|
||||||
|
const closePreviewModal = reduxHooks.useUpdateCertificatePreviewModalCallback(null);
|
||||||
|
|
||||||
|
const getCertificatePreviewUrl = () => `${getConfig().LMS_BASE_URL}/certificates/upsell/course/${courseId}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
showModal: selectedCardId != null,
|
||||||
|
header,
|
||||||
|
closePreviewModal,
|
||||||
|
getCertificatePreviewUrl,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useCertificatePreviewData;
|
||||||
48
src/containers/CertificatePreviewModal/index.jsx
Normal file
48
src/containers/CertificatePreviewModal/index.jsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
ModalDialog,
|
||||||
|
} from '@edx/paragon';
|
||||||
|
import { UpgradeButton } from '../CourseCard/components/CourseCardActions/UpgradeButton';
|
||||||
|
import useCertificatePreviewData from './hooks';
|
||||||
|
|
||||||
|
export const CertificatePreviewModal = ({
|
||||||
|
cardId,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
showModal,
|
||||||
|
header,
|
||||||
|
closePreviewModal,
|
||||||
|
getCertificatePreviewUrl,
|
||||||
|
} = useCertificatePreviewData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalDialog
|
||||||
|
isOpen={showModal}
|
||||||
|
onClose={closePreviewModal}
|
||||||
|
hasCloseButton
|
||||||
|
isFullscreenOnMobile
|
||||||
|
size="lg"
|
||||||
|
className="p-4 px-4.5"
|
||||||
|
title={header}
|
||||||
|
>
|
||||||
|
<h3>{header}</h3>
|
||||||
|
<div>
|
||||||
|
<iframe
|
||||||
|
title={header}
|
||||||
|
src={getCertificatePreviewUrl()}
|
||||||
|
width={725}
|
||||||
|
height={400}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<UpgradeButton
|
||||||
|
cardId={cardId}
|
||||||
|
/>
|
||||||
|
</ModalDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
CertificatePreviewModal.propTypes = {
|
||||||
|
cardId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CertificatePreviewModal;
|
||||||
12
src/containers/CertificatePreviewModal/messages.js
Normal file
12
src/containers/CertificatePreviewModal/messages.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/* eslint-disable quotes */
|
||||||
|
import { StrictDict } from 'utils';
|
||||||
|
|
||||||
|
export const messages = StrictDict({
|
||||||
|
previewTitle: {
|
||||||
|
id: 'learner-dash.certificatePreview.title',
|
||||||
|
description: 'The title of the email settings modal',
|
||||||
|
defaultMessage: 'Your certificate preview for {courseTitle} ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default messages;
|
||||||
@@ -47,6 +47,7 @@ export const useCardDetailsData = ({ cardId }) => {
|
|||||||
} = reduxHooks.useCardEntitlementData(cardId);
|
} = reduxHooks.useCardEntitlementData(cardId);
|
||||||
|
|
||||||
const openSessionModal = reduxHooks.useUpdateSelectSessionModalCallback(cardId);
|
const openSessionModal = reduxHooks.useUpdateSelectSessionModalCallback(cardId);
|
||||||
|
const openCertificatePreview = reduxHooks.useUpdateCertificatePreviewModalCallback(cardId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
providerName: providerName || formatMessage(messages.unknownProviderName),
|
providerName: providerName || formatMessage(messages.unknownProviderName),
|
||||||
@@ -57,6 +58,7 @@ export const useCardDetailsData = ({ cardId }) => {
|
|||||||
openSessionModal,
|
openSessionModal,
|
||||||
courseNumber,
|
courseNumber,
|
||||||
changeOrLeaveSessionMessage: formatMessage(messages.changeOrLeaveSessionButton),
|
changeOrLeaveSessionMessage: formatMessage(messages.changeOrLeaveSessionButton),
|
||||||
|
openCertificatePreview,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,23 +16,35 @@ export const CourseCardDetails = ({ cardId }) => {
|
|||||||
openSessionModal,
|
openSessionModal,
|
||||||
courseNumber,
|
courseNumber,
|
||||||
changeOrLeaveSessionMessage,
|
changeOrLeaveSessionMessage,
|
||||||
|
openCertificatePreview,
|
||||||
} = useCardDetailsData({ cardId });
|
} = useCardDetailsData({ cardId });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="small" data-testid="CourseCardDetails">
|
<div>
|
||||||
{providerName} • {courseNumber}
|
<span className="small" data-testid="CourseCardDetails">
|
||||||
{!(isEntitlement && !isFulfilled) && accessMessage && (
|
{providerName} • {courseNumber}
|
||||||
` • ${accessMessage}`
|
{!(isEntitlement && !isFulfilled) && accessMessage && (
|
||||||
)}
|
` • ${accessMessage}`
|
||||||
{isEntitlement && isFulfilled && canChange ? (
|
)}
|
||||||
<>
|
{isEntitlement && isFulfilled && canChange ? (
|
||||||
{' • '}
|
<>
|
||||||
<Button variant="link" size="inline" className="m-0 p-0" onClick={openSessionModal}>
|
{' • '}
|
||||||
{changeOrLeaveSessionMessage}
|
<Button variant="link" size="inline" className="m-0 p-0" onClick={openSessionModal}>
|
||||||
</Button>
|
{changeOrLeaveSessionMessage}
|
||||||
</>
|
</Button>
|
||||||
) : null}
|
</>
|
||||||
</span>
|
) : null}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
size="inline"
|
||||||
|
className="float-right"
|
||||||
|
data-testid="certificate-preview"
|
||||||
|
onClick={openCertificatePreview}
|
||||||
|
>
|
||||||
|
Preview Your Certificate
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { MoreVert } from '@edx/paragon/icons';
|
|||||||
import { StrictDict } from '@edx/react-unit-test-utils';
|
import { StrictDict } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import EmailSettingsModal from 'containers/EmailSettingsModal';
|
import EmailSettingsModal from 'containers/EmailSettingsModal';
|
||||||
|
import CertificatePreviewModal from 'containers/CertificatePreviewModal';
|
||||||
import UnenrollConfirmModal from 'containers/UnenrollConfirmModal';
|
import UnenrollConfirmModal from 'containers/UnenrollConfirmModal';
|
||||||
import { reduxHooks } from 'hooks';
|
import { reduxHooks } from 'hooks';
|
||||||
import SocialShareMenu from './SocialShareMenu';
|
import SocialShareMenu from './SocialShareMenu';
|
||||||
@@ -32,6 +33,7 @@ export const CourseCardMenu = ({ cardId }) => {
|
|||||||
const { shouldShowUnenrollItem, shouldShowDropdown } = useOptionVisibility(cardId);
|
const { shouldShowUnenrollItem, shouldShowDropdown } = useOptionVisibility(cardId);
|
||||||
const { isMasquerading } = reduxHooks.useMasqueradeData();
|
const { isMasquerading } = reduxHooks.useMasqueradeData();
|
||||||
const { isEmailEnabled } = reduxHooks.useCardEnrollmentData(cardId);
|
const { isEmailEnabled } = reduxHooks.useCardEnrollmentData(cardId);
|
||||||
|
const showCertificatePreviewModal = reduxHooks.useShowCertificatePreviewModal(cardId);
|
||||||
|
|
||||||
if (!shouldShowDropdown) {
|
if (!shouldShowDropdown) {
|
||||||
return null;
|
return null;
|
||||||
@@ -73,6 +75,11 @@ export const CourseCardMenu = ({ cardId }) => {
|
|||||||
cardId={cardId}
|
cardId={cardId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showCertificatePreviewModal && (
|
||||||
|
<CertificatePreviewModal
|
||||||
|
cardId={cardId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ import PaintedDoorExperimentProvider from 'widgets/RecommendationsPaintedDoorBtn
|
|||||||
export const AppWrapper = ({
|
export const AppWrapper = ({
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
if (process.env.EXPERIMENT_08_23_VAN_PAINTED_DOOR) {
|
console.log(`process.env.EXPERIMENT_08_23_VAN_PAINTED_DOOR = ${Boolean(process.env.EXPERIMENT_08_23_VAN_PAINTED_DOOR)}`);
|
||||||
return (
|
return (
|
||||||
<PaintedDoorExperimentProvider>
|
<PaintedDoorExperimentProvider>
|
||||||
{children}
|
{children}
|
||||||
</PaintedDoorExperimentProvider>
|
</PaintedDoorExperimentProvider>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return children;
|
|
||||||
};
|
};
|
||||||
AppWrapper.propTypes = {
|
AppWrapper.propTypes = {
|
||||||
children: PropTypes.oneOfType([
|
children: PropTypes.oneOfType([
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const initialState = {
|
|||||||
suggestedCourses: [],
|
suggestedCourses: [],
|
||||||
filterState: {},
|
filterState: {},
|
||||||
selectSessionModal: {},
|
selectSessionModal: {},
|
||||||
|
certificatePreviewModal: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cardId = (val) => `card-${val}`;
|
export const cardId = (val) => `card-${val}`;
|
||||||
@@ -48,6 +49,10 @@ const app = createSlice({
|
|||||||
...state,
|
...state,
|
||||||
selectSessionModal: { cardId: payload },
|
selectSessionModal: { cardId: payload },
|
||||||
}),
|
}),
|
||||||
|
updateCertificatePreviewModal: (state, { payload }) => ({
|
||||||
|
...state,
|
||||||
|
certificatePreviewModal: { cardId: payload },
|
||||||
|
}),
|
||||||
setPageNumber: (state, { payload }) => ({ ...state, pageNumber: payload }),
|
setPageNumber: (state, { payload }) => ({ ...state, pageNumber: payload }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ export const showSelectSessionModal = createSelector(
|
|||||||
(data) => data.cardId != null,
|
(data) => data.cardId != null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const showCertificatePreviewModal = createSelector(
|
||||||
|
[simpleSelectors.certificatePreviewModal],
|
||||||
|
(data) => data.cardId != null,
|
||||||
|
);
|
||||||
|
|
||||||
export default StrictDict({
|
export default StrictDict({
|
||||||
numCourses,
|
numCourses,
|
||||||
hasCourses,
|
hasCourses,
|
||||||
hasAvailableDashboards,
|
hasAvailableDashboards,
|
||||||
showSelectSessionModal,
|
showSelectSessionModal,
|
||||||
|
showCertificatePreviewModal,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const simpleSelectors = StrictDict({
|
|||||||
emailConfirmation: mkSimpleSelector(app => app.emailConfirmation),
|
emailConfirmation: mkSimpleSelector(app => app.emailConfirmation),
|
||||||
enterpriseDashboard: mkSimpleSelector(app => app.enterpriseDashboard || {}),
|
enterpriseDashboard: mkSimpleSelector(app => app.enterpriseDashboard || {}),
|
||||||
selectSessionModal: mkSimpleSelector(app => app.selectSessionModal),
|
selectSessionModal: mkSimpleSelector(app => app.selectSessionModal),
|
||||||
|
certificatePreviewModal: mkSimpleSelector(app => app.certificatePreviewModal),
|
||||||
pageNumber: mkSimpleSelector(app => app.pageNumber),
|
pageNumber: mkSimpleSelector(app => app.pageNumber),
|
||||||
socialShareSettings: mkSimpleSelector(app => app.socialShareSettings),
|
socialShareSettings: mkSimpleSelector(app => app.socialShareSettings),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export const useEmailConfirmationData = () => useSelector(selectors.emailConfirm
|
|||||||
export const useEnterpriseDashboardData = () => useSelector(selectors.enterpriseDashboard);
|
export const useEnterpriseDashboardData = () => useSelector(selectors.enterpriseDashboard);
|
||||||
export const usePlatformSettingsData = () => useSelector(selectors.platformSettings);
|
export const usePlatformSettingsData = () => useSelector(selectors.platformSettings);
|
||||||
export const useSelectSessionModalData = () => useSelector(selectors.selectSessionModal);
|
export const useSelectSessionModalData = () => useSelector(selectors.selectSessionModal);
|
||||||
|
export const useCertificatePreviewData = () => useSelector(selectors.certificatePreviewModal);
|
||||||
|
|
||||||
export const useSocialShareSettings = () => useSelector(selectors.socialShareSettings);
|
export const useSocialShareSettings = () => useSelector(selectors.socialShareSettings);
|
||||||
|
|
||||||
/** global-level meta-selectors **/
|
/** global-level meta-selectors **/
|
||||||
@@ -22,6 +24,7 @@ export const useCurrentCourseList = (opts) => useSelector(
|
|||||||
state => selectors.currentList(state, opts),
|
state => selectors.currentList(state, opts),
|
||||||
);
|
);
|
||||||
export const useShowSelectSessionModal = () => useSelector(selectors.showSelectSessionModal);
|
export const useShowSelectSessionModal = () => useSelector(selectors.showSelectSessionModal);
|
||||||
|
export const useShowCertificatePreviewModal = () => useSelector(selectors.showCertificatePreviewModal);
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
export const useCourseCardData = (selector) => (cardId) => useSelector(
|
export const useCourseCardData = (selector) => (cardId) => useSelector(
|
||||||
@@ -67,6 +70,11 @@ export const useUpdateSelectSessionModalCallback = (cardId) => {
|
|||||||
return () => dispatch(actions.updateSelectSessionModal(cardId));
|
return () => dispatch(actions.updateSelectSessionModal(cardId));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useUpdateCertificatePreviewModalCallback = (cardId) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return () => dispatch(actions.updateCertificatePreviewModal(cardId));
|
||||||
|
};
|
||||||
|
|
||||||
export const useTrackCourseEvent = (tracker, cardId, ...args) => {
|
export const useTrackCourseEvent = (tracker, cardId, ...args) => {
|
||||||
const { courseId } = module.useCardCourseRunData(cardId);
|
const { courseId } = module.useCardCourseRunData(cardId);
|
||||||
return (e) => tracker(courseId, ...args)(e);
|
return (e) => tracker(courseId, ...args)(e);
|
||||||
|
|||||||
Reference in New Issue
Block a user