Completed
Pull Request — master (#162)
by Alejandro
09:21
created

src/short-urls/CreateShortUrl.js   A

Complexity

Total Complexity 6
Complexity/F 6

Size

Lines of Code 160
Function Count 1

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 90%

Importance

Changes 0
Metric Value
wmc 6
eloc 144
mnd 5
bc 5
fnc 1
dl 0
loc 160
ccs 18
cts 20
cp 0.9
rs 10
bpm 5
cpm 6
noi 0
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
C CreateShortUrl.js ➔ render 0 118 6
1
import { faAngleDoubleDown as downIcon, faAngleDoubleUp as upIcon } from '@fortawesome/free-solid-svg-icons';
2
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
import { assoc, dissoc, isEmpty, isNil, pipe, replace, trim } from 'ramda';
4
import React from 'react';
5
import { Collapse } from 'reactstrap';
6
import * as PropTypes from 'prop-types';
7
import DateInput from '../utils/DateInput';
8
import Checkbox from '../utils/Checkbox';
9
import ForVersion from '../utils/ForVersion';
10
import { serverType } from '../servers/prop-types';
11
import { compareVersions } from '../utils/utils';
12
import { createShortUrlResultType } from './reducers/shortUrlCreation';
13
import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';
14
15 1
const normalizeTag = pipe(trim, replace(/ /g, '-'));
16 2
const formatDate = (date) => isNil(date) ? date : date.format();
17
18 1
const CreateShortUrl = (TagsSelector, CreateShortUrlResult) => class CreateShortUrl extends React.Component {
19
  static propTypes = {
20
    createShortUrl: PropTypes.func,
21
    shortUrlCreationResult: createShortUrlResultType,
22
    resetCreateShortUrl: PropTypes.func,
23
    selectedServer: serverType,
24
  };
25
26
  state = {
27
    longUrl: '',
28
    tags: [],
29
    customSlug: undefined,
30
    domain: undefined,
31
    validSince: undefined,
32
    validUntil: undefined,
33
    maxVisits: undefined,
34
    findIfExists: false,
35
    moreOptionsVisible: false,
36
  };
37
38
  render() {
39 8
    const { createShortUrl, shortUrlCreationResult, resetCreateShortUrl } = this.props;
40
41 8
    const changeTags = (tags) => this.setState({ tags: tags.map(normalizeTag) });
42 8
    const renderOptionalInput = (id, placeholder, type = 'text', props = {}) => (
43 24
      <div className="form-group">
44
        <input
45
          className="form-control"
46
          id={id}
47
          type={type}
48
          placeholder={placeholder}
49
          value={this.state[id]}
50 3
          onChange={(e) => this.setState({ [id]: e.target.value })}
51
          {...props}
52
        />
53
      </div>
54
    );
55 8
    const renderDateInput = (id, placeholder, props = {}) => (
56 16
      <div className="form-group">
57
        <DateInput
58
          selected={this.state[id]}
59
          placeholderText={placeholder}
60
          isClearable
61 2
          onChange={(date) => this.setState({ [id]: date })}
62
          {...props}
63
        />
64
      </div>
65
    );
66 8
    const save = (e) => {
67 1
      e.preventDefault();
68 1
      createShortUrl(pipe(
69
        dissoc('moreOptionsVisible'),
70
        assoc('validSince', formatDate(this.state.validSince)),
71
        assoc('validUntil', formatDate(this.state.validUntil))
72
      )(this.state));
73
    };
74 8
    const currentServerVersion = this.props.selectedServer ? this.props.selectedServer.version : '';
75 8
    const disableDomain = isEmpty(currentServerVersion) || compareVersions(currentServerVersion, '<', '1.19.0-beta.1');
76
77 8
    return (
78
      <div className="shlink-container">
79
        <form onSubmit={save}>
80
          <div className="form-group">
81
            <input
82
              className="form-control form-control-lg"
83
              type="url"
84
              placeholder="Insert the URL to be shortened"
85
              required
86
              value={this.state.longUrl}
87 1
              onChange={(e) => this.setState({ longUrl: e.target.value })}
88
            />
89
          </div>
90
91
          <Collapse isOpen={this.state.moreOptionsVisible}>
92
            <div className="form-group">
93
              <TagsSelector tags={this.state.tags} onChange={changeTags} />
94
            </div>
95
96
            <div className="row">
97
              <div className="col-sm-6">
98
                {renderOptionalInput('customSlug', 'Custom slug')}
99
              </div>
100
              <div className="col-sm-6">
101
                {renderOptionalInput('domain', 'Domain', 'text', {
102
                  disabled: disableDomain,
103
                  ...disableDomain && { title: 'Shlink 1.19.0 or higher is required to be able to provide the domain' },
104
                })}
105
              </div>
106
            </div>
107
108
            <div className="row">
109
              <div className="col-sm-6">
110
                {renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
111
              </div>
112
              <div className="col-sm-3">
113
                {renderDateInput('validSince', 'Enabled since...', { maxDate: this.state.validUntil })}
114
              </div>
115
              <div className="col-sm-3">
116
                {renderDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })}
117
              </div>
118
            </div>
119
120
            <ForVersion minVersion="1.16.0" currentServerVersion={currentServerVersion}>
121
              <div className="mb-4 text-right">
122
                <Checkbox
123
                  className="mr-2"
124
                  checked={this.state.findIfExists}
125
                  onChange={(findIfExists) => this.setState({ findIfExists })}
126
                >
127
                  Use existing URL if found
128
                </Checkbox>
129
                <UseExistingIfFoundInfoIcon />
130
              </div>
131
            </ForVersion>
132
          </Collapse>
133
134
          <div>
135
            <button
136
              type="button"
137
              className="btn btn-outline-secondary"
138
              onClick={() => this.setState(({ moreOptionsVisible }) => ({ moreOptionsVisible: !moreOptionsVisible }))}
139
            >
140
              <FontAwesomeIcon icon={this.state.moreOptionsVisible ? upIcon : downIcon} />
141
              &nbsp;
142
              {this.state.moreOptionsVisible ? 'Less' : 'More'} options
143
            </button>
144
            <button
145
              className="btn btn-outline-primary float-right"
146
              disabled={shortUrlCreationResult.loading || isEmpty(this.state.longUrl)}
147
            >
148
              {shortUrlCreationResult.loading ? 'Creating...' : 'Create'}
149
            </button>
150
          </div>
151
152
          <CreateShortUrlResult {...shortUrlCreationResult} resetCreateShortUrl={resetCreateShortUrl} />
153
        </form>
154
      </div>
155
    );
156
  }
157
};
158
159
export default CreateShortUrl;
160