Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit ed92b29

Browse files
committed
final fix for Topcoder Self Service Dashboard MFE
1 parent 6eecd23 commit ed92b29

File tree

11 files changed

+248
-20
lines changed

11 files changed

+248
-20
lines changed

src/components/NavBar/index.jsx

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@
33
*
44
* Shows global top navigation bar with all apps menu, logo and user menu.
55
*/
6-
import React, {
6+
import React, {
77
useState,
88
useCallback,
99
Fragment,
1010
useEffect,
1111
useMemo,
1212
} from "react";
13+
import cn from "classnames";
1314
import _ from "lodash";
1415
import PropTypes from "prop-types";
1516
import UserMenu from "../UserMenu";
1617
import AllAppsMenu from "../AllAppsMenu";
1718
import { useSelector } from "react-redux";
1819
import { Link, useLocation } from "@reach/router";
1920
import TCLogo from "../../assets/images/tc-logo.svg";
20-
import { getLoginUrl } from "../../utils";
21+
import { getLoginUrl, getSelfServiceLoginUrl } from "../../utils";
2122
import "./styles.css";
2223
import { useMediaQuery } from "react-responsive";
2324
import NotificationsMenu from "../NotificationsMenu";
25+
import SelfServiceNotifications from "../SelfServiceNotificationsMenu";
26+
import SelfServiceUserMenu from "../SelfServiceUserMenu";
2427

2528
const NavBar = ({ hideSwitchTools }) => {
2629
// all menu options
@@ -35,13 +38,18 @@ const NavBar = ({ hideSwitchTools }) => {
3538
});
3639

3740
const routerLocation = useLocation();
41+
42+
const loginUrl = routerLocation.pathname.startsWith("/self-service/wizard")
43+
? getSelfServiceLoginUrl()
44+
: getLoginUrl();
45+
3846
// Check app title with route activated
3947
useEffect(() => {
4048
const activeApp = apps.find(
4149
(f) => routerLocation.pathname.indexOf(f.path) !== -1
4250
);
4351
setActiveApp(activeApp);
44-
}, [routerLocation]);
52+
}, [routerLocation, apps]);
4553

