From 5fb6bca7be13960911170435cbed9a4abea5d020 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 30 Jan 2025 10:35:58 -0300 Subject: [PATCH] fix: Refactored Chat to be easier to read --- src/constants.ts | 15 +++-- src/courseware/course/chat/Chat.jsx | 91 +++++++++++++---------------- 2 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 20f7d35d15..1f57ad3b05 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -18,7 +18,7 @@ export const DECODE_ROUTES = { ], REDIRECT_HOME: 'home/:courseId', REDIRECT_SURVEY: 'survey/:courseId', -} as const satisfies Readonly<{ [k: string]: string | readonly string[] }>; +} as const satisfies Readonly<{ [k: string]: string | readonly string[]; }>; export const ROUTES = { UNSUBSCRIBE: '/goal-unsubscribe/:token', @@ -27,7 +27,7 @@ export const ROUTES = { DASHBOARD: 'dashboard', ENTERPRISE_LEARNER_DASHBOARD: 'enterprise-learner-dashboard', CONSENT: 'consent', -} as const satisfies Readonly<{ [k: string]: string }>; +} as const satisfies Readonly<{ [k: string]: string; }>; export const REDIRECT_MODES = { DASHBOARD_REDIRECT: 'dashboard-redirect', @@ -35,7 +35,7 @@ export const REDIRECT_MODES = { CONSENT_REDIRECT: 'consent-redirect', HOME_REDIRECT: 'home-redirect', SURVEY_REDIRECT: 'survey-redirect', -} as const satisfies Readonly<{ [k: string]: string }>; +} as const satisfies Readonly<{ [k: string]: string; }>; export const VERIFIED_MODES = [ 'professional', @@ -55,10 +55,17 @@ export const AUDIT_MODES = [ 'unpaid-bootcamp', ] as const satisfies readonly string[]; +// In sync with CourseMode.UPSELL_TO_VERIFIED_MODES +// https://github.com/openedx/edx-platform/blob/master/common/djangoapps/course_modes/models.py#L231 +export const ALLOW_UPSELL_MODES = [ + 'audit', + 'honor', +] as const satisfies readonly string[]; + export const WIDGETS = { DISCUSSIONS: 'DISCUSSIONS', NOTIFICATIONS: 'NOTIFICATIONS', -} as const satisfies Readonly<{ [k: string]: string }>; +} as const satisfies Readonly<{ [k: string]: string; }>; export const LOADING = 'loading'; export const LOADED = 'loaded'; diff --git a/src/courseware/course/chat/Chat.jsx b/src/courseware/course/chat/Chat.jsx index 702d76e784..275257f5ae 100644 --- a/src/courseware/course/chat/Chat.jsx +++ b/src/courseware/course/chat/Chat.jsx @@ -6,7 +6,7 @@ import { Xpert } from '@edx/frontend-lib-learning-assistant'; import { getConfig } from '@edx/frontend-platform'; import { injectIntl } from '@edx/frontend-platform/i18n'; -import { AUDIT_MODES, VERIFIED_MODES } from '@src/constants'; +import { ALLOW_UPSELL_MODES, VERIFIED_MODES } from '@src/constants'; import { useModel } from '../../../generic/model-store'; const Chat = ({ @@ -22,67 +22,54 @@ const Chat = ({ } = useSelector(state => state.specialExams); const course = useModel('coursewareMeta', courseId); + // If is disabled or taking an exam, we don't show the chat. + if (!enabled || activeAttempt?.attempt_id || exam?.id) { return null; } + + // If is not staff and doesn't have an entollment, we don't show the chat. + if (!isStaff && !enrollmentMode) { return null; } + + const verifiedMode = VERIFIED_MODES.includes(enrollmentMode); // Enrollment verified + const auditMode = ( + !isStaff + && !verifiedMode + && ALLOW_UPSELL_MODES.includes(enrollmentMode) // Can upgrade course + && getConfig().ENABLE_XPERT_AUDIT + ); + + // If user has no access, we don't show the chat. + if (!isStaff && !(verifiedMode || auditMode)) { return null; } + + // Date validation const { accessExpiration, start, end, } = course; - const hasVerifiedEnrollment = ( - enrollmentMode !== null - && enrollmentMode !== undefined - && VERIFIED_MODES.includes(enrollmentMode) - ); + const utcDate = (new Date()).toISOString(); - // audit learners should only have access if the ENABLE_XPERT_AUDIT setting is true - const hasAuditEnrollmentAndAccess = ( - enrollmentMode !== null - && enrollmentMode !== undefined - && AUDIT_MODES.includes(enrollmentMode) - && getConfig().ENABLE_XPERT_AUDIT - ); + const startDate = start || utcDate; + const endDate = end || utcDate; + const expiration = accessExpiration?.expirationDate || utcDate; - const validDates = () => { - const date = new Date(); - const utcDate = date.toISOString(); - - const startDate = start || utcDate; - const endDate = end || utcDate; - const accessExpirationDate = accessExpiration && accessExpiration.expirationDate - ? accessExpiration.expirationDate : utcDate; - - return ( - startDate <= utcDate - && utcDate <= endDate - && (hasAuditEnrollmentAndAccess ? utcDate <= accessExpirationDate : true) - ); - }; - - const shouldDisplayChat = ( - enabled - && (hasVerifiedEnrollment || isStaff || hasAuditEnrollmentAndAccess) - && validDates() - // it is necessary to check both whether the user is in an exam, and whether or not they are viewing an exam - // this will prevent the learner from interacting with the tool at any point of the exam flow, even at the - // entrance interstitial. - && !(activeAttempt?.attempt_id || exam?.id) + const validDate = ( + startDate <= utcDate + && endDate >= utcDate + && (auditMode ? expiration >= utcDate : true) ); - const isUpgradeEligible = !hasVerifiedEnrollment && !isStaff; - - return ( - <> - {/* Use a portal to ensure that component overlay does not compete with learning MFE styles. */} - {shouldDisplayChat && (createPortal( - , - document.body, - ))} - + // If date is invalid, we don't show the chat. + if (!validDate) { return null; } + + // Use a portal to ensure that component overlay does not compete with learning MFE styles. + return createPortal( + , + document.body, ); };