src/short-urls/CreateShortUrl.js   A
last analyzed

Complexity

Total Complexity 4
Complexity/F 0

Size

Lines of Code 174
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 96.43%

Importance

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