Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: npm run build

- name: Run Coverage
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@openedx/paragon": "^23.4.5",
"@tabler/icons-react": "^3.44.0",
"@tanstack/react-query": "^5.90.16",
"classnames": "^2.3.1",
"core-js": "3.49.0",
Expand Down
3 changes: 1 addition & 2 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ $input-focus-box-shadow: var(--pgn-elevation-form-input-base); // hack to get up
display: block;
box-sizing: content-box;
position: relative;
top: 0.1em;
height: 1.75rem;
height: 37px;
margin-right: 1rem;
img {
display: block;
Expand Down
214 changes: 153 additions & 61 deletions src/containers/LearnerDashboardHeader/LearnerDashboardMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,169 @@
import React from 'react';
import {
IconHome,
IconBook,
IconClockHour3,
IconHelpHexagon,
IconBell,
} from '@tabler/icons-react';
import { getConfig } from '@edx/frontend-platform';

import urls from 'data/services/lms/urls';

import messages from './messages';

const ICON_MAP = {
Home: IconHome,
LibraryBooks: IconBook,
ClockHour3: IconClockHour3,
Search: ({ size = 18, className, ...props }) => (
<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
aria-hidden="true"
{...props}
>
<path
d="M18.665 18.665L12.665 12.665M0.665039 7.66504C0.665039 8.58429 0.846099 9.49454 1.19788 10.3438C1.54967 11.1931 2.06528 11.9648 2.71529 12.6148C3.3653 13.2648 4.13698 13.7804 4.98626 14.1322C5.83553 14.484 6.74579 14.665 7.66504 14.665C8.58429 14.665 9.49454 14.484 10.3438 14.1322C11.1931 13.7804 11.9648 13.2648 12.6148 12.6148C13.2648 11.9648 13.7804 11.1931 14.1322 10.3438C14.484 9.49454 14.665 8.58429 14.665 7.66504C14.665 6.74579 14.484 5.83553 14.1322 4.98626C13.7804 4.13698 13.2648 3.3653 12.6148 2.71529C11.9648 2.06528 11.1931 1.54967 10.3438 1.19788C9.49454 0.846099 8.58429 0.665039 7.66504 0.665039C6.74579 0.665039 5.83553 0.846099 4.98626 1.19788C4.13698 1.54967 3.3653 2.06528 2.71529 2.71529C2.06528 3.3653 1.54967 4.13698 1.19788 4.98626C0.846099 5.83553 0.665039 6.74579 0.665039 7.66504Z"
stroke="currentColor"
strokeWidth="1.33"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
HelpHexagon: IconHelpHexagon,
};

const NavItem = ({ icon: IconComponent, label }) => (
<span className="d-inline-flex align-items-center lw-nav-item">
<IconComponent size={18} className="lw-nav-icon" />
<span>{label}</span>
</span>
);

const getLearnerHeaderMenu = (
formatMessage,
courseSearchUrl,
authenticatedUser,
exploreCoursesClick,
) => ({
mainMenu: [
{
type: 'item',
href: '/',
content: formatMessage(messages.course),
isActive: true,
},
...(getConfig().ENABLE_PROGRAMS ? [{
type: 'item',
href: `${urls.programsUrl()}`,
content: formatMessage(messages.program),
}] : []),
...(!getConfig().NON_BROWSABLE_COURSES ? [{
) => {
const BASE_URL = getConfig().LMS_BASE_URL;
const searchCatalogUrl = getConfig().SEARCH_CATALOG_URL;
const configNavLinks = getConfig().HEADER_NAV_LINKS;
const isLinkActive = (link) => {
if (link.url === '/dashboard' || link.url.endsWith('/dashboard')) {
return getConfig().APP_ID === 'learner-dashboard';
}
const linkPath = link.url.startsWith('http')
? new URL(link.url).pathname
: link.url;
return window.location.pathname === linkPath;
};

const mainMenu = configNavLinks
? configNavLinks.map((link) => ({
type: 'item',
href: `${urls.baseAppUrl(courseSearchUrl)}`,
content: formatMessage(messages.discoverNew),
onClick: (e) => {
exploreCoursesClick(e);
href: link.url.startsWith('http') ? link.url : `${BASE_URL}${link.url}`,
isActive: isLinkActive(link),
content: (
<NavItem
icon={ICON_MAP[link.icon] ?? IconHome}
label={link.title}
/>
),
}))
: [
{
type: 'item',
href: '/',
content: formatMessage(messages.course),
isActive: true,
},
}]
: []),
],
secondaryMenu: [
...(getConfig().SUPPORT_URL ? [{
type: 'item',
href: `${getConfig().SUPPORT_URL}`,
content: formatMessage(messages.help),
}] : []),
],
userMenu: [
{
heading: '',
items: [
{
type: 'item',
href: `${getConfig().ACCOUNT_PROFILE_URL}/u/${authenticatedUser?.username}`,
content: formatMessage(messages.profile),
...(getConfig().ENABLE_PROGRAMS ? [{
type: 'item',
href: `${urls.programsUrl()}`,
content: formatMessage(messages.program),
}] : []),
...(!getConfig().NON_BROWSABLE_COURSES ? [{
type: 'item',
href: `${urls.baseAppUrl(courseSearchUrl)}`,
content: formatMessage(messages.discoverNew),
onClick: (e) => {
exploreCoursesClick(e);
},
{
type: 'item',
href: `${getConfig().ACCOUNT_SETTINGS_URL}`,
content: formatMessage(messages.account),
},
...(getConfig().ORDER_HISTORY_URL ? [{
type: 'item',
href: getConfig().ORDER_HISTORY_URL,
content: formatMessage(messages.orderHistory),
}] : []),
],
},
{
heading: '',
items: [
{
type: 'item',
href: `${getConfig().LOGOUT_URL}`,
content: formatMessage(messages.signOut),
},
],
},
],
}
);
}]
: []),
];

const searchItem = searchCatalogUrl ? [{
type: 'item',
href: null,
className: 'lw-search-item',
content: (
<div className="lw-search-wrapper">
<ICON_MAP.Search size={18} className="lw-search-icon" />
<input
className="lw-search-input"
type="search"
aria-label={formatMessage(messages.searchPlaceholder)}
placeholder={formatMessage(messages.searchPlaceholder)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
const q = e.target.value.trim();
window.location.href = urls.baseAppUrl(searchCatalogUrl)
+ (q ? `?q=${encodeURIComponent(q)}` : '');
}
}}
/>
</div>
),
}] : [];

return {
mainMenu: [...mainMenu, ...searchItem],
secondaryMenu: (
<button className="lw-notification-btn" aria-label="Notifications">
<IconBell size={24} />
</button>
),
userMenu: [
{
heading: '',
items: [
{
type: 'item',
href: `${getConfig().ACCOUNT_PROFILE_URL}/u/${authenticatedUser?.username}`,
content: formatMessage(messages.profile),
},
{
type: 'item',
href: `${getConfig().ACCOUNT_SETTINGS_URL}`,
content: formatMessage(messages.account),
},
...(getConfig().ORDER_HISTORY_URL ? [{
type: 'item',
href: getConfig().ORDER_HISTORY_URL,
content: formatMessage(messages.orderHistory),
}] : []),
],
},
{
heading: '',
items: [
{
type: 'item',
href: `${getConfig().LOGOUT_URL}`,
content: formatMessage(messages.signOut),
},
],
},
],
};
};

export default getLearnerHeaderMenu;
Loading