From 4b1f5e9f4cf1b7f6aeda5fa25ed41ea94fcb312d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 18 Dec 2018 19:59:50 +0100 Subject: [PATCH] Extracted short-url related services to its own service provider --- src/container/index.js | 67 ++--------------- src/servers/reducers/selectedServer.js | 2 - src/servers/services/ServersExporter.js | 8 +-- src/servers/services/ServersImporter.js | 7 +- src/servers/services/ServersService.js | 7 +- src/servers/services/provideServices.js | 6 +- src/short-urls/reducers/shortUrlCreation.js | 6 +- src/short-urls/reducers/shortUrlDeletion.js | 6 +- src/short-urls/services/provideServices.js | 71 +++++++++++++++++++ src/utils/ColorGenerator.js | 7 +- src/utils/Storage.js | 14 +--- test/servers/services/ServersExporter.test.js | 2 +- test/servers/services/ServersImporter.test.js | 2 +- test/servers/services/ServersService.test.js | 2 +- .../reducers/shortUrlCreation.test.js | 6 +- test/utils/ColorGenerator.test.js | 2 +- 16 files changed, 94 insertions(+), 121 deletions(-) create mode 100644 src/short-urls/services/provideServices.js diff --git a/src/container/index.js b/src/container/index.js index a5e8ceda..79a65834 100644 --- a/src/container/index.js +++ b/src/container/index.js @@ -1,31 +1,18 @@ import Bottle from 'bottlejs'; import { withRouter } from 'react-router-dom'; import { connect as reduxConnect } from 'react-redux'; -import { assoc, pick } from 'ramda'; +import { pick } from 'ramda'; import axios from 'axios'; import App from '../App'; import ScrollToTop from '../common/ScrollToTop'; import MainHeader from '../common/MainHeader'; -import { resetSelectedServer } from '../servers/reducers/selectedServer'; import Home from '../common/Home'; import MenuLayout from '../common/MenuLayout'; -import ShortUrls from '../short-urls/ShortUrls'; -import SearchBar from '../short-urls/SearchBar'; -import { listShortUrls } from '../short-urls/reducers/shortUrlsList'; -import ShortUrlsList from '../short-urls/ShortUrlsList'; -import { resetShortUrlParams } from '../short-urls/reducers/shortUrlsListParams'; -import { ColorGenerator } from '../utils/ColorGenerator'; -import { Storage } from '../utils/Storage'; -import ShortUrlsRow from '../short-urls/helpers/ShortUrlsRow'; -import ShortUrlsRowMenu from '../short-urls/helpers/ShortUrlsRowMenu'; import AsideMenu from '../common/AsideMenu'; -import CreateShortUrl from '../short-urls/CreateShortUrl'; -import { createShortUrl, resetCreateShortUrl } from '../short-urls/reducers/shortUrlCreation'; -import DeleteShortUrlModal from '../short-urls/helpers/DeleteShortUrlModal'; -import { deleteShortUrl, resetDeleteShortUrl, shortUrlDeleted } from '../short-urls/reducers/shortUrlDeletion'; -import EditTagsModal from '../short-urls/helpers/EditTagsModal'; -import { editShortUrlTags, resetShortUrlsTags, shortUrlTagsEdited } from '../short-urls/reducers/shortUrlTags'; +import ColorGenerator from '../utils/ColorGenerator'; +import Storage from '../utils/Storage'; import buildShlinkApiClient from '../api/ShlinkApiClientBuilder'; +import provideShortUrlsServices from '../short-urls/services/provideServices'; import provideServersServices from '../servers/services/provideServices'; import provideVisitsServices from '../visits/services/provideServices'; import provideTagsServices from '../tags/services/provideServices'; @@ -54,7 +41,7 @@ bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown'); bottle.decorator('MainHeader', withRouter); bottle.serviceFactory('Home', () => Home); -bottle.decorator('Home', connect([ 'servers' ], { resetSelectedServer })); +bottle.decorator('Home', connect([ 'servers' ], [ 'resetSelectedServer' ])); bottle.serviceFactory( 'MenuLayout', @@ -77,49 +64,7 @@ bottle.service('ColorGenerator', ColorGenerator, 'Storage'); bottle.constant('axios', axios); bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios'); -bottle.serviceFactory('ShortUrls', ShortUrls, 'SearchBar', 'ShortUrlsList'); -bottle.decorator('ShortUrls', reduxConnect( - (state) => assoc('shortUrlsList', state.shortUrlsList.shortUrls, state.shortUrlsList) -)); - -bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator'); -bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], { listShortUrls })); - -bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsRow'); -bottle.decorator('ShortUrlsList', connect( - [ 'selectedServer', 'shortUrlsListParams' ], - [ 'listShortUrls', 'resetShortUrlParams' ] -)); - -bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator'); - -bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'EditTagsModal'); - -bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'TagsSelector'); -bottle.decorator('CreateShortUrl', connect([ 'shortUrlCreationResult' ], { - createShortUrl, - resetCreateShortUrl, -})); - -bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal); -bottle.decorator('DeleteShortUrlModal', connect( - [ 'shortUrlDeletion' ], - { deleteShortUrl, resetDeleteShortUrl, shortUrlDeleted } -)); - -bottle.serviceFactory('EditTagsModal', EditTagsModal, 'TagsSelector'); -bottle.decorator('EditTagsModal', connect( - [ 'shortUrlTags' ], - [ 'editShortUrlTags', 'resetShortUrlsTags', 'shortUrlTagsEdited' ] -)); - -bottle.serviceFactory('editShortUrlTags', editShortUrlTags, 'buildShlinkApiClient'); -bottle.serviceFactory('resetShortUrlsTags', () => resetShortUrlsTags); -bottle.serviceFactory('shortUrlTagsEdited', () => shortUrlTagsEdited); - -bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient'); -bottle.serviceFactory('resetShortUrlParams', () => resetShortUrlParams); - +provideShortUrlsServices(bottle, connect); provideServersServices(bottle, connect, withRouter); provideTagsServices(bottle, connect); provideVisitsServices(bottle, connect); diff --git a/src/servers/reducers/selectedServer.js b/src/servers/reducers/selectedServer.js index dfee15ec..51b53e86 100644 --- a/src/servers/reducers/selectedServer.js +++ b/src/servers/reducers/selectedServer.js @@ -23,8 +23,6 @@ export const resetSelectedServer = () => ({ type: RESET_SELECTED_SERVER }); export const selectServer = (serversService) => (serverId) => (dispatch) => { dispatch(resetShortUrlParams()); - console.log('Setting server'); - const selectedServer = serversService.findServerById(serverId); dispatch({ diff --git a/src/servers/services/ServersExporter.js b/src/servers/services/ServersExporter.js index 7262ac0f..9caf5ab9 100644 --- a/src/servers/services/ServersExporter.js +++ b/src/servers/services/ServersExporter.js @@ -1,6 +1,4 @@ import { dissoc, head, keys, values } from 'ramda'; -import csvjson from 'csvjson'; -import serversService from './ServersService'; const saveCsv = (window, csv) => { const { navigator, document } = window; @@ -26,7 +24,7 @@ const saveCsv = (window, csv) => { document.body.removeChild(link); }; -export class ServersExporter { +export default class ServersExporter { constructor(serversService, window, csvjson) { this.serversService = serversService; this.window = window; @@ -49,7 +47,3 @@ export class ServersExporter { } }; } - -const serverExporter = new ServersExporter(serversService, global.window, csvjson); - -export default serverExporter; diff --git a/src/servers/services/ServersImporter.js b/src/servers/services/ServersImporter.js index 0734952c..af855a64 100644 --- a/src/servers/services/ServersImporter.js +++ b/src/servers/services/ServersImporter.js @@ -1,11 +1,10 @@ -import csvjson from 'csvjson'; import PropTypes from 'prop-types'; export const serversImporterType = PropTypes.shape({ importServersFromFile: PropTypes.func, }); -export class ServersImporter { +export default class ServersImporter { constructor(csvjson) { this.csvjson = csvjson; } @@ -28,7 +27,3 @@ export class ServersImporter { }); }; } - -const serversImporter = new ServersImporter(csvjson); - -export default serversImporter; diff --git a/src/servers/services/ServersService.js b/src/servers/services/ServersService.js index 25568526..52bb8fed 100644 --- a/src/servers/services/ServersService.js +++ b/src/servers/services/ServersService.js @@ -1,9 +1,8 @@ import { assoc, dissoc, reduce } from 'ramda'; -import storage from '../../utils/Storage'; const SERVERS_STORAGE_KEY = 'servers'; -export class ServersService { +export default class ServersService { constructor(storage) { this.storage = storage; } @@ -30,7 +29,3 @@ export class ServersService { dissoc(server.id, this.listServers()) ); } - -const serversService = new ServersService(storage); - -export default serversService; diff --git a/src/servers/services/provideServices.js b/src/servers/services/provideServices.js index bbc026fc..a2464749 100644 --- a/src/servers/services/provideServices.js +++ b/src/servers/services/provideServices.js @@ -6,9 +6,9 @@ import DeleteServerButton from '../DeleteServerButton'; import ImportServersBtn from '../helpers/ImportServersBtn'; import { resetSelectedServer, selectServer } from '../reducers/selectedServer'; import { createServer, createServers, deleteServer, listServers } from '../reducers/server'; -import { ServersImporter } from './ServersImporter'; -import { ServersService } from './ServersService'; -import { ServersExporter } from './ServersExporter'; +import ServersImporter from './ServersImporter'; +import ServersService from './ServersService'; +import ServersExporter from './ServersExporter'; const provideServices = (bottle, connect, withRouter) => { // Components diff --git a/src/short-urls/reducers/shortUrlCreation.js b/src/short-urls/reducers/shortUrlCreation.js index 80150550..8a6d772f 100644 --- a/src/short-urls/reducers/shortUrlCreation.js +++ b/src/short-urls/reducers/shortUrlCreation.js @@ -1,6 +1,4 @@ -import { curry } from 'ramda'; import PropTypes from 'prop-types'; -import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../api/ShlinkApiClientBuilder'; /* eslint-disable padding-line-between-statements, newline-after-var */ export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START'; @@ -50,7 +48,7 @@ export default function reducer(state = defaultState, action) { } } -export const _createShortUrl = (buildShlinkApiClient, data) => async (dispatch, getState) => { +export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => { dispatch({ type: CREATE_SHORT_URL_START }); const { selectedServer } = getState(); @@ -65,6 +63,4 @@ export const _createShortUrl = (buildShlinkApiClient, data) => async (dispatch, } }; -export const createShortUrl = curry(_createShortUrl)(buildShlinkApiClient); - export const resetCreateShortUrl = () => ({ type: RESET_CREATE_SHORT_URL }); diff --git a/src/short-urls/reducers/shortUrlDeletion.js b/src/short-urls/reducers/shortUrlDeletion.js index 20812079..aeb46ed5 100644 --- a/src/short-urls/reducers/shortUrlDeletion.js +++ b/src/short-urls/reducers/shortUrlDeletion.js @@ -1,6 +1,4 @@ -import { curry } from 'ramda'; import PropTypes from 'prop-types'; -import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../api/ShlinkApiClientBuilder'; /* eslint-disable padding-line-between-statements, newline-after-var */ const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START'; @@ -56,7 +54,7 @@ export default function reducer(state = defaultState, action) { } } -export const _deleteShortUrl = (buildShlinkApiClient, shortCode) => async (dispatch, getState) => { +export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => { dispatch({ type: DELETE_SHORT_URL_START }); const { selectedServer } = getState(); @@ -72,8 +70,6 @@ export const _deleteShortUrl = (buildShlinkApiClient, shortCode) => async (dispa } }; -export const deleteShortUrl = curry(_deleteShortUrl)(buildShlinkApiClient); - export const resetDeleteShortUrl = () => ({ type: RESET_DELETE_SHORT_URL }); export const shortUrlDeleted = (shortCode) => ({ type: SHORT_URL_DELETED, shortCode }); diff --git a/src/short-urls/services/provideServices.js b/src/short-urls/services/provideServices.js new file mode 100644 index 00000000..c86811f4 --- /dev/null +++ b/src/short-urls/services/provideServices.js @@ -0,0 +1,71 @@ +import { connect as reduxConnect } from 'react-redux'; +import { assoc } from 'ramda'; +import ShortUrls from '../ShortUrls'; +import SearchBar from '../SearchBar'; +import ShortUrlsList from '../ShortUrlsList'; +import ShortUrlsRow from '../helpers/ShortUrlsRow'; +import ShortUrlsRowMenu from '../helpers/ShortUrlsRowMenu'; +import CreateShortUrl from '../CreateShortUrl'; +import DeleteShortUrlModal from '../helpers/DeleteShortUrlModal'; +import EditTagsModal from '../helpers/EditTagsModal'; +import { listShortUrls } from '../reducers/shortUrlsList'; +import { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation'; +import { deleteShortUrl, resetDeleteShortUrl, shortUrlDeleted } from '../reducers/shortUrlDeletion'; +import { editShortUrlTags, resetShortUrlsTags, shortUrlTagsEdited } from '../reducers/shortUrlTags'; +import { resetShortUrlParams } from '../reducers/shortUrlsListParams'; + +const provideServices = (bottle, connect) => { + // Components + bottle.serviceFactory('ShortUrls', ShortUrls, 'SearchBar', 'ShortUrlsList'); + bottle.decorator('ShortUrls', reduxConnect( + (state) => assoc('shortUrlsList', state.shortUrlsList.shortUrls, state.shortUrlsList) + )); + + bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator'); + bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], [ 'listShortUrls' ])); + + bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsRow'); + bottle.decorator('ShortUrlsList', connect( + [ 'selectedServer', 'shortUrlsListParams' ], + [ 'listShortUrls', 'resetShortUrlParams' ] + )); + + bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator'); + + bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'EditTagsModal'); + + bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'TagsSelector'); + bottle.decorator( + 'CreateShortUrl', + connect([ 'shortUrlCreationResult' ], [ 'createShortUrl', 'resetCreateShortUrl' ]) + ); + + bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal); + bottle.decorator('DeleteShortUrlModal', connect( + [ 'shortUrlDeletion' ], + [ 'deleteShortUrl', 'resetDeleteShortUrl', 'shortUrlDeleted' ] + )); + + bottle.serviceFactory('EditTagsModal', EditTagsModal, 'TagsSelector'); + bottle.decorator('EditTagsModal', connect( + [ 'shortUrlTags' ], + [ 'editShortUrlTags', 'resetShortUrlsTags', 'shortUrlTagsEdited' ] + )); + + // Actions + bottle.serviceFactory('editShortUrlTags', editShortUrlTags, 'buildShlinkApiClient'); + bottle.serviceFactory('resetShortUrlsTags', () => resetShortUrlsTags); + bottle.serviceFactory('shortUrlTagsEdited', () => shortUrlTagsEdited); + + bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient'); + bottle.serviceFactory('resetShortUrlParams', () => resetShortUrlParams); + + bottle.serviceFactory('createShortUrl', createShortUrl, 'buildShlinkApiClient'); + bottle.serviceFactory('resetCreateShortUrl', () => resetCreateShortUrl); + + bottle.serviceFactory('deleteShortUrl', deleteShortUrl, 'buildShlinkApiClient'); + bottle.serviceFactory('resetDeleteShortUrl', () => resetDeleteShortUrl); + bottle.serviceFactory('shortUrlDeleted', () => shortUrlDeleted); +}; + +export default provideServices; diff --git a/src/utils/ColorGenerator.js b/src/utils/ColorGenerator.js index 673eba3c..8f276835 100644 --- a/src/utils/ColorGenerator.js +++ b/src/utils/ColorGenerator.js @@ -1,6 +1,5 @@ import { range } from 'ramda'; import PropTypes from 'prop-types'; -import storage from './Storage'; const HEX_COLOR_LENGTH = 6; const { floor, random } = Math; @@ -13,7 +12,7 @@ const buildRandomColor = () => }`; const normalizeKey = (key) => key.toLowerCase().trim(); -export class ColorGenerator { +export default class ColorGenerator { constructor(storage) { this.storage = storage; this.colors = this.storage.get('colors') || {}; @@ -45,7 +44,3 @@ export const colorGeneratorType = PropTypes.shape({ getColorForKey: PropTypes.func, setColorForKey: PropTypes.func, }); - -const colorGenerator = new ColorGenerator(storage); - -export default colorGenerator; diff --git a/src/utils/Storage.js b/src/utils/Storage.js index 22a52632..35f9eb74 100644 --- a/src/utils/Storage.js +++ b/src/utils/Storage.js @@ -1,7 +1,7 @@ const PREFIX = 'shlink'; const buildPath = (path) => `${PREFIX}.${path}`; -export class Storage { +export default class Storage { constructor(localStorage) { this.localStorage = localStorage; } @@ -14,15 +14,3 @@ export class Storage { set = (key, value) => this.localStorage.setItem(buildPath(key), JSON.stringify(value)); } - -const browserStorage = global.localStorage || { - getItem() { - return ''; - }, - setItem() { - return ''; - }, -}; -const storage = new Storage(browserStorage); - -export default storage; diff --git a/test/servers/services/ServersExporter.test.js b/test/servers/services/ServersExporter.test.js index eea6e19a..173292e3 100644 --- a/test/servers/services/ServersExporter.test.js +++ b/test/servers/services/ServersExporter.test.js @@ -1,5 +1,5 @@ import sinon from 'sinon'; -import { ServersExporter } from '../../../src/servers/services/ServersExporter'; +import ServersExporter from '../../../src/servers/services/ServersExporter'; describe('ServersExporter', () => { const createLinkMock = () => ({ diff --git a/test/servers/services/ServersImporter.test.js b/test/servers/services/ServersImporter.test.js index af1b5e8c..ef79d790 100644 --- a/test/servers/services/ServersImporter.test.js +++ b/test/servers/services/ServersImporter.test.js @@ -1,5 +1,5 @@ import sinon from 'sinon'; -import { ServersImporter } from '../../../src/servers/services/ServersImporter'; +import ServersImporter from '../../../src/servers/services/ServersImporter'; describe('ServersImporter', () => { const servers = [{ name: 'foo' }, { name: 'bar' }]; diff --git a/test/servers/services/ServersService.test.js b/test/servers/services/ServersService.test.js index a8fb4281..b8c60d9e 100644 --- a/test/servers/services/ServersService.test.js +++ b/test/servers/services/ServersService.test.js @@ -1,6 +1,6 @@ import sinon from 'sinon'; import { last } from 'ramda'; -import { ServersService } from '../../../src/servers/services/ServersService'; +import ServersService from '../../../src/servers/services/ServersService'; describe('ServersService', () => { const servers = { diff --git a/test/short-urls/reducers/shortUrlCreation.test.js b/test/short-urls/reducers/shortUrlCreation.test.js index 28aac024..371d257f 100644 --- a/test/short-urls/reducers/shortUrlCreation.test.js +++ b/test/short-urls/reducers/shortUrlCreation.test.js @@ -4,7 +4,7 @@ import reducer, { CREATE_SHORT_URL_ERROR, CREATE_SHORT_URL, RESET_CREATE_SHORT_URL, - _createShortUrl, + createShortUrl, resetCreateShortUrl, } from '../../../src/short-urls/reducers/shortUrlCreation'; @@ -62,7 +62,7 @@ describe('shortUrlCreationReducer', () => { const expectedDispatchCalls = 2; const result = 'foo'; const apiClientMock = createApiClientMock(Promise.resolve(result)); - const dispatchable = _createShortUrl(() => apiClientMock, {}); + const dispatchable = createShortUrl(() => apiClientMock)({}); await dispatchable(dispatch, getState); @@ -77,7 +77,7 @@ describe('shortUrlCreationReducer', () => { const expectedDispatchCalls = 2; const error = 'Error'; const apiClientMock = createApiClientMock(Promise.reject(error)); - const dispatchable = _createShortUrl(() => apiClientMock, {}); + const dispatchable = createShortUrl(() => apiClientMock)({}); try { await dispatchable(dispatch, getState); diff --git a/test/utils/ColorGenerator.test.js b/test/utils/ColorGenerator.test.js index e0a359c6..a70de95b 100644 --- a/test/utils/ColorGenerator.test.js +++ b/test/utils/ColorGenerator.test.js @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import { ColorGenerator } from '../../src/utils/ColorGenerator'; +import ColorGenerator from '../../src/utils/ColorGenerator'; describe('ColorGenerator', () => { let colorGenerator;