Skip to content

Enterprise theming changes#6

Merged
ssurendrannair merged 9 commits intorelease-ulmofrom
enterprise-theming-changes
Feb 20, 2026
Merged

Enterprise theming changes#6
ssurendrannair merged 9 commits intorelease-ulmofrom
enterprise-theming-changes

Conversation

@subhashree-sahu31
Copy link

Enterprise theming changes

Copilot AI review requested due to automatic review settings February 19, 2026 14:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements enterprise theming changes for the authentication MFE, including a major refactoring from Redux connect to React hooks (useDispatch/useSelector), new enterprise branding layout components, and associated styling changes.

Changes:

  • Refactored Logistration.jsx and LoginPage.jsx from Redux connect HOC to React hooks for state management
  • Added new enterprise-themed hero layouts (SmallLayout, MediumLayout, LargeLayout) with support for enterprise branding
  • Added enterprise theming SCSS styles and updated existing layout styles
  • Extended data utilities with enterprise redirect URL functions
  • Added enterpriseBranding support to the Redux store and selectors

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 24 comments.

Show a summary per file
File Description
src/sass/_base_component.scss Added new auth-hero styling classes for enterprise theming, reformatted existing gradient styles
src/logistration/Logistration.test.jsx Added React import, mocked plugin framework, updated config values from strings to booleans, changed test selectors
src/logistration/Logistration.jsx Refactored from connect to hooks, added LoginComponentSlot plugin integration, added enterprise branding support
src/login/LoginPage.jsx Refactored from connect to hooks, removed cohesion tracking, simplified tracking calls
src/data/utils/dataUtils.js Added enterprise redirect URL utility functions and improved redirectWithDelay function
src/data/constants.js Changed APP_NAME value from 'authn_mfe' to 'authn', added 'enterprise_customer' to AUTH_PARAMS
src/common-components/data/tests/reducer.test.js Added enterpriseBranding field to default state test
src/common-components/data/reducers.js Added enterpriseBranding to state, reformatted SUCCESS case
src/base-container/components/welcome-page-layout/messages.js Added new message keys for enterprise hero text
src/base-container/components/welcome-page-layout/SmallLayout.jsx Replaced progressive profiling layout with enterprise-themed hero layout
src/base-container/components/welcome-page-layout/MediumLayout.jsx Replaced progressive profiling layout with enterprise-themed hero layout
src/base-container/components/welcome-page-layout/LargeLayout.jsx Replaced progressive profiling layout with enterprise-themed hero layout

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +262 to +263
.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS specificity: Using !important can make future style overrides difficult. Consider increasing selector specificity or restructuring the CSS to avoid the need for !important.

Suggested change
.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
.auth-hero-heading .auth-hero-heading-line.text-accent-a {
color: #03C7E8; // for "with edX"

Copilot uses AI. Check for mistakes.
} from '../data/utils';
import { LoginPage } from '../login';
import { backupLoginForm } from '../login/data/actions';
import LoginComponentSlot from '../plugin-slots/LoginComponentSlot';
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing module: The import LoginComponentSlot from '../plugin-slots/LoginComponentSlot' references a file that doesn't exist in the codebase. Based on the test mock at line 31-34 in Logistration.test.jsx, it appears this should be a plugin slot that wraps LoginPage. Either create the missing plugin slot file or import LoginPage directly.

Suggested change
import LoginComponentSlot from '../plugin-slots/LoginComponentSlot';
import { LoginPage as LoginComponentSlot } from '../login';

Copilot uses AI. Check for mistakes.
window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };

const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration />));
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double render: The component is rendered twice on consecutive lines (277 and 278), with the second render destructuring container. This means the test will be interacting with the wrong render. Remove the first render on line 277.

