Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 71 additions & 21 deletions src/base-container/components/welcome-page-layout/LargeLayout.jsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,92 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Hyperlink, Image } from '@openedx/paragon';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import messages from './messages';

const LargeLayout = ({ fullName }) => {
const LargeLayout = () => {
const { formatMessage } = useIntl();

const enterpriseBranding = useSelector(
state => state.commonComponents?.thirdPartyAuthContext?.enterpriseBranding,
);

const enterpriseLogoUrl = enterpriseBranding?.enterpriseLogoUrl || null;
const enterpriseName = enterpriseBranding?.enterpriseName || null;

const enterpriseWelcomeHtml = enterpriseBranding?.enterpriseBrandedWelcomeString
|| enterpriseBranding?.platformWelcomeString
|| '';

const siteName = getConfig().SITE_NAME;
const baseLogoSrc = getConfig().LOGO_WHITE_URL || getConfig().LOGO_URL;

return (
<div className="w-50 d-flex">
<div className="col-md-10 bg-light-200 p-0">
<div className="col-md-10 bg-primary-400 auth-hero-left position-relative">
{/* base edX logo at very top-left */}
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
<Image className="logo position-absolute" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
<Image
className="logo auth-hero-base-logo"
alt={siteName}
src={baseLogoSrc}
/>
</Hyperlink>
<div className="min-vh-100 d-flex align-items-center">
<div className="large-screen-left-container mr-n4.5 large-yellow-line mt-5" />
<div>
<h1 className="welcome-to-platform data-hj-suppress">
{formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, fullName })}
</h1>
<h2 className="complete-your-profile">
{formatMessage(messages['complete.your.profile.1'])}
<div className="text-accent-a">
{formatMessage(messages['complete.your.profile.2'])}

{/* main hero content block, aligned like Figma */}
<div className="auth-hero-content d-flex flex-column">
{/* row: [enterprise logo] [yellow slash] [Start learning with edX] */}
<div className="d-flex align-items-center">
{enterpriseLogoUrl && (
<div className="auth-hero-enterprise-logo-wrapper mr-4">
<Image
alt={enterpriseName || 'Enterprise'}
src={enterpriseLogoUrl}
className="auth-hero-enterprise-logo"
/>
</div>
)}

<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-heading">
<div
className={classNames(
'auth-hero-heading-line text-white',
)}
>
{formatMessage(messages['start.learning'])}
</div>
</h2>
<div className="auth-hero-heading-line text-accent-a">
{formatMessage(messages['with.edx'])}
</div>
</div>
</div>

{/* enterprise-specific message aligned under heading */}
{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}

Check warning on line 78 in src/base-container/components/welcome-page-layout/LargeLayout.jsx

View workflow job for this annotation

GitHub Actions / tests

Dangerous property 'dangerouslySetInnerHTML' found
/>
)}
</div>
</div>
<div className="col-md-2 bg-white p-0">
<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">
<svg
className="m1-n1 w-100 h-100 large-screen-svg-primary"
preserveAspectRatio="xMaxYMin meet"
>
<g transform="skewX(171.6)">
<rect x="0" y="0" height="100%" width="100%" />
</g>
Expand All @@ -42,8 +96,4 @@
);
};

LargeLayout.propTypes = {
fullName: PropTypes.string.isRequired,
};

export default LargeLayout;
71 changes: 51 additions & 20 deletions src/base-container/components/welcome-page-layout/MediumLayout.jsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,75 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Hyperlink, Image } from '@openedx/paragon';
import PropTypes from 'prop-types';

import messages from './messages';

const MediumLayout = ({ fullName }) => {
const MediumLayout = () => {
const { formatMessage } = useIntl();

const enterpriseBranding = useSelector(
state => state.commonComponents?.thirdPartyAuthContext?.enterpriseBranding,
);

const enterpriseLogoUrl = enterpriseBranding?.enterpriseLogoUrl || null;
const enterpriseName = enterpriseBranding?.enterpriseName || null;
const enterpriseWelcomeHtml = enterpriseBranding?.enterpriseBrandedWelcomeString
|| enterpriseBranding?.platformWelcomeString
|| '';

const siteName = getConfig().SITE_NAME;
const baseLogoSrc = getConfig().LOGO_WHITE_URL || getConfig().LOGO_URL;

return (
<>
<div className="w-100 medium-screen-top-stripe" />
<div className="w-100 p-0 mb-3 d-flex">
<div className="col-md-10 bg-light-200">
<div className="col-md-10 bg-primary-400 auth-hero-left">
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
<Image className="logo" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
<Image className="logo auth-hero-base-logo" alt={siteName} src={baseLogoSrc} />
</Hyperlink>
<div className="d-flex align-items-center justify-content-center mb-4 ml-5">
<div className="medium-yellow-line mt-5 mr-n2" />
<div>
<h1 className="h3 data-hj-suppress mw-320">
{formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, fullName })}
</h1>
<h2 className="display-1">
{formatMessage(messages['complete.your.profile.1'])}
<div className="text-accent-a">
{formatMessage(messages['complete.your.profile.2'])}

<div className="auth-hero-content d-flex flex-column">
<div className="d-flex align-items-center">
{enterpriseLogoUrl && (
<div className="auth-hero-enterprise-logo-wrapper mr-4">
<Image
alt={enterpriseName || 'Enterprise'}
src={enterpriseLogoUrl}
className="auth-hero-enterprise-logo"
/>
</div>
)}

<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-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>
</div>

{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-4"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}

Check warning on line 66 in src/base-container/components/welcome-page-layout/MediumLayout.jsx

View workflow job for this annotation

GitHub Actions / tests

Dangerous property 'dangerouslySetInnerHTML' found
/>
)}
</div>
</div>
<div className="col-md-2 bg-white p-0">
<svg className="w-100 h-100 medium-screen-svg-light" preserveAspectRatio="xMaxYMin meet">
<svg className="w-100 h-100 medium-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
<g transform="skewX(168)">
<rect x="0" y="0" height="100%" width="100%" />
</g>
Expand All @@ -45,8 +80,4 @@
);
};

