mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Added create short URL form
This commit is contained in:
parent
b2fa86a917
commit
d382ee8d95
8 changed files with 129 additions and 3 deletions
|
@ -47,6 +47,7 @@
|
||||||
"react-moment": "^0.7.6",
|
"react-moment": "^0.7.6",
|
||||||
"react-redux": "^5.0.7",
|
"react-redux": "^5.0.7",
|
||||||
"react-router-dom": "^4.2.2",
|
"react-router-dom": "^4.2.2",
|
||||||
|
"react-tag-autocomplete": "^5.5.1",
|
||||||
"reactstrap": "^6.0.1",
|
"reactstrap": "^6.0.1",
|
||||||
"redux": "^4.0.0",
|
"redux": "^4.0.0",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
|
|
|
@ -1,5 +1,102 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import './CreateShortUrl.scss';
|
||||||
|
import downIcon from '@fortawesome/fontawesome-free-solid/faAngleDoubleDown';
|
||||||
|
import upIcon from '@fortawesome/fontawesome-free-solid/faAngleDoubleUp';
|
||||||
|
import FontAwesomeIcon from '@fortawesome/react-fontawesome';
|
||||||
|
import { Collapse } from 'reactstrap';
|
||||||
|
import ReactTags from 'react-tag-autocomplete';
|
||||||
|
import { assoc, replace } from 'ramda';
|
||||||
|
|
||||||
export default function CreateShortUrl() {
|
export default class CreateShortUrl extends React.Component {
|
||||||
return <div className="short-urls-container">Create short URL</div>
|
state = {
|
||||||
|
longUrl: '',
|
||||||
|
tags: [],
|
||||||
|
customSlug: null,
|
||||||
|
validSince: null,
|
||||||
|
validUntil: null,
|
||||||
|
maxVisits: null,
|
||||||
|
moreOptionsVisible: false
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const addTag = tag => this.setState({
|
||||||
|
tags: [].concat(this.state.tags, assoc('name', replace(/ /g, '-', tag.name), tag))
|
||||||
|
});
|
||||||
|
const removeTag = i => {
|
||||||
|
const tags = this.state.tags.slice(0);
|
||||||
|
tags.splice(i, 1);
|
||||||
|
this.setState({ tags });
|
||||||
|
};
|
||||||
|
const renderOptionalInput = (id, placeholder, type = 'text', props = {}) =>
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
type={type}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={this.state[id]}
|
||||||
|
onChange={e => this.setState({ [id]: e.target.value })}
|
||||||
|
{...props}
|
||||||
|
/>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="short-urls-container">
|
||||||
|
<form onSubmit={e => e.preventDefault()}>
|
||||||
|
<div className="form-group">
|
||||||
|
<input
|
||||||
|
className="form-control form-control-lg"
|
||||||
|
type="url"
|
||||||
|
placeholder="Insert the URL to be shortened"
|
||||||
|
required
|
||||||
|
value={this.state.longUrl}
|
||||||
|
onChange={e => this.setState({ longUrl: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Collapse isOpen={this.state.moreOptionsVisible}>
|
||||||
|
<div className="form-group">
|
||||||
|
<ReactTags
|
||||||
|
tags={this.state.tags}
|
||||||
|
classNames={{}}
|
||||||
|
handleAddition={addTag}
|
||||||
|
handleDelete={removeTag}
|
||||||
|
allowNew={true}
|
||||||
|
placeholder="Add tags you want to apply to the URL"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-6">
|
||||||
|
<div className="form-group">
|
||||||
|
{renderOptionalInput('customSlug', 'Custom slug')}
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-6">
|
||||||
|
<div className="form-group">
|
||||||
|
{renderOptionalInput('validSince', 'Enabled since...', 'date')}
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
{renderOptionalInput('validUntil', 'Enabled until...', 'date')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-outline-secondary create-short-url__btn"
|
||||||
|
onClick={() => this.setState({ moreOptionsVisible: !this.state.moreOptionsVisible })}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={this.state.moreOptionsVisible ? upIcon : downIcon} />
|
||||||
|
|
||||||
|
{this.state.moreOptionsVisible ? 'Less' : 'More'} options
|
||||||
|
</button>
|
||||||
|
<button className="btn btn-outline-primary create-short-url__btn float-right">Create</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/short-urls/CreateShortUrl.scss
Normal file
19
src/short-urls/CreateShortUrl.scss
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
@import "../../node_modules/react-tag-autocomplete/example/styles.css";
|
||||||
|
@import "../utils/mixins/box-shadow";
|
||||||
|
@import "../utils/mixins/border-radius";
|
||||||
|
|
||||||
|
.create-short-url__btn:not(:first-child) {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-tags {
|
||||||
|
@include border-radius(.25rem);
|
||||||
|
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, -webkit-box-shadow .15s ease-in-out;
|
||||||
|
}
|
||||||
|
.react-tags.is-focused {
|
||||||
|
color: #495057;
|
||||||
|
background-color: #fff;
|
||||||
|
border-color: #80bdff;
|
||||||
|
outline: 0;
|
||||||
|
@include box-shadow(0 0 0 0.2rem rgba(0,123,255,.25));
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ export class ShortUrlsList extends React.Component {
|
||||||
|
|
||||||
renderShortUrls() {
|
renderShortUrls() {
|
||||||
const { shortUrlsList, selectedServer, loading } = this.props;
|
const { shortUrlsList, selectedServer, loading } = this.props;
|
||||||
|
console.log('Is loading?: ', loading);
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <tr><td colSpan="6" className="text-center">Loading...</td></tr>;
|
return <tr><td colSpan="6" className="text-center">Loading...</td></tr>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export default function reducer(state = initialState, action) {
|
||||||
|
|
||||||
export const listShortUrls = (serverId, params = {}) => {
|
export const listShortUrls = (serverId, params = {}) => {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
|
dispatch({ type: LIST_SHORT_URLS_START });
|
||||||
const selectedServer = ServersService.findServerById(serverId);
|
const selectedServer = ServersService.findServerById(serverId);
|
||||||
|
|
||||||
ShlinkApiClient.setConfig(selectedServer);
|
ShlinkApiClient.setConfig(selectedServer);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
@mixin border-radius($radius) {
|
@mixin border-radius($radius) {
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
-webkit-border-radius: $radius;
|
-webkit-border-radius: $radius;
|
||||||
-moz-border-radius: $radius;
|
|
||||||
}
|
}
|
||||||
|
|
4
src/utils/mixins/box-shadow.scss
Normal file
4
src/utils/mixins/box-shadow.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
@mixin box-shadow($shadow) {
|
||||||
|
-webkit-box-shadow: $shadow;
|
||||||
|
box-shadow: $shadow;
|
||||||
|
}
|
|
@ -6152,6 +6152,10 @@ react-router@^4.3.1:
|
||||||
prop-types "^15.6.1"
|
prop-types "^15.6.1"
|
||||||
warning "^4.0.1"
|
warning "^4.0.1"
|
||||||
|
|
||||||
|
react-tag-autocomplete@^5.5.1:
|
||||||
|
version "5.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-tag-autocomplete/-/react-tag-autocomplete-5.5.1.tgz#6b3f253d3d69eb546925118cdf43138a9aafe113"
|
||||||
|
|
||||||
react-test-renderer@^16.0.0-0:
|
react-test-renderer@^16.0.0-0:
|
||||||
version "16.4.1"
|
version "16.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.4.1.tgz#f2fb30c2c7b517db6e5b10ed20bb6b0a7ccd8d70"
|
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.4.1.tgz#f2fb30c2c7b517db6e5b10ed20bb6b0a7ccd8d70"
|
||||||
|
|
Loading…
Reference in a new issue