Skip to content

Instantly share code, notes, and snippets.

@mike-casas
Forked from insin/AddTravel.js
Created May 27, 2016 23:15
Show Gist options
  • Select an option

  • Save mike-casas/a366e6bfc923f77fbfaa068cc40285b0 to your computer and use it in GitHub Desktop.

Select an option

Save mike-casas/a366e6bfc923f77fbfaa068cc40285b0 to your computer and use it in GitHub Desktop.

Revisions

  1. @insin insin revised this gist Sep 30, 2015. 2 changed files with 4 additions and 4 deletions.
    2 changes: 1 addition & 1 deletion AddTravel.js
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,9 @@
    var Col = require('react-bootstrap/lib/Col')
    var PageHeader = require('react-bootstrap/lib/PageHeader')
    var React = require('react')
    var reduxForm = require('redux-form').default
    var Row = require('react-bootstrap/lib/Row')
    var {connect} = require('react-redux')
    var {reduxForm} = require('redux-form')

    var DateInput = require('./DateInput')
    var FormField = require('./FormField')
    6 changes: 3 additions & 3 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -4,13 +4,13 @@
    },
    "dependencies": {
    "bootstrap": "3.3.5",
    "classnames": "2.1.3",
    "classnames": "2.1.4",
    "react": "0.13.3",
    "react-bootstrap": "0.25.2",
    "react-redux": "3.0.0",
    "react-redux": "3.0.1",
    "react-widgets": "2.8.1",
    "redux": "3.0.2",
    "redux-form": "1.7.0"
    "redux-form": "2.0.0"
    },
    "devDependencies": {
    "react-heatpack": "^1.5.0"
  2. @insin insin revised this gist Sep 30, 2015. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,14 @@
    Example of implementing form components backed by [redux-form](https://github.com/erikras/redux-form), extracted from an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.

    To run example:
    Live version: http://insin.github.io/redux-form-example/

    To run the example with hot reloading via [react-heatpack](https://github.com/insin/react-heatpack):

    ```
    git clone [email protected]:bbf116e8ea10ef38447b.git redux-form-example
    cd redux-form-example
    npm install
    npm start
    ```

    ## MIT Licensed
  3. @insin insin revised this gist Sep 30, 2015. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions react-widgets-overrides.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    /* Use Bootstrap error styles for widgets. */
    .has-error .rw-widget {
    border-color: #A94442;
    box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset;
    }
    .has-error .rw-widget.rw-state-focus {
    border-color: #A94442;
    box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset, 0px 0px 6px #CE8483;
    }
  4. @insin insin revised this gist Sep 27, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -10,3 +10,5 @@ cd redux-form-example
    npm install
    npm start
    ```

    ## MIT Licensed
  5. @insin insin revised this gist Sep 27, 2015. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,8 @@
    Example of implementing form components backed by [redux-form](https://github.com/erikras/redux-form), extracted from an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.

    To run example:
    Live version: http://insin.github.io/redux-form-example/

    To run the example with hot reloading via [react-heatpack](https://github.com/insin/react-heatpack):

    ```
    git clone [email protected]:bbf116e8ea10ef38447b.git redux-form-example
  6. @insin insin revised this gist Sep 26, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Form components being used with [redux-form](https://github.com/erikras/redux-form) in an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.
    Example of implementing form components backed by [redux-form](https://github.com/erikras/redux-form), extracted from an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.

    To run example:

  7. @insin insin revised this gist Sep 26, 2015. No changes.
  8. @insin insin revised this gist Sep 26, 2015. 1 changed file with 10 additions and 1 deletion.
    11 changes: 10 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,10 @@
    Form components being used with [redux-form](https://github.com/erikras/redux-form) in an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.
    Form components being used with [redux-form](https://github.com/erikras/redux-form) in an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.

    To run example:

    ```
    git clone [email protected]:bbf116e8ea10ef38447b.git redux-form-example
    cd redux-form-example
    npm install
    npm start
    ```
  9. @insin insin revised this gist Sep 26, 2015. 4 changed files with 26 additions and 18 deletions.
    28 changes: 17 additions & 11 deletions AddTravel.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    var Col = require('react-bootstrap/lib/Col')
    var PageHeader = require('react-bootstrap/lib/PageHeader')
    var React = require('react')
    var reduxForm = require('redux-form').default
    var Row = require('react-bootstrap/lib/Row')
    @@ -19,7 +20,7 @@ var mapStateToProps = state => state
    var form = reduxForm({
    form: 'addTravel',
    fields: ['startDate', 'endDate', 'origin', 'destination', 'hotel', 'hasCar'],
    touchOnChange: true,
    touchOnChange: true, // react-widgets DateTimePicker doesn't blur
    validate(travel) {
    var errors = {}
    if (!travel.startDate) errors.startDate = 'Please enter a start date.'
    @@ -37,7 +38,8 @@ var form = reduxForm({
    var AddTravel = React.createClass({
    getInitialState() {
    return {
    fakeSaving: false
    fakeSaving: false,
    fakeSubmitted: null
    }
    },
    componentWillMount() {
    @@ -61,17 +63,15 @@ var AddTravel = React.createClass({
    }
    },
    handleSubmit(data) {
    this.setState({fakeSaving: true})
    this.setState({fakeSaving: true, fakeSubmitted: data})
    setTimeout(() => this.setState({fakeSaving: false}), 2000)
    },

    render() {
    var {fields} = this.props
    var {fakeSaving} = this.state
    return <div className="AddTravel">
    <p className="lead">
    Enter travel below.
    </p>
    var {fakeSaving, fakeSubmitted} = this.state
    return <div className="container">
    <PageHeader>redux-form example</PageHeader>
    <form className="form-horizontal" onSubmit={this.props.handleSubmit(this.handleSubmit)}>
    <Row>
    <StaticField label="First Name:" value="Steve"/>
    @@ -128,11 +128,17 @@ var AddTravel = React.createClass({
    </Row>
    <Row className="form-group">
    <Col sm={12} className="text-center">
    <LoadingButton type="submit" bsSize="large" bsStyle="primary" disabled={fakeSaving}>
    <img src={require('images/add-travel-button.png')}/> Add Travel
    </LoadingButton>
    <LoadingButton
    bsSize="large"
    bsStyle="primary"
    label="Add Travel"
    loading={fakeSaving}
    loadingLabel="Adding Travel"
    type="submit"
    />
    </Col>
    </Row>
    {fakeSubmitted && <pre><code>{JSON.stringify(fakeSubmitted, null, 2)}</code></pre>}
    </form>
    </div>
    }
    4 changes: 2 additions & 2 deletions LoadingButton.js
    Original file line number Diff line number Diff line change
    @@ -3,13 +3,13 @@ require('./LoadingButton.css')
    var React = require('react')
    var Button = require('react-bootstrap/lib/Button')

    var Loading = require('Loading')
    var Loading = require('./Loading')

    var LoadingButton = React.createClass({
    propTypes: {
    label: React.PropTypes.string.isRequired,
    loading: React.PropTypes.bool.isRequired,
    icom: React.PropTypes.string,
    icon: React.PropTypes.string,
    // Defaults to label + 'ing' if not provided
    loadingLabel: React.PropTypes.string
    },
    3 changes: 2 additions & 1 deletion index.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    require('bootstrap/dist/css/bootstrap.min.css')
    require('react-widgets/dist/css/react-widgets.css')
    require('./react-widgets-overrides.css')

    var React = require('react')
    var {Provider} = require('react-redux')
    @@ -9,4 +10,4 @@ var configureStore = require('./configureStore')

    var store = configureStore()

    React.render(<Provider store={store}>{() => <AddTravel/>}</Provider>, document.querySelector('#app'))
    React.render(<Provider store={store}>{() => <AddTravel/>}</Provider>, document.querySelector('#app'))
    9 changes: 5 additions & 4 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -4,14 +4,15 @@
    },
    "dependencies": {
    "bootstrap": "3.3.5",
    "classnames": "2.1.3",
    "react": "0.13.3",
    "react-bootstrap": "0.25.2",
    "react-redux": "2.1.2",
    "react-redux": "3.0.0",
    "react-widgets": "2.8.1",
    "redux": "3.0.0",
    "redux-form": "1.6.7"
    "redux": "3.0.2",
    "redux-form": "1.7.0"
    },
    "devDependencies": {
    "react-heatpack": "^1.5.0"
    }
    }
    }
  10. @insin insin created this gist Sep 26, 2015.
    141 changes: 141 additions & 0 deletions AddTravel.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,141 @@
    var Col = require('react-bootstrap/lib/Col')
    var React = require('react')
    var reduxForm = require('redux-form').default
    var Row = require('react-bootstrap/lib/Row')
    var {connect} = require('react-redux')

    var DateInput = require('./DateInput')
    var FormField = require('./FormField')
    var LoadingButton = require('./LoadingButton')
    var StaticField = require('./StaticField')
    var TextInput = require('./TextInput')

    var {zeroTime} = require('./utils')

    var TODAY = zeroTime(new Date())

    var mapStateToProps = state => state

    var form = reduxForm({
    form: 'addTravel',
    fields: ['startDate', 'endDate', 'origin', 'destination', 'hotel', 'hasCar'],
    touchOnChange: true,
    validate(travel) {
    var errors = {}
    if (!travel.startDate) errors.startDate = 'Please enter a start date.'
    if (!travel.endDate) errors.endDate = 'Please enter an end date.'
    if (travel.startDate && travel.endDate &&
    zeroTime(travel.endDate) < zeroTime(travel.startDate)) {
    errors.endDate = 'End date must not be earlier than start date.'
    }
    if (!travel.origin) errors.origin = 'Please enter an origin.'
    if (!travel.destination) errors.destination = 'Please enter a destination.'
    return errors
    }
    })

    var AddTravel = React.createClass({
    getInitialState() {
    return {
    fakeSaving: false
    }
    },
    componentWillMount() {
    this.props.initializeForm({
    startDate: null,
    endDate: null,
    origin: '',
    destination: '',
    hotel: '',
    hasCar: 'no'
    })
    },

    /**
    * Set endDate to startDate if it's blank or would otherwise be invalid.
    */
    handleStartDateChange(startDate) {
    var {endDate} = this.props.fields
    if (endDate.value == null || endDate.value < startDate) {
    endDate.onChange(startDate)
    }
    },
    handleSubmit(data) {
    this.setState({fakeSaving: true})
    setTimeout(() => this.setState({fakeSaving: false}), 2000)
    },

    render() {
    var {fields} = this.props
    var {fakeSaving} = this.state
    return <div className="AddTravel">
    <p className="lead">
    Enter travel below.
    </p>
    <form className="form-horizontal" onSubmit={this.props.handleSubmit(this.handleSubmit)}>
    <Row>
    <StaticField label="First Name:" value="Steve"/>
    <StaticField label="Last Name:" value="Test"/>
    </Row>
    <Row>
    <DateInput
    afterChange={this.handleStartDateChange}
    disabled={fakeSaving}
    field={fields.startDate}
    id="startDate"
    label="Start Date:"
    min={TODAY}
    />
    <DateInput
    disabled={fakeSaving}
    field={fields.endDate}
    id="endDate"
    label="End Date:"
    min={fields.startDate.value || TODAY}
    />
    </Row>
    <Row>
    <TextInput
    disabled={fakeSaving}
    field={fields.origin}
    id="origin"
    label="Origin:"
    />
    <TextInput
    disabled={fakeSaving}
    field={fields.destination}
    label="Destination:"
    id="destination"
    />
    </Row>
    <Row>
    <TextInput
    disabled={fakeSaving}
    field={fields.hotel}
    help="Please enter name of hotel here. If no hotel booking exists or unknown put 'N/A'"
    id="hotel"
    label="Hotel:"
    />
    <FormField help="Please select 'Yes' if access to a car (rented or personal) during travel and 'No' if no access to a car during travel"
    label="Car:">
    <label className="radio-inline">
    <input type="radio" name="hasCar" value="yes" onChange={fields.hasCar.onChange} disabled={fakeSaving}/> Yes
    </label>
    <label className="radio-inline">
    <input type="radio" name="hasCar" value="no" onChange={fields.hasCar.onChange} defaultChecked disabled={fakeSaving}/> No
    </label>
    </FormField>
    </Row>
    <Row className="form-group">
    <Col sm={12} className="text-center">
    <LoadingButton type="submit" bsSize="large" bsStyle="primary" disabled={fakeSaving}>
    <img src={require('images/add-travel-button.png')}/> Add Travel
    </LoadingButton>
    </Col>
    </Row>
    </form>
    </div>
    }
    })

    module.exports = connect(mapStateToProps)(form(AddTravel))
    34 changes: 34 additions & 0 deletions DateInput.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    var React = require('react')
    var {PropTypes} = React
    var DateTimePicker = require('react-widgets/lib/DateTimePicker')

    var FormField = require('./FormField')

    var DateInput = React.createClass({
    propTypes: {
    field: PropTypes.object.isRequired
    },
    shouldComponentUpdate: FormField.shouldFormFieldUpdate,
    render() {
    var {field, help, label, afterChange, ...inputProps} = this.props
    var onChange = field.onChange
    if (afterChange) {
    onChange = function(...args) {
    field.onChange(...args)
    afterChange(...args)
    }
    }
    return <FormField field={field} help={help} inputProps={inputProps} label={label}>
    <DateTimePicker
    {...inputProps}
    format="dd/MM/yyyy"
    name={field.name}
    onChange={onChange}
    time={false}
    value={field.value}
    />
    </FormField>
    }
    })

    module.exports = DateInput
    104 changes: 104 additions & 0 deletions FormField.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    var classNames = require('classnames')
    var Col = require('react-bootstrap/lib/Col')
    var React = require('react')
    var Row = require('react-bootstrap/lib/Row')
    var {PropTypes} = React

    var Help = require('./Help')
    var Loading = require('./Loading')

    var FIELD_EVENT_HANDLER = /^(?:on|handle)[A-Z]/

    /**
    * Perform shallow equals comparison of two redux-form field objects to
    * determine if the field has changed.
    */
    function fieldShallowEquals(field, nextField) {
    for (var prop in field) {
    // Ignore event handlers, as they continually get recreated by redux-form
    if (!FIELD_EVENT_HANDLER.test(prop) && field[prop] !== nextField[prop]) {
    return false
    }
    }
    return true
    }

    /**
    * Perform shallow equals comparison to determine if the props of the context
    * form field component have changed, with special-case handling for the "field"
    * prop, provided by redux-form.
    * Use this as shouldComponentUpdate() on components which compose a
    * FormField in their render() method and they will only re-render when
    * necessary.
    */
    function shouldFormFieldUpdate(nextProps) {
    var keys = Object.keys(this.props)
    var nextKeys = Object.keys(nextProps)
    if (keys.length !== nextKeys.length) return true
    var nextHasOwnProperty = Object.prototype.hasOwnProperty.bind(nextProps)
    for (var i = 0; i < keys.length; i++) {
    var key = keys[i]
    if (!nextHasOwnProperty(key) ||
    key === 'field' ? !fieldShallowEquals(this.props[key], nextProps[key])
    : this.props[key] !== nextProps[key]) {
    return true
    }
    }
    return false
    }

    /**
    * A form field in a Bootstrap 3 two column layout.
    *
    * This component manages:
    * - Bootstrap structure and classes
    * - A loading indicator
    * - A <Label> for the field
    * - Label help text
    * - Validation error style and display
    *
    * The form input itself should be passed as content.
    */
    var FormField = React.createClass({
    statics: {
    shouldFormFieldUpdate
    },
    propTypes: {
    // A redux-form field object
    field: PropTypes.object,
    // Help text to be displayed next to the label
    help: PropTypes.string,
    // An additional class to be applied to the input container
    inputClass: PropTypes.string,
    // Props used for the input (id is used to link the label to the input)
    inputProps: PropTypes.object,
    // Label text
    label: PropTypes.string,
    // Loading state
    loading: PropTypes.bool
    },
    getDefaultProps() {
    return {
    field: {},
    inputProps: {}
    }
    },
    render() {
    var {field, help, inputClass, inputProps, label, loading} = this.props
    var error = field.touched && field.error
    return <Col sm={6}>
    <Row className={classNames('form-group', {'has-error': error})}>
    <Col sm={4} className="control-label">
    {loading && <Loading inline/>} <label htmlFor={inputProps.id}>{label}</label>
    {help && <Help text={help}/>}
    </Col>
    <Col sm={8} className={inputClass}>
    {this.props.children}
    {error && <p className="help-block" style={{marginBottom: 0}}>{error}</p>}
    </Col>
    </Row>
    </Col>
    }
    })

    module.exports = FormField
    7 changes: 7 additions & 0 deletions Help.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    .Help {
    cursor: help;
    display: inline-block;
    font-size: 18px;
    margin-left: .33em;
    vertical-align: middle;
    }
    20 changes: 20 additions & 0 deletions Help.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    require('./Help.css')

    var Glyphicon = require('react-bootstrap/lib/Glyphicon')
    var OverlayTrigger = require('react-bootstrap/lib/OverlayTrigger')
    var React = require('react')
    var Tooltip = require('react-bootstrap/lib/Tooltip')

    var Help = React.createClass({
    propTypes: {
    text: React.PropTypes.string.isRequired
    },
    render() {
    var tooltip = <Tooltip>{this.props.text}</Tooltip>
    return <OverlayTrigger overlay={tooltip} delayShow={300} delayHide={150}>
    <Glyphicon className="Help" glyph="question-sign"/>
    </OverlayTrigger>
    }
    })

    module.exports = Help
    43 changes: 43 additions & 0 deletions Loading.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    .Loading {
    text-align: center;
    color: #777;
    padding: 2em 0;
    transition: opacity .25s ease-in;
    }
    .Loading--inline {
    color: inherit;
    display: inline;
    padding: 0;
    }
    .Loading--delaying {
    visibility: hidden;
    width: 0;
    height: 0;
    opacity: 0.01;
    }
    .Loading--displaying {
    visibility: visible;
    height: auto;
    width: auto;
    opacity: 1;
    }
    .Loading .glyphicon {
    font-size: 60px;
    animation: loading-spin 2s infinite linear;
    }
    /* Avoid height changes when an inline loading indicator appears */
    .Loading--inline .glyphicon {
    font-size: .75em;
    }
    .Loading__text {
    margin-top: 12px;
    }

    @keyframes loading-spin {
    0% {
    transform: rotate(0deg);
    }
    100% {
    transform: rotate(359deg);
    }
    }
    58 changes: 58 additions & 0 deletions Loading.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    require('./Loading.css')

    var classNames = require('classnames')
    var Glyphicon = require('react-bootstrap/lib/Glyphicon')
    var React = require('react')

    var Loading = React.createClass({
    propTypes: {
    delay: React.PropTypes.oneOfType([
    React.PropTypes.bool,
    React.PropTypes.number
    ]),
    inline: React.PropTypes.bool,
    text: React.PropTypes.string
    },
    getDefaultProps() {
    return {
    delay: 500,
    inline: false
    }
    },
    getInitialState() {
    return {
    delaying: !!this.props.delay
    }
    },
    componentDidMount() {
    if (this.props.delay) {
    this.timeout = setTimeout(this.handleDisplay, this.props.delay)
    }
    },
    componentWillUnmount() {
    if (this.timeout) {
    clearTimeout(this.timeout)
    }
    },

    handleDisplay() {
    this.timeout = null
    this.setState({delaying: false})
    },

    render() {
    var {delay, inline, text} = this.props
    var {delaying} = this.state
    var className = classNames('Loading', {
    'Loading--delaying': delaying,
    'Loading--displaying': delay && !delaying,
    'Loading--inline': inline
    })
    return <div className={className}>
    <Glyphicon glyph="refresh"/>
    {text && <div className="Loading__text">{text}&hellip;</div>}
    </div>
    }
    })

    module.exports = Loading
    3 changes: 3 additions & 0 deletions LoadingButton.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    .LoadingButton__icon {
    margin-right: 5px;
    }
    30 changes: 30 additions & 0 deletions LoadingButton.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    require('./LoadingButton.css')

    var React = require('react')
    var Button = require('react-bootstrap/lib/Button')

    var Loading = require('Loading')

    var LoadingButton = React.createClass({
    propTypes: {
    label: React.PropTypes.string.isRequired,
    loading: React.PropTypes.bool.isRequired,
    icom: React.PropTypes.string,
    // Defaults to label + 'ing' if not provided
    loadingLabel: React.PropTypes.string
    },
    render() {
    var {icon, label, loading, loadingLabel, ...props} = this.props
    if (!loadingLabel) {
    loadingLabel = `${label}ing`
    }
    return <Button disabled={loading} {...props}>
    {loading
    ? <span><Loading inline delay={false}/> {icon && <img src={icon} className="LoadingButton__icon"/>} {loadingLabel}&hellip;</span>
    : <span>{icon && <img src={icon} className="LoadingButton__icon"/>} {label}</span>
    }
    </Button>
    }
    })

    module.exports = LoadingButton
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Form components being used with [redux-form](https://github.com/erikras/redux-form) in an application which uses [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) for layout and [react-widgets](https://github.com/jquense/react-widgets)' date picker, where all the forms redux-form is being used to manage happen to have 2 column layouts.
    16 changes: 16 additions & 0 deletions StaticField.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    var React = require('react')

    var FormField = require('./FormField')

    var StaticField = React.createClass({
    shouldComponentUpdate(nextProps) {
    return (this.props.label !== nextProps.label ||
    this.props.value !== nextProps.value)
    },
    render() {
    var {label, value} = this.props
    return <FormField inputClass="form-control-static" label={label}>{value}</FormField>
    }
    })

    module.exports = StaticField
    25 changes: 25 additions & 0 deletions TextInput.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    var React = require('react')
    var {PropTypes} = React

    var FormField = require('./FormField')

    var TextInput = React.createClass({
    propTypes: {
    field: PropTypes.object.isRequired
    },
    shouldComponentUpdate: FormField.shouldFormFieldUpdate,
    render() {
    var {field, help, label, onChange, ...inputProps} = this.props
    return <FormField field={field} help={help} inputProps={inputProps} label={label}>
    <input
    {...inputProps}
    className="form-control"
    name={field.name}
    onBlur={field.onBlur}
    onChange={onChange && field.onChange}
    />
    </FormField>
    }
    })

    module.exports = TextInput
    19 changes: 19 additions & 0 deletions configureStore.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    var {createStore} = require('redux')

    var rootReducer = require('./reducers')

    module.exports = function configureStore() {
    var store = createStore(rootReducer)

    if (process.env.NODE_ENV !== 'production') {
    if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('./reducers', () => {
    var nextRootReducer = require('./reducers')
    store.replaceReducer(nextRootReducer)
    })
    }
    }

    return store
    }
    12 changes: 12 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    require('bootstrap/dist/css/bootstrap.min.css')
    require('react-widgets/dist/css/react-widgets.css')

    var React = require('react')
    var {Provider} = require('react-redux')

    var AddTravel = require('./AddTravel')
    var configureStore = require('./configureStore')

    var store = configureStore()

    React.render(<Provider store={store}>{() => <AddTravel/>}</Provider>, document.querySelector('#app'))
    17 changes: 17 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    {
    "scripts": {
    "start": "heatpack index.js"
    },
    "dependencies": {
    "bootstrap": "3.3.5",
    "react": "0.13.3",
    "react-bootstrap": "0.25.2",
    "react-redux": "2.1.2",
    "react-widgets": "2.8.1",
    "redux": "3.0.0",
    "redux-form": "1.6.7"
    },
    "devDependencies": {
    "react-heatpack": "^1.5.0"
    }
    }
    6 changes: 6 additions & 0 deletions reducers.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    var {combineReducers} = require('redux')
    var {reducer: formReducer} = require('redux-form')

    module.exports = combineReducers({
    form: formReducer
    })
    11 changes: 11 additions & 0 deletions utils.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    /**
    * Convenience method for setting all time values to zero on a Date.
    */
    function zeroTime(date) {
    date.setHours(0, 0, 0, 0)
    return date
    }

    module.exports = {
    zeroTime
    }