From 02487dc5cf7061bd37904eafef6290fc5b48ec16 Mon Sep 17 00:00:00 2001 From: Makar Kotlov Date: Sun, 23 Jun 2019 22:42:55 +0600 Subject: [PATCH] Code refactored, table search rewritten using API calls, toastify replaced with ant notification --- package-lock.json | 47 +---------- package.json | 3 +- src/App.test.js | 47 ----------- src/components/EditUserForm.js | 13 +-- src/components/Notification.js | 16 ++++ src/components/Search.js | 45 ++++++++++ src/components/TableComponent.js | 107 ++++++++++++------------ src/components/UserForm.js | 13 +-- src/containers/EditUserFormContainer.js | 6 +- src/containers/TableContainer.js | 9 +- src/pages/App.css | 6 +- src/pages/TablePage.js | 12 ++- src/store/users/actions.js | 89 +++++++++++++------- src/store/users/reducer.js | 1 + 14 files changed, 212 insertions(+), 202 deletions(-) delete mode 100644 src/App.test.js create mode 100644 src/components/Notification.js create mode 100644 src/components/Search.js diff --git a/package-lock.json b/package-lock.json index df3ee01..329c238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "PERX", + "name": "perx", "version": "0.1.0", "lockfileVersion": 1, "requires": true, @@ -4820,14 +4820,6 @@ "utila": "~0.4" } }, - "dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", - "requires": { - "@babel/runtime": "^7.1.2" - } - }, "dom-matches": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz", @@ -14019,43 +14011,6 @@ "resize-observer-polyfill": "^1.5.0" } }, - "react-toastify": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-5.2.1.tgz", - "integrity": "sha512-OEZQld/jvjFCQnmXShb73dxVgslEuVz6Jb9/K22x+OcpQH5abtb278tO+Z9FwWsnu8aOvKiPuEYRrSfXC0HF8w==", - "requires": { - "@babel/runtime": "^7.4.2", - "classnames": "^2.2.6", - "prop-types": "^15.7.2", - "react-transition-group": "^2.6.1" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "regenerator-runtime": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", - "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" - } - } - }, - "react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", - "requires": { - "dom-helpers": "^3.4.0", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" - } - }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", diff --git a/package.json b/package.json index b8ac963..6560fe5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "PERX", + "name": "perx", "version": "0.1.0", "private": true, "dependencies": { @@ -10,7 +10,6 @@ "react-helmet": "^5.2.0", "react-redux": "^6.0.1", "react-scripts": "^2.1.8", - "react-toastify": "^5.0.0-rc.3", "redux": "^4.0.1", "redux-thunk": "^2.3.0", "uuid": "^3.3.2" diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index b6ad83f..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom' -import { shallow, mount } from 'enzyme' -import renderer from 'react-test-renderer' -import td from 'testdouble' -import App from './pages/App' - -const setUp = (props = {}) => { - const component = shallow(
) - return component -} - -// it('renders without crashing', () => { -// const div = document.createElement('div') -// ReactDOM.render(, div) -// ReactDOM.unmountComponentAtNode(div) -// }) - -it('displays the title', () => { - const wrapper = shallow() - //expect(wrapper.find('h1').text()).toEqual('An album') - expect(wrapper.contains('An album')).toBe(true) -}) - -it('displays the img', () => { - const wrapper = shallow() - expect(wrapper.containsMatchingElement()).toBe(true) -}) - -it('likes', () => { - const onRate = () => {} - const wrapper = shallow() - - expect(wrapper.containsMatchingElement()).toBe(true) - - // const onRate = td.function('onRate') - // const wrapper = mount() - - // wrapper.find('[data-icon="thumbsup"]').simulate('click') - - // td.verify(onRate(Rating.liked)) -}) - -it('renders h1', () => { - const output = renderer.create( {}} />) - expect(output).toMatchSnapshot() -}) diff --git a/src/components/EditUserForm.js b/src/components/EditUserForm.js index 64bbcca..2e7b84a 100644 --- a/src/components/EditUserForm.js +++ b/src/components/EditUserForm.js @@ -1,7 +1,6 @@ import React from 'react' import { Form, Button, Input } from 'antd' -import { toast } from 'react-toastify' -import 'react-toastify/dist/ReactToastify.css' +import Notification from './Notification' const CustomForm = Form.create({ mapPropsToFields(props) { @@ -42,12 +41,16 @@ const CustomForm = Form.create({ ...formData, } updateUser(data) - .then(() => { + .then(success => { + if (!success) { + Notification.error('User is NOT UPDATED!') + return + } _toggleModal() _getData() - toast.success('User is Updated!') + Notification.success('User is UPDATED!') }) - .catch(err => toast.error(err)) + .catch(err => Notification.error(err)) } }) } diff --git a/src/components/Notification.js b/src/components/Notification.js new file mode 100644 index 0000000..d858a62 --- /dev/null +++ b/src/components/Notification.js @@ -0,0 +1,16 @@ +import { notification } from 'antd' + +const Notification = { + error: data => + notification.error({ + message: 'Error', + description: `${data}`, + }), + success: data => + notification.success({ + message: 'Success', + description: `${data}`, + }), +} + +export default Notification diff --git a/src/components/Search.js b/src/components/Search.js new file mode 100644 index 0000000..b310e9e --- /dev/null +++ b/src/components/Search.js @@ -0,0 +1,45 @@ +import React, { useState } from 'react' +import { Button, Input } from 'antd' + +const Search = ({ handleSearch, getData, dataIndex }) => { + const [searchRef, setSearchRef] = useState({}) + return ( +
+
+ { + if (phrase) handleSearch(dataIndex, phrase) + }} + ref={c => setSearchRef(c)} + /> +
+
+ + +
+
+ ) +} + +export default Search diff --git a/src/components/TableComponent.js b/src/components/TableComponent.js index f8bb8ea..82341fb 100644 --- a/src/components/TableComponent.js +++ b/src/components/TableComponent.js @@ -1,8 +1,10 @@ +// @flow import React, { useState, useEffect } from 'react' -import { Table, Button, Divider, Modal, Popconfirm, Input, Icon } from 'antd' +import { Table, Button, Divider, Modal, Popconfirm, Icon } from 'antd' import UserFormContainer from '../containers/UserFormContainer' import EditUserFormContainer from '../containers/EditUserFormContainer' -import { toast } from 'react-toastify' +import Search from './Search' +import Notification from './Notification' const TableComponent = ({ users, @@ -10,51 +12,37 @@ const TableComponent = ({ fetchUsers, getTotal, total, + pageSize, loading, }) => { const [visible, _setVisible] = useState(false), [showEdit, _setShowEdit] = useState(false), [submitBtnRef, _setSubmitBtnRef] = useState({}), [updateBtnRef, _setUpdateBtnRef] = useState({}), - [searchInputRef, _setSearchInputRef] = useState({}), [record, _setRecord] = useState({}), + [pageNumber, setPageNumber] = useState(1), + _handleSearch = (dataIndex, phrase) => { + const search = { + name: dataIndex === 'name', + phrase, + }, + pageNum = 1 + fetchUsers(pageNum, search) + .then(success => { + if (!success) + Notification.error( + 'An error occured while fetching the users' + ) + }) + .catch(err => Notification.error(err)) + }, _getColumnSearchProps = dataIndex => ({ - filterDropdown: ({ - setSelectedKeys, - selectedKeys, - confirm, - clearFilters, - }) => ( -
- _setSearchInputRef(node)} - placeholder={`Search ${dataIndex}`} - value={selectedKeys[0]} - onChange={e => - setSelectedKeys( - e.target.value ? [e.target.value] : [] - ) - } - onPressEnter={() => confirm()} - className="search-input" - /> - - -
+ filterDropdown: () => ( + ), filterIcon: filtered => ( ), - onFilter: (value, record) => - record[dataIndex] - .toString() - .toLowerCase() - .includes(value.toLowerCase()), - onFilterDropdownVisibleChange: visible => { - if (visible) { - setTimeout(() => searchInputRef.select()) - } - }, }), columns = [ { @@ -117,16 +95,34 @@ const TableComponent = ({ _handleUpdate = () => updateBtnRef.buttonNode.click(), _getData = () => { getTotal() - .then(() => fetchUsers()) - .catch(err => toast.error(err)) + .then(success => { + if (!success) { + Notification.error( + 'An error occured while fetching the users quantity' + ) + return + } + fetchUsers(pageNumber) + }) + .catch(err => Notification.error(err)) }, _deleteUser = record => { deleteUser(record.objectId) - .then(() => { - toast.success('User was successfully Deleted!') + .then(success => { + if (!success) { + Notification.error( + 'An error occured while deleting the user' + ) + return + } + Notification.success('User is DELETED!') _getData() }) - .catch(err => toast.error(err)) + .catch(err => Notification.error(err)) + }, + _handleChange = ({ current }) => { + setPageNumber(current) + fetchUsers(current) } useEffect(() => { @@ -139,7 +135,8 @@ const TableComponent = ({ columns={columns} dataSource={users} loading={loading} - pagination={{ total, pageSize: 4 }} + pagination={{ total, pageSize }} + onChange={_handleChange} />