Skip to content

Commit e64cd49

Browse files
Merge pull request #5442 from topcoder-platform/develop
Release 2021/03/18 (v1.8.3)
2 parents df549d5 + 295b20e commit e64cd49

File tree

19 files changed

+318
-100
lines changed

19 files changed

+318
-100
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,21 +283,21 @@ workflows:
283283
filters:
284284
branches:
285285
only:
286-
- route-redirects
286+
- gig-application-update
287287
# This is alternate dev env for parallel testing
288288
- "build-qa":
289289
context : org-global
290290
filters:
291291
branches:
292292
only:
293-
- tco-leaderboard-fix
293+
- free
294294
# This is beta env for production soft releases
295295
- "build-prod-beta":
296296
context : org-global
297297
filters:
298298
branches:
299299
only:
300-
- free
300+
- develop
301301
# This is stage env for production QA releases
302302
- "build-prod-staging":
303303
context : org-global

src/assets/images/checkmark-green.svg

Lines changed: 12 additions & 0 deletions
Loading

src/assets/images/social.jpg

-121 KB
Binary file not shown.

src/assets/images/social.png

800 KB
Loading

src/server/services/recruitCRM.js

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,9 @@ export default class RecruitCRMService {
187187
const { body, file } = req;
188188
const form = JSON.parse(body.form);
189189
const fileData = new FormData();
190-
fileData.append('resume', file.buffer, file.originalname);
190+
if (file) {
191+
fileData.append('resume', file.buffer, file.originalname);
192+
}
191193
let candidateSlug;
192194
let referralCookie = req.cookies[config.GROWSURF_COOKIE];
193195
if (referralCookie) referralCookie = JSON.parse(referralCookie);
@@ -272,29 +274,31 @@ export default class RecruitCRMService {
272274
});
273275
}
274276
candidateData = await workCandidateResponse.json();
275-
// Attach resume to candidate
276-
const formHeaders = fileData.getHeaders();
277-
const fileCandidateResponse = await fetch(`${this.private.baseUrl}/v1/candidates/${candidateData.slug}`, {
278-
method: 'POST',
279-
headers: {
280-
Authorization: this.private.authorization,
281-
...formHeaders,
282-
},
283-
body: fileData,
284-
});
285-
if (fileCandidateResponse.status >= 300) {
286-
return res.send({
287-
error: true,
288-
status: fileCandidateResponse.status,
289-
url: `${this.private.baseUrl}/v1/candidates/${candidateData.slug}`,
290-
form,
291-
fileData,
292-
file,
293-
formHeaders,
294-
errObj: await fileCandidateResponse.json(),
277+
// Attach resume to candidate if uploaded
278+
if (file) {
279+
const formHeaders = fileData.getHeaders();
280+
const fileCandidateResponse = await fetch(`${this.private.baseUrl}/v1/candidates/${candidateData.slug}`, {
281+
method: 'POST',
282+
headers: {
283+
Authorization: this.private.authorization,
284+
...formHeaders,
285+
},
286+
body: fileData,
295287
});
288+
if (fileCandidateResponse.status >= 300) {
289+
return res.send({
290+
error: true,
291+
status: fileCandidateResponse.status,
292+
url: `${this.private.baseUrl}/v1/candidates/${candidateData.slug}`,
293+
form,
294+
fileData,
295+
file,
296+
formHeaders,
297+
errObj: await fileCandidateResponse.json(),
298+
});
299+
}
300+
candidateData = await fileCandidateResponse.json();
296301
}
297-
candidateData = await fileCandidateResponse.json();
298302
// Candidate ready to apply for job
299303
const applyResponse = await fetch(`${this.private.baseUrl}/v1/candidates/${candidateData.slug}/assign?job_slug=${id}`, {
300304
method: 'POST',

src/shared/actions/recruitCRM.js

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,47 +58,45 @@ function normalizeRecruitPayload(job, payload) {
5858
const perJob = [
5959
`${job.name} ->`,
6060
`Pay Expectation: ${payload.payExpectation}`,
61-
`Date Available: ${new Date(payload.availFrom).toDateString()}`,
62-
`Heard About Gig: ${payload.reffereal}`,
63-
`Why fit: ${payload.whyFit}`,
6461
`Able to work during timezone? ${payload.timezoneConfirm.filter(s => s.value).map(() => getCustomField(job.custom_fields, 'Timezone')).join(',')}`,
65-
`Am I ok to work the duration? ${payload.durationConfirm.filter(s => s.value).map(s => s.label).join(',')}`,
66-
`Notes: ${payload.notes}`,
62+
`Am I ok to work the duration? ${payload.durationConfirm.filter(s => s.value).map(() => getCustomField(job.custom_fields, 'Duration')).join(',')}`,
6763
];
68-
return {
64+
const referral = _.find(payload.reffereal, { selected: true });
65+
const normalized = {
6966
last_name: payload.lname,
7067
first_name: payload.fname,
7168
email: payload.email,
7269
contact_number: payload.phone,
7370
city: payload.city,
7471
locality: _.find(payload.country, { selected: true }).label,
75-
available_from: payload.availFrom,
7672
salary_expectation: payload.payExpectation,
7773
skill: payload.skills.filter(s => s.selected).map(s => s.label).join(','),
7874
custom_fields: [
79-
{
80-
field_id: 13,
81-
value: payload.reffereal || '',
82-
},
8375
{
8476
field_id: 1,
85-
value: payload.tcProfileLink || (payload.handle ? `topcoder.com/members/${payload.handle}` : ''),
77+
value: payload.tcProfileLink || (payload.handle ? `https://topcoder.com/members/${payload.handle}` : ''),
8678
},
8779
{
8880
field_id: 2,
8981
value: payload.handle || '',
9082
},
91-
{
92-
field_id: 3,
93-
value: payload.whyFit || '',
94-
},
9583
{
9684
field_id: 14,
9785
value: perJob.join(','),
9886
},
9987
],
100-
resume: payload.fileCV,
10188
};
89+
if (referral) {
90+
normalized.custom_fields.push({
91+
field_id: 13,
92+
value: referral.label,
93+
});
94+
}
95+
if (payload.fileCV) {
96+
normalized.resume = payload.fileCV;
97+
}
98+
99+
return normalized;
102100
}
103101

104102
/**
@@ -124,6 +122,37 @@ async function applyForJobDone(job, payload) {
124122
}
125123
}
126124

125+
/**
126+
* Search for cnadidate in recruit
127+
*/
128+
function searchCandidatesInit(email) {
129+
return { email };
130+
}
131+
132+
/**
133+
* Search for cnadidate in recruit and get profile if available
134+
* @param {string} email the email to search
135+
*/
136+
async function searchCandidatesDone(email) {
137+
const ss = new Service();
138+
try {
139+
const res = await ss.searchCandidates(email);
140+
141+
return {
142+
email,
143+
data: res,
144+
};
145+
} catch (error) {
146+
return {
147+
email,
148+
data: {
149+
error: true,
150+
errorObj: error,
151+
},
152+
};
153+
}
154+
}
155+
127156
export default redux.createActions({
128157
RECRUIT: {
129158
GET_JOBS_INIT: getJobsInit,
@@ -132,5 +161,7 @@ export default redux.createActions({
132161
GET_JOB_DONE: getJobDone,
133162
APPLY_FOR_JOB_INIT: applyForJobInit,
134163
APPLY_FOR_JOB_DONE: applyForJobDone,
164+
SEARCH_CANDIDATES_INIT: searchCandidatesInit,
165+
SEARCH_CANDIDATES_DONE: searchCandidatesDone,
135166
},
136167
});

src/shared/components/GUIKit/Assets/Styles/Includes/_mixin.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ $gui-kit-gray-90: #2a2a2a;
44
$gui-kit-level-2: #0ab88a;
55
$gui-kit-level-5: #ef476f;
66
$gui-kit-active-label: #229174;
7+
$gui-kit-readonly: #d4d4d4;
78

89
@mixin textInputLabel {
910
font-size: 12px;

src/shared/components/GUIKit/DropdownTerms/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ function DropdownTerms({
4141
selectInput[0].style.borderTop = 'none';
4242
}
4343
}, [focused, selectedOption]);
44+
useEffect(() => {
45+
setInternalTerms(terms);
46+
}, [terms]);
4447

4548
const CustomReactSelectRow = React.forwardRef(({
4649
className,

src/shared/components/GUIKit/JobListCard/index.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import iconBlackSkills from 'assets/images/icon-skills.png';
1515
export default function JobListCard({
1616
job,
1717
}) {
18+
const duration = getCustomField(job.custom_fields, 'Duration');
1819
let skills = getCustomField(job.custom_fields, 'Technologies Required');
1920
if (skills !== 'n/a') {
2021
skills = skills.split(',');
@@ -39,7 +40,7 @@ export default function JobListCard({
3940
<IconBlackPayment /> ${job.min_annual_salary} - {job.max_annual_salary} (USD) / {getSalaryType(job.salary_type)}
4041
</div>
4142
<div styleName="icon-val">
42-
<IconBlackDuration /> {getCustomField(job.custom_fields, 'Duration')}
43+
<IconBlackDuration /> {/^\d+$/.test(duration) ? `${duration} Weeks` : duration}
4344
</div>
4445
<div styleName="row-btn">
4546
<Link styleName="primary-green-md" to={`${config.GIGS_PAGES_PATH}/${job.slug}`}>VIEW DETAILS</Link>

src/shared/components/GUIKit/TextInput/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function TextInput({
2828
const sizeStyle = size === 'lg' ? 'lgSize' : 'xsSize';
2929

3030
return (
31-
<div className="textInputContainer" styleName={`container ${sizeStyle}`}>
31+
<div className="textInputContainer" styleName={`container ${sizeStyle}${readonly ? ' readonly' : ''}`}>
3232
<input
3333
readOnly={readonly}
3434
defaultValue={value}

src/shared/components/GUIKit/TextInput/style.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
}
4141
}
4242

43+
// readonly
44+
&.readonly {
45+
input:not([type='checkbox']) {
46+
border: 1px solid $gui-kit-readonly;
47+
color: $gui-kit-gray-30;
48+
}
49+
}
50+
4351
input:not([type='checkbox']).haveValue + label,
4452
input:not([type='checkbox']).haveError + label,
4553
input:not([type='checkbox']):focus + label {

0 commit comments

Comments
 (0)