4654
// Change micro-app callback
4755
const changeApp = useCallback(
@@ -60,7 +68,7 @@ const NavBar = ({ hideSwitchTools }) => {
6068
);
6169

6270
return (
63-
<div className="navbar">
71+
<div className={cn("navbar", { "self-service-navbar": hideSwitchTools })}>
6472
<div className="navbar-left">
6573
{isMobile ? (
6674
hideSwitchTools ? null : (
@@ -89,38 +97,54 @@ const NavBar = ({ hideSwitchTools }) => {
8997
<Fragment>
9098
{auth.isInitialized &&
9199
(auth.tokenV3 ? (
92-
auth.profile && (
100+
auth.profile &&
101+
(hideSwitchTools ? (
102+
<Fragment>
103+
<SelfServiceNotifications />
104+
<SelfServiceUserMenu profile={auth.profile} />
105+
</Fragment>
106+
) : (
93107
<Fragment>
94-
{hideSwitchTools ? null : <NotificationsMenu />}
108+
<NotificationsMenu />
95109
<UserMenu
96110
profile={auth.profile}
97111
hideSwitchTools={hideSwitchTools}
98112
/>
99113
</Fragment>
100-
)
114+
))
101115
) : (
102-
<a href={getLoginUrl()} className="navbar-login">
116+
<a href={loginUrl} className="navbar-login">
103117
Login
104118
</a>
105119
))}
106120
</Fragment>
107121
) : (
108122
<Fragment>
109-
{hideSwitchTools ? null : <AllAppsMenu appChange={changeApp} />}
110-
<div className="navbar-divider"></div>
123+
{hideSwitchTools ? null : (
124+
<Fragment>
125+
<AllAppsMenu appChange={changeApp} />
126+
<div className="navbar-divider" />
127+
</Fragment>
128+
)}
111129
{auth.isInitialized &&
112130
(auth.tokenV3 ? (
113-
auth.profile && (
131+
auth.profile &&
132+
(hideSwitchTools ? (
133+
<Fragment>
134+
<SelfServiceNotifications />
135+
<SelfServiceUserMenu profile={auth.profile} />
136+
</Fragment>
137+
) : (
114138
<Fragment>
115-
{hideSwitchTools ? null : <NotificationsMenu />}
139+
<NotificationsMenu />
116140
<UserMenu
117141
profile={auth.profile}
118142
hideSwitchTools={hideSwitchTools}
119143
/>
120144
</Fragment>
121-
)
145+
))
122146
) : (
123-
<a href={getLoginUrl()} className="navbar-login">
147+
<a href={loginUrl} className="navbar-login">
124148
Login
125149
</a>
126150
))}

src/components/NavBar/styles.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
z-index: 1;
1111
font-family: "Roboto", Arial, Helvetica, sans-serif;
1212
}
13+
.navbar.self-service-navbar {
14+
padding: 0 24px;
15+
background-color: #0C0C0C;
16+
}
1317

1418
.navbar-left {
1519
display: flex;
@@ -26,6 +30,25 @@
2630
text-align: left;
2731
color: #fff;
2832
}
33+
.self-service-navbar .navbar-app-title {
34+
position: relative;
35+
font-family: "Barlow Condensed", Arial, Helvetica, sans-serif;
36+
font-weight: 500;
37+
font-size: 20px;
38+
line-height: 18px;
39+
}
40+
.self-service-navbar .navbar-app-title::after {
41+
content: "";
42+
display: block;
43+
position: absolute;
44+
left: 8.5px;
45+
top: 100%;
46+
right: 8.5px;
47+
margin: 10px 0 0;
48+
border-radius: 2px;
49+
height: 2px;
50+
background-color: #0AB88A;
51+
}
2952
.navbar-divider {
3053
width: 1px;
3154
height: 30px;
@@ -34,6 +57,9 @@
3457
.navbar-left .navbar-divider {
3558
margin: 0 30px;
3659
}
60+
.self-service-navbar .navbar-left .navbar-divider {
61+
margin: 0 23px;
62+
}
3763
.navbar-center {
3864
left: 50%;
3965
position: absolute;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import Bell from "../../assets/icons/ui-bell.svg";
3+
import styles from "./styles.module.scss";
4+
5+
/**
6+
* Displays self service notification bell.
7+
*
8+
* @returns {JSX.Element}
9+
*/
10+
const SelfServiceNotifications = () => {
11+
return (
12+
<div className={styles.container}>
13+
<div className={styles.button}>
14+
<Bell className={styles.bell} />
15+
<div className={styles.count}>0</div>
16+
</div>
17+
</div>
18+
);
19+
};
20+
21+
export default SelfServiceNotifications;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.container {
2+
position: relative;
3+
display: flex;
4+
margin-right: 16px;
5+
}
6+
7+
.button {
8+
position: relative;
9+
width: 16px;
10+
height: 16px;
11+
cursor: pointer;
12+
}
13+
14+
.bell {
15+
display: block;
16+
width: 16px;
17+
height: auto;
18+
19+
path {
20+
fill: #fff;
21+
}
22+
}
23+
24+
.count {
25+
position: absolute;
26+
top: -8px;
27+
right: -8px;
28+
border-radius: 8px;
29+
width: 16px;
30+
height: 16px;
31+
font-family: "Roboto", Arial, Helvetica, sans-serif;
32+
font-weight: 700;
33+
font-size: 8px;
34+
line-height: 16px;
35+
text-align: center;
36+
background-color: #E90C5A;
37+
color: #fff;
38+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React, { useCallback, useState } from "react";
2+
import PT from "prop-types";
3+
import OutsideClickHandler from "react-outside-click-handler";
4+
import { logout, getLogoutUrl } from "utils";
5+
import styles from "./styles.module.scss";
6+
7+
/**
8+
* Displays user profile icon.
9+
*
10+
* @param {Object} props component properties
11+
* @returns {JSX.Element}
12+
*/
13+
const SelfServiceUserMenu = ({ profile }) => {
14+
const [isOpenMenu, setIsOpenMenu] = useState(false);
15+
16+
const { firstName, lastName } = profile;
17+
18+
const onClickBtn = useCallback(() => {
19+
setIsOpenMenu((value) => !value);
20+
}, []);
21+
22+
const onClickOutsideMenu = useCallback(() => {
23+
setIsOpenMenu(false);
24+
}, []);
25+
26+
const onClickLogout = useCallback((event) => {
27+
event.preventDefault();
28+
logout();
29+
}, []);
30+
31+
return (
32+
<div className={styles.container}>
33+
<OutsideClickHandler onOutsideClick={onClickOutsideMenu}>
34+
<div
35+
className={styles.button}
36+
onClick={onClickBtn}
37+
role="button"
38+
tabIndex={0}
39+
>
40+
{firstName.charAt(0)}
41+
{lastName.charAt(0)}
42+
</div>
43+
{isOpenMenu && (
44+
<div className={styles.menu}>
45+
<a href={getLogoutUrl()} onClick={onClickLogout}>
46+
Log Out
47+
</a>
48+
</div>
49+
)}
50+
</OutsideClickHandler>
51+
</div>
52+
);
53+
};
54+
55+
SelfServiceUserMenu.propTypes = {
56+
profile: PT.shape({
57+
firstName: PT.string.isRequired,
58+
lastName: PT.string.isRequired,
59+
}).isRequired,
60+
};
61+
62+
export default SelfServiceUserMenu;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.container {
2+
position: relative;
3+
display: flex;
4+
}
5+
6+
.button {
7+
border: 2px solid #fff;
8+
border-radius: 16px;
9+
width: 32px;
10+
height: 32px;
11+
font-family: "Barlow Condensed", Arial, Helvetica, sans-serif;
12+
font-weight: 700;
13+
font-size: 14px;
14+
line-height: 28px;
15+
text-align: center;
16+
background: linear-gradient(90deg, #16679A 0%, #2C95D7 100%);
17+
color: #fff;
18+
user-select: none;
19+
cursor: pointer;
20+
}
21+
22+
.menu {
23+
z-index: 3;
24+
position: absolute;
25+
top: 100%;
26+
right: 0;
27+
margin-top: 10px;
28+
border: 1px solid #555;
29+
border-radius: 8px;
30+
padding: 5px 12px;
31+
white-space: nowrap;
32+
background-color: #fff;
33+
user-select: none;
34+
}

src/constants/apps.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ export const APP_CATEGORIES = [
6060
},
6161
],
6262
},
63+
{
64+
category: "Self Service",
65+
apps: [
66+
{
67+
title: "Work",
68+
icon: earnIcon,
69+
path: "/self-service",
70+
menu: [],
71+
},
72+
],
73+
},
6374
{
6475
category: "Do",
6576
apps: [

src/reducers/auth.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ const authReducer = (state = initialState, action) => {
3030
isProfileLoaded: true,
3131
};
3232
case ACTIONS.AUTH.SET_PROFILE_PHOTO:
33-
return state.profile ? ({
34-
...state,
35-
profile: {...state.profile, photoURL: action.payload},
36-
}) : state;
33+
return state.profile
34+
? {
35+
...state,
36+
profile: { ...state.profile, photoURL: action.payload },
37+
}
38+
: state;
3739
case ACTIONS.AUTH.SET_INITIALIZED:
3840
return {
3941
...state,

src/services/auth.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,3 @@ export function authenticate(store) {
125125
}
126126
});
127127
}
128-

src/utils/exports.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const {
1616
disableSidebarForRoute,
1717
enableSidebarForRoute,
1818
setNotificationPlatform,
19-
setUserProfilePhoto
19+
setUserProfilePhoto,
2020
} = bindActionCreators(
2121
{
2222
setAppMenu: menuActions.setAppMenu,

src/utils/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ export const getBusinessLoginUrl = () =>
2626
window.location.href.match(/[^?]*/)[0]
2727
)}`;
2828

29+
/**
30+
* Returns login URL using which the user should be redirected to self service
31+
* dashboard page after login.
32+
*
33+
* @returns {string}
34+
*/
35+
export const getSelfServiceLoginUrl = () =>
36+
`${config.URL.AUTH}?retUrl=${encodeURIComponent(
37+
`${window.location.origin}/self-service`
38+
)}`;
39+
2940
/**
3041
* Logout user from Topcoder
3142
*/

0 commit comments

Comments
 (0)