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

My gigs Release on 7/26 #162

Merged
merged 24 commits into from
Jul 23, 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: 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
45 changes: 41 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,44 @@ 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.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 +144,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