MediumLayout.propTypes = {
fullName: PropTypes.string.isRequired,
};

export default MediumLayout;
69 changes: 50 additions & 19 deletions src/base-container/components/welcome-page-layout/SmallLayout.jsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,72 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Hyperlink, Image } from '@openedx/paragon';
import PropTypes from 'prop-types';

import messages from './messages';

const SmallLayout = ({ fullName }) => {
const SmallLayout = () => {
const { formatMessage } = useIntl();

const enterpriseBranding = useSelector(
state => state.commonComponents?.thirdPartyAuthContext?.enterpriseBranding,
);

const enterpriseLogoUrl = enterpriseBranding?.enterpriseLogoUrl || null;
const enterpriseName = enterpriseBranding?.enterpriseName || null;
const enterpriseWelcomeHtml = enterpriseBranding?.enterpriseBrandedWelcomeString
|| enterpriseBranding?.platformWelcomeString
|| '';

const siteName = getConfig().SITE_NAME;
const baseLogoSrc = getConfig().LOGO_WHITE_URL || getConfig().LOGO_URL;

return (
<div className="min-vw-100 bg-light-200">
<div className="min-vw-100 bg-primary-400 auth-hero-left">
<div className="col-md-12 small-screen-top-stripe" />
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
<Image className="logo-small" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
<Image className="logo-small auth-hero-base-logo" alt={siteName} src={baseLogoSrc} />
</Hyperlink>
<div className="d-flex align-items-center m-3.5">
<div className="small-yellow-line mt-4.5" />
<div>
<h1 className="h5 data-hj-suppress">
{formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, fullName })}
</h1>
<h2 className="h1">
{formatMessage(messages['complete.your.profile.1'])}
<div className="text-accent-a">
{formatMessage(messages['complete.your.profile.2'])}

<div className="auth-hero-content d-flex flex-column">
<div className="d-flex align-items-center">
{enterpriseLogoUrl && (
<div className="auth-hero-enterprise-logo-wrapper mr-3">
<Image
alt={enterpriseName || 'Enterprise'}
src={enterpriseLogoUrl}
className="auth-hero-enterprise-logo"
/>
</div>
)}

<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-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>
</div>

{enterpriseWelcomeHtml && (
<div
className="auth-hero-message mt-3"
dangerouslySetInnerHTML={{ __html: enterpriseWelcomeHtml }}

Check warning on line 64 in src/base-container/components/welcome-page-layout/SmallLayout.jsx

View workflow job for this annotation

GitHub Actions / tests

Dangerous property 'dangerouslySetInnerHTML' found
/>
)}
</div>
</div>
);
};

SmallLayout.propTypes = {
fullName: PropTypes.string.isRequired,
};

export default SmallLayout;
14 changes: 14 additions & 0 deletions src/base-container/components/welcome-page-layout/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ const messages = defineMessages({
defaultMessage: 'Welcome to {siteName}, {fullName}!',
description: 'Welcome message that appears on progressive profile page',
},
'start.learning': {
id: 'start.learning',
defaultMessage: 'Start learning',
description: 'Header text for logistration MFE pages',
},
'with.site.name': {
id: 'with.site.name',
defaultMessage: 'with {siteName}',
description: 'Header text with site name for logistration MFE pages',
},
'with.edx': {
id: 'with.edx',
defaultMessage: ' with edX',
},
'complete.your.profile.1': {
id: 'complete.your.profile.1',
defaultMessage: 'Complete',
Expand Down
29 changes: 19 additions & 10 deletions src/common-components/data/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const defaultState = {
pipelineUserDetails: null,
errorMessage: null,
welcomePageRedirectUrl: null,
enterpriseBranding: null,
},
};

Expand All @@ -28,16 +29,24 @@ const reducer = (state = defaultState, action = {}) => {
...state,
thirdPartyAuthApiStatus: PENDING_STATE,
};
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS: {
return {
...state,
fieldDescriptions: action.payload.fieldDescriptions?.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: action.payload.thirdPartyAuthContext,
thirdPartyAuthApiStatus: COMPLETE_STATE,
countriesCodesList: action.payload.countriesCodesList,
};
}
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
? {
...action.payload.thirdPartyAuthContext.enterpriseBranding,
enterpriseSlug: action.payload.thirdPartyAuthContext.enterpriseBranding.enterpriseSlug || null,
}
: null,
},
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
}

case THIRD_PARTY_AUTH_CONTEXT.FAILURE:
return {
...state,
Expand Down
1 change: 1 addition & 0 deletions src/common-components/data/tests/reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe('common components reducer', () => {
secondaryProviders: [],
pipelineUserDetails: null,
errorMessage: null,
enterpriseBranding: null,
},
};
const fieldDescriptions = {
Expand Down
4 changes: 2 additions & 2 deletions src/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const RECOMMENDATIONS = '/recommendations';
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';

// Constants
export const SUPPORTED_ICON_CLASSES = ['apple', 'facebook', 'google', 'microsoft'];
Expand All @@ -35,6 +36,5 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+

// Query string parameters that can be passed to LMS to manage
// things like auto-enrollment upon login and registration.
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta'];
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'register_for_free', 'track', 'is_account_recovery', 'variant', 'host', 'cta', 'enterprise_customer'];
export const REDIRECT = 'redirect';
export const APP_NAME = 'authn_mfe';
Loading