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

Work periods, part 2 #20

Merged
merged 2 commits into from
Jun 14, 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 config/dev.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module.exports = {
API: {
V3: "https://api.topcoder-dev.com/v3",
V5: "https://api.topcoder-dev.com/v5",
},
PLATFORM_WEBSITE_URL: "https://platform.topcoder-dev.com",
TOPCODER_WEBSITE_URL: "https://www.topcoder-dev.com",
};
4 changes: 0 additions & 4 deletions config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@

module.exports = (() => {
const appEnv = process.env.APPENV === "prod" ? "prod" : "dev";

// eslint-disable-next-line no-console
console.log(`APPENV: "${appEnv}"`);

return require(`./${appEnv}`);
})();
2 changes: 2 additions & 0 deletions config/prod.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module.exports = {
API: {
V3: "https://api.topcoder.com/v3",
V5: "https://api.topcoder.com/v5",
},
PLATFORM_WEBSITE_URL: "https://platform.topcoder.com",
TOPCODER_WEBSITE_URL: "https://www.topcoder.com",
};
20 changes: 20 additions & 0 deletions src/assets/images/icon-computer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/icon-copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/icon-dollar-circled.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/icon-link.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/icon-open-outside.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/Button/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import styles from "./styles.module.scss";
* @param {Object} props.children button text
* @param {string} [props.className] class name added to root element
* @param {'primary'|'primary-dark'|'primary-light'} [props.color] button color
* @param {boolean} [props.isDisabled] if button is disabled
* @param {boolean} [props.isSelected] if button is selected
* @param {string} [props.name] button name
* @param {(e: any) => void} props.onClick function called when button is clicked
Expand All @@ -24,6 +25,7 @@ const Button = ({
children,
className,
color = "primary",
isDisabled = false,
isSelected = false,
name,
onClick,
Expand All @@ -35,6 +37,7 @@ const Button = ({
}) => (
<button
data-value={value}
disabled={isDisabled}
name={name || ""}
type={type}
className={cn(
Expand All @@ -58,6 +61,7 @@ Button.propTypes = {
children: PT.node,
className: PT.string,
color: PT.oneOf(["primary"]),
isDisabled: PT.bool,
isSelected: PT.bool,
name: PT.string,
onClick: PT.func,
Expand Down
17 changes: 17 additions & 0 deletions src/components/Button/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
text-transform: uppercase;
outline: none;
cursor: pointer;

&:disabled {
opacity: 1;
cursor: not-allowed;
}
}

.medium {
Expand Down Expand Up @@ -55,6 +60,12 @@
border-color: $primary-dark-color;
color: $primary-dark-text-color;
}

&:disabled {
border-color: $control-disabled-border-color;
background-color: $control-disabled-bg-color;
color: $control-disabled-text-color;
}
}

.contained {
Expand All @@ -76,6 +87,12 @@
border-color: $primary-dark-color;
background-color: $primary-dark-color;
}

&:disabled {
border-color: $control-disabled-border-color;
background-color: $control-disabled-bg-color;
color: $control-disabled-text-color;
}
}

.circle,
Expand Down
10 changes: 10 additions & 0 deletions src/components/Checkbox/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import PT from "prop-types";
import cn from "classnames";
import { stopPropagation } from "utils/misc";
import styles from "./styles.module.scss";

/**
Expand All @@ -9,30 +10,37 @@ import styles from "./styles.module.scss";
* @param {Object} props component properties
* @param {boolean} props.checked whether checkbox is checked
* @param {string} [props.className] class name added to root element
* @param {boolean} [props.isDisabled] if checkbox is disabled
* @param {string} props.name name for input element
* @param {() => void} props.onChange function called when checkbox changes state
* @param {Object} [props.option] object { value, label }
* @param {'medium'|'small'} [props.size] checkbox size
* @param {boolean} [props.stopClickPropagation] whether to stop click event propagation
* @returns {JSX.Element}
*/
const Checkbox = ({
checked,
className,
isDisabled = false,
name,
onChange,
option,
size = "medium",
stopClickPropagation = false,
}) => (
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
<label
className={cn(
styles.container,
styles[size],
{ [styles.single]: !option || !option.label },
className
)}
onClick={stopClickPropagation ? stopPropagation : null}
>
<input
type="checkbox"
disabled={isDisabled}
className={styles.checkbox}
name={name}
onChange={onChange}
Expand All @@ -49,13 +57,15 @@ const Checkbox = ({
Checkbox.propTypes = {
checked: PT.bool,
className: PT.string,
isDisabled: PT.bool,
name: PT.string.isRequired,
size: PT.oneOf(["medium", "small"]),
onChange: PT.func.isRequired,
option: PT.shape({
value: PT.string.isRequired,
label: PT.string,
}),
stopClickPropagation: PT.bool,
};

export default Checkbox;
7 changes: 7 additions & 0 deletions src/components/Checkbox/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ input.checkbox {
}
}
}

&:disabled {
+ .impostor {
background-color: $control-disabled-bg-color;
cursor: not-allowed;
}
}
}

.impostor {
Expand Down
25 changes: 22 additions & 3 deletions src/components/IntegerField/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import styles from "./styles.module.scss";
*
* @param {Object} props component properties
* @param {string} [props.className] class name to be added to root element
* @param {boolean} [props.isDisabled] if the field is disabled
* @param {string} props.name field's name
* @param {number} props.value field's value
* @param {number} [props.maxValue] maximum allowed value
Expand All @@ -17,27 +18,45 @@ import styles from "./styles.module.scss";
*/
const IntegerField = ({
className,
isDisabled = false,
name,
onChange,
value,
maxValue = Infinity,
minValue = -Infinity,
}) => (
<div className={cn(styles.container, className)}>
<input
disabled={isDisabled}
readOnly
className={styles.input}
name={name}
value={value}
/>
<button
className={styles.btnMinus}
onClick={() => onChange(Math.max(value - 1, minValue))}
onClick={(event) => {
event.stopPropagation();
if (!isDisabled) {
onChange(Math.max(value - 1, minValue));
}
}}
/>
<button
className={styles.btnPlus}
onClick={() => onChange(Math.min(+value + 1, maxValue))}
onClick={(event) => {
event.stopPropagation();
if (!isDisabled) {
onChange(Math.min(+value + 1, maxValue));
}
}}
/>
<input readOnly className={styles.input} name={name} value={value} />
</div>
);

IntegerField.propTypes = {
className: PT.string,
isDisabled: PT.bool,
name: PT.string.isRequired,
maxValue: PT.number,
minValue: PT.number,
Expand Down
12 changes: 12 additions & 0 deletions src/components/IntegerField/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ input.input {
outline: none !important;
box-shadow: none !important;
text-align: center;

&:disabled {
border-color: $control-disabled-border-color;
background-color: $control-disabled-bg-color;
color: $control-disabled-text-color;
cursor: not-allowed;

~ .btnMinus,
~ .btnPlus {
cursor: not-allowed;
}
}
}

.btnMinus,
Expand Down
11 changes: 10 additions & 1 deletion src/components/Page/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import PT from "prop-types";
import cn from "classnames";
import ReduxToastr from "react-redux-toastr";
import styles from "./styles.module.scss";

/**
Expand All @@ -12,7 +13,15 @@ import styles from "./styles.module.scss";
* @returns {Object}
*/
const Page = ({ className, children }) => (
<div className={cn(styles.container, className)}>{children}</div>
<div className={cn(styles.container, className)}>
{children}
<ReduxToastr
timeOut={60000}
position="top-right"
transitionIn="fadeIn"
transitionOut="fadeOut"
/>
</div>
);

Page.propTypes = {
Expand Down
102 changes: 102 additions & 0 deletions src/components/SearchHandleField/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useCallback, useState } from "react";
import PT from "prop-types";
import cn from "classnames";
import _ from "lodash";
import AsyncSelect from "react-select/async";
import { getMemberSuggestions } from "services/teams";
// import { getOptionByValue } from "utils/misc";
import styles from "./styles.module.scss";

const selectComponents = {
DropdownIndicator: () => null,
IndicatorSeparator: () => null,
};

/**
* Displays search input field.
*
* @param {Object} props component properties
* @param {string} [props.className] class name added to root element
* @param {string} props.id id for input element
* @param {string} props.placeholder placeholder text
* @param {string} props.name name for input element
* @param {'medium'|'small'} [props.size] field size
* @param {function} props.onChange function called when input value changes
* @param {string} props.value input value
* @returns {JSX.Element}
*/
const SearchAutocomplete = ({
className,
id,
size = "medium",
onChange,
placeholder,
value,
}) => {
// const option = getOptionByValue(options, value);
const [savedInput, setSavedInput] = useState("");

const onValueChange = useCallback(
(option) => {
onChange(option.value);
},
[onChange]
);

return (
<div className={cn(styles.container, styles[size], className)}>
<span className={styles.icon} />
<AsyncSelect
className={styles.select}
classNamePrefix="custom"
components={selectComponents}
id={id}
isSearchable={true}
// menuIsOpen={true} // for debugging
// onChange={onOptionChange}
// onMenuOpen={onMenuOpen}
// onMenuClose={onMenuClose}
value={{ value, label: value }}
onInputChange={setSavedInput}
onFocus={() => {
setSavedInput("");
onChange(savedInput);
}}
placeholder={placeholder}
onChange={onValueChange}
noOptionsMessage={() => "No options"}
loadingMessage={() => "Loading..."}
loadOptions={loadSuggestions}
blurInputOnSelect
/>
</div>
);
};

const loadSuggestions = (inputVal) => {
return getMemberSuggestions(inputVal)
.then((res) => {
const users = _.get(res, "data.result.content", []);
return users.map((user) => ({
label: user.handle,
value: user.handle,
}));
})
.catch(() => {
console.warn("could not get suggestions");
return [];
});
};

SearchAutocomplete.propTypes = {
className: PT.string,
id: PT.string.isRequired,
size: PT.oneOf(["medium", "small"]),
name: PT.string.isRequired,
onChange: PT.func.isRequired,
options: PT.array,
placeholder: PT.string,
value: PT.oneOfType([PT.number, PT.string]),
};

export default SearchAutocomplete;
Loading