From f4dbd03c7e96a9ad60f86207f375b84be6f4db06 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 17 Mar 2019 17:48:05 +0100 Subject: [PATCH] Added checkbox to control the findIfExists shlink flag --- package.json | 2 +- src/short-urls/CreateShortUrl.js | 21 +++++-- src/short-urls/UseExistingIfFoundInfoIcon.js | 56 +++++++++++++++++++ .../UseExistingIfFoundInfoIcon.scss | 7 +++ src/utils/Checkbox.js | 32 +++++++++++ yarn.lock | 29 +++++----- 6 files changed, 125 insertions(+), 22 deletions(-) create mode 100644 src/short-urls/UseExistingIfFoundInfoIcon.js create mode 100644 src/short-urls/UseExistingIfFoundInfoIcon.scss create mode 100644 src/utils/Checkbox.js diff --git a/package.json b/package.json index 29cb437b..bdb53a80 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "react-router-dom": "^4.2.2", "react-swipeable": "^4.3.0", "react-tagsinput": "^3.19.0", - "reactstrap": "^6.0.1", + "reactstrap": "^7.1.0", "redux": "^4.0.0", "redux-actions": "^2.6.5", "redux-thunk": "^2.3.0", diff --git a/src/short-urls/CreateShortUrl.js b/src/short-urls/CreateShortUrl.js index 89838947..38d1d4be 100644 --- a/src/short-urls/CreateShortUrl.js +++ b/src/short-urls/CreateShortUrl.js @@ -5,7 +5,9 @@ import React from 'react'; import { Collapse } from 'reactstrap'; import * as PropTypes from 'prop-types'; import DateInput from '../utils/DateInput'; +import Checkbox from '../utils/Checkbox'; import { createShortUrlResultType } from './reducers/shortUrlCreation'; +import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon'; const normalizeTag = pipe(trim, replace(/ /g, '-')); const formatDate = (date) => isNil(date) ? date : date.format(); @@ -24,6 +26,7 @@ const CreateShortUrl = (TagsSelector, CreateShortUrlResult) => class CreateShort validSince: undefined, validUntil: undefined, maxVisits: undefined, + findIfExists: false, moreOptionsVisible: false, }; @@ -93,22 +96,30 @@ const CreateShortUrl = (TagsSelector, CreateShortUrlResult) => class CreateShort {renderDateInput('validUntil', 'Enabled until...', { minDate: this.state.validSince })} + +
+ this.setState({ findIfExists })} + > + Use existing URL if found + + +
-
diff --git a/src/short-urls/UseExistingIfFoundInfoIcon.js b/src/short-urls/UseExistingIfFoundInfoIcon.js new file mode 100644 index 00000000..e96457cb --- /dev/null +++ b/src/short-urls/UseExistingIfFoundInfoIcon.js @@ -0,0 +1,56 @@ +import React, { useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; +import { Modal, ModalBody, ModalHeader } from 'reactstrap'; +import './UseExistingIfFoundInfoIcon.scss'; + +const renderInfoModal = (isOpen, toggle) => ( + + Info + +

+ When the  + "Use existing URL if found" +  checkbox is checked, the server will return an existing short URL if it matches provided params. +

+

+ These are the checks performed by Shlink in order to determine if an existing short URL should be returned: +

+
    +
  • + When only the long URL is provided: The most recent match will be returned, or a new short URL will be created + if none is found +
  • +
  • + When long URL and custom slug are provided: Same as in previous case, but it will try to match the short URL + using both the long URL and the slug. +
    + If the slug is being used by another long URL, an error will be returned. +
  • +
  • + When other params are provided: Same as in previous cases, but it will try to match existing short URLs with + all provided data. If any of them does not match, a new short URL will be created +
  • +
+
+ Important: This feature will be ignored while using a Shlink version older than v1.16.0. +
+
+
+); + +const UseExistingIfFoundInfoIcon = () => { + const [ isModalOpen, setIsModalOpen ] = useState(false); + const toggleModal = () => setIsModalOpen(!isModalOpen); + + return ( + + + + + {renderInfoModal(isModalOpen, toggleModal)} + + ); +}; + +export default UseExistingIfFoundInfoIcon; diff --git a/src/short-urls/UseExistingIfFoundInfoIcon.scss b/src/short-urls/UseExistingIfFoundInfoIcon.scss new file mode 100644 index 00000000..835e5d2d --- /dev/null +++ b/src/short-urls/UseExistingIfFoundInfoIcon.scss @@ -0,0 +1,7 @@ +.use-existing-if-found-info-icon__modal-quote { + margin-bottom: 0; + padding: 10px 15px; + font-size: 17.5px; + border-left: 5px solid #eee; + background-color: #f9f9f9; +} diff --git a/src/utils/Checkbox.js b/src/utils/Checkbox.js new file mode 100644 index 00000000..c83d1a10 --- /dev/null +++ b/src/utils/Checkbox.js @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { v4 as uuid } from 'uuid'; + +const propTypes = { + checked: PropTypes.bool.isRequired, + onChange: PropTypes.func.isRequired, + children: PropTypes.oneOfType([ PropTypes.string, PropTypes.node ]), + className: PropTypes.string, +}; + +const Checkbox = ({ checked, onChange, className, children }) => { + const id = uuid(); + + return ( + + onChange(e.target.checked, e)} + /> + + + ); +}; + +Checkbox.propTypes = propTypes; + +export default Checkbox; diff --git a/yarn.lock b/yarn.lock index 639969e8..8c51b072 100644 --- a/yarn.lock +++ b/yarn.lock @@ -742,7 +742,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.3.1": +"@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1": version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83" integrity sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g== @@ -1221,6 +1221,11 @@ array-filter@^1.0.0: resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -1244,12 +1249,12 @@ array-includes@^3.0.3: define-properties "^1.1.2" es-abstract "^1.7.0" -array-map@^0.0.0: +array-map@^0.0.0, array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= -array-reduce@^0.0.0: +array-reduce@^0.0.0, array-reduce@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= @@ -7617,11 +7622,6 @@ postcss-reduce-initial@^4.0.2: postcss-reduce-transforms@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.1.tgz#8600d5553bdd3ad640f43bff81eb52f8760d4561" - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" postcss-replace-overflow-wrap@^3.0.0: version "3.0.0" @@ -8214,10 +8214,12 @@ reactcss@^1.2.0: dependencies: lodash "^4.0.1" -reactstrap@^6.0.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-6.5.0.tgz#ba655e32646e2621829f61faa033e607ec6624e5" +reactstrap@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-7.1.0.tgz#fd7125901737a3001c8564c0f8b40e319eec23b2" + integrity sha512-wtc4RkgnGn1TsZ0AxOZ2OqT+b8YmCWZj/tErPujWLepxzlEEhveZGC+uDerdaHVSAzJUP2DTk605iper7hutQQ== dependencies: + "@babel/runtime" "^7.2.0" classnames "^2.2.3" lodash.isfunction "^3.0.9" lodash.isobject "^3.0.2" @@ -8962,11 +8964,6 @@ shebang-regex@^1.0.0: shell-quote@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - dependencies: - array-filter "~0.0.0" - array-map "~0.0.0" - array-reduce "~0.0.0" - jsonify "~0.0.0" shellwords@^0.1.1: version "0.1.1"