Skip to content

Release v1.14.4 #5839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 30, 2021
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ workflows:
filters:
branches:
only:
- free
- ca-profile-bug-bash
# This is alternate dev env for parallel testing
- "build-qa":
context : org-global
Expand Down
18 changes: 17 additions & 1 deletion src/shared/components/Contentful/Article/Article.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ class Article extends React.Component {
},
).substring(0, CONTENT_PREVIEW_LENGTH);
const catsGrouped = _.groupBy(fields.contentCategory, cat => cat.fields.trackParent);
// captures clicks on article
// for opening external links in new tab
const articleClickHandler = (e) => {
if (e.target.href && fields.openExternalLinksInNewTab !== false) {
const target = new URL(e.target.href);
if (!target.host.includes('topcoder')) {
window.open(e.target.href, '_blank');
e.preventDefault();
}
}
};

return (
<React.Fragment>
Expand Down Expand Up @@ -291,7 +302,12 @@ class Article extends React.Component {
</div>
</div>
{/* Content */}
<div className={theme.articleContent}>
<div
className={theme.articleContent}
role="presentation"
onClick={articleClickHandler}
onKeyPress={articleClickHandler}
>
<MarkdownRenderer markdown={fields.content} {...contentfulConfig} />
{
fields.type === 'Video' && fields.contentUrl ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@
ol {
@include tc-body-md;

padding-left: 20px;
padding-left: 30px;
margin-bottom: 20px;

@include roboto-regular;
Expand Down Expand Up @@ -485,6 +485,10 @@
margin-bottom: 108px;
}

@media screen and (min-width: 1440px) and (max-width: 1900px) {
margin-bottom: 70px;
}

@media screen and (max-width: 768px) {
margin-bottom: 300px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
@include xs-to-sm {
margin: 5px;
}

@media screen and (max-width: 425px) {
max-height: none;
}
}

.contentWrapper {
Expand All @@ -23,6 +27,10 @@
display: flex;
flex-direction: row;
align-items: stretch;

@media screen and (max-width: 425px) {
flex-direction: column;
}
}

.main {
Expand Down Expand Up @@ -225,6 +233,11 @@
min-width: 150px;
}

@media screen and (max-width: 425px) {
width: 100%;
min-height: 130px;
}

&::before {
content: '';
width: 35px;
Expand All @@ -234,5 +247,12 @@
background-size: cover;
background-position: right -2px;
position: absolute;

@media screen and (max-width: 425px) {
background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 290 31.73' style='enable-background:new 0 0 290 31.73;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill-rule:evenodd;clip-rule:evenodd;fill:%23F4F4F4;%7D%0A%3C/style%3E%3Cg id='Thrive'%3E%3Cg id='Artboard' transform='translate(-22.000000, -20.000000)'%3E%3Cg id='Combined-Shape'%3E%3Cpath class='st0' d='M22,20h290l0,24.11c-60.39,13.64-90.73-0.4-142.15-10.48C118.1,23.5,97,79,22.08,33.64l0,0l0,1.34'/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
width: 100%;
height: 33px;
background-position: 0 -10px;
}
}
}
4 changes: 2 additions & 2 deletions src/shared/components/Contentful/SearchBar/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class SearchBarInner extends Component {

onKeyDown(e) {
const { inputlVal, selectedFilter } = this.state;
if (inputlVal && e.which === 13) {
if (_.trim(inputlVal) && e.which === 13) {
const searchQuery = {};
if (this.searchFieldRef && this.searchFieldRef.value) {
if (selectedFilter.name === 'Tags') {
Expand All @@ -90,7 +90,7 @@ export class SearchBarInner extends Component {
if (selectedFilter.name !== 'Author') {
window.location.href = `${config.TC_EDU_BASE_PATH}${config.TC_EDU_SEARCH_PATH}?${qs.stringify(searchQuery)}`;
} else {
window.location.href = `${config.TC_EDU_BASE_PATH}${config.TC_EDU_SEARCH_PATH}?author=${inputlVal}`;
window.location.href = `${config.TC_EDU_BASE_PATH}${config.TC_EDU_SEARCH_PATH}?author=${_.trim(inputlVal)}`;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default class ImageInput extends React.Component {
this.state = {
newBasicInfo: {},
isImageOversize: false,
isImageFile: true,
};
}

Expand Down Expand Up @@ -72,6 +73,13 @@ export default class ImageInput extends React.Component {
if (file === undefined) {
return;
}
const allowedTypes = ['image/png', 'image/jpg', 'image/jpeg'];
if (!allowedTypes.includes(file.type)) {
this.setState({
isImageFile: false,
});
return;
}
if (file.size > 2 * 1024 * 1024) {
// If file size is greater than 2 MB, show error message
this.setState({
Expand All @@ -81,6 +89,7 @@ export default class ImageInput extends React.Component {
}
this.setState({
isImageOversize: false,
isImageFile: true,
});
uploadPhotoInit();
loadImage.parseMetaData(file, (data) => {
Expand Down Expand Up @@ -126,7 +135,7 @@ export default class ImageInput extends React.Component {
deletingPhoto,
} = profileState;

const { newBasicInfo, isImageOversize } = this.state;
const { newBasicInfo, isImageOversize, isImageFile } = this.state;

return (
<div styleName="image">
Expand Down Expand Up @@ -157,7 +166,8 @@ export default class ImageInput extends React.Component {
<input type="file" name="image" accept="image/*" onChange={this.onUploadPhoto} id="change-image-input" className="hidden" />
</div>
</div>
{isImageOversize && <div styleName="error-message">Please select an image smaller than 2MB</div>}
{!isImageFile && <div styleName="error-message">Please select jpg, jpeg or png image files only</div>}
{isImageFile && isImageOversize && <div styleName="error-message">Please select an image smaller than 2MB</div>}
</div>
);
}
Expand Down
12 changes: 8 additions & 4 deletions src/shared/components/Settings/Profile/BasicInfo/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export default class BasicInfo extends ConsentComponent {
personalizationTrait: this.loadPersonalizationTrait(userTraits),
newBasicInfo: {
handle: '',
firstName: '',
lastName: '',
firstName: null,
lastName: null,
gender: '',
ethnicBackground: null,
shortBio: '',
Expand Down Expand Up @@ -377,6 +377,8 @@ export default class BasicInfo extends ConsentComponent {
}
if (_.has(value, 'firstName')) {
newBasicInfo.firstName = value.firstName;
} else {
newBasicInfo.firstName = '';
}
if (_.has(value, 'gender')) {
newBasicInfo.gender = value.gender;
Expand All @@ -390,6 +392,8 @@ export default class BasicInfo extends ConsentComponent {
}
if (_.has(value, 'lastName')) {
newBasicInfo.lastName = value.lastName;
} else {
newBasicInfo.lastName = '';
}
if (_.has(value, 'primaryInterestInTopcoder')) {
newBasicInfo.primaryInterestInTopcoder = value.primaryInterestInTopcoder;
Expand Down Expand Up @@ -501,7 +505,7 @@ export default class BasicInfo extends ConsentComponent {
<div styleName="field col-2">
<span styleName="text-required">* Required</span>
<input disabled={!canModifyTrait} id="firstName" name="firstName" type="text" placeholder="First Name" onChange={this.onUpdateInput} value={newBasicInfo.firstName} maxLength="64" required />
<ErrorMessage invalid={_.isEmpty(newBasicInfo.firstName) && inputChanged} message="First Name cannot be empty" />
<ErrorMessage invalid={_.isEmpty(newBasicInfo.firstName) && !_.isNull(newBasicInfo.firstName) && inputChanged} message="First Name cannot be empty" />
</div>
</div>
<div styleName="row">
Expand All @@ -514,7 +518,7 @@ export default class BasicInfo extends ConsentComponent {
<div styleName="field col-2">
<span styleName="text-required">* Required</span>
<input disabled={!canModifyTrait} id="lastName" name="lastName" type="text" placeholder="Last Name" onChange={this.onUpdateInput} value={newBasicInfo.lastName} maxLength="64" required />
<ErrorMessage invalid={_.isEmpty(newBasicInfo.lastName) && inputChanged} message="Last Name cannot be empty" />
<ErrorMessage invalid={_.isEmpty(newBasicInfo.lastName) && !_.isNull(newBasicInfo.lastName) && inputChanged} message="Last Name cannot be empty" />
</div>
</div>
<div styleName="row">
Expand Down
93 changes: 43 additions & 50 deletions src/shared/containers/Gigs/RecruitCRMJobDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,6 @@ ${config.URL.BASE}${config.GIGS_PAGES_PATH}/${props.id}`,
// exit no email sending
return;
}
// process sent log
let { emailInvitesLog, emailInvitesStatus } = growSurf.data.metadata;
if (!emailInvitesLog) emailInvitesLog = '';
// check if email is in sent log alredy?
const foundInLog = emailInvitesLog.indexOf(email);
if (foundInLog !== -1) {
this.setState({
isReferrError: {
message: `${email} was already invited.`,
userError: true,
},
});
// exit no email sending
return;
}
// check if email is already referred?
const growCheck = await fetch(`${PROXY_ENDPOINT}/growsurf/participant/${email}`);
if (growCheck.status === 200) {
Expand Down Expand Up @@ -125,43 +110,51 @@ ${config.URL.BASE}${config.GIGS_PAGES_PATH}/${props.id}`,
// exit no email tracking due to the error
return;
}
// parse the log to array of emails
if (emailInvitesLog.length) {
emailInvitesLog = emailInvitesLog.split(',');
} else emailInvitesLog = [];
// prepare growSurf update payload
// we keep only 10 emails in the log to justify program rules
if (emailInvitesLog.length < 10) {
emailInvitesLog.push(email);
}
// Auto change status when 10 emails sent
if (emailInvitesLog.length === 10 && emailInvitesStatus !== 'Paid' && emailInvitesStatus !== 'Payment Pending') {
emailInvitesStatus = 'Payment Pending';
}
// put the tracking update in growsurf
const updateRed = await fetch(`${PROXY_ENDPOINT}/growsurf/participant/${growSurf.data.id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${tokenV3}`,
},
body: JSON.stringify({
...growSurf.data,
metadata: {
...growSurf.data.metadata,
emailInvitesSent: Number(growSurf.data.metadata.emailInvitesSent || 0) + 1,
emailInvitesLog: emailInvitesLog.join(),
emailInvitesStatus,
// process sent log
let { emailInvitesLog, emailInvitesStatus } = growSurf.data.metadata;
if (!emailInvitesLog) emailInvitesLog = '';
// check if email is in sent log alredy?
const foundInLog = emailInvitesLog.indexOf(email);
// only when email is new - put it in log, update counters and etc.
if (foundInLog === -1) {
// parse the log to array of emails
if (emailInvitesLog.length) {
emailInvitesLog = emailInvitesLog.split(',');
} else emailInvitesLog = [];
// prepare growSurf update payload
// we keep only 10 emails in the log to justify program rules
if (emailInvitesLog.length < 10) {
emailInvitesLog.push(email);
}
// Auto change status when 10 emails sent
if (emailInvitesLog.length === 10 && emailInvitesStatus !== 'Paid' && emailInvitesStatus !== 'Payment Pending') {
emailInvitesStatus = 'Payment Pending';
}
// put the tracking update in growsurf
const updateRed = await fetch(`${PROXY_ENDPOINT}/growsurf/participant/${growSurf.data.id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${tokenV3}`,
},
}),
});
if (updateRed.status >= 300) {
this.setState({
isReferrError: await updateRed.json(),
body: JSON.stringify({
...growSurf.data,
metadata: {
...growSurf.data.metadata,
emailInvitesSent: Number(growSurf.data.metadata.emailInvitesSent || 0) + 1,
emailInvitesLog: emailInvitesLog.join(),
emailInvitesStatus,
},
}),
});
// exit no email tracking due to the error
// just notify the user about it
return;
if (updateRed.status >= 300) {
this.setState({
isReferrError: await updateRed.json(),
});
// exit no email tracking due to the error
// just notify the user about it
return;
}
}
// finally do:
this.setState({
Expand Down