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

[PROD] Next Release #165

Merged
merged 29 commits into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e705183
API update finished
Jul 17, 2021
82dcf75
Add Redirection Link Finished
Jul 17, 2021
30b4fda
Add Filter Completed
Jul 17, 2021
1470310
V1 filter
Jul 18, 2021
832f173
adjusting APIs
LieutenantRoger Jul 19, 2021
0aa35c8
fix: issue
LieutenantRoger Jul 19, 2021
d2de697
fix: archived jobs
LieutenantRoger Jul 19, 2021
e00c48e
fix: completed jobs
LieutenantRoger Jul 19, 2021
d67e7d7
fix: skills url format
LieutenantRoger Jul 19, 2021
6b6b698
fix: adding gig external Id
LieutenantRoger Jul 20, 2021
cb4a7ce
add link to the Gig Title
dedywahyudi Jul 21, 2021
827b30a
adjust archived filter
LieutenantRoger Jul 22, 2021
9808c79
fix: archived job
LieutenantRoger Jul 22, 2021
55edd60
integrat withdraw status
LieutenantRoger Jul 22, 2021
bb8503d
persist completed job
LieutenantRoger Jul 22, 2021
09ed6a0
completed gigs UI deploy
LieutenantRoger Jul 22, 2021
ee6a257
adjusting completed status
LieutenantRoger Jul 22, 2021
486de83
fix: completed
LieutenantRoger Jul 22, 2021
e29ef4f
fix: completed status v2
LieutenantRoger Jul 22, 2021
df1360e
add active jobs
LieutenantRoger Jul 23, 2021
9ee24fd
integration
LieutenantRoger Jul 23, 2021
82aa831
fix: empty text
LieutenantRoger Jul 23, 2021
e55fde2
Merge pull request #161 from topcoder-platform/features/gigs-detail-link
LieutenantRoger Jul 23, 2021
39ca379
Merge branch 'dev' into gigs-filter
LieutenantRoger Jul 23, 2021
9efd066
Merge pull request #162 from topcoder-platform/gigs-filter
LieutenantRoger Jul 23, 2021
9a70afc
restore ci branch
LieutenantRoger Jul 23, 2021
09f453b
fix: reset gig bucket
LieutenantRoger Jul 24, 2021
cbcf2d5
Merge branch 'dev' into gigs-filter
LieutenantRoger Jul 24, 2021
b32a626
Merge pull request #164 from topcoder-platform/gigs-filter
LieutenantRoger Jul 24, 2021
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: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev-https": "cross-env APPMODE=development webpack-dev-server --https --port 8008",
"build": "webpack --mode=${APPMODE:-development} --env.config=${APPENV:-dev}",
"analyze": "webpack --mode=production --env.analyze=true",
"lint": "eslint src --ext js,jsx",
"lint": "eslint src --ext js,jsx --fix",
"format": "prettier --write \"./**\"",
"test": "cross-env BABEL_ENV=test jest",
"watch-tests": "cross-env BABEL_ENV=test jest --watch",
Expand Down
47 changes: 43 additions & 4 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import React, { useState, useLayoutEffect, useEffect, useRef } from "react";
import { Router, useLocation, Redirect } from "@reach/router";
import Challenges from "./containers/Challenges";
import Filter from "./containers/Filter";
import MyGigsFilter from "./containers/MyGigsFilter";
import MyGigs from "./containers/MyGigs";
import Menu from "./components/Menu";
import { disableSidebarForRoute } from "@topcoder/micro-frontends-navbar-app";
import * as constants from "./constants";
import actions from "./actions";
import * as utils from "./utils";
import store from "./store";
import { initialChallengeFilter } from "./reducers/filter";
import { initialChallengeFilter, initialGigFilter } from "./reducers/filter";
import _ from "lodash";
import { usePreviousLocation } from "./utils/hooks";
import { useSelector } from "react-redux";
Expand All @@ -38,6 +39,9 @@ const App = () => {
selected={selectedMenuItem}
onSelect={(item) => {
setSelectedMenuItem(item);
if (item == "Gigs") {
window.location.href = `${process.env.URL.BASE}/gigs`;
}
}}
isLoggedIn={isLoggedIn}
/>
Expand All @@ -46,7 +50,7 @@ const App = () => {
const location = useLocation();
const previousLocation = usePreviousLocation();

const getChallengesDebounced = useRef(_.debounce((f) => f(), 500));
const getDataDebounced = useRef(_.debounce((f) => f(), 500));

useEffect(() => {
store.dispatch(actions.lookup.checkIsLoggedIn());
Expand Down Expand Up @@ -74,12 +78,46 @@ const App = () => {
if (diff) {
store.dispatch(actions.filter.updateFilter(updatedFilter));
}
getChallengesDebounced.current(() =>
getDataDebounced.current(() =>
store.dispatch(actions.challenges.getChallenges(updatedFilter))
);
}
}, [location]);

useEffect(() => {
if (location.pathname === "/earn/my-gigs" && isLoggedIn) {
if (!location.search) {
store.dispatch(actions.filter.updateGigFilter(initialGigFilter));

store.dispatch(
actions.myGigs.getMyGigs(
constants.GIGS_FILTER_STATUSES_PARAM[initialGigFilter.status]
)
);
return;
}
const params = utils.url.parseUrlQuery(location.search);
if (_.keys(params).length == 1 && params.externalId) {
return;
}
const updatedGigFilter = {
status: params.status || "Open Applications",
};
const currentGig = store.getState().filter.gig;
const diff = !_.isEqual(updatedGigFilter, currentGig);
if (diff) {
store.dispatch(actions.filter.updateGigFilter(updatedGigFilter));
}
getDataDebounced.current(() =>
store.dispatch(
actions.myGigs.getMyGigs(
constants.GIGS_FILTER_STATUSES_PARAM[updatedGigFilter.status]
)
)
);
}
}, [location, isLoggedIn]);

const varsRef = useRef();
varsRef.current = { previousLocation };

Expand Down Expand Up @@ -108,7 +146,8 @@ const App = () => {
<div className="sidebar-content">
{menu}
<hr />
<Filter />
{location.pathname === "/earn/find/challenges" && <Filter />}
{location.pathname === "/earn/my-gigs" && <MyGigsFilter />}
</div>
<div className="sidebar-footer">
<a
Expand Down
12 changes: 12 additions & 0 deletions src/actions/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ function updateFilter(partialUpdate) {
return partialUpdate;
}

function updateGigFilter(partialUpdate) {
return partialUpdate;
}

function clearChallengeFilter(defaultFilter) {
return defaultFilter;
}
Expand All @@ -15,8 +19,16 @@ function updateChallengeQuery(filter) {
return params;
}

function updateGigQuery(filter) {
const params = utils.myGig.createGigParams(filter);
utils.url.updateQuery(params);
return params;
}

export default createActions({
UPDATE_FILTER: updateFilter,
CLEAR_CHALLENGE_FILTER: clearChallengeFilter,
UPDATE_CHALLENGE_QUERY: updateChallengeQuery,
UPDATE_GIG_FILTER: updateGigFilter,
UPDATE_GIG_QUERY: updateGigQuery,
});
8 changes: 4 additions & 4 deletions src/actions/myGigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import service from "../services/myGigs";
* @param {number} perPage items per page. by default is 10.
* @returns
*/
async function getMyGigs(page = 1, perPage = PER_PAGE) {
return service.getMyGigs(page, perPage);
async function getMyGigs(status = "open_jobs", page = 1, perPage = PER_PAGE) {
return service.getMyGigs(status, page, perPage);
}

/**
Expand All @@ -22,8 +22,8 @@ async function getMyGigs(page = 1, perPage = PER_PAGE) {
* @param {*} perPage items per page. by default is 10
* @returns
*/
async function loadMoreMyGigs(nextPage, perPage = PER_PAGE) {
return service.getMyGigs(nextPage, perPage);
async function loadMoreMyGigs(status, nextPage, perPage = PER_PAGE) {
return service.getMyGigs(status, nextPage, perPage);
}

async function getProfile() {
Expand Down
54 changes: 54 additions & 0 deletions src/api/app-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,60 @@ const Scopes = {
ALL_PROFILE: "all:earn-profile",
};

const MY_GIGS_JOB_STATUS = {
APPLIED: "applied",
SKILLS_TEST: "skills-test",
PHONE_SCREEN: "phone-screen",
SCREEN_PASS: "open",
INTERVIEW: "interview",
SELECTED: "selected",
OFFERED: "offered",
PLACED: "placed",
REJECTED_OTHER: "rejected - other",
REJECTED_PRE_SCREEN: "rejected-pre-screen",
CLIENT_REJECTED_INTERVIEW: "client rejected - interview",
CLIENT_REJECTED_SCREENING: "client rejected - screening",
JOB_CLOSED: "job-closed",
WITHDRAWN: "withdrawn",
WITHDRAWN_PRESCREEN: "withdrawn-prescreen",
};

const JOB_APPLICATION_STATUS_MAPPER = {
active_jobs: {
statuses: [MY_GIGS_JOB_STATUS.PLACED],
},
open_jobs: {
statuses: [
MY_GIGS_JOB_STATUS.APPLIED,
MY_GIGS_JOB_STATUS.SKILLS_TEST,
MY_GIGS_JOB_STATUS.PHONE_SCREEN,
MY_GIGS_JOB_STATUS.SCREEN_PASS,
MY_GIGS_JOB_STATUS.INTERVIEW,
MY_GIGS_JOB_STATUS.SELECTED,
MY_GIGS_JOB_STATUS.OFFERED,
],
},
completed_jobs: {
statuses: [MY_GIGS_JOB_STATUS.PLACED],
},
archived_jobs: {
statuses: [
MY_GIGS_JOB_STATUS.JOB_CLOSED,
MY_GIGS_JOB_STATUS.REJECTED_OTHER,
MY_GIGS_JOB_STATUS.REJECTED_PRE_SCREEN,
MY_GIGS_JOB_STATUS.CLIENT_REJECTED_INTERVIEW,
MY_GIGS_JOB_STATUS.CLIENT_REJECTED_SCREENING,
MY_GIGS_JOB_STATUS.WITHDRAWN,
MY_GIGS_JOB_STATUS.WITHDRAWN_PRESCREEN,
],
},
};

const MIN_HOUR_PER_WEEK_TO_WITHDRAW = 20;

module.exports = {
Scopes,
MY_GIGS_JOB_STATUS,
JOB_APPLICATION_STATUS_MAPPER,
MIN_HOUR_PER_WEEK_TO_WITHDRAW,
};
70 changes: 70 additions & 0 deletions src/api/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

const _ = require("lodash");
const config = require("config");
const constants = require("../app-constants");
const logger = require("./logger");
const httpStatus = require("http-status");
const Interceptor = require("express-interceptor");
Expand Down Expand Up @@ -265,10 +266,18 @@ async function getCurrentUserDetails(token) {
*/
async function getJobCandidates(criteria) {
const token = await getM2MToken();
let body = { statuses: [] };
if (criteria.status) {
body = constants.JOB_APPLICATION_STATUS_MAPPER[criteria.status] || {
statuses: [],
};
}
delete criteria.status;
const url = `${config.API.V5}/jobCandidates`;
const res = await request
.get(url)
.query(criteria)
.send(body)
.set("Authorization", `Bearer ${token}`)
.set("Accept", "application/json");
localLogger.debug({
Expand All @@ -283,6 +292,66 @@ async function getJobCandidates(criteria) {
};
}

/**
* Process placed job candidate to calculate the completed status
*
* @param {*} jobCandidates
* @param {*} userId
* @returns
*/
async function handlePlacedJobCandidates(jobCandidates, userId) {
if (!jobCandidates || jobCandidates.length == 0 || !userId) {
return;
}
const placedJobs = jobCandidates.filter(
(item) => item.status == constants.MY_GIGS_JOB_STATUS.PLACED
);
if (placedJobs.length == 0) {
return;
}
const token = await getM2MToken();
const url = `${config.API.V5}/resourceBookings`;
const criteria = {
userId: userId,
page: 1,
perPage: placedJobs.length,
};
const body = {
jobIds: _.map(placedJobs, "jobId"),
};
const res = await request
.get(url)
.query(criteria)
.send(body)
.set("Authorization", `Bearer ${token}`)
.set("Accept", "application/json");
localLogger.debug({
context: "handlePlacedJobCandidates",
message: `response body: ${JSON.stringify(res.body)}`,
});
if (res.body && res.body.length == 0) {
return;
}
// Handle placed job status with RB result
const rbRes = res.body;
_.each(rbRes, (rb) => {
const jc = jobCandidates.find(
(item) => item.userId == rb.userId && item.jobId == rb.jobId
);
if (jc) {
if (rb.endDate) {
if (
new Date(rb.endDate) < new Date() &&
new Date(rb.endDate).toDateString() != new Date().toDateString()
) {
jc.status = "completed";
}
}
}
});
return;
}

/**
* Return jobs by given criteria
* @param {string} criteria the search criteria
Expand Down Expand Up @@ -467,6 +536,7 @@ module.exports = {
getM2MToken,
getCurrentUserDetails,
getJobCandidates,
handlePlacedJobCandidates,
getJobs,
getMember,
getMemberTraits,
Expand Down
11 changes: 11 additions & 0 deletions src/api/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ paths:
type: string
default: desc
enum: ["desc", "asc"]
- in: query
name: status
required: false
schema:
type: string
enum: ["active_jobs", "open_jobs", "completed_jobs", "archived_jobs"]
responses:
"200":
description: OK
Expand Down Expand Up @@ -260,6 +266,7 @@ components:
- status
- remark
- interview
- jobExternalId
properties:
title:
type: string
Expand Down Expand Up @@ -305,6 +312,10 @@ components:
description: "The remark of candidate"
interview:
$ref: "#/components/schemas/Interview"
jobExternalId:
type: string
example: "51313517"
description: "The corresponding gig ID on community app"
Payment:
required:
- min
Expand Down
Loading