Skip to content

Commit 5c03871

Browse files
author
vikasrohit
authored
Merge pull request #310 from maxceem/feature/connectv2-form-redesign
Wizard redesign - Checkboxes and radio buttons with optional description and price (without design update)
2 parents 21cb49d + d0a4282 commit 5c03871

File tree

5 files changed

+191
-6
lines changed

5 files changed

+191
-6
lines changed

components/Formsy/CheckboxGroup.jsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component, PropTypes } from 'react'
22
import { HOC as hoc } from 'formsy-react'
33
import cn from 'classnames'
4+
import { numberWithCommas } from './format'
45

56
class CheckboxGroup extends Component {
67

@@ -21,7 +22,7 @@ class CheckboxGroup extends Component {
2122
}
2223

2324
render() {
24-
const { label, name, options, layout } = this.props
25+
const { label, name, options, layout, wrapperClass } = this.props
2526
const hasError = !this.props.isPristine() && !this.props.isValid()
2627
const disabled = this.props.isFormDisabled() || this.props.disabled
2728
const errorMessage = this.props.getErrorMessage() || this.props.validationError
@@ -30,7 +31,7 @@ class CheckboxGroup extends Component {
3031
const curValue = this.props.getValue() || []
3132
const checked = curValue.indexOf(cb.value) !== -1
3233
const disabled = this.props.isFormDisabled() || cb.disabled || this.props.disabled
33-
const rClass = cn('checkbox-group-item', { disabled })
34+
const rClass = cn('checkbox-group-item', { disabled, selected: checked })
3435
const id = name+'-opt-'+key
3536
const setRef = (c) => this['element-' + key] = c
3637
return (
@@ -48,10 +49,16 @@ class CheckboxGroup extends Component {
4849
<label htmlFor={id}/>
4950
</div>
5051
<label className="tc-checkbox-label" htmlFor={id}>{cb.label}</label>
52+
{
53+
cb.quoteUp && !checked && <div className="checkbox-option-price"> {`+ $${numberWithCommas(cb.quoteUp)}`} </div>
54+
}
55+
{
56+
cb.description && checked && <div className="checkbox-option-description"> {cb.description} </div>
57+
}
5158
</div>
5259
)
5360
}
54-
const chkGrpClass = cn('checkbox-group', {
61+
const chkGrpClass = cn('checkbox-group', wrapperClass, {
5562
horizontal: layout === 'horizontal',
5663
vertical: layout === 'vertical'
5764
})

components/Formsy/RadioGroup.jsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import React, { Component, PropTypes } from 'react'
22
import { HOC as hoc } from 'formsy-react'
33
import cn from 'classnames'
4+
import { find } from "lodash";
5+
import { numberWithCommas } from './format'
46

57
class RadioGroup extends Component {
68

@@ -15,16 +17,28 @@ class RadioGroup extends Component {
1517
this.props.onChange(this.props.name, value)
1618
}
1719

20+
getSelectedOption() {
21+
const {options = [], getValue} = this.props;
22+
const value = getValue()
23+
return find(options, o => value === o.value)
24+
}
25+
1826
render() {
1927
const { label, name, wrapperClass, options } = this.props
2028
const hasError = !this.props.isPristine() && !this.props.isValid()
2129
const disabled = this.props.isFormDisabled() || this.props.disabled
2230
const errorMessage = this.props.getErrorMessage() || this.props.validationError
31+
const selectedOption = this.getSelectedOption()
32+
const hasPrice = find(options, o => o.quoteUp)
2333

2434
const renderOption = (radio, key) => {
25-
const checked = (this.props.getValue() === radio.value)
35+
const relativePrice = (selectedOption, radio) => {
36+
const price = (radio.quoteUp || 0) - (selectedOption.quoteUp || 0)
37+
return (price < 0 ? '-' : '+') + ' $' + numberWithCommas(Math.abs(price))
38+
}
39+
const checked = (selectedOption && selectedOption.value === radio.value)
2640
const disabled = this.props.isFormDisabled() || radio.disabled || this.props.disabled
27-
const rClass = cn('radio', { disabled })
41+
const rClass = cn('radio', { disabled, selected: checked })
2842
const id = name+'-opt-'+key
2943
const setRef = (c) => this['element-' + key] = c
3044
return (
@@ -39,6 +53,15 @@ class RadioGroup extends Component {
3953
disabled={disabled}
4054
/>
4155
<label htmlFor={id}>{radio.label}</label>
56+
{
57+
hasPrice &&
58+
!checked &&
59+
(radio.quoteUp || selectedOption) &&
60+
<div className="radio-option-price"> {selectedOption ? relativePrice(selectedOption, radio) : `$${numberWithCommas(radio.quoteUp)}`} </div>
61+
}
62+
{
63+
radio.description && checked && <div className="radio-option-description"> {radio.description} </div>
64+
}
4265
</div>
4366
)
4467
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
'use strict'
2+
import React, { PropTypes, Component } from 'react'
3+
import classNames from 'classnames'
4+
import Tooltip from '../Tooltip/Tooltip'
5+
import IconUICheckSimple from '../Icons/IconUICheckSimple'
6+
import { HOC as hoc } from 'formsy-react'
7+
8+
class TiledCheckboxGroup extends Component {
9+
constructor(props) {
10+
super(props)
11+
this.onChange = this.onChange.bind(this)
12+
this.getCheckMarkIconActive = this.getCheckMarkIconActive.bind(this)
13+
}
14+
15+
onChange(value) {
16+
const curValue = this.props.getValue() || []
17+
const index = curValue.indexOf(value)
18+
let newValue = [...curValue]
19+
if (index > -1) {
20+
newValue.splice(index, 1)
21+
} else {
22+
newValue.push(value)
23+
}
24+
this.props.setValue(newValue)
25+
this.props.onChange(this.props.name, newValue)
26+
}
27+
28+
getCheckMarkIconActive() {
29+
return (this.props.checkMarkActiveIcon ? this.props.checkMarkActiveIcon : (
30+
<span className="check-mark">
31+
<IconUICheckSimple fill="#fff" width={12} height={12}/>
32+
</span>))
33+
}
34+
35+
render() {
36+
const { wrapperClass, options, theme, tabable } = this.props
37+
const curValue = this.props.getValue() || []
38+
const hasError = !this.props.isPristine() && !this.props.isValid()
39+
const disabled = this.props.isFormDisabled() || this.props.disabled
40+
const errorMessage = this.props.getErrorMessage() || this.props.validationError
41+
42+
const renderOption = (opt, idx) => {
43+
const checked = curValue.indexOf(opt.value) > -1
44+
const itemClassnames = classNames('tiled-group-item', theme, {
45+
active: checked
46+
}, {
47+
disabled: opt.disabled
48+
})
49+
const handleClick = () => this.onChange(opt.value)
50+
const handleFocus = (e) => {
51+
e.target.parentNode.classList.add('focused')
52+
}
53+
const handleBlur = (e) => {
54+
e.target.parentNode.classList.remove('focused')
55+
}
56+
const Icon = opt.icon
57+
const setRef = (c) => this['element-' + idx] = c
58+
const renderTile = () => (
59+
<a onClick={ !disabled && !opt.disabled && handleClick } data-value={opt.value} className={itemClassnames} key={idx} >
60+
{
61+
!!tabable &&
62+
<input
63+
ref={setRef}
64+
type="checkbox"
65+
name={ this.props.name }
66+
style={{ position : 'absolute', left : '-9999px'}}
67+
onFocus={handleFocus}
68+
onChange={this.onChange}
69+
onBlur={handleBlur}
70+
/>
71+
}
72+
{
73+
this.props.showCheckMarkBeforeTitle
74+
&& (checked
75+
? this.getCheckMarkIconActive()
76+
: this.props.checkMarkUnActiveIcon)
77+
}
78+
<span className="icon">{ opt.icon && <Icon {...opt.iconOptions} />}</span>
79+
<span className="title">{opt.title}</span>
80+
<small>{opt.desc}</small>
81+
{
82+
!this.props.showCheckMarkBeforeTitle
83+
&& (checked
84+
? this.getCheckMarkIconActive()
85+
: this.props.checkMarkUnActiveIcon)
86+
}
87+
</a>
88+
)
89+
return (
90+
<span key={ idx } className="tiled-group-item-container">
91+
{
92+
opt.disabled && opt.errorMessage ?
93+
<Tooltip>
94+
<div className="tooltip-target" id={'tooltip-' + idx}>
95+
{renderTile()}
96+
</div>
97+
<div className="tooltip-body">
98+
<p>{opt.errorMessage}</p>
99+
</div>
100+
</Tooltip> :
101+
renderTile()
102+
}
103+
</span>
104+
)
105+
}
106+
107+
return (
108+
<div className={`${wrapperClass} tiled-group-row`}>
109+
110+
{this.props.label && (
111+
<label className="tc-label">
112+
{this.props.label}
113+
</label>)}
114+
{options.map(renderOption)}
115+
{ hasError ? (<p className="error-message">{errorMessage}</p>) : null}
116+
</div>
117+
)
118+
}
119+
}
120+
TiledCheckboxGroup.propTypes = {
121+
options: PropTypes.arrayOf(
122+
PropTypes.shape({
123+
title: PropTypes.string.isRequired,
124+
value: PropTypes.string.isRequired,
125+
desc: PropTypes.string
126+
// icon: PropTypes.
127+
}).isRequired
128+
).isRequired,
129+
checkMarkActiveIcon: PropTypes.node,
130+
checkMarkUnActiveIcon: PropTypes.node,
131+
showCheckMarkBeforeTitle: PropTypes.bool
132+
}
133+
134+
TiledCheckboxGroup.defaultProps = {
135+
onChange: () => {},
136+
showCheckMarkBeforeTitle: false
137+
}
138+
139+
export default hoc(TiledCheckboxGroup)

components/Formsy/format.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Helper methods to format values
3+
*/
4+
5+
/**
6+
* Fomats number, separating every 3 digits with comma
7+
*
8+
* @param {Number} number
9+
*/
10+
export function numberWithCommas(number) {
11+
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
12+
}

components/Formsy/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import RadioGroup from './RadioGroup'
88
import CheckboxGroup from './CheckboxGroup'
99
import SliderRadioGroup from './SliderRadioGroup'
1010
import TiledRadioGroup from './TiledRadioGroup'
11+
import TiledCheckboxInput from './TiledCheckboxInput'
12+
import TiledCheckboxGroup from './TiledCheckboxGroup'
1113

1214
require('./FormFields.scss')
1315

@@ -37,6 +39,8 @@ export default {
3739
Checkbox,
3840
CheckboxGroup,
3941
SliderRadioGroup,
40-
TiledRadioGroup
42+
TiledRadioGroup,
43+
TiledCheckboxInput,
44+
TiledCheckboxGroup
4145
}
4246
}

0 commit comments

Comments
 (0)