diff --git a/src/components/NavBar/index.jsx b/src/components/NavBar/index.jsx index f05eb39..cdffdde 100644 --- a/src/components/NavBar/index.jsx +++ b/src/components/NavBar/index.jsx @@ -10,6 +10,7 @@ import React, { useEffect, useMemo, } from "react"; +import cn from "classnames"; import _ from "lodash"; import PropTypes from "prop-types"; import UserMenu from "../UserMenu"; @@ -17,10 +18,12 @@ import AllAppsMenu from "../AllAppsMenu"; import { useSelector } from "react-redux"; import { Link, useLocation } from "@reach/router"; import TCLogo from "../../assets/images/tc-logo.svg"; -import { getLoginUrl } from "../../utils"; +import { getLoginUrl, getSelfServiceLoginUrl } from "../../utils"; import "./styles.css"; import { useMediaQuery } from "react-responsive"; import NotificationsMenu from "../NotificationsMenu"; +import SelfServiceNotifications from "../SelfServiceNotificationsMenu"; +import SelfServiceUserMenu from "../SelfServiceUserMenu"; const NavBar = ({ hideSwitchTools }) => { // all menu options @@ -35,13 +38,18 @@ const NavBar = ({ hideSwitchTools }) => { }); const routerLocation = useLocation(); + + const loginUrl = routerLocation.pathname.startsWith("/self-service/wizard") + ? getSelfServiceLoginUrl() + : getLoginUrl(); + // Check app title with route activated useEffect(() => { const activeApp = apps.find( (f) => routerLocation.pathname.indexOf(f.path) !== -1 ); setActiveApp(activeApp); - }, [routerLocation]); + }, [routerLocation, apps]); // Change micro-app callback const changeApp = useCallback( @@ -60,7 +68,7 @@ const NavBar = ({ hideSwitchTools }) => { ); return ( -
+
{isMobile ? ( hideSwitchTools ? null : ( @@ -89,38 +97,54 @@ const NavBar = ({ hideSwitchTools }) => { {auth.isInitialized && (auth.tokenV3 ? ( - auth.profile && ( + auth.profile && + (hideSwitchTools ? ( + + + + + ) : ( - {hideSwitchTools ? null : } + - ) + )) ) : ( - + Login ))} ) : ( - {hideSwitchTools ? null : } -
+ {hideSwitchTools ? null : ( + + +
+ + )} {auth.isInitialized && (auth.tokenV3 ? ( - auth.profile && ( + auth.profile && + (hideSwitchTools ? ( + + + + + ) : ( - {hideSwitchTools ? null : } + - ) + )) ) : ( - + Login ))} diff --git a/src/components/NavBar/styles.css b/src/components/NavBar/styles.css index 482709f..a43f09a 100644 --- a/src/components/NavBar/styles.css +++ b/src/components/NavBar/styles.css @@ -10,6 +10,10 @@ z-index: 1; font-family: "Roboto", Arial, Helvetica, sans-serif; } +.navbar.self-service-navbar { + padding: 0 24px; + background-color: #0C0C0C; +} .navbar-left { display: flex; @@ -26,6 +30,25 @@ text-align: left; color: #fff; } +.self-service-navbar .navbar-app-title { + position: relative; + font-family: "Barlow Condensed", Arial, Helvetica, sans-serif; + font-weight: 500; + font-size: 20px; + line-height: 18px; +} +.self-service-navbar .navbar-app-title::after { + content: ""; + display: block; + position: absolute; + left: 8.5px; + top: 100%; + right: 8.5px; + margin: 10px 0 0; + border-radius: 2px; + height: 2px; + background-color: #0AB88A; +} .navbar-divider { width: 1px; height: 30px; @@ -34,6 +57,9 @@ .navbar-left .navbar-divider { margin: 0 30px; } +.self-service-navbar .navbar-left .navbar-divider { + margin: 0 23px; +} .navbar-center { left: 50%; position: absolute; diff --git a/src/components/SelfServiceNotificationsMenu/index.jsx b/src/components/SelfServiceNotificationsMenu/index.jsx new file mode 100644 index 0000000..ec3dc23 --- /dev/null +++ b/src/components/SelfServiceNotificationsMenu/index.jsx @@ -0,0 +1,21 @@ +import React from "react"; +import Bell from "../../assets/icons/ui-bell.svg"; +import styles from "./styles.module.scss"; + +/** + * Displays self service notification bell. + * + * @returns {JSX.Element} + */ +const SelfServiceNotifications = () => { + return ( +
+
+ +
0
+
+
+ ); +}; + +export default SelfServiceNotifications; diff --git a/src/components/SelfServiceNotificationsMenu/styles.module.scss b/src/components/SelfServiceNotificationsMenu/styles.module.scss new file mode 100644 index 0000000..b3db2b2 --- /dev/null +++ b/src/components/SelfServiceNotificationsMenu/styles.module.scss @@ -0,0 +1,38 @@ +.container { + position: relative; + display: flex; + margin-right: 16px; +} + +.button { + position: relative; + width: 16px; + height: 16px; + cursor: pointer; +} + +.bell { + display: block; + width: 16px; + height: auto; + + path { + fill: #fff; + } +} + +.count { + position: absolute; + top: -8px; + right: -8px; + border-radius: 8px; + width: 16px; + height: 16px; + font-family: "Roboto", Arial, Helvetica, sans-serif; + font-weight: 700; + font-size: 8px; + line-height: 16px; + text-align: center; + background-color: #E90C5A; + color: #fff; +} diff --git a/src/components/SelfServiceUserMenu/index.jsx b/src/components/SelfServiceUserMenu/index.jsx new file mode 100644 index 0000000..ef7bf7e --- /dev/null +++ b/src/components/SelfServiceUserMenu/index.jsx @@ -0,0 +1,62 @@ +import React, { useCallback, useState } from "react"; +import PT from "prop-types"; +import OutsideClickHandler from "react-outside-click-handler"; +import { logout, getLogoutUrl } from "utils"; +import styles from "./styles.module.scss"; + +/** + * Displays user profile icon. + * + * @param {Object} props component properties + * @returns {JSX.Element} + */ +const SelfServiceUserMenu = ({ profile }) => { + const [isOpenMenu, setIsOpenMenu] = useState(false); + + const { firstName, lastName } = profile; + + const onClickBtn = useCallback(() => { + setIsOpenMenu((value) => !value); + }, []); + + const onClickOutsideMenu = useCallback(() => { + setIsOpenMenu(false); + }, []); + + const onClickLogout = useCallback((event) => { + event.preventDefault(); + logout(); + }, []); + + return ( +
+ +
+ {firstName.charAt(0)} + {lastName.charAt(0)} +
+ {isOpenMenu && ( + + )} +
+
+ ); +}; + +SelfServiceUserMenu.propTypes = { + profile: PT.shape({ + firstName: PT.string.isRequired, + lastName: PT.string.isRequired, + }).isRequired, +}; + +export default SelfServiceUserMenu; diff --git a/src/components/SelfServiceUserMenu/styles.module.scss b/src/components/SelfServiceUserMenu/styles.module.scss new file mode 100644 index 0000000..836168d --- /dev/null +++ b/src/components/SelfServiceUserMenu/styles.module.scss @@ -0,0 +1,34 @@ +.container { + position: relative; + display: flex; +} + +.button { + border: 2px solid #fff; + border-radius: 16px; + width: 32px; + height: 32px; + font-family: "Barlow Condensed", Arial, Helvetica, sans-serif; + font-weight: 700; + font-size: 14px; + line-height: 28px; + text-align: center; + background: linear-gradient(90deg, #16679A 0%, #2C95D7 100%); + color: #fff; + user-select: none; + cursor: pointer; +} + +.menu { + z-index: 3; + position: absolute; + top: 100%; + right: 0; + margin-top: 10px; + border: 1px solid #555; + border-radius: 8px; + padding: 5px 12px; + white-space: nowrap; + background-color: #fff; + user-select: none; +} diff --git a/src/constants/apps.js b/src/constants/apps.js index 1d377dc..a83cc68 100644 --- a/src/constants/apps.js +++ b/src/constants/apps.js @@ -60,6 +60,17 @@ export const APP_CATEGORIES = [ }, ], }, + { + category: "Self Service", + apps: [ + { + title: "Work", + icon: earnIcon, + path: "/self-service", + menu: [], + }, + ], + }, { category: "Do", apps: [ diff --git a/src/reducers/auth.js b/src/reducers/auth.js index 65c1d84..0ef6930 100644 --- a/src/reducers/auth.js +++ b/src/reducers/auth.js @@ -30,10 +30,12 @@ const authReducer = (state = initialState, action) => { isProfileLoaded: true, }; case ACTIONS.AUTH.SET_PROFILE_PHOTO: - return state.profile ? ({ - ...state, - profile: {...state.profile, photoURL: action.payload}, - }) : state; + return state.profile + ? { + ...state, + profile: { ...state.profile, photoURL: action.payload }, + } + : state; case ACTIONS.AUTH.SET_INITIALIZED: return { ...state, diff --git a/src/utils/index.js b/src/utils/index.js index 35ab947..a12fc82 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -26,6 +26,17 @@ export const getBusinessLoginUrl = () => window.location.href.match(/[^?]*/)[0] )}`; +/** + * Returns login URL using which the user should be redirected to self service + * dashboard page after login. + * + * @returns {string} + */ +export const getSelfServiceLoginUrl = () => + `${config.URL.AUTH}?retUrl=${encodeURIComponent( + `${window.location.origin}/self-service` + )}`; + /** * Logout user from Topcoder */