import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/analytics'; import { FormattedDate, FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n'; import { setLocalStorage } from '../../data/localStorage'; import { UpgradeButton } from '../upgrade-button'; import { VerifiedCertBullet, UnlockGradedBullet, FullAccessBullet, SupportMissionBullet, } from '../upsell-bullets/UpsellBullets'; function UpsellNoFBECardContent() { return ( ); } function UpsellFBEFarAwayCardContent() { return ( ); } function UpsellFBESoonCardContent({ accessExpirationDate, timezoneFormatArgs }) { const includingAnyProgress = ( ); const date = ( ); const benefitsOfUpgrading = ( ); return (

); } UpsellFBESoonCardContent.propTypes = { accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired, timezoneFormatArgs: PropTypes.shape({ timeZone: PropTypes.string, }), }; UpsellFBESoonCardContent.defaultProps = { timezoneFormatArgs: {}, }; function ExpirationCountdown({ hoursToExpiration, setupgradeNotificationCurrentState, type }) { let expirationText; if (hoursToExpiration >= 24) { // setupgradeNotificationCurrentState is available in NotificationTray (not course home) if (setupgradeNotificationCurrentState) { if (type === 'access') { setupgradeNotificationCurrentState('accessDaysLeft'); setLocalStorage('upgradeNotificationCurrentState', 'accessDaysLeft'); } if (type === 'offer') { setupgradeNotificationCurrentState('FPDdaysLeft'); setLocalStorage('upgradeNotificationCurrentState', 'FPDdaysLeft'); } } expirationText = ( ); } else if (hoursToExpiration >= 1) { // setupgradeNotificationCurrentState is available in NotificationTray (not course home) if (setupgradeNotificationCurrentState) { if (type === 'access') { setupgradeNotificationCurrentState('accessHoursLeft'); setLocalStorage('upgradeNotificationCurrentState', 'accessHoursLeft'); } if (type === 'offer') { setupgradeNotificationCurrentState('FPDHoursLeft'); setLocalStorage('upgradeNotificationCurrentState', 'FPDHoursLeft'); } } expirationText = ( ); } else { // setupgradeNotificationCurrentState is available in NotificationTray (not course home) if (setupgradeNotificationCurrentState) { if (type === 'access') { setupgradeNotificationCurrentState('accessLastHour'); setLocalStorage('upgradeNotificationCurrentState', 'accessLastHour'); } if (type === 'offer') { setupgradeNotificationCurrentState('FPDLastHour'); setLocalStorage('upgradeNotificationCurrentState', 'FPDLastHour'); } } expirationText = ( ); } return (
{expirationText}
); } ExpirationCountdown.propTypes = { hoursToExpiration: PropTypes.number.isRequired, setupgradeNotificationCurrentState: PropTypes.func, type: PropTypes.string, }; ExpirationCountdown.defaultProps = { setupgradeNotificationCurrentState: null, type: null, }; function AccessExpirationDateBanner({ accessExpirationDate, timezoneFormatArgs, setupgradeNotificationCurrentState }) { if (setupgradeNotificationCurrentState) { setupgradeNotificationCurrentState('accessDateView'); setLocalStorage('upgradeNotificationCurrentState', 'accessDateView'); } return (
), }} />
); } AccessExpirationDateBanner.propTypes = { accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired, timezoneFormatArgs: PropTypes.shape({ timeZone: PropTypes.string, }), setupgradeNotificationCurrentState: PropTypes.func, }; AccessExpirationDateBanner.defaultProps = { timezoneFormatArgs: {}, setupgradeNotificationCurrentState: null, }; function UpgradeNotification({ accessExpiration, contentTypeGatingEnabled, courseId, offer, org, setupgradeNotificationCurrentState, shouldDisplayBorder, timeOffsetMillis, upsellPageName, userTimezone, verifiedMode, }) { const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {}; const correctedTime = new Date(Date.now() + timeOffsetMillis); if (!verifiedMode) { return null; } const eventProperties = { org_key: org, courserun_key: courseId, }; const promotionEventProperties = { creative: 'sidebarupsell', name: 'In-Course Verification Prompt', position: 'sidebar-message', promotion_id: 'courseware_verified_certificate_upsell', ...eventProperties, }; useEffect(() => { sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.displayed', eventProperties); sendTrackEvent('Promotion Viewed', promotionEventProperties); }, []); const logClick = () => { sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.clicked', eventProperties); sendTrackingLogEvent('edx.course.enrollment.upgrade.clicked', { ...eventProperties, location: 'sidebar-message', }); sendTrackEvent('Promotion Clicked', promotionEventProperties); sendTrackEvent('edx.bi.ecommerce.upsell_links_clicked', { ...eventProperties, linkCategory: 'green_upgrade', linkName: `${upsellPageName}_green`, linkType: 'button', pageName: upsellPageName, }); }; /* There are 4 parts that change in the upgrade card: upgradeNotificationHeaderText expirationBanner upsellMessage offerCode */ let upgradeNotificationHeaderText; let expirationBanner; let upsellMessage; let offerCode; if (!!accessExpiration && !!contentTypeGatingEnabled) { const accessExpirationDate = new Date(accessExpiration.expirationDate); const hoursToAccessExpiration = Math.floor((accessExpirationDate - correctedTime) / 1000 / 60 / 60); if (hoursToAccessExpiration >= (7 * 24)) { if (offer) { // countdown to the first purchase discount if there is one const hoursToDiscountExpiration = Math.floor((new Date(offer.expirationDate) - correctedTime) / 1000 / 60 / 60); upgradeNotificationHeaderText = ( ); expirationBanner = ( ); } else { upgradeNotificationHeaderText = ( ); expirationBanner = ( ); } upsellMessage = ; } else { // more urgent messaging if there's less than 7 days left to access expiration upgradeNotificationHeaderText = ( ); expirationBanner = ( ); upsellMessage = ( ); } } else { // FBE is turned off upgradeNotificationHeaderText = ( ); upsellMessage = (); } if (offer) { // if there's a first purchase discount, message the code at the bottom offerCode = (
{offer.code}), }} />
); } return (

{upgradeNotificationHeaderText}

{expirationBanner}
{upsellMessage}
{offerCode}
); } UpgradeNotification.propTypes = { courseId: PropTypes.string.isRequired, org: PropTypes.string.isRequired, accessExpiration: PropTypes.shape({ expirationDate: PropTypes.string, }), contentTypeGatingEnabled: PropTypes.bool, offer: PropTypes.shape({ expirationDate: PropTypes.string, percentage: PropTypes.number, code: PropTypes.string, }), shouldDisplayBorder: PropTypes.bool, setupgradeNotificationCurrentState: PropTypes.func, timeOffsetMillis: PropTypes.number, upsellPageName: PropTypes.string.isRequired, userTimezone: PropTypes.string, verifiedMode: PropTypes.shape({ currencySymbol: PropTypes.string.isRequired, price: PropTypes.number.isRequired, upgradeUrl: PropTypes.string.isRequired, }), }; UpgradeNotification.defaultProps = { accessExpiration: null, contentTypeGatingEnabled: false, offer: null, setupgradeNotificationCurrentState: null, shouldDisplayBorder: null, timeOffsetMillis: 0, userTimezone: null, verifiedMode: null, }; export default injectIntl(UpgradeNotification);