Skip to content
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
15 changes: 15 additions & 0 deletions src/components/Buttons/PrimaryButton/PrimaryButton.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,28 @@

&.danger {
background-color: $tc-red;

&:disabled {
cursor: default;
background-color: $inactive;
}
}

&.info {
background-color: $tc-blue-20;

&:disabled {
cursor: default;
background-color: $inactive;
}
}

&.success {
background-color: $tc-green-40;

&:disabled {
cursor: default;
background-color: $inactive;
}
}
}
7 changes: 4 additions & 3 deletions src/components/Buttons/PrimaryButton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import cn from 'classnames'

import styles from './PrimaryButton.module.scss'

const PrimaryButton = ({ type, text, link, onClick, submit }) => {
const PrimaryButton = ({ type, text, link, onClick, submit, disabled }) => {
if (_.isEmpty(link)) {
return (
<button type={submit ? 'submit' : 'button'} className={cn(styles.container, styles[type])} onClick={submit ? null : onClick}>
<button type={submit ? 'submit' : 'button'} className={cn(styles.container, styles[type])} onClick={submit ? null : onClick} disabled={disabled}>
<span>{text}</span>
</button>
)
Expand All @@ -26,7 +26,8 @@ PrimaryButton.propTypes = {
text: PropTypes.string.isRequired,
link: PropTypes.string,
onClick: PropTypes.func,
submit: PropTypes.bool
submit: PropTypes.bool,
disabled: PropTypes.bool
}

export default PrimaryButton
Original file line number Diff line number Diff line change
Expand Up @@ -47,104 +47,55 @@
}
}

.tcCheckbox {
@include tc-checkbox;

.tc-checkbox-label {
@include roboto-light();

line-height: 17px;
font-weight: 300;
margin-left: 21px;
user-select: none;
cursor: pointer;
width: 195px;
font-size: 14px;
color: #3d3d3d;
}

height: 18px;
width: 210px;
.fileTypeList {
margin: 0;
padding: 0;
vertical-align: bottom;
position: relative;
display: inline-block;
margin-bottom: 18px;

input[type='checkbox'] {
display: none;

&:checked ~ label {
background: $tc-blue-20;
}

&:checked + label::after {
border-color: $white;
}
}

label {
@include roboto-light();

line-height: 17px;
font-weight: 300;
cursor: pointer;
position: absolute;
display: inline-block;
width: 14px;
height: 14px;
top: 0;
left: 0;
border: none;
box-shadow: none;
background: $tc-gray-30;
transition: all 0.15s ease-in-out;

&.readOnly {
cursor: auto;
}
}

&::after {
opacity: 0;
content: '';
position: absolute;
width: 9px;
height: 5px;
background: transparent;
top: 2px;
left: 2px;
border-top: none;
border-right: none;
transform: rotate(-45deg);
transition: all 0.15s ease-in-out;
}
.fileTypeListEditable {

&:hover::after {
opacity: 0.3;
}
&:hover:read-only::after {
opacity: 0;
}
}

div {
margin-left: 24px;
width: 500px;
}
}
.fileTypeItem {
background-color: #2C95D7;
border-radius: 2px;
border: 1px solid #c9e6f2;
color: #ffffff;
display: inline-block;
font-size: 14px;
margin-right: 5px;
padding: 2px 30px 2px 5px;
position: relative;
vertical-align: top;
}

.checkList {
.fileTypeDelete {
align-items: center;
background-color: #c6def1;
border: 0;
color: #2C95D7;
cursor: pointer;
display: flex;
flex-direction: column;
margin-left: 30px;
border-radius: 50%;
font-size: 14px;
height: 16px;
justify-content: center;
position: absolute;
right: 5px;
top: 50%;
transform: translateY(-50%);
width: 16px;

&:hover {
background-color: #fff;
}
}

form {
display: flex;
flex-direction: row;
}

.button {
width: 137px;
height: 40px;
Expand Down
46 changes: 21 additions & 25 deletions src/components/ChallengeEditor/FinalDeliverables-Field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ class FinalDeliverablesField extends Component {
}

onChangeInput (value) {
this.setState({ newFileType: _.trim(value) })
this.setState({ newFileType: value })
}

onAddFileType (event) {
if (!_.isEmpty(this.state.newFileType)) {
this.props.addFileType(this.state.newFileType)
this.props.addFileType(this.state.newFileType.trim())
this.setState({ newFileType: '' })
}

Expand All @@ -31,7 +31,11 @@ class FinalDeliverablesField extends Component {
}

render () {
const { challenge, onUpdateCheckbox, readOnly } = this.props
const { challenge, readOnly, removeFileType } = this.props
const fileTypesMetadata = _.find(challenge.metadata, { name: 'fileTypes' })
const fileTypes = (fileTypesMetadata && JSON.parse(fileTypesMetadata.value)) || []
const isDuplicateValue = _.includes(fileTypes, this.state.newFileType.trim())

return (
<React.Fragment>
<div className={styles.row}>
Expand All @@ -40,27 +44,18 @@ class FinalDeliverablesField extends Component {
</div>
</div>
<div className={styles.row}>
<div className={styles.checkList}>
{
_.map(challenge.fileTypes, (type, index) => (
<div className={styles.tcCheckbox} key={type.name}>
<input
name={type.name}
type='checkbox'
id={type.name}
checked={type.check}
onChange={(e) => onUpdateCheckbox(type.name, e.target.checked, 'fileTypes', index)}
readOnly={readOnly}
/>
<label htmlFor={type.name} className={cn({ [styles.readOnly]: readOnly })}>
<div className={styles.checkboxLabel}>
{type.name}
</div>
</label>
</div>
))
}
</div>
{!readOnly ? (
<ul className={styles.fileTypeList}>
{_.map(fileTypes, (type) => (
<li key={type} htmlFor={type} className={styles.fileTypeItem}>
{type}
<button className={styles.fileTypeDelete} type='button' onClick={() => removeFileType(type)}>×</button>
</li>
))}
</ul>
) : (
fileTypes.join(', ')
)}
</div>
{!readOnly && (<div className={styles.row}>
<form name='add-file-type-form' autoComplete='off' onSubmit={this.onAddFileType}>
Expand All @@ -76,6 +71,7 @@ class FinalDeliverablesField extends Component {
<PrimaryButton
text={'Add File Type'}
type={'info'}
disabled={!this.state.newFileType.trim() || isDuplicateValue}
submit
/>
</div>
Expand All @@ -93,8 +89,8 @@ FinalDeliverablesField.defaultProps = {

FinalDeliverablesField.propTypes = {
challenge: PropTypes.shape().isRequired,
onUpdateCheckbox: PropTypes.func.isRequired,
addFileType: PropTypes.func.isRequired,
removeFileType: PropTypes.func.isRequired,
readOnly: PropTypes.bool
}

Expand Down
3 changes: 3 additions & 0 deletions src/components/ChallengeEditor/TextEditor-Field/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class TextEditorField extends Component {
challenge,
onUpdateCheckbox,
addFileType,
removeFileType,
onUpdateDescription,
onUpdateMultiSelect,
shouldShowPrivateDescription,
Expand Down Expand Up @@ -87,6 +88,7 @@ class TextEditorField extends Component {
challenge={challenge}
onUpdateCheckbox={onUpdateCheckbox}
addFileType={addFileType}
removeFileType={removeFileType}
readOnly={readOnly}
/>
<StockArtsField
Expand Down Expand Up @@ -128,6 +130,7 @@ TextEditorField.propTypes = {
challenge: PropTypes.shape().isRequired,
onUpdateCheckbox: PropTypes.func,
addFileType: PropTypes.func,
removeFileType: PropTypes.func,
onUpdateMetadata: PropTypes.func,
onUpdateDescription: PropTypes.func,
onUpdateMultiSelect: PropTypes.func,
Expand Down
65 changes: 58 additions & 7 deletions src/components/ChallengeEditor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class ChallengeEditor extends Component {
this.onUpdateCheckbox = this.onUpdateCheckbox.bind(this)
this.onUpdateAssignedMember = this.onUpdateAssignedMember.bind(this)
this.addFileType = this.addFileType.bind(this)
this.removeFileType = this.removeFileType.bind(this)
this.updateFileTypesMetadata = this.updateFileTypesMetadata.bind(this)
this.toggleAdvanceSettings = this.toggleAdvanceSettings.bind(this)
this.toggleNdaRequire = this.toggleNdaRequire.bind(this)
this.removeAttachment = this.removeAttachment.bind(this)
Expand Down Expand Up @@ -412,19 +414,67 @@ class ChallengeEditor extends Component {
}

/**
* Add new file type
* @param {String} newFileType The new file type
* Helper method which updates the value of `fileTypes` metadata without mutation of the challenge object.
*
* @param {Function} processValue callback function to update the value
*/
addFileType (newFileType) {
updateFileTypesMetadata (processValue) {
const { challenge: oldChallenge } = this.state
const newChallenge = { ...oldChallenge }
if (!_.isArray(newChallenge.fileTypes)) {
newChallenge.fileTypes = []
// avoid mutation of `challenge` object
const newChallenge = {
...oldChallenge,
// avoid mutation of `metadata` array
metadata: [
...(oldChallenge.metadata || [])
]
}
newChallenge.fileTypes.push({ name: newFileType, check: false })

// find existent fileType metadata
let fileTypesMetadataIndex = _.findIndex(newChallenge.metadata, { name: 'fileTypes' })
let fileTypesMetadata

// if found existent fileType metadata we have to recreate the record to avoid mutation
if (fileTypesMetadataIndex > -1) {
fileTypesMetadata = { ...newChallenge.metadata[fileTypesMetadataIndex] }
newChallenge.metadata[fileTypesMetadataIndex] = fileTypesMetadata
// if not yet, create an empty record in metadata
} else {
fileTypesMetadata = { name: 'fileTypes', value: '[]' }
newChallenge.metadata.push(fileTypesMetadata)
}

// as values in metadata are always stored as string, we have to parse it, update and stringify again
const oldFileTypes = JSON.parse(fileTypesMetadata.value)
const newFileTypes = processValue(oldFileTypes)
fileTypesMetadata.value = JSON.stringify(newFileTypes)

this.setState({ challenge: newChallenge })
}

/**
* Add new file type
* @param {String} newFileType The new file type
*/
addFileType (newFileType) {
this.updateFileTypesMetadata((oldFileTypes) => {
const newFileTypes = [...oldFileTypes, newFileType]

return newFileTypes
})
}

/**
* Remove file type
* @param {String} fileType file type
*/
removeFileType (fileType) {
this.updateFileTypesMetadata((oldFileTypes) => {
const newFileTypes = _.reject(oldFileTypes, (type) => type === fileType)

return newFileTypes
})
}

/**
* Update Metadata
* @param name Name of data
Expand Down Expand Up @@ -1312,6 +1362,7 @@ class ChallengeEditor extends Component {
challenge={challenge}
onUpdateCheckbox={this.onUpdateCheckbox}
addFileType={this.addFileType}
removeFileType={this.removeFileType}
onUpdateInput={this.onUpdateInput}
onUpdateDescription={this.onUpdateDescription}
onUpdateMultiSelect={this.onUpdateMultiSelect}
Expand Down