From 0a5c20e3ee8e370781c9c50e33531d4b8b6f7e5c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 28 Jul 2018 10:41:05 +0200 Subject: [PATCH] Connected creation form with redux, and created reducer for short URL creation --- src/api/ShlinkApiClient.js | 15 ++++-- src/common/MenuLayout.js | 6 +-- src/reducers/index.js | 2 + src/servers/CreateServer.js | 7 +-- src/servers/ServersDropdown.js | 13 ++---- src/short-urls/CreateShortUrl.js | 16 +++++-- src/short-urls/Paginator.js | 5 +- src/short-urls/SearchBar.js | 5 +- src/short-urls/ShortUrlsList.js | 6 +-- .../helpers/CreateShortUrlResult.js | 18 ++++++++ .../reducers/shortUrlCreationResult.js | 46 +++++++++++++++++++ src/short-urls/reducers/shortUrlsList.js | 18 ++++---- src/utils/Tag.js | 7 +-- 13 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 src/short-urls/helpers/CreateShortUrlResult.js create mode 100644 src/short-urls/reducers/shortUrlCreationResult.js diff --git a/src/api/ShlinkApiClient.js b/src/api/ShlinkApiClient.js index 50a7e989..b9158802 100644 --- a/src/api/ShlinkApiClient.js +++ b/src/api/ShlinkApiClient.js @@ -2,6 +2,8 @@ import axios from 'axios'; import { isEmpty } from 'ramda'; import qs from 'qs'; +const API_VERSION = '1'; + export class ShlinkApiClient { constructor(axios) { this.axios = axios; @@ -16,7 +18,7 @@ export class ShlinkApiClient { * @param {String} apiKey */ setConfig = ({ url, apiKey }) => { - this._baseUrl = url; + this._baseUrl = `${url}/rest/v${API_VERSION}`; this._apiKey = apiKey; }; @@ -26,11 +28,18 @@ export class ShlinkApiClient { * @returns {Promise} */ listShortUrls = (options = {}) => { - return this._performRequest('/rest/short-codes', 'GET', options) + return this._performRequest('/short-codes', 'GET', options) .then(resp => resp.data.shortUrls) .catch(e => this._handleAuthError(e, this.listShortUrls, [options])); }; + createShortUrl = options => { + console.log(options); + // this._performRequest('/short-codes', 'POST', options) + // .then(resp => resp.data) + // .catch(e => this._handleAuthError(e, this.listShortUrls, [options])); + }; + _performRequest = async (url, method = 'GET', params = {}, data = {}) => { if (isEmpty(this._token)) { this._token = await this._authenticate(); @@ -54,7 +63,7 @@ export class ShlinkApiClient { _authenticate = async () => { const resp = await this.axios({ method: 'POST', - url: `${this._baseUrl}/rest/authenticate`, + url: `${this._baseUrl}/authenticate`, data: { apiKey: this._apiKey } }); return resp.data.token; diff --git a/src/common/MenuLayout.js b/src/common/MenuLayout.js index c9488ac9..4cbaaa7c 100644 --- a/src/common/MenuLayout.js +++ b/src/common/MenuLayout.js @@ -5,6 +5,7 @@ import { selectServer } from '../servers/reducers/selectedServer'; import CreateShortUrl from '../short-urls/CreateShortUrl'; import ShortUrls from '../short-urls/ShortUrls'; import AsideMenu from './AsideMenu'; +import { pick } from 'ramda'; export class MenuLayout extends React.Component { componentDidMount() { @@ -35,7 +36,4 @@ export class MenuLayout extends React.Component { } } -export default connect(state => ({ - selectedServer: state.selectedServer, - shortUrlsListParams: state.shortUrlsListParams, -}), { selectServer })(MenuLayout); +export default connect(pick(['selectedServer', 'shortUrlsListParams']), { selectServer })(MenuLayout); diff --git a/src/reducers/index.js b/src/reducers/index.js index b7a9af04..afa1c33a 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -4,10 +4,12 @@ import serversReducer from '../servers/reducers/server'; import selectedServerReducer from '../servers/reducers/selectedServer'; import shortUrlsListReducer from '../short-urls/reducers/shortUrlsList'; import shortUrlsListParamsReducer from '../short-urls/reducers/shortUrlsListParams'; +import shortUrlCreationResultReducer from '../short-urls/reducers/shortUrlCreationResult'; export default combineReducers({ servers: serversReducer, selectedServer: selectedServerReducer, shortUrlsList: shortUrlsListReducer, shortUrlsListParams: shortUrlsListParamsReducer, + shortUrlCreationResult: shortUrlCreationResultReducer, }); diff --git a/src/servers/CreateServer.js b/src/servers/CreateServer.js index f9e9296a..4f3331c5 100644 --- a/src/servers/CreateServer.js +++ b/src/servers/CreateServer.js @@ -1,4 +1,4 @@ -import { assoc } from 'ramda'; +import { assoc, pick } from 'ramda'; import React from 'react'; import { connect } from 'react-redux'; import { createServer } from './reducers/server'; @@ -57,7 +57,4 @@ export class CreateServer extends React.Component { } } -export default connect(state => ({ selectedServer: state.selectedServer }), { - createServer, - resetSelectedServer -})(CreateServer); +export default connect(pick(['selectedServer']), {createServer, resetSelectedServer })(CreateServer); diff --git a/src/servers/ServersDropdown.js b/src/servers/ServersDropdown.js index 823e2ea0..482a7c5f 100644 --- a/src/servers/ServersDropdown.js +++ b/src/servers/ServersDropdown.js @@ -1,4 +1,4 @@ -import { isEmpty } from 'ramda'; +import { isEmpty, pick } from 'ramda'; import React from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; @@ -8,7 +8,7 @@ import { listServers } from './reducers/server'; export class ServersDropdown extends React.Component { renderServers = () => { - const { servers, currentServer } = this.props; + const { servers, selectedServer } = this.props; if (isEmpty(servers)) { return Add a server first... @@ -19,7 +19,7 @@ export class ServersDropdown extends React.Component { {name} @@ -41,9 +41,4 @@ export class ServersDropdown extends React.Component { } } -const mapStateToProps = state => ({ - servers: state.servers, - currentServer: state.selectedServer, -}); - -export default connect(mapStateToProps, { listServers })(ServersDropdown); +export default connect(pick(['servers', 'selectedServer']), { listServers })(ServersDropdown); diff --git a/src/short-urls/CreateShortUrl.js b/src/short-urls/CreateShortUrl.js index 67f48684..c3374cd5 100644 --- a/src/short-urls/CreateShortUrl.js +++ b/src/short-urls/CreateShortUrl.js @@ -2,15 +2,18 @@ import calendarIcon from '@fortawesome/fontawesome-free-regular/faCalendarAlt'; import downIcon from '@fortawesome/fontawesome-free-solid/faAngleDoubleDown'; import upIcon from '@fortawesome/fontawesome-free-solid/faAngleDoubleUp'; import FontAwesomeIcon from '@fortawesome/react-fontawesome'; -import { assoc, replace } from 'ramda'; +import { assoc, replace, pick } from 'ramda'; import React from 'react'; import DatePicker from 'react-datepicker'; import ReactTags from 'react-tag-autocomplete'; import { Collapse } from 'reactstrap'; import '../../node_modules/react-datepicker/dist/react-datepicker.css'; import './CreateShortUrl.scss'; +import CreateShortUrlResult from './helpers/CreateShortUrlResult'; +import { createShortUrl } from './reducers/shortUrlCreationResult'; +import { connect } from 'react-redux'; -export default class CreateShortUrl extends React.Component { +export class CreateShortUrl extends React.Component { state = { longUrl: '', tags: [], @@ -49,10 +52,13 @@ export default class CreateShortUrl extends React.Component { readOnly {...props} />; + const save = e => { + e.preventDefault(); + }; return (
-
e.preventDefault()}> +
+ +
); } } + +export default connect(pick(['shortUrlCreationResult']), { createShortUrl })(CreateShortUrl); diff --git a/src/short-urls/Paginator.js b/src/short-urls/Paginator.js index 6463004e..7ece521f 100644 --- a/src/short-urls/Paginator.js +++ b/src/short-urls/Paginator.js @@ -1,9 +1,8 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { Pagination, PaginationItem, PaginationLink } from 'reactstrap'; -import { connect } from 'react-redux'; -export class Paginator extends React.Component { +export default class Paginator extends React.Component { render() { const { paginator = {}, serverId } = this.props; const { currentPage, pagesCount = 0 } = paginator; @@ -51,5 +50,3 @@ export class Paginator extends React.Component { ); } } - -export default connect()(Paginator); diff --git a/src/short-urls/SearchBar.js b/src/short-urls/SearchBar.js index feb60af8..859f5d6c 100644 --- a/src/short-urls/SearchBar.js +++ b/src/short-urls/SearchBar.js @@ -4,6 +4,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { updateShortUrlsList } from './reducers/shortUrlsList'; import './SearchBar.scss'; +import { pick } from 'ramda'; export class SearchBar extends React.Component { state = { @@ -52,6 +53,4 @@ export class SearchBar extends React.Component { } } -export default connect(state => ( - { shortUrlsListParams: state.shortUrlsListParams } -), { updateShortUrlsList })(SearchBar); +export default connect(pick(['shortUrlsListParams']), { updateShortUrlsList })(SearchBar); diff --git a/src/short-urls/ShortUrlsList.js b/src/short-urls/ShortUrlsList.js index a6b9dd38..fa04ede3 100644 --- a/src/short-urls/ShortUrlsList.js +++ b/src/short-urls/ShortUrlsList.js @@ -8,6 +8,7 @@ import Tag from '../utils/Tag'; import { ShortUrlsRow } from './helpers/ShortUrlsRow'; import { listShortUrls } from './reducers/shortUrlsList'; import './ShortUrlsList.scss'; +import { pick } from 'ramda'; export class ShortUrlsList extends React.Component { refreshList = extraParams => { @@ -122,7 +123,4 @@ export class ShortUrlsList extends React.Component { } } -export default connect(state => ({ - selectedServer: state.selectedServer, - shortUrlsListParams: state.shortUrlsListParams, -}), { listShortUrls })(ShortUrlsList); +export default connect(pick(['selectedServer', 'shortUrlsListParams']), { listShortUrls })(ShortUrlsList); diff --git a/src/short-urls/helpers/CreateShortUrlResult.js b/src/short-urls/helpers/CreateShortUrlResult.js new file mode 100644 index 00000000..c03067b2 --- /dev/null +++ b/src/short-urls/helpers/CreateShortUrlResult.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { isNil } from 'ramda'; + +export default function CreateShortUrlResult ({ creationResult }) { + if (creationResult.loading) { + return
Loading...
+ } + + if (creationResult.error) { + return
An error occurred while creating the URL :(
+ } + + if (isNil(creationResult.result)) { + return null; + } + + return
Great!
; +}; diff --git a/src/short-urls/reducers/shortUrlCreationResult.js b/src/short-urls/reducers/shortUrlCreationResult.js new file mode 100644 index 00000000..7622a190 --- /dev/null +++ b/src/short-urls/reducers/shortUrlCreationResult.js @@ -0,0 +1,46 @@ +import ShlinkApiClient from '../../api/ShlinkApiClient'; + +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 = 'shlink/createShortUrl/CREATE_SHORT_URL'; + +const defaultState = { + result: null, + saving: false, + error: false, +}; + +export default function reducer(state = defaultState, action) { + switch (action.type) { + case CREATE_SHORT_URL_START: + return { + ...state, + saving: true, + }; + case CREATE_SHORT_URL_ERROR: + return { + ...state, + saving: false, + error: true, + }; + case CREATE_SHORT_URL: + return { + result: action.result, + saving: false, + error: true, + }; + default: + return state; + } +} + +export const createShortUrl = data => async dispatch => { + dispatch({ type: CREATE_SHORT_URL_START }); + + try { + const result = await ShlinkApiClient.createShortUrl(data); + dispatch({ type: CREATE_SHORT_URL, result }); + } catch (e) { + dispatch({ type: CREATE_SHORT_URL_ERROR }); + } +}; diff --git a/src/short-urls/reducers/shortUrlsList.js b/src/short-urls/reducers/shortUrlsList.js index 34c92d54..e642c57a 100644 --- a/src/short-urls/reducers/shortUrlsList.js +++ b/src/short-urls/reducers/shortUrlsList.js @@ -41,15 +41,13 @@ export const listShortUrls = (serverId, params = {}) => { return updateShortUrlsList(params); }; -export const updateShortUrlsList = (params = {}) => { - return async dispatch => { - dispatch({ type: LIST_SHORT_URLS_START }); +export const updateShortUrlsList = (params = {}) => async dispatch => { + dispatch({ type: LIST_SHORT_URLS_START }); - try { - const shortUrls = await ShlinkApiClient.listShortUrls(params); - dispatch({ type: LIST_SHORT_URLS, shortUrls, params }); - } catch (e) { - dispatch({ type: LIST_SHORT_URLS_ERROR, params }); - } - }; + try { + const shortUrls = await ShlinkApiClient.listShortUrls(params); + dispatch({ type: LIST_SHORT_URLS, shortUrls, params }); + } catch (e) { + dispatch({ type: LIST_SHORT_URLS_ERROR, params }); + } }; diff --git a/src/utils/Tag.js b/src/utils/Tag.js index 4e483e1b..0dceb0df 100644 --- a/src/utils/Tag.js +++ b/src/utils/Tag.js @@ -1,9 +1,8 @@ import React from 'react'; -import { connect } from 'react-redux'; import ColorGenerator from '../utils/ColorGenerator'; import './Tag.scss'; -export class Tag extends React.Component { +export default class Tag extends React.Component { constructor(props) { super(props); this.colorGenerator = props.ColorGenerator; @@ -18,4 +17,6 @@ export class Tag extends React.Component { } } -export default connect(state => ({ ColorGenerator }))(Tag); +Tag.defaultProps = { + ColorGenerator +};