Implemented behavior to create new short URLs

This commit is contained in:
Alejandro Celaya 2018-07-29 18:13:18 +02:00
parent f7249cfe6e
commit 92f7fffcf3
6 changed files with 73 additions and 20 deletions

View file

@ -8,11 +8,15 @@
white-space: nowrap; white-space: nowrap;
} }
.bg-main {
background-color: $mainColor !important;
}
.dropdown-item { .dropdown-item {
cursor: pointer; cursor: pointer;
} }
.dropdown-item.active { .dropdown-item.active {
background-color: $mainColor !important; @extend .bg-main;
} }
.short-urls-container { .short-urls-container {

View file

@ -11,7 +11,7 @@ import { Collapse } from 'reactstrap';
import '../../node_modules/react-datepicker/dist/react-datepicker.css'; import '../../node_modules/react-datepicker/dist/react-datepicker.css';
import './CreateShortUrl.scss'; import './CreateShortUrl.scss';
import CreateShortUrlResult from './helpers/CreateShortUrlResult'; import CreateShortUrlResult from './helpers/CreateShortUrlResult';
import { createShortUrl } from './reducers/shortUrlCreationResult'; import { createShortUrl, resetCreateShortUrl } from './reducers/shortUrlCreationResult';
export class CreateShortUrl extends React.Component { export class CreateShortUrl extends React.Component {
state = { state = {
@ -25,6 +25,8 @@ export class CreateShortUrl extends React.Component {
}; };
render() { render() {
const { createShortUrl, shortUrlCreationResult, resetCreateShortUrl } = this.props;
const addTag = tag => this.setState({ const addTag = tag => this.setState({
tags: [].concat(this.state.tags, assoc('name', replace(/ /g, '-', tag.name), tag)) tags: [].concat(this.state.tags, assoc('name', replace(/ /g, '-', tag.name), tag))
}); });
@ -55,7 +57,7 @@ export class CreateShortUrl extends React.Component {
const formatDate = date => isNil(date) ? date : date.format(); const formatDate = date => isNil(date) ? date : date.format();
const save = e => { const save = e => {
e.preventDefault(); e.preventDefault();
this.props.createShortUrl(pipe( createShortUrl(pipe(
dissoc('moreOptionsVisible'), // Remove moreOptionsVisible property dissoc('moreOptionsVisible'), // Remove moreOptionsVisible property
assoc('tags', pluck('name', this.state.tags)), // Map tags array to use only their names assoc('tags', pluck('name', this.state.tags)), // Map tags array to use only their names
assoc('validSince', formatDate(this.state.validSince)), assoc('validSince', formatDate(this.state.validSince)),
@ -120,14 +122,22 @@ export class CreateShortUrl extends React.Component {
   
{this.state.moreOptionsVisible ? 'Less' : 'More'} options {this.state.moreOptionsVisible ? 'Less' : 'More'} options
</button> </button>
<button className="btn btn-outline-primary create-short-url__btn float-right">Create</button> <button
className="btn btn-outline-primary create-short-url__btn float-right"
disabled={shortUrlCreationResult.loading}
>
{shortUrlCreationResult.loading ? 'Creating...' : 'Create'}
</button>
</div> </div>
<CreateShortUrlResult {...this.props.shortUrlCreationResult} /> <CreateShortUrlResult {...shortUrlCreationResult} resetCreateShortUrl={resetCreateShortUrl} />
</form> </form>
</div> </div>
); );
} }
} }
export default connect(pick(['shortUrlCreationResult']), { createShortUrl })(CreateShortUrl); export default connect(pick(['shortUrlCreationResult']), {
createShortUrl,
resetCreateShortUrl
})(CreateShortUrl);

View file

@ -1,18 +1,48 @@
import React from 'react'; import copyIcon from '@fortawesome/fontawesome-free-regular/faCopy';
import FontAwesomeIcon from '@fortawesome/react-fontawesome';
import { isNil } from 'ramda'; import { isNil } from 'ramda';
import React from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import './CreateShortUrlResult.scss'
import { Tooltip } from 'reactstrap';
export default function CreateShortUrlResult ({ loading, error, result }) { export default class CreateShortUrlResult extends React.Component {
if (loading) { state = { showCopyTooltip: false };
return <div className="text-center">Loading...</div>
componentDidMount() {
this.props.resetCreateShortUrl();
} }
render() {
const { error, result } = this.props;
if (error) { if (error) {
return <div className="text-center color-danger">An error occurred while creating the URL :(</div> return <div className="alert bg-danger text-white mt-3">An error occurred while creating the URL :(</div>
} }
if (isNil(result)) { if (isNil(result)) {
return null; return null;
} }
return <div className="text-center">Great!</div>; const { shortUrl } = result;
const onCopy = () => {
this.setState({ showCopyTooltip: true });
setTimeout(() => this.setState({ showCopyTooltip: false }), 2000);
};
return (
<div className="alert bg-main text-white mt-3">
<b>Great!</b> The short URL is <b>{shortUrl}</b>
<CopyToClipboard text={shortUrl} onCopy={onCopy}>
<button className="btn btn-light btn-sm create-short-url-result__copy-btn" id="copyBtn">
<FontAwesomeIcon icon={copyIcon}/> Copy
</button>
</CopyToClipboard>
<Tooltip placement="left" isOpen={this.state.showCopyTooltip} target="copyBtn">
Copied!
</Tooltip>
</div>
);
}
}; };

View file

@ -0,0 +1,4 @@
.create-short-url-result__copy-btn {
margin-left: 10px;
vertical-align: inherit;
}

View file

@ -38,8 +38,8 @@ export class ShortUrlsRow extends React.Component {
display={this.state.displayMenu} display={this.state.displayMenu}
shortUrl={completeShortUrl} shortUrl={completeShortUrl}
onCopyToClipboard={() => { onCopyToClipboard={() => {
this.setState({copiedToClipboard: true}); this.setState({ copiedToClipboard: true });
setTimeout(() => this.setState({copiedToClipboard: false}), 2000); setTimeout(() => this.setState({ copiedToClipboard: false }), 2000);
}} }}
/> />
</td> </td>

View file

@ -3,6 +3,7 @@ import ShlinkApiClient from '../../api/ShlinkApiClient';
const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START'; const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';
const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR'; const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR';
const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL'; const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL';
const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';
const defaultState = { const defaultState = {
result: null, result: null,
@ -27,8 +28,10 @@ export default function reducer(state = defaultState, action) {
return { return {
result: action.result, result: action.result,
saving: false, saving: false,
error: true, error: false,
}; };
case RESET_CREATE_SHORT_URL:
return defaultState;
default: default:
return state; return state;
} }
@ -44,3 +47,5 @@ export const createShortUrl = data => async dispatch => {
dispatch({ type: CREATE_SHORT_URL_ERROR }); dispatch({ type: CREATE_SHORT_URL_ERROR });
} }
}; };
export const resetCreateShortUrl = () => ({ type: RESET_CREATE_SHORT_URL });