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

Commit c69cb7e

Browse files
Merge pull request #49 from topcoder-platform/dev
Dry Release v0.2
2 parents 4c4732a + 3f1d9cb commit c69cb7e

File tree

32 files changed

+844
-196
lines changed

32 files changed

+844
-196
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This is a [single-spa](https://single-spa.js.org/) example React microapp.
1515
- Router via [Reach Router](https://reach.tech/router/)
1616
- CSS Modules with SCSS via [babel-plugin-react-css-modules](https://github.com/gajus/babel-plugin-react-css-modules)
1717
- [React Inline SVG](https://github.com/airbnb/babel-plugin-inline-react-svg)
18+
- We use **Redux Store** for storing page data if we need to edit it. Otherwise we can use local state.
19+
- [react-redux-toastr](https://www.npmjs.com/package/react-redux-toastr) for success/error popups in the bottom left corner.
1820

1921
## Config
2022

config/development.js

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ module.exports = {
88
* Email to report issues to
99
*/
1010
EMAIL_REPORT_ISSUE: "[email protected]",
11+
12+
/**
13+
* Email to request extension
14+
*/
15+
EMAIL_REQUEST_EXTENSION: "[email protected]",
16+
1117
API: {
1218
V5: "https://api.topcoder-dev.com/v5",
1319
},

config/production.js

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ module.exports = {
88
* Email to report issues to
99
*/
1010
EMAIL_REPORT_ISSUE: "[email protected]",
11+
12+
/**
13+
* Email to request extension
14+
*/
15+
EMAIL_REQUEST_EXTENSION: "[email protected]",
16+
1117
API: {
1218
V5: "https://api.topcoder.com/v5",
1319
},

package-lock.json

+89-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"axios": "^0.21.0",
6060
"classnames": "^2.2.6",
6161
"express": "^4.17.1",
62+
"immutability-helper": "^3.1.1",
6263
"lodash": "^4.17.20",
6364
"moment": "^2.29.1",
6465
"prop-types": "^15.7.2",
@@ -67,7 +68,13 @@
6768
"react-dom": "^16.12.0",
6869
"react-outside-click-handler": "^1.3.0",
6970
"react-popper": "^2.2.3",
70-
"react-use": "^15.3.4"
71+
"react-redux": "^7.2.2",
72+
"react-redux-toastr": "^7.6.5",
73+
"react-use": "^15.3.4",
74+
"redux": "^4.0.5",
75+
"redux-logger": "^3.0.6",
76+
"redux-promise-middleware": "^6.1.2",
77+
"redux-thunk": "^2.3.0"
7178
},
7279
"browserslist": [
7380
"last 1 version",

src/components/LoadingIndicator/index.jsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44
* Optionally shows error.
55
*/
66
import React from "react";
7+
import _ from "lodash";
78
import PT from "prop-types";
89
import "./styles.module.scss";
910

1011
const LoadingIndicator = ({ error }) => {
1112
return (
12-
<div styleName="loading-indicator">{!error ? "Loading..." : error}</div>
13+
<div styleName="loading-indicator">
14+
{!error
15+
? "Loading..."
16+
: _.get(error, "response.data.message", error.toString())}
17+
</div>
1318
);
1419
};
1520

1621
LoadingIndicator.propTypes = {
17-
error: PT.string,
22+
error: PT.object,
1823
};
1924

2025
export default LoadingIndicator;

src/components/SkillsList/index.jsx

+31-11
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
* SkillsList
33
*
44
* Shows list of skills with "N more" link which is showing tooltip with a full list of skills.
5-
* If `showMatches = true` it marks matched and not matched required skills.
65
*/
7-
import React, { useCallback, useState } from "react";
6+
import React, { useCallback, useState, useMemo } from "react";
87
import PT from "prop-types";
98
import _ from "lodash";
109
import "./styles.module.scss";
@@ -13,17 +12,19 @@ import IconCross from "../../assets/images/icon-cross.svg";
1312
import { usePopper } from "react-popper";
1413
import OutsideClickHandler from "react-outside-click-handler";
1514

16-
const SkillsList = ({
17-
skills,
18-
limit = 3,
19-
showMatches = false,
20-
}) => {
15+
const SkillsList = ({ requiredSkills, skills, limit = 3 }) => {
2116
const skillsToShow = skills.slice(0, limit);
2217
const skillsToHide = skills.slice(limit);
2318

19+
// if has requiredSkills, show two columns, eles show only one column
20+
const showMatches = !!requiredSkills;
2421
const [isOpen, setIsOpen] = useState(false);
2522
const [referenceElement, setReferenceElement] = useState(null);
2623
const [popperElement, setPopperElement] = useState(null);
24+
25+
const otherSkills = useMemo(() => {
26+
return _.differenceBy(skills, requiredSkills, "id");
27+
}, [requiredSkills, skills]);
2728
const { styles, attributes } = usePopper(referenceElement, popperElement, {
2829
placement: "bottom",
2930
modifiers: [
@@ -96,11 +97,30 @@ const SkillsList = ({
9697
{...attributes.popper}
9798
>
9899
<div styleName="popover-content">
99-
{skills && (
100+
{requiredSkills && (
101+
<div styleName="skills-section">
102+
<div styleName="skills-title">Required Job Skills</div>
103+
<ul styleName="skills-list">
104+
{requiredSkills.map((skill) => (
105+
<li key={skill.id}>
106+
{_.find(skills, { id: skill.id }) ? (
107+
<IconCheck />
108+
) : (
109+
<IconCross />
110+
)}{" "}
111+
{skill.name}
112+
</li>
113+
))}
114+
</ul>
115+
</div>
116+
)}
117+
{otherSkills && (
100118
<div styleName="skills-section">
101-
<div styleName="skills-title">Skills</div>
119+
<div styleName="skills-title">
120+
{showMatches ? "Other User Skills" : "Required Skills"}
121+
</div>
102122
<ul styleName="skills-list">
103-
{skills.map((skill) => (
123+
{otherSkills.map((skill) => (
104124
<li key={skill.id}>{skill.name}</li>
105125
))}
106126
</ul>
@@ -123,8 +143,8 @@ export const skillShape = PT.shape({
123143

124144
SkillsList.propTypes = {
125145
skills: PT.arrayOf(skillShape),
146+
requiredSkills: PT.arrayOf(skillShape),
126147
limit: PT.number,
127-
showMatches: PT.bool,
128148
};
129149

130150
export default SkillsList;

src/components/SkillsSummary/index.jsx

+11-5
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,23 @@ import PercentageBar from "components/PercentageBar";
1010
import SkillsList from "components/SkillsList";
1111
import "./styles.module.scss";
1212

13-
const SkillsSummary = ({ skills, skillMatched, limit }) => {
13+
const SkillsSummary = ({ skills, requiredSkills = [], limit }) => {
14+
const skillsMatched = _.intersectionBy(skills, requiredSkills, "id");
15+
const skillsMatchedRatio =
16+
requiredSkills.length > 0
17+
? skillsMatched.length / requiredSkills.length
18+
: 1;
19+
1420
return (
1521
<div>
1622
<div styleName="percentage">
17-
<PercentageBar ratio={skillMatched / 100} styleName="percentage-bar" />
18-
{Math.round(skillMatched)}% skill matched
23+
<PercentageBar ratio={skillsMatchedRatio} styleName="percentage-bar" />
24+
{Math.round(skillsMatchedRatio * 100)}% skill matched
1925
</div>
2026
<SkillsList
2127
skills={skills}
28+
requiredSkills={requiredSkills}
2229
limit={limit}
23-
showMatches
2430
/>
2531
</div>
2632
);
@@ -33,8 +39,8 @@ const skillShape = PT.shape({
3339

3440
SkillsSummary.propTypes = {
3541
skills: PT.arrayOf(skillShape),
42+
requiredSkills: PT.arrayOf(skillShape),
3643
limit: PT.number,
37-
skillMatched: PT.number,
3844
};
3945

4046
export default SkillsSummary;

src/constants/index.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ export const DAY_FORMAT = "MM/DD/YYYY";
1212
*/
1313
export const TEAM_MEMBERS_PER_PAGE = 5;
1414

15+
/**
16+
* How many teams show per page by default
17+
*/
18+
export const TEAMS_PER_PAGE = 20;
19+
1520
/**
1621
* How many position candidates show per page by default
1722
*/
1823
export const POSITION_CANDIDATES_PER_PAGE = 5;
1924

25+
/**
26+
* Input debounce delay (ms)
27+
*/
28+
export const INPUT_DEBOUNCE_DELAY = 200;
29+
2030
/**
2131
* Position statuses
2232
*/
@@ -110,7 +120,7 @@ export const CANDIDATE_STATUS_FILTERS = [
110120
* Candidates "sort by" values
111121
*/
112122
export const CANDIDATES_SORT_BY = {
113-
SKILL_MATCHED: "skillMatched",
123+
SKILL_MATCHED: "skillsMatched",
114124
HANDLE: "handle",
115125
};
116126

@@ -121,3 +131,20 @@ export const CANDIDATES_SORT_OPTIONS = [
121131
{ label: "Skill Matched", value: CANDIDATES_SORT_BY.SKILL_MATCHED },
122132
{ label: "Handle", value: CANDIDATES_SORT_BY.HANDLE },
123133
];
134+
135+
/**
136+
* All action types
137+
*/
138+
export const ACTION_TYPE = {
139+
LOAD_POSITION: "LOAD_POSITION",
140+
LOAD_POSITION_PENDING: "LOAD_POSITION_PENDING",
141+
LOAD_POSITION_SUCCESS: "LOAD_POSITION_SUCCESS",
142+
LOAD_POSITION_ERROR: "LOAD_POSITION_ERROR",
143+
144+
RESET_POSITION_STATE: "RESET_POSITION_STATE",
145+
146+
UPDATE_CANDIDATE: "UPDATE_CANDIDATE",
147+
UPDATE_CANDIDATE_PENDING: "UPDATE_CANDIDATE_PENDING",
148+
UPDATE_CANDIDATE_SUCCESS: "UPDATE_CANDIDATE_SUCCESS",
149+
UPDATE_CANDIDATE_ERROR: "UPDATE_CANDIDATE_ERROR",
150+
};

0 commit comments

Comments
 (0)