github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-server/web/src/routes/automation/components/SavedStatePicker.js (about)

     1  import React from 'react';
     2  import Modal from 'react-modal';
     3  import classnames from 'classnames';
     4  import { connect } from 'react-redux';
     5  import makeUUID from 'uuid/v4';
     6  
     7  import './SavedStatePicker.scss';
     8  import Scene from './Scene';
     9  import { save } from '../../../ducks/savedstates';
    10  
    11  Modal.setAppElement('#app');
    12  
    13  const valueToText = (value, savedstates) => {
    14    if (value && value.length === 36) {
    15      return (
    16        <React.Fragment>
    17          <small>Scene</small>{' '}
    18          <strong>{savedstates.getIn([value, 'name']) || value}</strong>
    19        </React.Fragment>
    20      );
    21    }
    22  
    23    if (value && value.length > 0) {
    24      return (
    25        <React.Fragment>
    26          <small>Delay for</small> <strong>{value}</strong>
    27        </React.Fragment>
    28      );
    29    }
    30  
    31    return 'New action';
    32  };
    33  
    34  const valueToTab = (value) => {
    35    if (value && value.length === 36) {
    36      return 'state';
    37    }
    38  
    39    if (value && value.length > 0) {
    40      return 'time';
    41    }
    42  
    43    return 'state';
    44  };
    45  
    46  class SavedStatePicker extends React.Component {
    47    constructor(props) {
    48      super(props);
    49  
    50      const scene = props.savedstates.get(props.value);
    51      this.state = {
    52        tab: valueToTab(props.value),
    53        value: props.value,
    54        modalIsOpen: props.value === undefined,
    55        scene: (scene && scene.toJS()) || {},
    56      };
    57  
    58      this.selectRef = React.createRef();
    59    }
    60  
    61    componentWillReceiveProps(props) {
    62      if (props.value !== this.props.value) {
    63        const scene = props.savedstates.get(props.value);
    64        this.setState({
    65          tab: valueToTab(props.value),
    66          value: props.value,
    67          scene: (scene && scene.toJS()) || {},
    68        });
    69      }
    70    }
    71  
    72    onSceneChange = () => (state) => {
    73      const { scene } = this.state;
    74      this.setState({
    75        scene: { ...scene, state },
    76      });
    77    };
    78  
    79    openModal = () => () => {
    80      const { value } = this.props;
    81      this.setState({
    82        modalIsOpen: true,
    83        tab: valueToTab(value),
    84        value,
    85      });
    86      return false;
    87    };
    88  
    89    closeModal = () => () => {
    90      this.setState({ modalIsOpen: false });
    91    };
    92  
    93    save = () => () => {
    94      const { onChange, dispatch } = this.props;
    95      const { value, scene } = this.state;
    96  
    97      if (value.length === 36) {
    98        dispatch(save({ ...scene, uuid: value }));
    99      }
   100  
   101      onChange(value);
   102      this.setState({ modalIsOpen: false });
   103    };
   104  
   105    render() {
   106      const {
   107        tab, modalIsOpen, value, scene,
   108      } = this.state;
   109      const { state: states } = scene || {};
   110      const { savedstates, options } = this.props;
   111  
   112      return (
   113        <React.Fragment>
   114          <div
   115            className="btn btn-secondary btn-block"
   116            onClick={this.openModal()}
   117            role="button"
   118            tabIndex={-1}
   119          >
   120            {valueToText(this.props.value, savedstates)}
   121          </div>
   122          <Modal
   123            className="Modal__Bootstrap modal-dialog saved-state-modal"
   124            closeTimeoutMS={150}
   125            isOpen={modalIsOpen}
   126            onRequestClose={this.closeModal()}
   127          >
   128            <div className="modal-content">
   129              <div style={{ display: 'flex' }}>
   130                <ul
   131                  className="nav nav-tabs"
   132                  style={{ marginLeft: '-1px', flex: '1 1 0%' }}
   133                >
   134                  <li className="nav-item">
   135                    <a
   136                      className={classnames(
   137                        'nav-link',
   138                        tab === 'state' && 'active',
   139                      )}
   140                      role="button"
   141                      tabIndex="0"
   142                      onClick={() => this.setState({ tab: 'state' })}
   143                    >
   144                      Scene
   145                    </a>
   146                  </li>
   147                  {!(value && value.length === 36) && !options.hideDelay && (
   148                    <li className="nav-item">
   149                      <a
   150                        className={classnames(
   151                          'nav-link',
   152                          tab === 'time' && 'active',
   153                        )}
   154                        role="button"
   155                        tabIndex="0"
   156                        onClick={() => this.setState({ tab: 'time' })}
   157                      >
   158                        Time delay
   159                      </a>
   160                    </li>
   161                  )}
   162                </ul>
   163                <button
   164                  type="button"
   165                  className="close"
   166                  style={{
   167                    padding: '0px 15px',
   168                    borderBottom: '1px solid rgb(222, 226, 230)',
   169                  }}
   170                  onClick={this.closeModal()}
   171                >
   172                  <span aria-hidden="true">×</span>
   173                  <span className="sr-only">Close</span>
   174                </button>
   175              </div>
   176              <div className="modal-body">
   177                {tab === 'time' && (
   178                  <form>
   179                    <div className="form-group">
   180                      <label htmlFor="name">Duration</label>
   181                      <input
   182                        type="text"
   183                        id="name"
   184                        className="form-control"
   185                        placeholder="ex. 2h15m"
   186                        value={value || ''}
   187                        onChange={event =>
   188                          this.setState({ value: event.target.value })
   189                        }
   190                      />
   191                      <small className="form-text text-muted">
   192                        ParseDuration parses a duration string. A duration string
   193                        is a sequence of decimal numbers, each with optional
   194                        fraction and a unit suffix, such as <strong>300ms</strong>
   195                        , <strong>1.5h</strong> or <strong>2h45m</strong>. Valid
   196                        time units are <strong>n</strong>, <strong>us</strong> (or{' '}
   197                        <strong>µs</strong>), <strong>ms</strong>,
   198                        <strong>s</strong>, <strong>m</strong>, <strong>h</strong>
   199                        .
   200                      </small>
   201                    </div>
   202                  </form>
   203                )}
   204                {tab === 'state' && (!value || value.length !== 36) && (
   205                  <React.Fragment>
   206                    <button
   207                      type="button"
   208                      className="btn btn-success btn-block"
   209                      onClick={() => this.setState({ value: makeUUID() })}
   210                    >
   211                      Create a new scene
   212                    </button>
   213                    <div className="text-center p-4">or select an existing</div>
   214                    <div>
   215                      <select
   216                        size={10}
   217                        style={{ width: '100%' }}
   218                        ref={this.selectRef}
   219                      >
   220                        {savedstates.map(savedstate => (
   221                          <option value={savedstate.get('uuid')}>
   222                            {savedstate.get('name')}
   223                          </option>
   224                        ))}
   225                      </select>
   226                    </div>
   227                    <button
   228                      type="button"
   229                      className="btn btn-secondary btn-block"
   230                      onClick={() => {
   231                        this.setState({
   232                          value: this.selectRef.current.value,
   233                          scene:
   234                            savedstates
   235                              .get(this.selectRef.current.value)
   236                              .toJS() || {},
   237                        });
   238                      }}
   239                    >
   240                      Select
   241                    </button>
   242                  </React.Fragment>
   243                )}
   244                {tab === 'state' && value && value.length === 36 && (
   245                  <form>
   246                    <div className="form-group">
   247                      <label htmlFor="name">Name</label>
   248                      <input
   249                        type="text"
   250                        id="name"
   251                        className="form-control"
   252                        placeholder=""
   253                        value={(scene && scene.name) || ''}
   254                        onChange={event =>
   255                          this.setState({
   256                            scene: { ...scene, name: event.target.value },
   257                          })
   258                        }
   259                      />
   260                      <small className="form-text text-muted">
   261                        Give the state a good name so you can find it later
   262                      </small>
   263                    </div>
   264                    <div className="form-group">
   265                      <label htmlFor="name">State</label>
   266                      <Scene
   267                        id={value}
   268                        onChange={this.onSceneChange()}
   269                        states={states}
   270                      />
   271                    </div>
   272                  </form>
   273                )}
   274              </div>
   275              <div className="modal-footer">
   276                {!value && (
   277                  <button
   278                    type="button"
   279                    className="btn btn-secondary"
   280                    onClick={this.closeModal()}
   281                  >
   282                    Close
   283                  </button>
   284                )}
   285                {value && (
   286                  <button
   287                    type="button"
   288                    className="btn btn-primary"
   289                    onClick={this.save()}
   290                  >
   291                    Use
   292                  </button>
   293                )}
   294              </div>
   295            </div>
   296          </Modal>
   297        </React.Fragment>
   298      );
   299    }
   300  }
   301  
   302  const mapStateToProps = state => ({
   303    devices: state.getIn(['devices', 'list']),
   304    savedstates: state.getIn(['savedstates', 'list']),
   305  });
   306  
   307  export default connect(mapStateToProps)(SavedStatePicker);