diff --git a/.circleci/config.yml b/.circleci/config.yml index 6d96e22b..34ee3dfc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -83,6 +83,7 @@ workflows: branches: only: - develop + - feature/timeline-template # Production builds are exectuted only on tagged commits to the # master branch. diff --git a/src/components/ChallengeEditor/ChallengeName-Field/ChallengeName-Field.module.scss b/src/components/ChallengeEditor/ChallengeName-Field/ChallengeName-Field.module.scss index d6aa6895..51348657 100644 --- a/src/components/ChallengeEditor/ChallengeName-Field/ChallengeName-Field.module.scss +++ b/src/components/ChallengeEditor/ChallengeName-Field/ChallengeName-Field.module.scss @@ -52,16 +52,18 @@ } } -@-moz-document url-prefix() { - .challengeName { - &::-moz-placeholder { /* Mozilla Firefox 19+ */ - line-height: 38px; - } - &::-webkit-input-placeholder { /* Webkit */ - line-height: 38px; - } - &:-ms-input-placeholder { /* IE */ - line-height: 38px; - } +.challengeName { + &::-moz-placeholder { /* Mozilla Firefox 19+ */ + line-height: 38px; + color: $tc-gray-80; + } + &::-webkit-input-placeholder { /* Webkit */ + line-height: 38px; + color: $tc-gray-80; + } + &:-ms-input-placeholder { /* IE */ + line-height: 38px; + color: $tc-gray-80; } } + diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js index 1d25750b..0e65044f 100644 --- a/src/components/ChallengeEditor/ChallengeView/index.js +++ b/src/components/ChallengeEditor/ChallengeView/index.js @@ -26,6 +26,7 @@ import { isBetaMode } from '../../../util/cookie' import { loadGroupDetails } from '../../../actions/challenges' import Tooltip from '../../Tooltip' import { MESSAGE, REVIEW_TYPES } from '../../../config/constants' +import TimelineTemplateField from '../TimelineTemplate-Field' const ChallengeView = ({ projectDetail, @@ -202,6 +203,13 @@ const ChallengeView = ({ {isBetaMode() && ( )} + {}} + readOnly + /> )} { diff --git a/src/components/ChallengeEditor/TimelineTemplate-Field/TimelineTemplate-Field.module.scss b/src/components/ChallengeEditor/TimelineTemplate-Field/TimelineTemplate-Field.module.scss new file mode 100644 index 00000000..f6707a0c --- /dev/null +++ b/src/components/ChallengeEditor/TimelineTemplate-Field/TimelineTemplate-Field.module.scss @@ -0,0 +1,55 @@ +@import "../../../styles/includes"; + +.row { + box-sizing: border-box; + display: flex; + flex-direction: row; + margin: 30px 30px 0 30px; + align-content: space-between; + justify-content: flex-start; + + .field { + @include upto-sm { + display: block; + padding-bottom: 10px; + } + + label { + @include roboto-bold(); + + font-size: 16px; + line-height: 19px; + font-weight: 500; + color: $tc-gray-80; + } + + &.col1 { + max-width: 185px; + min-width: 185px; + margin-right: 14px; + white-space: nowrap; + display: flex; + align-items: center; + flex-grow: 1; + + span { + color: $tc-red; + } + } + + &.col2.error { + color: $tc-red; + margin-top: -25px; + } + &.col2 { + align-self: flex-end; + width: 80%; + margin-bottom: auto; + margin-top: auto; + display: flex; + flex-direction: row; + max-width: 600px; + min-width: 600px; + } + } +} diff --git a/src/components/ChallengeEditor/TimelineTemplate-Field/index.js b/src/components/ChallengeEditor/TimelineTemplate-Field/index.js new file mode 100644 index 00000000..242f4e07 --- /dev/null +++ b/src/components/ChallengeEditor/TimelineTemplate-Field/index.js @@ -0,0 +1,126 @@ +import _ from 'lodash' +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import Select from '../../Select' +import cn from 'classnames' +import styles from './TimelineTemplate-Field.module.scss' + +class TimelineTemplateField extends Component { + constructor (props) { + super(props) + this.state = { + validOptions: [], + selectedOption: {} + } + + this.checkData = this.checkData.bind(this) + this.loadSelectedOption = this.loadSelectedOption.bind(this) + this.getErrorMessage = this.getErrorMessage.bind(this) + } + + componentDidMount () { + const { challengeTimelines, timelineTemplates, challenge, currentTemplate } = this.props + this.checkData(challengeTimelines, timelineTemplates, challenge, currentTemplate) + } + + componentWillUnmount () { + this.props.onUpdateSelect(this.state.selectedOption.value) + } + + loadSelectedOption (validOptions, value) { + const { timelineTemplates, challenge } = this.props + const selectedOption = {} + const selectedTemplate = _.find(timelineTemplates, t => t.id === (value)) + this.props.onUpdateSelect(selectedTemplate) + + selectedOption.label = selectedTemplate.name + selectedOption.value = selectedTemplate.id + this.setState({ + validOptions, + matchString: `${challenge.typeId}-${challenge.trackId}-${value}`, + selectedOption + }) + } + + checkData (challengeTimelines, timelineTemplates, challenge, currentTemplate) { + const availableTemplates = _.filter(challengeTimelines, ct => ct.typeId === challenge.typeId && ct.trackId === challenge.trackId) + const availableTemplateIds = availableTemplates.map(tt => tt.timelineTemplateId) + const validOptions = _.filter(timelineTemplates, t => _.includes(availableTemplateIds, t.id)) + const defaultValue = _.get(_.find(availableTemplates, t => t.isDefault), 'timelineTemplateId') + if (currentTemplate && currentTemplate.id) { + if (!_.includes(_.map(validOptions, o => o.id), currentTemplate.id)) { + this.loadSelectedOption(validOptions, defaultValue) + } else { + this.loadSelectedOption(validOptions, currentTemplate.id) + } + } else if (defaultValue) { + return this.loadSelectedOption(validOptions, defaultValue) + } + } + + getErrorMessage () { + if (!this.props.challenge.typeId || !this.props.challenge.trackId) { + return 'Please select a work type and format to enable this field' + } else if (this.props.challenge.submitTriggered && !this.props.currentTemplate) { + return 'Timeline template is required field' + } else if (this.state.validOptions.length === 0) { + return 'Sorry, there are no available timeline templates for the options you have selected' + } + return null + } + + render () { + const { challengeTimelines, timelineTemplates, challenge, currentTemplate } = this.props + const hasSelectedTypeAndTrack = !_.isEmpty(challenge.typeId) && !_.isEmpty(challenge.trackId) + if ((hasSelectedTypeAndTrack && this.state.validOptions.length === 0) || this.state.matchString !== `${challenge.typeId}-${challenge.trackId}-${this.state.selectedOption.value}`) { + this.checkData(challengeTimelines, timelineTemplates, challenge, currentTemplate) + } + const error = this.getErrorMessage() + return ( + <> +
+
+ +
+
+