Add enterprise portal links to user dropdown menu and dashboard alerts. (#21833)

This commit is contained in:
Brittney Exline
2019-10-09 14:01:41 -06:00
committed by Douglas Hall
parent e05f244bba
commit 6e2887f851
19 changed files with 476 additions and 13 deletions

View File

@@ -0,0 +1,11 @@
module.exports = {
extends: 'eslint-config-edx',
root: true,
settings: {
'import/resolver': {
webpack: {
config: 'webpack.dev.config.js',
},
},
},
};

View File

@@ -0,0 +1,16 @@
import { getAuthenticatedAPIClient } from '@edx/frontend-auth';
import { NewRelicLoggingService } from '@edx/frontend-logging';
const apiClient = getAuthenticatedAPIClient({
appBaseUrl: process.env.LMS_ROOT_URL,
authBaseUrl: process.env.LMS_ROOT_URL,
loginUrl: `${process.env.LMS_ROOT_URL}/login`,
logoutUrl: `${process.env.LMS_ROOT_URL}/logout`,
csrfTokenApiPath: '/csrf/api/v1/token',
refreshAccessTokenEndpoint: `${process.env.LMS_ROOT_URL}/login_refresh`,
accessTokenCookieName: process.env.JWT_AUTH_COOKIE_HEADER_PAYLOAD,
userInfoCookieName: process.env.EDXMKTG_USER_INFO_COOKIE_NAME,
loggingService: NewRelicLoggingService,
});
export default apiClient;

View File

@@ -0,0 +1,11 @@
module.exports = {
extends: 'eslint-config-edx',
root: true,
settings: {
'import/resolver': {
webpack: {
config: 'webpack.dev.config.js',
},
},
},
};

View File

@@ -0,0 +1,20 @@
import { getLearnerPortalLinks } from '@edx/frontend-enterprise';
import apiClient from '../apiClient';
function CustomUserMenuLinks() {
// Inject enterprise learner portal links
getLearnerPortalLinks(apiClient).then((learnerPortalLinks) => {
const $dashboardLink = $('#user-menu .dashboard');
const classNames = 'mobile-nav-item dropdown-item dropdown-nav-item';
for (let i = 0; i < learnerPortalLinks.length; i += 1) {
const link = learnerPortalLinks[i];
$dashboardLink.after( // xss-lint: disable=javascript-jquery-insertion
`<div class="${classNames}"><a href="${link.url}" role="menuitem">${link.title} Dashboard</a></div>`,
);
}
});
}
export { CustomUserMenuLinks }; // eslint-disable-line import/prefer-default-export

View File

@@ -0,0 +1,78 @@
import React, { Component } from 'react';
import { getLearnerPortalLinks } from '@edx/frontend-enterprise';
import { StatusAlert } from '@edx/paragon';
import apiClient from '../apiClient';
const LOCAL_STORAGE_KEY = 'has-viewed-enterprise-learner-portal-banner';
function getAlertHtml(learnerPortalLinks) {
let html = '';
for (let i = 0; i < learnerPortalLinks.length; i += 1) {
const link = learnerPortalLinks[i];
html += `<div>
${link.title} has a dedicated page where you can see all of your sponsored courses.
Go to <a href="${link.url}">your learner portal</a>.
</div>`;
}
return html;
}
function setViewedBanner() {
window.localStorage.setItem(LOCAL_STORAGE_KEY, true);
}
function hasViewedBanner() {
window.localStorage.getItem(LOCAL_STORAGE_KEY);
}
class EnterpriseLearnerPortalBanner extends Component {
constructor(props) {
super(props);
this.onClose = this.onClose.bind(this);
this.state = {
open: false,
alertHtml: '',
};
}
componentDidMount() {
if (!hasViewedBanner()) {
getLearnerPortalLinks(apiClient).then((learnerPortalLinks) => {
this.setState({
open: true,
alertHtml: getAlertHtml(learnerPortalLinks),
});
});
}
}
onClose() {
this.setState({ open: false });
setViewedBanner();
}
render() {
const { alertHtml, open } = this.state;
if (open) {
return (
<div className="edx-enterprise-learner-portal-banner-wrapper">
<StatusAlert
className={['edx-enterprise-learner-portal-banner']}
open={open}
// eslint-disable-next-line react/no-danger
dialog={(<span dangerouslySetInnerHTML={{ __html: alertHtml }} />)}
onClose={this.onClose}
/>
</div>
);
}
return null;
}
}
export { EnterpriseLearnerPortalBanner }; // eslint-disable-line import/prefer-default-export

View File

@@ -73,6 +73,7 @@
@import 'features/_unsupported-browser-alert';
@import 'features/content-type-gating';
@import 'features/course-duration-limits';
@import 'features/enterprise-learner-portal-banner';
// search
@import 'search/search';

View File

@@ -33,6 +33,7 @@
@import 'features/course-sock';
@import 'features/course-upgrade-message';
@import 'features/content-type-gating';
@import 'features/enterprise-learner-portal-banner';
// Responsive Design

View File

@@ -25,6 +25,7 @@ $static-path: '../..';
@import 'features/course-sock';
@import 'features/course-upgrade-message';
@import 'features/course-duration-limits';
@import 'features/enterprise-learner-portal-banner';
// Individual Pages

View File

@@ -0,0 +1,89 @@
$enterprise-learner-portal-banner-background-color: #d9edf7 !default;
$enterprise-learner-portal-banner-text-color: #4e4e4e !default;
$enterprise-learner-portal-banner-cta-base: #0075b4 !default;
$enterprise-learner-portal-banner-cta-hover: #075683 !default;
.edx-enterprise-learner-portal-banner-wrapper {
background: $enterprise-learner-portal-banner-background-color;
box-sizing: border-box;
/** Base Styles - start **/
text-align: left;
line-height: 1.5;
font: {
family: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif;
size: 1rem;
weight: 400;
}
.alert {
position: relative;
padding: 0.75rem 1.25rem;
}
.alert-dismissible {
.close {
position: absolute;
top: 0;
right: 0;
padding: 0.75rem 1.25rem;
background: transparent;
border: 0;
text-shadow: 0 1px 0 #fff;
opacity: 0.5;
float: right;
line-height: 1;
font: {
size: 1.5rem;
weight: 700;
}
}
.btn {
display: inline-block;
text-align: center;
white-space: nowrap;
vertical-align: middle;
box-shadow: none;
}
}
/** Base Styles - end **/
.edx-enterprise-learner-portal-banner {
box-sizing: border-box;
display: flex;
justify-content: space-between;
max-width: 1200px;
min-width: 0;
margin: 0 auto;
background: inherit;
border: none;
.policy-link {
color: $enterprise-learner-portal-banner-cta-base;
text-decoration: underline;
&:focus,
&:hover {
color: $enterprise-learner-portal-banner-cta-hover;
border: none;
}
}
.alert-dialog {
margin-right: 30px;
color: $enterprise-learner-portal-banner-text-color;
}
.btn.close {
color: $enterprise-learner-portal-banner-cta-base;
&:focus,
&:hover {
color: $enterprise-learner-portal-banner-cta-hover;
cursor: pointer;
}
}
}
}

View File

@@ -1,6 +1,6 @@
## mako
<%page expression_filter="h"/>
<%namespace name='static' file='static_content.html'/>
<%namespace name='static' file='../static_content.html'/>
<%!
from django.conf import settings
@@ -22,6 +22,12 @@ resume_block = retrieve_last_sitewide_block_completed(self.real_user)
displayname = get_enterprise_learner_generic_name(request) or username
%>
<%static:webpack entry="CustomUserMenuLinks">
$(document).ready(function() {
CustomUserMenuLinks();
});
</%static:webpack>
<div class="nav-item hidden-mobile">
<a href="${reverse('dashboard')}" class="menu-title">
<img class="user-image-frame" src="${profile_image_url}" alt="">
@@ -37,7 +43,7 @@ displayname = get_enterprise_learner_generic_name(request) or username
% if resume_block:
<div class="mobile-nav-item dropdown-item dropdown-nav-item"><a href="${resume_block}" role="menuitem">${_("Resume your last course")}</a></div>
% endif
<div class="mobile-nav-item dropdown-item dropdown-nav-item"><a href="${reverse('dashboard')}" role="menuitem">${_("Dashboard")}</a></div>
<div class="mobile-nav-item dropdown-item dropdown-nav-item dashboard"><a href="${reverse('dashboard')}" role="menuitem">${_("Dashboard")}</a></div>
<div class="mobile-nav-item dropdown-item dropdown-nav-item"><a href="${reverse('learner_profile', kwargs={'username': username})}" role="menuitem">${_("Profile")}</a></div>
<div class="mobile-nav-item dropdown-item dropdown-nav-item"><a href="${reverse('account_settings')}" role="menuitem">${_("Account")}</a></div>
% if should_redirect_to_order_history_microfrontend():