Suggested change
render(reduxWrapper(<Logistration />));

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +65
<div
className="auth-hero-message mt-3"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
/>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Using dangerouslySetInnerHTML with enterpriseWelcomeHtml without sanitization can expose the application to XSS vulnerabilities. The HTML content comes from enterpriseBranding?.enterpriseBrandedWelcomeString or enterpriseBranding?.platformWelcomeString which appears to come from backend data. Ensure this content is properly sanitized on the backend, or use a sanitization library like DOMPurify on the frontend before rendering.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +42
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS: {
return {
...state,
fieldDescriptions: action.payload.fieldDescriptions?.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: {
...action.payload.thirdPartyAuthContext,
enterpriseBranding: action.payload.thirdPartyAuthContext.enterpriseBranding || null,
},
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential data loss: The SUCCESS case previously set countriesCodesList: action.payload.countriesCodesList which is now removed. If this data is still needed elsewhere in the application, this change could break functionality. Verify that countriesCodesList is no longer needed or is handled elsewhere.

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +43
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS: {
return {
...state,
fieldDescriptions: action.payload.fieldDescriptions?.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: {
...action.payload.thirdPartyAuthContext,
enterpriseBranding: action.payload.thirdPartyAuthContext.enterpriseBranding || null,
},
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: The case statement and return block have inconsistent indentation. The case on line 32 should be indented at the same level as other case statements (lines 27, 45), and the return block should be consistently indented.

Suggested change
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS: {
return {
...state,
fieldDescriptions: action.payload.fieldDescriptions?.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: {
...action.payload.thirdPartyAuthContext,
enterpriseBranding: action.payload.thirdPartyAuthContext.enterpriseBranding || null,
},
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
}
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS: {
return {
...state,
fieldDescriptions: action.payload.fieldDescriptions?.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: {
...action.payload.thirdPartyAuthContext,
enterpriseBranding: action.payload.thirdPartyAuthContext.enterpriseBranding || null,
},
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
}

Copilot uses AI. Check for mistakes.
@@ -227,7 +239,10 @@ describe('Logistration', () => {

const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration {...props} />));
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double render: The component is rendered twice on consecutive lines (241 and 242), with the second render destructuring container. This means the test will be interacting with the wrong render. Remove the first render on line 241.

Suggested change
render(reduxWrapper(<Logistration {...props} />));

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +67
{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
/>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Using dangerouslySetInnerHTML with enterpriseWelcomeHtml without sanitization can expose the application to XSS vulnerabilities. The HTML content comes from enterpriseBranding?.enterpriseBrandedWelcomeString or enterpriseBranding?.platformWelcomeString which appears to come from backend data. Ensure this content is properly sanitized on the backend, or use a sanitization library like DOMPurify on the frontend before rendering.

Copilot uses AI. Check for mistakes.
Comment on lines +223 to +286
background: #ffffff;
border-radius: 6px;
padding: 0.75rem 1rem;
display: inline-flex;
align-items: center;
justify-content: center;
}

.auth-hero-enterprise-logo {
max-width: 145px;
max-height: 74px;
object-fit: contain;
}

/* yellow slanted line */
.auth-hero-slash {
width: 0; // only height+border matters
height: 110px; // tune this to match logo/heading height
border-left: 6px solid #F0CC00; // Figma yellow
border-radius: 999px;
transform: skewX(-12deg); // gives that forward slash look
transform-origin: center;
}

/* heading text: "Start learning" + "with edX" */
.auth-hero-heading {
display: flex;
flex-direction: column;
}

.auth-hero-heading-line {
font-family: 'Inter', sans-serif;
font-size: 60px;
font-weight: 700;
line-height: 60px;
letter-spacing: -1.2px;
color: #FFFFFF; // for "Start learning"
}

.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
}

/* enterprise message aligned under heading, same left edge */
.auth-hero-message {
max-width: 492px;
color: #fff;
font-family: 'Inter', sans-serif;
font-size: 22px;
font-weight: 400;
line-height: 36px;
}

.auth-hero-message p {
margin: 0;
color: inherit;
font-size: inherit;
line-height: inherit;
}

.auth-hero-message a {
color: #03c7e8;
text-decoration: underline;
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainability: Hardcoded color values (#F0CC00, #03C7E8, #ffffff, #03c7e8) are used throughout the SCSS. Consider using CSS custom properties (CSS variables) or SCSS variables that are already defined in the project (like var(--pgn-color-*)) for better maintainability and theming consistency.

Copilot uses AI. Check for mistakes.

const LargeLayout = ({ fullName }) => {

const LargeLayout = ({ fullName = null }) => {
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused parameter: The fullName parameter is defined with a default value but never used in the component. Either remove this unused parameter or use it if it's intended for future functionality.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 20, 2026 05:46
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 14 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };

const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration />));
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component is being rendered twice here. Line 277 renders the component without capturing the result, then line 278 renders it again and captures the container. This is wasteful and could cause unexpected behavior in tests. Remove line 277 since line 278 already renders the component properly.

Suggested change
render(reduxWrapper(<Logistration />));

Copilot uses AI. Check for mistakes.
@@ -228,7 +241,6 @@ const LoginPage = (props) => {
success={loginResult.success}
redirectUrl={loginResult.redirectUrl}
finishAuthUrl={finishAuthUrl}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RedirectLogistration component receives currentProvider but has a typo in its prop definition (currectProvider instead of currentProvider). While removing this prop from LoginPage appears intentional, ThirdPartyAuth component at line 304 still receives currentProvider. You should verify that removing currentProvider from RedirectLogistration doesn't break cohesion event tracking logic at line 34 of RedirectLogistration.jsx, which checks if (!currectProvider).

Suggested change
finishAuthUrl={finishAuthUrl}
finishAuthUrl={finishAuthUrl}
currectProvider={currentProvider}

Copilot uses AI. Check for mistakes.
Comment on lines 247 to 248
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login', { app_name: APP_NAME });
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tracking events in this test still expect the app_name parameter, but it was removed from the tracking calls in the updated code (lines 75, 77, 79 in Logistration.jsx). Update the test expectations to remove app_name from the expected parameters to match the actual implementation.

Suggested change
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login', { app_name: APP_NAME });
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'institution_login', {});

Copilot uses AI. Check for mistakes.
export const PASSWORD_RESET_CONFIRM = '/password_reset_confirm/:token/';
export const PAGE_NOT_FOUND = '/notfound';
export const ENTERPRISE_LOGIN_URL = '/enterprise/login';
export const APP_NAME = 'authn';
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The APP_NAME constant was changed from 'authn_mfe' to 'authn', but this change may break analytics tracking and reporting that depend on the specific 'authn_mfe' identifier. Verify that all analytics dashboards, reports, and downstream systems are updated to handle 'authn' instead of 'authn_mfe', or consider maintaining backward compatibility.

Suggested change
export const APP_NAME = 'authn';
export const APP_NAME = 'authn_mfe';

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +49
<div className="auth-hero-slash" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="191" height="250" viewBox="0 0 191 250" fill="none" style={{ width: '100%', height: '100%' }}>
<line x1="69.8107" y1="33.833" x2="32.9503" y2="206.952" stroke="#F0CC00" strokeWidth="8" />
</svg>
</div>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auth-hero-slash div has specific styling (width: 0, height: 110px, border-left: 6px) but contains an inline SVG with viewBox and percentage-based dimensions that override the container. This creates confusion about which approach is being used. Either use the border-based approach (removing the SVG) or use the SVG approach (removing the border/width/height styles). The current implementation mixes both approaches inconsistently.

Suggested change
<div className="auth-hero-slash" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="191" height="250" viewBox="0 0 191 250" fill="none" style={{ width: '100%', height: '100%' }}>
<line x1="69.8107" y1="33.833" x2="32.9503" y2="206.952" stroke="#F0CC00" strokeWidth="8" />
</svg>
</div>
<div className="auth-hero-slash" aria-hidden="true" />

Copilot uses AI. Check for mistakes.
Comment on lines +241 to +242
render(reduxWrapper(<Logistration {...props} />));
fireEvent.click(screen.getByText('Institution/campus credentials'));
const { container } = render(reduxWrapper(<Logistration {...props} />));
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component is being rendered twice here. Line 241 renders the component but doesn't capture the result, then line 242 renders it again. This is wasteful and could cause unexpected behavior in tests. Remove line 241 since line 242 already captures the container properly.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +65
<div
className="auth-hero-message mt-3"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
/>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dangerouslySetInnerHTML without sanitization is a security risk. The enterpriseWelcomeHtml contains HTML from enterpriseBrandedWelcomeString or platformWelcomeString which could potentially include malicious scripts. Consider sanitizing the HTML content using a library like DOMPurify before rendering it.

Copilot uses AI. Check for mistakes.
Comment on lines +254 to +274
font-family: 'Inter', sans-serif;
font-size: 60px;
font-weight: 700;
line-height: 60px;
letter-spacing: -1.2px;
color: #FFFFFF; // for "Start learning"
}

.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
}

/* enterprise message aligned under heading, same left edge */
.auth-hero-message {
max-width: 492px;
color: #fff;
font-family: 'Inter', sans-serif;
font-size: 22px;
font-weight: 400;
line-height: 36px;
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The font-family 'Inter' is hardcoded in the styles but there's no guarantee this font is loaded in the application. If 'Inter' is not available, the browser will fall back to the generic sans-serif, which may not match the design. Verify that the 'Inter' font is properly loaded in the application, or use a CSS variable that references the application's font stack.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +67
{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
/>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dangerouslySetInnerHTML without sanitization is a security risk. The enterpriseWelcomeHtml contains HTML from enterpriseBrandedWelcomeString or platformWelcomeString which could potentially include malicious scripts. Consider sanitizing the HTML content using a library like DOMPurify before rendering it.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +75
{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
/>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dangerouslySetInnerHTML without sanitization is a security risk. The enterpriseWelcomeHtml contains HTML from enterpriseBrandedWelcomeString or platformWelcomeString which could potentially include malicious scripts. Consider sanitizing the HTML content using a library like DOMPurify before rendering it.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 20, 2026 06:06
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

import messages from './messages';

const SmallLayout = ({ fullName }) => {
const SmallLayout = () => {
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BaseContainer component passes a fullName prop to the layout components (SmallLayout, MediumLayout, LargeLayout), but these components have been refactored to no longer accept this prop. This will generate React PropTypes warnings in development and the fullName is never used. Either update BaseContainer to not pass fullName to these components, or add PropTypes validation to handle it gracefully.

Copilot uses AI. Check for mistakes.
import messages from './messages';

const MediumLayout = ({ fullName }) => {
const MediumLayout = () => {
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BaseContainer component passes a fullName prop to the layout components, but this component has been refactored to no longer accept this prop. This will generate React PropTypes warnings in development and the fullName is never used. Either update BaseContainer to not pass fullName to these components, or add PropTypes validation to handle it gracefully.

Copilot uses AI. Check for mistakes.
import messages from './messages';

const LargeLayout = ({ fullName }) => {
const LargeLayout = () => {
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BaseContainer component passes a fullName prop to the layout components, but this component has been refactored to no longer accept this prop. This will generate React PropTypes warnings in development and the fullName is never used. Either update BaseContainer to not pass fullName to these components, or add PropTypes validation to handle it gracefully.

Copilot uses AI. Check for mistakes.
window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };

const props = { selectedPage: LOGIN_PAGE };
render(reduxWrapper(<Logistration />));
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component is being rendered twice, which may cause duplicate queries and unnecessary re-renders. The first render at line 283 doesn't use the return value, and the second render at line 284 captures the container. Remove the first render call at line 283.

Suggested change
render(reduxWrapper(<Logistration />));

Copilot uses AI. Check for mistakes.
}));
};
const trackForgotPasswordLinkClick = () => {
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analytics tracking calls now omit the app_name parameter. The code changed from using the wrapper tracking functions (which automatically include APP_NAME) to calling sendTrackEvent directly without the app_name parameter. This creates inconsistency with other parts of the codebase that use the wrapper functions in src/data/segment/utils.js. For consistency and to ensure proper tracking, either use the existing wrapper functions or explicitly include app_name: APP_NAME in the tracking calls.

Suggested change
sendTrackEvent('edx.bi.password-reset_form.toggled', { category: 'user-engagement' });
sendTrackEvent('edx.bi.password-reset_form.toggled', {
category: 'user-engagement',
app_name: getConfig().APP_NAME,
});

Copilot uses AI. Check for mistakes.
},
'with.edx': {
id: 'with.edx',
defaultMessage: ' with edX',
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message 'with.edx' is missing a description field. All other messages in this file have descriptions that explain their purpose. Add a description like "description: 'Second line of header text with edX branding for logistration MFE pages'" for consistency with the codebase conventions.

Suggested change
defaultMessage: ' with edX',
defaultMessage: ' with edX',
description: 'Second line of header text with edX branding for logistration MFE pages',

Copilot uses AI. Check for mistakes.
{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of dangerouslySetInnerHTML with enterpriseWelcomeHtml from backend data creates a Cross-Site Scripting (XSS) vulnerability. If the backend data is compromised or contains malicious content, it could execute arbitrary JavaScript in users' browsers. Consider using a sanitization library like DOMPurify to sanitize the HTML before rendering, or better yet, use a safer rendering approach that doesn't require raw HTML insertion.

Copilot uses AI. Check for mistakes.

useEffect(() => {
trackLoginPageViewed();
sendPageEvent('login_and_registration', 'login');
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analytics tracking calls now omit the app_name parameter. The code changed from using wrapper functions like trackLoginPageViewed() and trackForgotPasswordLinkClick() (which automatically include APP_NAME) to calling sendPageEvent and sendTrackEvent directly without the app_name parameter. This creates inconsistency with other parts of the codebase that use the wrapper functions in src/data/segment/utils.js. For consistency and to ensure proper tracking, either use the existing wrapper functions or explicitly include app_name: APP_NAME in the tracking calls.

Copilot uses AI. Check for mistakes.
<svg className="m1-n1 w-100 h-100 large-screen-svg-light" preserveAspectRatio="xMaxYMin meet">

{/* keep existing right decorative triangle */}
<div className="col-md-3 bg-white p-0">
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The column width has changed from col-md-2 to col-md-3, which alters the layout proportions. The left column is still col-md-10, so the total is now 13 columns instead of 12, which exceeds Bootstrap's 12-column grid system. This will cause layout issues. Either change the left column to col-md-9 or change the right column back to col-md-2 to maintain a valid 12-column grid.

Suggested change
<div className="col-md-3 bg-white p-0">
<div className="col-md-2 bg-white p-0">

Copilot uses AI. Check for mistakes.
</div>
</h2>
<div className="auth-hero-heading-line text-accent-a">
{formatMessage(messages['with.edx'])}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent messaging across different layout sizes. SmallLayout and MediumLayout use messages['with.site.name'] with dynamic siteName, while LargeLayout uses messages['with.edx'] with hard-coded " with edX" text. This creates an inconsistent user experience where the message changes based on screen size. Use the same message pattern across all layouts for consistency, preferably messages['with.site.name'] to support different site configurations.

Suggested change
{formatMessage(messages['with.edx'])}
{formatMessage(messages['with.site.name'], { siteName })}

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 20, 2026 06:18
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 14 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 60 to +64
useEffect(() => {
const authService = getAuthService();
if (authService) {
authService.getCsrfTokenService().getCsrfToken(getConfig().LMS_BASE_URL);
authService.getCsrfTokenService()
.getCsrfToken(getConfig().LMS_BASE_URL);
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This useEffect has no dependency array, so it will request a CSRF token on every render. That can create unnecessary network traffic and flaky behavior; add an appropriate dependency array (likely []) so the token is fetched once on mount (or when LMS_BASE_URL changes).

Copilot uses AI. Check for mistakes.
Comment on lines 74 to 78
const handleInstitutionLogin = (e) => {
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
if (typeof e === 'string') {
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register', { app_name: APP_NAME });
sendPageEvent('login_and_registration', e === '/login' ? 'login' : 'register');
} else {
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These analytics calls were changed to omit the { app_name: APP_NAME } payload property. Elsewhere in the repo (e.g., src/data/segment/utils.js) tracking helpers always include app_name, so this makes event payloads inconsistent. Consider using the shared tracking helpers or continue passing app_name here for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines 245 to 249
<RedirectLogistration
success={loginResult.success}
redirectUrl={loginResult.redirectUrl}
finishAuthUrl={finishAuthUrl}
currentProvider={currentProvider}
/>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThirdPartyAuthAlert sets the ssoPipelineRedirectionDone cookie when currentProvider is present. Previously the login flow cleared that cookie on successful login; that cleanup (and the login-success tracking) is now gone, so the cookie may linger across sessions. Consider re-adding a useEffect on loginResult.success to track login success and clear ssoPipelineRedirectionDone after a successful login.

Copilot uses AI. Check for mistakes.
props.dismissPasswordResetBanner();
dispatch(dismissPasswordResetBanner());
}

Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sign-in submit handler no longer emits the Cohesion element-click event (compare with RegistrationPage, which still dispatches setCohesionEventStates). If Cohesion is still required for the sign-in button, please restore the Cohesion tracking dispatch in this handler.

Suggested change
// Cohesion element-click tracking for the sign-in button
sendTrackEvent('cohesion.element-click', {
page: 'login',
elementId: 'sign-in-submit',
elementLabel: 'sign-in',
});

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +58
<div className="auth-hero-heading">
<div className="auth-hero-heading-line text-white">
{formatMessage(messages['start.learning'])}
</div>
<div className="auth-hero-heading-line text-accent-a">
{formatMessage(messages['with.site.name'], { siteName })}
</div>
</h2>
</div>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hero heading is now built with <div> elements instead of semantic heading tags (<h1>, <h2>, etc.). This reduces document structure information for screen readers; consider using appropriate heading elements (and styling them) to preserve accessibility semantics.

Copilot uses AI. Check for mistakes.
Comment on lines +289 to +296
@media (max-width: 1199.98px) {
.auth-hero-heading-line {
font-size: 2.5rem;
}

.auth-hero-content {
margin-top: 4rem;
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This media query uses a hard-coded pixel breakpoint (1199.98px), while the rest of this stylesheet uses Paragon custom media breakpoints (e.g. @media (--pgn-size-breakpoint-min-width-xl)). For consistency and easier future updates, please use the same breakpoint tokens here.

Copilot uses AI. Check for mistakes.
},
'with.edx': {
id: 'with.edx',
defaultMessage: ' with edX',
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultMessage for with.edx includes a leading space (' with edX'). Since this string is rendered on its own line in LargeLayout, the leading space will be visible and may affect alignment; consider removing the leading space.

Suggested change
defaultMessage: ' with edX',
defaultMessage: 'with edX',

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +60
<div className="auth-hero-heading">
<div className="auth-hero-heading-line text-white">
{formatMessage(messages['start.learning'])}
</div>
<div className="auth-hero-heading-line text-accent-a">
{formatMessage(messages['with.site.name'], { siteName })}
</div>
</h2>
</div>
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hero heading uses <div> elements rather than semantic headings. For accessibility and SEO, consider using <h1>/<h2> (or role="heading" with aria-level) so screen readers can correctly navigate the page structure.

Copilot uses AI. Check for mistakes.
Comment on lines +262 to +265
.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
}

Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These heading styles hard-code font + colors and use !important for the accent color. This makes them harder to theme and override consistently; prefer existing typography tokens/utilities and avoid !important by adjusting specificity or using the provided Paragon text utility classes.

Suggested change
.auth-hero-heading-line.text-accent-a {
color: #03C7E8 !important; // for "with edX"
}

Copilot uses AI. Check for mistakes.
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.password-reset_form.toggled', { category: 'user-engagement', app_name: APP_NAME });
expect(sendTrackEvent).toHaveBeenCalledWith(
'edx.bi.password-reset_form.toggled',
expect.any(Object),
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion was weakened to expect.any(Object), which could let regressions slip (e.g., missing category: 'user-engagement'). Since the current implementation sends a stable payload shape, consider asserting the expected properties instead of any(Object).

Suggested change
expect.any(Object),
expect.objectContaining({
category: 'user-engagement',
}),

Copilot uses AI. Check for mistakes.
Copy link

@ssurendrannair ssurendrannair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@ssurendrannair ssurendrannair merged commit 756487a into release-ulmo Feb 20, 2026
3 checks passed
@ssurendrannair ssurendrannair deleted the enterprise-theming-changes branch February 20, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants