From 68f51ff3f85ba513db3a2d5fedb616ed54678369 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 3 Mar 2021 10:38:43 +0200 Subject: [PATCH 1/4] fix #5414 --- src/server/services/growsurf.js | 3 +++ src/server/services/recruitCRM.js | 2 ++ src/shared/components/Gigs/GigDetails/index.jsx | 6 +++--- src/shared/containers/Gigs/RecruitCRMJobDetails.jsx | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/server/services/growsurf.js b/src/server/services/growsurf.js index 9de3dfa2eb..920541b84a 100644 --- a/src/server/services/growsurf.js +++ b/src/server/services/growsurf.js @@ -87,6 +87,9 @@ export default class GrowsurfService { email: body.email, firstName: body.firstName, lastName: body.lastName, + metadata: { + tcHandle: body.tcHandle, + }, })); if (result.error) { res.status(result.code); diff --git a/src/server/services/recruitCRM.js b/src/server/services/recruitCRM.js index 33c44d72ff..1320f95467 100644 --- a/src/server/services/recruitCRM.js +++ b/src/server/services/recruitCRM.js @@ -195,6 +195,7 @@ export default class RecruitCRMService { // referral tracking via growsurf if (referralCookie && referralCookie.gigId === id) { const gs = new GrowsurfService(); + const tcHandle = _.findIndex(form.custom_fields, { field_id: 2 }); const growRes = await gs.addParticipant(JSON.stringify({ email: form.email, referredBy: referralCookie.referralId, @@ -203,6 +204,7 @@ export default class RecruitCRMService { lastName: form.last_name, metadata: { gigId: id, + tcHandle: form.custom_fields[tcHandle].value, }, })); // If everything set in Growsurf diff --git a/src/shared/components/Gigs/GigDetails/index.jsx b/src/shared/components/Gigs/GigDetails/index.jsx index 9e714cb4e3..b48698fa3f 100644 --- a/src/shared/components/Gigs/GigDetails/index.jsx +++ b/src/shared/components/Gigs/GigDetails/index.jsx @@ -179,15 +179,15 @@ export default function GigDetails(props) { diff --git a/src/shared/containers/Gigs/RecruitCRMJobDetails.jsx b/src/shared/containers/Gigs/RecruitCRMJobDetails.jsx index 1580e93aa7..31d1e56f48 100644 --- a/src/shared/containers/Gigs/RecruitCRMJobDetails.jsx +++ b/src/shared/containers/Gigs/RecruitCRMJobDetails.jsx @@ -155,6 +155,7 @@ ${config.URL.BASE}${config.GIGS_PAGES_PATH}/${props.id}`, email: profile.email, firstName: profile.firstName, lastName: profile.lastName, + tcHandle: profile.handle, }), headers: { 'Content-Type': 'application/json', From e275c2405d33445ff2fd6895c30ee364b3bced92 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 3 Mar 2021 12:13:27 +0200 Subject: [PATCH 2/4] Fix #5415 --- .../TextInput/__snapshots__/index.jsx.snap | 1 + .../components/GUIKit/TextInput/index.jsx | 4 + src/shared/components/Gigs/GigApply/index.jsx | 24 +++++- .../components/Gigs/GigApply/style.scss | 15 +++- .../components/Gigs/GigDetails/index.jsx | 19 ++++- .../components/Gigs/LoginModal/index.jsx | 52 ++++++++++++ .../components/Gigs/LoginModal/modal.scss | 85 +++++++++++++++++++ 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 src/shared/components/Gigs/LoginModal/index.jsx create mode 100644 src/shared/components/Gigs/LoginModal/modal.scss diff --git a/__tests__/shared/components/GUIKit/TextInput/__snapshots__/index.jsx.snap b/__tests__/shared/components/GUIKit/TextInput/__snapshots__/index.jsx.snap index f7c29a7f58..739f1a551e 100644 --- a/__tests__/shared/components/GUIKit/TextInput/__snapshots__/index.jsx.snap +++ b/__tests__/shared/components/GUIKit/TextInput/__snapshots__/index.jsx.snap @@ -11,6 +11,7 @@ exports[`Default render 1`] = ` onChange={[Function]} onKeyPress={[Function]} placeholder="" + readOnly={false} type="text" /> diff --git a/src/shared/components/GUIKit/TextInput/index.jsx b/src/shared/components/GUIKit/TextInput/index.jsx index 519ea50dc6..d4ef9938c9 100644 --- a/src/shared/components/GUIKit/TextInput/index.jsx +++ b/src/shared/components/GUIKit/TextInput/index.jsx @@ -19,6 +19,7 @@ function TextInput({ size, type, onEnterKey, + readonly, }) { const [val, setVal] = useState(value); const delayedOnChange = useRef( @@ -29,6 +30,7 @@ function TextInput({ return (
{}, + readonly: false, }; TextInput.propTypes = { @@ -79,6 +82,7 @@ TextInput.propTypes = { size: PT.oneOf(['xs', 'lg']), type: PT.string, onEnterKey: PT.func, + readonly: PT.bool, }; export default TextInput; diff --git a/src/shared/components/Gigs/GigApply/index.jsx b/src/shared/components/Gigs/GigApply/index.jsx index 6a7eee3f15..614f96fb97 100644 --- a/src/shared/components/Gigs/GigApply/index.jsx +++ b/src/shared/components/Gigs/GigApply/index.jsx @@ -23,10 +23,11 @@ import BackArrowGig from 'assets/images/back-arrow-gig-apply.svg'; export default function GigApply(props) { const { - job, onFormInputChange, formData, formErrors, onApplyClick, applying, application, + job, onFormInputChange, formData, formErrors, onApplyClick, applying, application, user, } = props; + const retUrl = window.location.href; - return ( + return user ? (
{ job.error || job.enable_job_application_form !== 1 ? ( @@ -150,7 +151,6 @@ export default function GigApply(props) {

TOPCODER INFORMATION

-

If you have a Topcoder profile, please share. Not a Member?

onFormInputChange('handle', val)} errorMsg={formErrors.handle} value={formData.handle} + readonly /> onFormInputChange('tcProfileLink', val)} errorMsg={formErrors.tcProfileLink} - value={formData.handle ? `topcoder.com/members/${formData.handle}` : null} + value={formData.handle ? `https://topcoder.com/members/${formData.handle}` : null} + readonly />
@@ -279,6 +281,18 @@ export default function GigApply(props) { ) } + ) : ( +
+
+
+

You must be a Topcoder member to apply!

+
+ Login +
+

Not a member? Register here.

+
+
+
); } @@ -286,6 +300,7 @@ GigApply.defaultProps = { formErrors: {}, applying: false, application: null, + user: null, }; GigApply.propTypes = { @@ -296,4 +311,5 @@ GigApply.propTypes = { onApplyClick: PT.func.isRequired, applying: PT.bool, application: PT.shape(), + user: PT.shape(), }; diff --git a/src/shared/components/Gigs/GigApply/style.scss b/src/shared/components/Gigs/GigApply/style.scss index b14c0dbdd5..b807f0b8ab 100644 --- a/src/shared/components/Gigs/GigApply/style.scss +++ b/src/shared/components/Gigs/GigApply/style.scss @@ -28,12 +28,25 @@ padding: 0 15px; } - .error { + .wrap .error { display: flex; flex-direction: column; align-items: center; margin-top: 27px; height: 80vh; + + h3 { + text-align: center; + } + + .cta-buttons a.primaryBtn { + margin-bottom: 0 !important; + } + + .regTxt { + font-size: 14px; + margin: 10px 0 0; + } } .checkboxes-row { diff --git a/src/shared/components/Gigs/GigDetails/index.jsx b/src/shared/components/Gigs/GigDetails/index.jsx index b48698fa3f..09ea432d5e 100644 --- a/src/shared/components/Gigs/GigDetails/index.jsx +++ b/src/shared/components/Gigs/GigDetails/index.jsx @@ -26,6 +26,7 @@ import iconLabel2 from 'assets/images/l2.png'; import iconLabel3 from 'assets/images/l3.png'; import SadFace from 'assets/images/sad-face-icon.svg'; import ReferralModal from '../ReferralModal'; +import LoginModal from '../LoginModal'; // Cleanup HTML from style tags // so it won't affect other parts of the UI @@ -43,8 +44,10 @@ export default function GigDetails(props) { job, application, profile, onSendClick, isReferrSucess, formData, formErrors, onFormInputChange, isReferrError, getReferralId, referralId, onReferralDone, } = props; let shareUrl; + let retUrl; if (isomorphy.isClientSide()) { shareUrl = encodeURIComponent(window.location.href); + retUrl = `${window.location.origin}${window.location.pathname}/apply${window.location.search}`; } let skills = getCustomField(job.custom_fields, 'Technologies Required'); if (skills !== 'n/a') skills = skills.split(',').join(', '); @@ -52,6 +55,7 @@ export default function GigDetails(props) { const compens = job.min_annual_salary === job.max_annual_salary ? job.max_annual_salary : `${job.min_annual_salary} - ${job.max_annual_salary} (USD)`; const [isModalOpen, setModalOpen] = useState(false); + const [isLoginModalOpen, setLoginModalOpen] = useState(false); let inputRef; useEffect(() => { @@ -131,7 +135,17 @@ export default function GigDetails(props) {
{ !application || !application.success ? ( - APPLY TO THIS JOB + { + if (isEmpty(profile)) { + e.preventDefault(); + setLoginModalOpen(true); + } + }} + >APPLY TO THIS JOB + ) : null } VIEW OTHER JOBS @@ -211,6 +225,9 @@ export default function GigDetails(props) { ) }
+ { + isLoginModalOpen && + } diff --git a/src/shared/components/Gigs/LoginModal/index.jsx b/src/shared/components/Gigs/LoginModal/index.jsx new file mode 100644 index 0000000000..0e1174690b --- /dev/null +++ b/src/shared/components/Gigs/LoginModal/index.jsx @@ -0,0 +1,52 @@ +/** + * The modal used for login enforcing + */ + +/* global window */ + +import PT from 'prop-types'; +import React from 'react'; +import { Modal, PrimaryButton } from 'topcoder-react-ui-kit'; +import { config } from 'topcoder-react-utils'; +import tc from 'components/buttons/themed/tc.scss'; +import modalStyle from './modal.scss'; + +/** Themes for buttons + * those overwrite PrimaryButton style to match achieve various styles. + * Should implement pattern of classes. + */ +const buttonThemes = { + tc, +}; + +function LoginModal({ retUrl }) { + return ( + +
+

WARNING

+

You must be a Topcoder member to apply!

+
+ { + window.location = `${config.URL.AUTH}/member?retUrl=${encodeURIComponent(retUrl)}`; + }} + theme={{ + button: buttonThemes.tc['primary-green-md'], + }} + > + LOGIN + +
+

Not a member? Register here.

+
+
+ ); +} + +LoginModal.propTypes = { + retUrl: PT.string.isRequired, +}; + +export default LoginModal; diff --git a/src/shared/components/Gigs/LoginModal/modal.scss b/src/shared/components/Gigs/LoginModal/modal.scss new file mode 100644 index 0000000000..ad4df8efb7 --- /dev/null +++ b/src/shared/components/Gigs/LoginModal/modal.scss @@ -0,0 +1,85 @@ +@import "~styles/mixins"; +@import "~components/Contentful/default"; + +.container { + padding: 0; + width: auto; + max-width: 95vw; + height: auto; + max-height: 95vh; + border-radius: 10px; + display: flex; + flex-direction: column; + justify-content: center; + + @include gui-kit-headers; + @include gui-kit-content; + + .title { + color: #1e94a3; + font-family: BarlowCondensed, sans-serif; + font-size: 34px; + line-height: 38px; + font-weight: 500; + margin: 0; + margin-bottom: 20px; + } + + .loginMsg { + color: #ef476f; + font-size: 24px; + line-height: 36px; + margin-bottom: 40px; + } + + .ctaButtons { + display: flex; + align-content: center; + justify-content: center; + + & > button:first-child { + margin-right: 10px !important; + } + + & > a:first-child { + margin-right: 10px !important; + } + } + + .referrals { + display: flex; + overflow: auto; + + .sucessMsg { + font-size: 24px; + line-height: 36px; + margin-bottom: 40px; + } + + .rightAlign { + justify-content: flex-end; + } + } + + .loginRequired, + .referrSucess { + display: flex; + flex-direction: column; + padding: 100px 80px; + text-align: center; + + @include xs-to-sm { + padding: 50px 40px; + } + + .regTxt { + font-size: 14px; + margin: 10px 0 0; + } + } +} + +.overlay { + background-color: #2a2a2a; + opacity: 0.95; +} From 1fd4efcb8abedef3f3d780fe2d4d2659c8a1694a Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 3 Mar 2021 12:18:45 +0200 Subject: [PATCH 3/4] ci: on test --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 15009f5042..4fe405c05b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -283,7 +283,7 @@ workflows: filters: branches: only: - - free + - gigwork-updates # This is alternate dev env for parallel testing - "build-qa": context : org-global From eab915825a7944881574bd561cf3d01a3163469d Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 3 Mar 2021 16:26:42 +0200 Subject: [PATCH 4/4] hide modal with outside click --- src/shared/components/Gigs/GigDetails/index.jsx | 2 +- src/shared/components/Gigs/LoginModal/index.jsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shared/components/Gigs/GigDetails/index.jsx b/src/shared/components/Gigs/GigDetails/index.jsx index 09ea432d5e..1eca1ab48d 100644 --- a/src/shared/components/Gigs/GigDetails/index.jsx +++ b/src/shared/components/Gigs/GigDetails/index.jsx @@ -226,7 +226,7 @@ export default function GigDetails(props) { } { - isLoginModalOpen && + isLoginModalOpen && setLoginModalOpen(false)} /> } diff --git a/src/shared/components/Gigs/LoginModal/index.jsx b/src/shared/components/Gigs/LoginModal/index.jsx index 0e1174690b..978cc6bdea 100644 --- a/src/shared/components/Gigs/LoginModal/index.jsx +++ b/src/shared/components/Gigs/LoginModal/index.jsx @@ -19,10 +19,11 @@ const buttonThemes = { tc, }; -function LoginModal({ retUrl }) { +function LoginModal({ retUrl, onCancel }) { return (

WARNING

@@ -47,6 +48,7 @@ function LoginModal({ retUrl }) { LoginModal.propTypes = { retUrl: PT.string.isRequired, + onCancel: PT.func.isRequired, }; export default LoginModal;