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

feat: add roles page #84

Merged
merged 1 commit into from
Aug 3, 2021
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
2 changes: 2 additions & 0 deletions src/assets/images/icon-menu-item-roles.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions src/assets/images/icon-role-fallback.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/assets/images/icon-search.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions src/components/Icons/Roles/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import PT from "prop-types";
import cn from "classnames";
import IconWrapper from "components/IconWrapper";
import IconRoleManagement from "../../../assets/images/icon-menu-item-roles.svg";
import styles from "./styles.module.scss";

/**
* Displays a "role management" icon used in navigation menu.
*
* @param {Object} props component props
* @param {string} [props.className] class name added to root element
* @param {boolean} [props.isActive] a flag indicating whether the icon is active
* @returns {JSX.Element}
*/
const Roles = ({ className, isActive = false }) => (
<IconWrapper
className={cn(styles.container, className, { [styles.isActive]: isActive })}
>
<IconRoleManagement />
</IconWrapper>
);

Roles.propTypes = {
className: PT.string,
isActive: PT.bool,
};

export default Roles;
19 changes: 19 additions & 0 deletions src/components/Icons/Roles/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.container {
svg {
display: block;
width: auto;
height: 100%;

path {
fill: #7f7f7f;
}
}

&.isActive {
svg {
path {
fill: #06d6a0;
}
}
}
}
6 changes: 6 additions & 0 deletions src/components/Sidebar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import NavMenu from "components/NavMenu";
import styles from "./styles.module.scss";
import WorkPeriods from "components/Icons/WorkPeriods";
import Freelancers from "components/Icons/Freelancers";
import Roles from "components/Icons/Roles";
import { APP_BASE_PATH } from "../../constants";

/**
Expand Down Expand Up @@ -38,6 +39,11 @@ const NAV_ITEMS = [
label: "Freelancers",
path: `${APP_BASE_PATH}/freelancers`,
},
{
icon: Roles,
label: "Roles",
path: `${APP_BASE_PATH}/roles`,
},
];

export default Sidebar;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useCallback, useRef, useState } from "react";
import PT from "prop-types";
import cn from "classnames";
import get from "lodash/get";
import throttle from "lodash/throttle";
import Select, { components } from "react-select";
import { getMemberSuggestions } from "services/teams";
import { useUpdateEffect } from "utils/hooks";
import styles from "./styles.module.scss";

Expand Down Expand Up @@ -75,9 +75,11 @@ const selectComponents = {
* @param {function} [props.onInputChange] function called when input value changes
* @param {function} [props.onBlur] function called on input blur
* @param {string} props.value input value
* @param {function} props.getSuggestions the function to get suggestions
* @param {string} props.targetProp the target property of the returned object from getSuggestions
* @returns {JSX.Element}
*/
const SearchHandleField = ({
const Typeahead = ({
className,
id,
name,
Expand All @@ -87,6 +89,8 @@ const SearchHandleField = ({
onBlur,
placeholder,
value,
getSuggestions,
targetProp,
}) => {
const [inputValue, setInputValue] = useState(value);
const [isLoading, setIsLoading] = useState(false);
Expand Down Expand Up @@ -165,11 +169,15 @@ const SearchHandleField = ({
return;
}
setIsLoading(true);
const options = await loadSuggestions(value);
setIsMenuOpen(true);
const options = await loadSuggestions(
getSuggestions,
value,
targetProp
);
if (!isChangeAppliedRef.current) {
setOptions(options);
setIsLoading(false);
setIsMenuOpen(true);
}
},
300,
Expand Down Expand Up @@ -223,17 +231,17 @@ const SearchHandleField = ({
);
};

const loadSuggestions = async (inputValue) => {
const loadSuggestions = async (getSuggestions, inputValue, targetProp) => {
let options = [];
if (inputValue.length < 3) {
return options;
}
try {
const res = await getMemberSuggestions(inputValue);
const users = res.data.slice(0, 100);
const res = await getSuggestions(inputValue);
const items = res.data.slice(0, 100);
let match = null;
for (let i = 0, len = users.length; i < len; i++) {
let value = users[i].handle;
for (let i = 0, len = items.length; i < len; i++) {
let value = get(items[i], targetProp);
if (value === inputValue) {
match = { value, label: value };
} else {
Expand All @@ -250,7 +258,7 @@ const loadSuggestions = async (inputValue) => {
return options;
};

SearchHandleField.propTypes = {
Typeahead.propTypes = {
className: PT.string,
id: PT.string.isRequired,
size: PT.oneOf(["medium", "small"]),
Expand All @@ -260,6 +268,8 @@ SearchHandleField.propTypes = {
onBlur: PT.func,
placeholder: PT.string,
value: PT.oneOfType([PT.number, PT.string]),
getSuggestions: PT.func,
targetProp: PT.string,
};

export default SearchHandleField;
export default Typeahead;
2 changes: 2 additions & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const WORK_PERIODS_PATH = `${APP_BASE_PATH}/work-periods`;

export const FREELANCERS_PATH = `${APP_BASE_PATH}/freelancers`;

export const ROLES_PATH = `${APP_BASE_PATH}/roles`;

export const TAAS_BASE_PATH = "/taas";

export const ADMIN_ROLES = ["bookingmanager", "administrator"];
Expand Down
3 changes: 3 additions & 0 deletions src/root.component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import store from "store";
import { disableSidebarForRoute } from "@topcoder/micro-frontends-navbar-app";
import WorkPeriods from "routes/WorkPeriods";
import Freelancers from "routes/Freelancers";
import Roles from "routes/Roles";
import {
APP_BASE_PATH,
FREELANCERS_PATH,
WORK_PERIODS_PATH,
ROLES_PATH,
} from "./constants";
import "styles/global.scss";

Expand All @@ -23,6 +25,7 @@ export default function Root() {
<Redirect from={APP_BASE_PATH} to={WORK_PERIODS_PATH} exact noThrow />
<WorkPeriods path={WORK_PERIODS_PATH} />
<Freelancers path={FREELANCERS_PATH} />
<Roles path={ROLES_PATH} />
</Router>
</Provider>
);
Expand Down
Loading