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

[PROD] [HOTFIX] Post Release Patch 1.0.1 #115

Merged
merged 1 commit into from
Feb 24, 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
44 changes: 25 additions & 19 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,40 @@ export const CANDIDATE_STATUS = {
SELECTED: "selected",
SHORTLIST: "shortlist",
REJECTED: "rejected",
INTERVIEW: "interview",
};

/**
* Mapping between candidate status "server value" and human readable value
* Candidate status filters keys
*/
export const CANDIDATE_STATUS_TO_TEXT = {
[CANDIDATE_STATUS.OPEN]: "To Review",
[CANDIDATE_STATUS.SELECTED]: "Selected",
[CANDIDATE_STATUS.SHORTLIST]: "Interested",
[CANDIDATE_STATUS.REJECTED]: "Not Interested",
export const CANDIDATE_STATUS_FILTER_KEY = {
TO_REVIEW: "TO_REVIEW",
INTERESTED: "INTERESTED",
NOT_INTERESTED: "NOT_INTERESTED",
};

/**
* Mapping between candidate status "server value" and list title text
*/
export const CANDIDATE_STATUS_TO_TITLE_TEXT = {
[CANDIDATE_STATUS.OPEN]: "Candidates to Review",
[CANDIDATE_STATUS.SHORTLIST]: "Interested Candidates",
[CANDIDATE_STATUS.REJECTED]: "Not Interested Candidates",
};

/**
* Which candidate status filters to show on the open position details page
* Candidate status filters
*/
export const CANDIDATE_STATUS_FILTERS = [
CANDIDATE_STATUS.OPEN,
CANDIDATE_STATUS.SHORTLIST,
CANDIDATE_STATUS.REJECTED,
{
key: CANDIDATE_STATUS_FILTER_KEY.TO_REVIEW,
buttonText: "To Review",
title: "Candidates to Review",
statuses: [CANDIDATE_STATUS.OPEN],
},
{
key: CANDIDATE_STATUS_FILTER_KEY.INTERESTED,
buttonText: "Interested",
title: "Interested Candidates",
statuses: [CANDIDATE_STATUS.SHORTLIST, CANDIDATE_STATUS.INTERVIEW],
},
{
key: CANDIDATE_STATUS_FILTER_KEY.NOT_INTERESTED,
buttonText: "Not Interested",
title: "Not Interested Candidates",
statuses: [CANDIDATE_STATUS.REJECTED],
},
];

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,28 @@ import Button from "components/Button";
import {
CANDIDATE_STATUS,
CANDIDATE_STATUS_FILTERS,
CANDIDATE_STATUS_TO_TEXT,
CANDIDATE_STATUS_FILTER_KEY,
} from "constants";

const CandidatesStatusFilter = ({ currentStatus, onChange, candidates }) => {
const CandidatesStatusFilter = ({ statusFilterKey, onChange, candidates }) => {
return (
<div styleName="candidates-status-filter">
{CANDIDATE_STATUS_FILTERS.map((status) => (
{CANDIDATE_STATUS_FILTERS.map((statusFilter) => (
<Button
key={status}
type={currentStatus === status ? "segment-selected" : "segment"}
onClick={() => onChange(status)}
key={statusFilter.key}
type={statusFilterKey === statusFilter.key ? "segment-selected" : "segment"}
onClick={() => onChange(statusFilter)}
>
{CANDIDATE_STATUS_TO_TEXT[status]} (
{_.filter(candidates, { status }).length})
{statusFilter.buttonText} (
{_.filter(candidates, (candidate) => statusFilter.statuses.includes(candidate.status)).length})
</Button>
))}
</div>
);
};

CandidatesStatusFilter.propTypes = {
currentStatus: PT.oneOf(Object.values(CANDIDATE_STATUS)),
statusFilterKey: PT.oneOf(Object.values(CANDIDATE_STATUS_FILTER_KEY)),
onChange: PT.func,
candidates: PT.arrayOf(
PT.shape({
Expand Down
22 changes: 12 additions & 10 deletions src/routes/PositionDetails/components/PositionCandidates/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import CardHeader from "components/CardHeader";
import "./styles.module.scss";
import Select from "components/Select";
import {
CANDIDATE_STATUS_TO_TITLE_TEXT,
CANDIDATE_STATUS_FILTERS,
CANDIDATE_STATUS_FILTER_KEY,
CANDIDATES_SORT_OPTIONS,
CANDIDATES_SORT_BY,
CANDIDATE_STATUS,
Expand Down Expand Up @@ -54,19 +55,20 @@ const populateSkillsMatched = (position, candidate) => ({
skillsMatched: _.intersectionBy(position.skills, candidate.skills, "id"),
});

const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {
const PositionCandidates = ({ position, statusFilterKey, updateCandidate }) => {
const { candidates } = position;
const [sortBy, setSortBy] = useState(CANDIDATES_SORT_BY.SKILL_MATCHED);
const statusFilter = useMemo(() =>
_.find(CANDIDATE_STATUS_FILTERS, { key: statusFilterKey })
, [statusFilterKey]);
const filteredCandidates = useMemo(
() =>
_.chain(candidates)
.map((candidate) => populateSkillsMatched(position, candidate))
.filter({
status: candidateStatus,
})
.filter((candidate) => statusFilter.statuses.includes(candidate.status))
.value()
.sort(createSortCandidatesMethod(sortBy)),
[candidates, candidateStatus, sortBy, position]
[candidates, statusFilter, sortBy, position]
);

const onSortByChange = useCallback(
Expand Down Expand Up @@ -139,7 +141,7 @@ const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {
return (
<div styleName="position-candidates">
<CardHeader
title={`${CANDIDATE_STATUS_TO_TITLE_TEXT[candidateStatus]} (${filteredCandidates.length})`}
title={`${statusFilter.title} (${filteredCandidates.length})`}
aside={
<Select
options={CANDIDATES_SORT_OPTIONS}
Expand All @@ -152,7 +154,7 @@ const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {

{filteredCandidates.length === 0 && (
<div styleName="no-candidates">
No {CANDIDATE_STATUS_TO_TITLE_TEXT[candidateStatus]}
No {statusFilter.title}
</div>
)}
{filteredCandidates.length > 0 && (
Expand Down Expand Up @@ -186,7 +188,7 @@ const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {
)}
</div>
<div styleName="table-cell cell-action">
{candidateStatus === CANDIDATE_STATUS.OPEN && (
{statusFilterKey === CANDIDATE_STATUS_FILTER_KEY.TO_REVIEW && (
<>
Interested in this candidate?
<div styleName="actions">
Expand Down Expand Up @@ -239,7 +241,7 @@ const PositionCandidates = ({ position, candidateStatus, updateCandidate }) => {

PositionCandidates.propType = {
position: PT.object,
candidateStatus: PT.oneOf(Object.values(CANDIDATE_STATUS)),
statusFilterKey: PT.oneOf(Object.values(CANDIDATE_STATUS_FILTER_KEY)),
};

export default PositionCandidates;
14 changes: 7 additions & 7 deletions src/routes/PositionDetails/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ import PT from "prop-types";
import LayoutContainer from "components/LayoutContainer";
import LoadingIndicator from "components/LoadingIndicator";
import PageHeader from "components/PageHeader";
import { CANDIDATE_STATUS } from "constants";
import { CANDIDATE_STATUS_FILTER_KEY } from "constants";
import withAuthentication from "../../hoc/withAuthentication";
import PositionCandidates from "./components/PositionCandidates";
import CandidatesStatusFilter from "./components/CandidatesStatusFilter";
import { useTeamPositionsState } from "./hooks/useTeamPositionsState";
import "./styles.module.scss";

const PositionDetails = ({ teamId, positionId }) => {
const [candidateStatus, setCandidateStatus] = useState(CANDIDATE_STATUS.OPEN);
const [candidateStatusFilterKey, setCandidateStatusFilterKey] = useState(CANDIDATE_STATUS_FILTER_KEY.TO_REVIEW);
const {
state: { position, error },
updateCandidate,
} = useTeamPositionsState(teamId, positionId);

const onCandidateStatusChange = useCallback(
(status) => {
setCandidateStatus(status);
(statusFilter) => {
setCandidateStatusFilterKey(statusFilter.key);
},
[setCandidateStatus]
[setCandidateStatusFilterKey]
);

return (
Expand All @@ -41,14 +41,14 @@ const PositionDetails = ({ teamId, positionId }) => {
aside={
<CandidatesStatusFilter
onChange={onCandidateStatusChange}
currentStatus={candidateStatus}
statusFilterKey={candidateStatusFilterKey}
candidates={position.candidates}
/>
}
/>
<PositionCandidates
position={position}
candidateStatus={candidateStatus}
statusFilterKey={candidateStatusFilterKey}
updateCandidate={updateCandidate}
/>
</>
Expand Down