From c9c647aa271b36cf84028e6c44c02fe22db1cb12 Mon Sep 17 00:00:00 2001 From: Tito Date: Tue, 30 Mar 2021 22:15:53 -0300 Subject: [PATCH 01/11] feat(editprocess): generalStatsGrid redirects to EditProcess showing item grid item context --- .../GeneralStatsGrid/GeneralStatsGrid.jsx | 51 +++++++++++++ .../Grids/GeneralStatsGrid/styles.js | 15 ++++ .../Grids/GeneralStatsGrid/test.jsx | 21 ++++++ src/components/Grids/index.js | 1 + src/pages/EditProcess/EditProcess.jsx | 52 ++++++++++++++ src/pages/EditProcess/styles.js | 18 +++++ src/pages/EditProcess/test.jsx | 21 ++++++ src/pages/GeneralStats/GeneralStats.jsx | 39 ++++++++++ src/pages/GeneralStats/index.jsx | 71 +++++++++++++++++++ src/pages/GeneralStats/styles.js | 18 +++++ src/pages/GeneralStats/test.jsx | 21 ++++++ src/routes/index.js | 12 ++++ .../Endpoints/EditProcess/EditProcess.js | 22 ++++++ .../Endpoints/GeneralStats/GeneralStats.js | 9 +++ src/services/Endpoints/index.js | 2 + .../Loaders/EditProcess/EditProcess.js | 19 +++++ .../Loaders/GeneralStats/GeneralStats.js | 19 +++++ src/services/Loaders/index.js | 2 + src/utils/utils.js | 10 +++ 19 files changed, 423 insertions(+) create mode 100644 src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx create mode 100644 src/components/Grids/GeneralStatsGrid/styles.js create mode 100644 src/components/Grids/GeneralStatsGrid/test.jsx create mode 100644 src/pages/EditProcess/EditProcess.jsx create mode 100644 src/pages/EditProcess/styles.js create mode 100644 src/pages/EditProcess/test.jsx create mode 100644 src/pages/GeneralStats/GeneralStats.jsx create mode 100644 src/pages/GeneralStats/index.jsx create mode 100644 src/pages/GeneralStats/styles.js create mode 100644 src/pages/GeneralStats/test.jsx create mode 100644 src/services/Endpoints/EditProcess/EditProcess.js create mode 100644 src/services/Endpoints/GeneralStats/GeneralStats.js create mode 100644 src/services/Loaders/EditProcess/EditProcess.js create mode 100644 src/services/Loaders/GeneralStats/GeneralStats.js diff --git a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx new file mode 100644 index 0000000..ddaaf51 --- /dev/null +++ b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx @@ -0,0 +1,51 @@ +import React from 'react' +import { useHistory } from 'react-router-dom' + +import { AgGridReact } from 'ag-grid-react' +import 'ag-grid-community/dist/styles/ag-grid.css' +import 'ag-grid-community/dist/styles/ag-theme-alpine.css' +import PropTypes from 'prop-types' + +import * as S from './styles' + +const GeneralStatsGrid = ({ className, ...props }) => { + const gridOptions = { + columnDefs: [ + { headerName: 'ID', field: 'id' }, + { headerName: 'Name', field: 'name' }, + { headerName: 'Username', field: 'username' }, + { headerName: 'E-mail', field: 'email' }, + { headerName: 'Address', field: 'address' } + ] + } + + const history = useHistory() + + const onCellClickedHandler = (event) => { + console.log('[GeneralStatsGrid] event: ', event) + history.push('edit_process', { data: event.data }) + } + + return ( + +
+ onCellClickedHandler(event)} + /> +
+
+ ) +} + +GeneralStatsGrid.propTypes = { + className: PropTypes.string, + rowData: PropTypes.any +} + +GeneralStatsGrid.defaultProps = { + className: 'generalstatsgrid' +} + +export default GeneralStatsGrid diff --git a/src/components/Grids/GeneralStatsGrid/styles.js b/src/components/Grids/GeneralStatsGrid/styles.js new file mode 100644 index 0000000..4b5cc5e --- /dev/null +++ b/src/components/Grids/GeneralStatsGrid/styles.js @@ -0,0 +1,15 @@ +import styled, { css } from 'styled-components' + +export const Container = styled.div` + ${({ theme }) => css` + color: ${theme.colors.black}; + flex: 1; + height: 500px; + `} +` + +export const Wrapper = styled.div` + ${({ theme }) => css` + color: ${theme.colors.black}; + `} +` diff --git a/src/components/Grids/GeneralStatsGrid/test.jsx b/src/components/Grids/GeneralStatsGrid/test.jsx new file mode 100644 index 0000000..ba4cfe7 --- /dev/null +++ b/src/components/Grids/GeneralStatsGrid/test.jsx @@ -0,0 +1,21 @@ +import React from 'react' + +import { renderWithTheme } from 'utils/tests/helpers' + +import { screen } from '@testing-library/react' + +import GeneralStatsGrid from './index' + +describe('', () => { + it('should render the heading', () => { + renderWithTheme() + + expect(screen.getByRole('heading', { name: /GeneralStatsGrid/i })).toBeInTheDocument() + }) + + it('should render the colors correctly', () => { + const { container } = renderWithTheme() + + expect(container.firstChild).toHaveStyle({ color: '#222222' }) + }) +}) diff --git a/src/components/Grids/index.js b/src/components/Grids/index.js index aeab9ce..93f5bd9 100644 --- a/src/components/Grids/index.js +++ b/src/components/Grids/index.js @@ -1,2 +1,3 @@ +export { default as GeneralStatsGrid } from './GeneralStatsGrid/GeneralStatsGrid' export { default as ProcessMonitoringGrid } from './ProcessMonitoringGrid/ProcessMonitoringGrid' export { default as Viewer } from './Viewer/Viewer' diff --git a/src/pages/EditProcess/EditProcess.jsx b/src/pages/EditProcess/EditProcess.jsx new file mode 100644 index 0000000..f8098cd --- /dev/null +++ b/src/pages/EditProcess/EditProcess.jsx @@ -0,0 +1,52 @@ +import React, { useEffect, useState } from 'react' +import { useHistory } from 'react-router' + +import * as C from 'components' +import PropTypes from 'prop-types' +import * as API from 'services/Loaders' +import * as UTIL from 'utils' + +import * as S from './styles' + +const EditProcess = ({ className, ...props }) => { + const [processData, setProcessData] = useState('') + + const history = useHistory() + + const loadData = async (props) => { + const editProcessResponse = await API.loadEditProcess( + props?.location?.state + ) + UTIL.stringifyObjects(editProcessResponse) + setProcessData(editProcessResponse) + history.replace('/monitoring/edit_process', null) + } + console.log('[EditProcess] props: ', props) + useEffect(() => loadData(props), []) + + // console.log( + // '[EditProcess] props.location.state.data.id: ', + // props.location.state.data.id + // ) + + return ( + +

Edit Process

+ + + +
+ ) +} + +EditProcess.propTypes = { + className: PropTypes.string, + location: PropTypes.object, + state: PropTypes.object +} + +EditProcess.defaultProps = { + className: 'editprocess' +} + +export default EditProcess diff --git a/src/pages/EditProcess/styles.js b/src/pages/EditProcess/styles.js new file mode 100644 index 0000000..bf839e5 --- /dev/null +++ b/src/pages/EditProcess/styles.js @@ -0,0 +1,18 @@ +import * as PS from 'assets/styles/pages' +import styled, { css } from 'styled-components' + +export const Container = styled(PS.PageContainer)`` + +export const Content = styled.div` + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: center; + width: 100%; +` + +export const Wrapper = styled.div` + ${({ theme }) => css` + color: ${theme.colors.black}; + `} +` diff --git a/src/pages/EditProcess/test.jsx b/src/pages/EditProcess/test.jsx new file mode 100644 index 0000000..03593a3 --- /dev/null +++ b/src/pages/EditProcess/test.jsx @@ -0,0 +1,21 @@ +import React from 'react' + +import { renderWithTheme } from 'utils/tests/helpers' + +import { screen } from '@testing-library/react' + +import EditProcess from './index' + +describe('', () => { + it('should render the heading', () => { + renderWithTheme() + + expect(screen.getByRole('heading', { name: /EditProcess/i })).toBeInTheDocument() + }) + + it('should render the colors correctly', () => { + const { container } = renderWithTheme() + + expect(container.firstChild).toHaveStyle({ color: '#222222' }) + }) +}) diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx new file mode 100644 index 0000000..f8d71ea --- /dev/null +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -0,0 +1,39 @@ +import React, { useState, useEffect } from 'react' + +import * as C from 'components' +import PropTypes from 'prop-types' +import * as API from 'services/Loaders' +import * as UTIL from 'utils' + +import * as S from './styles' + +const GeneralStats = ({ className, ...props }) => { + const [generalStatsData, setGeneralStatsData] = useState('') + + const loadData = async () => { + const generalStatsResponse = await API.loadGeneralStats() + UTIL.stringifyObjects(generalStatsResponse) + setGeneralStatsData(generalStatsResponse) + } + + useEffect(() => loadData(), []) + + return ( + +

General Stats

+ + + +
+ ) +} + +GeneralStats.propTypes = { + className: PropTypes.string +} + +GeneralStats.defaultProps = { + className: 'generalstats' +} + +export default GeneralStats diff --git a/src/pages/GeneralStats/index.jsx b/src/pages/GeneralStats/index.jsx new file mode 100644 index 0000000..2b72aff --- /dev/null +++ b/src/pages/GeneralStats/index.jsx @@ -0,0 +1,71 @@ +import React, { useState, useEffect } from 'react' +import { useHistory } from 'react-router-dom' + +import axios from 'axios' +import Dropdown from 'components/Dropdown' +import GeneralStatsGrid from 'components/GeneralStatsGrid' +import Layout from 'components/Layout' +// import TextField from 'components/TextField' +import PropTypes from 'prop-types' + +import * as S from './styles' + +const GeneralStats = ({ className, ...props }) => { + const [gridData, setGridData] = useState('') + + const history = useHistory() + + const redirectPageHandler = () => { + history.push('edit_process') + } + + const stringifyObjects = (arr) => { + Object.keys(arr[0]).map((key) => { + if (typeof arr[0][key] === 'object') { + arr.map((el) => { + el[key] = JSON.stringify(el[key]) + }) + } + }) + } + + const getGridData = () => { + axios + .get('https://jsonplaceholder.typicode.com/users') + .then((response) => { + stringifyObjects(response.data) + setGridData(response.data) + }) + .catch((error) => console.log(error)) + } + + useEffect(() => getGridData(), []) + + const options = [ + { value: '1', text: 'option1' }, + { value: '2', text: 'option2' } + ] + return ( + +

General Stats

+ {/* */} + + + redirectPageHandler()} + /> + +
+ ) +} + +GeneralStats.propTypes = { + className: PropTypes.string +} + +GeneralStats.defaultProps = { + className: 'generalstats' +} + +export default GeneralStats diff --git a/src/pages/GeneralStats/styles.js b/src/pages/GeneralStats/styles.js new file mode 100644 index 0000000..bf839e5 --- /dev/null +++ b/src/pages/GeneralStats/styles.js @@ -0,0 +1,18 @@ +import * as PS from 'assets/styles/pages' +import styled, { css } from 'styled-components' + +export const Container = styled(PS.PageContainer)`` + +export const Content = styled.div` + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: center; + width: 100%; +` + +export const Wrapper = styled.div` + ${({ theme }) => css` + color: ${theme.colors.black}; + `} +` diff --git a/src/pages/GeneralStats/test.jsx b/src/pages/GeneralStats/test.jsx new file mode 100644 index 0000000..4aa40de --- /dev/null +++ b/src/pages/GeneralStats/test.jsx @@ -0,0 +1,21 @@ +import React from 'react' + +import { renderWithTheme } from 'utils/tests/helpers' + +import { screen } from '@testing-library/react' + +import GeneralStats from './index' + +describe('', () => { + it('should render the heading', () => { + renderWithTheme() + + expect(screen.getByRole('heading', { name: /GeneralStats/i })).toBeInTheDocument() + }) + + it('should render the colors correctly', () => { + const { container } = renderWithTheme() + + expect(container.firstChild).toHaveStyle({ color: '#222222' }) + }) +}) diff --git a/src/routes/index.js b/src/routes/index.js index 50b4d76..aaa5ccb 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -11,6 +11,8 @@ const Error404 = lazy(() => import('pages/Error404/Error404')) const ProcessMonitoring = lazy(() => import('pages/ProcessMonitoring/ProcessMonitoring') ) +const GeneralStats = lazy(() => import('pages/GeneralStats/GeneralStats')) +const EditProcess = lazy(() => import('pages/EditProcess/EditProcess')) const Routes = () => { const { signOut } = useAuthContext() @@ -28,6 +30,16 @@ const Routes = () => { path="/monitoring/process" component={ProcessMonitoring} /> + + { + if (params?.data) { + // console.log('[EditProcess - Endpoints] state: ', params) + return axios.get( + `https://jsonplaceholder.typicode.com/users?id=${params.data.id}`, + { + params: { + ...params + } + } + ) + } else { + // console.log('[EditProcess - Endpoints] state: ', params) + return axios.get('https://jsonplaceholder.typicode.com/users', { + params: { + ...params + } + }) + } +} diff --git a/src/services/Endpoints/GeneralStats/GeneralStats.js b/src/services/Endpoints/GeneralStats/GeneralStats.js new file mode 100644 index 0000000..c7f636c --- /dev/null +++ b/src/services/Endpoints/GeneralStats/GeneralStats.js @@ -0,0 +1,9 @@ +import axios from 'axios' + +export const getGeneralStats = async (params = {}) => { + return axios.get('https://jsonplaceholder.typicode.com/users', { + params: { + ...params + } + }) +} diff --git a/src/services/Endpoints/index.js b/src/services/Endpoints/index.js index fe72384..5201cb2 100644 --- a/src/services/Endpoints/index.js +++ b/src/services/Endpoints/index.js @@ -1 +1,3 @@ export * from './Auth/Auth' +export * from './GeneralStats/GeneralStats' +export * from './EditProcess/EditProcess' diff --git a/src/services/Loaders/EditProcess/EditProcess.js b/src/services/Loaders/EditProcess/EditProcess.js new file mode 100644 index 0000000..31d6381 --- /dev/null +++ b/src/services/Loaders/EditProcess/EditProcess.js @@ -0,0 +1,19 @@ +import * as API from 'services/Endpoints' +import * as UTIL from 'utils' + +import * as Messages from '../messages' + +export const loadEditProcess = async (params) => { + try { + const { data } = await API.getEditProcess(params) + return data || {} + } catch (err) { + console.error(err) + + UTIL.Notifications.createDangerNotification({ + message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT + }) + + return {} + } +} diff --git a/src/services/Loaders/GeneralStats/GeneralStats.js b/src/services/Loaders/GeneralStats/GeneralStats.js new file mode 100644 index 0000000..fd0bea0 --- /dev/null +++ b/src/services/Loaders/GeneralStats/GeneralStats.js @@ -0,0 +1,19 @@ +import * as API from 'services/Endpoints' +import * as UTIL from 'utils' + +import * as Messages from '../messages' + +export const loadGeneralStats = async (params) => { + try { + const { data } = await API.getGeneralStats(params) + return data || {} + } catch (err) { + console.error(err) + + UTIL.Notifications.createDangerNotification({ + message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT + }) + + return {} + } +} diff --git a/src/services/Loaders/index.js b/src/services/Loaders/index.js index fe72384..5201cb2 100644 --- a/src/services/Loaders/index.js +++ b/src/services/Loaders/index.js @@ -1 +1,3 @@ export * from './Auth/Auth' +export * from './GeneralStats/GeneralStats' +export * from './EditProcess/EditProcess' diff --git a/src/utils/utils.js b/src/utils/utils.js index 3c3168f..a101176 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -6,3 +6,13 @@ export const isExternalUrl = (url) => { return false } + +export const stringifyObjects = (arr) => { + Object.keys(arr[0]).map((key) => { + if (typeof arr[0][key] === 'object') { + arr.map((el) => { + el[key] = JSON.stringify(el[key], null, 2) + }) + } + }) +} From 1cb48e14a7ac38be60ba390ebd67cdeb239791f4 Mon Sep 17 00:00:00 2001 From: Tito Date: Mon, 5 Apr 2021 09:39:59 -0300 Subject: [PATCH 02/11] feat(generalstats): addition of filtering elements --- src/assets/images/chevronDownBlack.png | Bin 0 -> 272 bytes src/components/UI/Dropdown/Dropdown.jsx | 39 +++++++++++++++ src/components/UI/Dropdown/styles.js | 62 ++++++++++++++++++++++++ src/components/UI/Dropdown/test.jsx | 21 ++++++++ src/components/UI/index.js | 1 + src/pages/GeneralStats/GeneralStats.jsx | 60 +++++++++++++++++++++++ 6 files changed, 183 insertions(+) create mode 100644 src/assets/images/chevronDownBlack.png create mode 100644 src/components/UI/Dropdown/Dropdown.jsx create mode 100644 src/components/UI/Dropdown/styles.js create mode 100644 src/components/UI/Dropdown/test.jsx diff --git a/src/assets/images/chevronDownBlack.png b/src/assets/images/chevronDownBlack.png new file mode 100644 index 0000000000000000000000000000000000000000..589c0943e6ce1662895725548e7891b148d3b148 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#rJgR1Ar*{oC))BIGT?E`RW9u7>FHT>r>R%@ zfZz@$_k_n{v67P3&t#@bU0bc)C><0>EuJE0k9__(i6L9+d|M${Y zrJAf&e`J_0VNJ0#un|t0>Y8d9cIolz^`QaGQZHksY2@>qo)F0AIIF`sSFqG&=H!k( zVL`+A-`9PgZVK0ae3M6`mB-wtDENSuO7fK1%xQ``|C6U!_iYxI-SHzl { + return ( + + {label && {label}} + + + + Selecione o(s) tipo(s) + {options && + options.map((option, index) => ( + + {option.text} + + ))} + + + + + ) +} + +Dropdown.propTypes = { + className: PropTypes.string, + label: PropTypes.string, + options: PropTypes.array +} + +Dropdown.defaultProps = { + className: 'dropdown' +} + +export default Dropdown diff --git a/src/components/UI/Dropdown/styles.js b/src/components/UI/Dropdown/styles.js new file mode 100644 index 0000000..9dde6c9 --- /dev/null +++ b/src/components/UI/Dropdown/styles.js @@ -0,0 +1,62 @@ +import styled, { css } from 'styled-components' + +export const Wrapper = styled.div` + ${({ theme }) => css` + color: ${theme.colors.black}; + display: flex; + flex-direction: column; + margin-bottom: 1.6rem; + padding: 20px; + position: relative; + `} +` + +export const Label = styled.label` + color: #2e3a59; + font-size: 1.2rem; + font-weight: bold; + line-height: 1.6; + margin-bottom: 0.4rem; + text-transform: uppercase; +` + +export const DropdownContent = styled.div` + position: relative; +` + +export const Select = styled.select` + appearance: none; + background: #ffffff; + border: 2px solid #e4e9f2; + border-radius: 3px; + color: #c5cef4; + display: flex; + flex-direction: column; + font-size: 1.6rem; + font-weight: 400; + overflow: hidden; + padding: 1.2rem 0 1.2rem 0.8rem; + width: 100%; + + &:focus, + &:active { + border-color: #598bff; + } +` + +export const DropdownOption = styled.option` + color: #c5cef4; + font-size: 1.5rem; + font-weight: 700; + line-height: 2.4rem; +` + +export const DropdownIcon = styled.img` + height: auto; + pointer-events: none; + position: absolute; + right: 1rem; + top: 50%; + transform: translateY(-50%); + width: 2.5rem; +` diff --git a/src/components/UI/Dropdown/test.jsx b/src/components/UI/Dropdown/test.jsx new file mode 100644 index 0000000..c49cf98 --- /dev/null +++ b/src/components/UI/Dropdown/test.jsx @@ -0,0 +1,21 @@ +import React from 'react' + +import { renderWithTheme } from 'utils/tests/helpers' + +import { screen } from '@testing-library/react' + +import Dropdown from './index' + +describe('', () => { + it('should render the heading', () => { + renderWithTheme() + + expect(screen.getByRole('heading', { name: /Dropdown/i })).toBeInTheDocument() + }) + + it('should render the colors correctly', () => { + const { container } = renderWithTheme() + + expect(container.firstChild).toHaveStyle({ color: '#222222' }) + }) +}) diff --git a/src/components/UI/index.js b/src/components/UI/index.js index f83fd18..2084742 100644 --- a/src/components/UI/index.js +++ b/src/components/UI/index.js @@ -3,3 +3,4 @@ export { default as Link } from './Link/Link' export { default as Spinner } from './Spinner/Spinner' export { default as TextField } from './TextField/TextField' export { default as Tooltip } from './Tooltip/Tooltip' +export { default as Dropdown } from './Dropdown/Dropdown' diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index f8d71ea..0ce122e 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -9,18 +9,78 @@ import * as S from './styles' const GeneralStats = ({ className, ...props }) => { const [generalStatsData, setGeneralStatsData] = useState('') + const [searchString, setSearchString] = useState('') + const [generalStatsDataDefault, setGeneralStatsDataDefault] = useState('') const loadData = async () => { const generalStatsResponse = await API.loadGeneralStats() UTIL.stringifyObjects(generalStatsResponse) setGeneralStatsData(generalStatsResponse) + setGeneralStatsDataDefault(generalStatsResponse) + } + + const onSearchbarChangeHandler = (enteredText) => { + setSearchString(enteredText) + + // console.log('[GeneralStats] searchString: ', searchString) + // console.log('[GeneralStats] e.target.value: ', enteredText) + + const searchStringRegex = new RegExp(enteredText, 'i') + if (enteredText !== '') { + setGeneralStatsData( + [...generalStatsDataDefault].filter( + (el) => + searchStringRegex.test(el.id) || + searchStringRegex.test(el.name) || + searchStringRegex.test(el.username) || + searchStringRegex.test(el.address) + ) + ) + } else { + setGeneralStatsData(generalStatsDataDefault) + } + } + + const handleDropdownChange = (value) => { + // console.log('[GeneralStats] value: ', value) + const searchStringRegex = new RegExp(options[value - 1]?.text, 'i') + if (options[value - 1]) { + setGeneralStatsData( + [...generalStatsDataDefault].filter( + (el) => + searchStringRegex.test(el.id) || + searchStringRegex.test(el.name) || + searchStringRegex.test(el.username) || + searchStringRegex.test(el.address) + ) + ) + } else { + setGeneralStatsData(generalStatsDataDefault) + } } useEffect(() => loadData(), []) + const options = [ + { value: '1', text: 'Bret' }, + { value: '2', text: 'Delphine' } + ] + return (

General Stats

+ onSearchbarChangeHandler(e.target.value)} + value={searchString} + /> + handleDropdownChange(e.target.value)} + /> From f2c095e3236db16bc563e358ef530398e91141fb Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 7 Apr 2021 10:31:51 -0300 Subject: [PATCH 03/11] feat(generalstats): date filters added Date range picker and single date picker filters --- package.json | 1 + .../GeneralStatsGrid/GeneralStatsGrid.jsx | 3 +- src/pages/GeneralStats/GeneralStats.jsx | 97 +++++++-- src/utils/utils.js | 13 ++ yarn.lock | 204 +++++++++++++++++- 5 files changed, 284 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 32b1304..48c2445 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "polished": "^4.1.1", "prop-types": "^15.7.2", "react": "^17.0.1", + "react-dates": "^21.8.0", "react-dom": "^17.0.1", "react-icons": "^3.11.0", "react-notifications-component": "^3.0.5", diff --git a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx index ddaaf51..858c98b 100644 --- a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx +++ b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx @@ -15,7 +15,8 @@ const GeneralStatsGrid = ({ className, ...props }) => { { headerName: 'Name', field: 'name' }, { headerName: 'Username', field: 'username' }, { headerName: 'E-mail', field: 'email' }, - { headerName: 'Address', field: 'address' } + { headerName: 'Address', field: 'address' }, + { headerName: 'Created at', field: 'createdAt' } ] } diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index 0ce122e..c4f6640 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -1,4 +1,7 @@ import React, { useState, useEffect } from 'react' +import 'react-dates/initialize' +import 'react-dates/lib/css/_datepicker.css' +import { DateRangePicker, SingleDatePicker } from 'react-dates' import * as C from 'components' import PropTypes from 'prop-types' @@ -12,28 +15,37 @@ const GeneralStats = ({ className, ...props }) => { const [searchString, setSearchString] = useState('') const [generalStatsDataDefault, setGeneralStatsDataDefault] = useState('') + const [startDate, setStartDate] = useState(null) + const [endDate, setEndDate] = useState(null) + const [focusedInput, setFocusedInput] = useState(null) + + const [singleDate, setSingleDate] = useState(null) + const [focused, setFocused] = useState(false) + + const options = [ + { value: '1', text: 'Bret' }, + { value: '2', text: 'Delphine' } + ] + const loadData = async () => { const generalStatsResponse = await API.loadGeneralStats() UTIL.stringifyObjects(generalStatsResponse) setGeneralStatsData(generalStatsResponse) setGeneralStatsDataDefault(generalStatsResponse) + generalStatsResponse.map((el) => (el.createdAt = new Date())) } const onSearchbarChangeHandler = (enteredText) => { setSearchString(enteredText) - - // console.log('[GeneralStats] searchString: ', searchString) - // console.log('[GeneralStats] e.target.value: ', enteredText) - const searchStringRegex = new RegExp(enteredText, 'i') + const keys = Object.keys(generalStatsDataDefault[0]) + if (enteredText !== '') { setGeneralStatsData( [...generalStatsDataDefault].filter( (el) => - searchStringRegex.test(el.id) || - searchStringRegex.test(el.name) || - searchStringRegex.test(el.username) || - searchStringRegex.test(el.address) + searchStringRegex.test(keys.map((key) => el[key])) || + searchStringRegex.test(JSON.stringify(el.createdAt)) ) ) } else { @@ -41,17 +53,13 @@ const GeneralStats = ({ className, ...props }) => { } } - const handleDropdownChange = (value) => { - // console.log('[GeneralStats] value: ', value) + const onDropdownChangeHandler = (value) => { const searchStringRegex = new RegExp(options[value - 1]?.text, 'i') + const keys = Object.keys(generalStatsDataDefault[0]) if (options[value - 1]) { setGeneralStatsData( - [...generalStatsDataDefault].filter( - (el) => - searchStringRegex.test(el.id) || - searchStringRegex.test(el.name) || - searchStringRegex.test(el.username) || - searchStringRegex.test(el.address) + [...generalStatsDataDefault].filter((el) => + searchStringRegex.test(keys.map((key) => el[key])) ) ) } else { @@ -59,12 +67,35 @@ const GeneralStats = ({ className, ...props }) => { } } - useEffect(() => loadData(), []) + const onDatesChangeHandler = (dates) => { + setStartDate(dates.startDate) + setEndDate(dates.endDate) + if (dates.endDate) { + setGeneralStatsData( + [...generalStatsDataDefault].filter((el) => { + return UTIL.isDateBetweenDays( + dates.startDate?._d, + dates.endDate?._d, + el.createdAt + ) + }) + ) + } + } - const options = [ - { value: '1', text: 'Bret' }, - { value: '2', text: 'Delphine' } - ] + const onSingleDateChangeHandler = (date) => { + setSingleDate(date.date) + + if (date.date) { + setGeneralStatsData( + [...generalStatsDataDefault].filter((el) => { + return UTIL.areDatesOnSameDay(date.date?._d, el.createdAt) + }) + ) + } + } + + useEffect(() => loadData(), []) return ( @@ -72,14 +103,34 @@ const GeneralStats = ({ className, ...props }) => { onSearchbarChangeHandler(e.target.value)} value={searchString} /> handleDropdownChange(e.target.value)} + onChange={(e) => onDropdownChangeHandler(e.target.value)} + /> + { + onDatesChangeHandler({ startDate, endDate }) + }} + focusedInput={focusedInput} + onFocusChange={(focusedInput) => setFocusedInput(focusedInput)} + isOutsideRange={() => false} + /> + onSingleDateChangeHandler({ date })} + focused={focused} + onFocusChange={({ focused }) => setFocused(focused)} + id="unique_id" + isOutsideRange={() => false} /> diff --git a/src/utils/utils.js b/src/utils/utils.js index a101176..d0ca64a 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -16,3 +16,16 @@ export const stringifyObjects = (arr) => { } }) } + +export const isDateBetweenDays = (first, last, date) => + first.getFullYear() <= date.getFullYear() && + date.getFullYear() <= last.getFullYear() && + first.getMonth() <= date.getMonth() && + date.getMonth() <= last.getMonth() && + first.getDate() <= date.getDate() && + date.getDate() <= last.getDate() + +export const areDatesOnSameDay = (first, second) => + first.getFullYear() === second.getFullYear() && + first.getMonth() === second.getMonth() && + first.getDate() === second.getDate() diff --git a/yarn.lock b/yarn.lock index a0ffe1a..481f54b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2642,6 +2642,21 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +airbnb-prop-types@^2.10.0, airbnb-prop-types@^2.14.0, airbnb-prop-types@^2.15.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz#b96274cefa1abb14f623f804173ee97c13971dc2" + integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg== + dependencies: + array.prototype.find "^2.1.1" + function.prototype.name "^1.1.2" + is-regex "^1.1.0" + object-is "^1.1.2" + object.assign "^4.1.0" + object.entries "^1.1.2" + prop-types "^15.7.2" + prop-types-exact "^1.2.0" + react-is "^16.13.1" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -2917,7 +2932,15 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.3: +array.prototype.find@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.1.tgz#3baca26108ca7affb08db06bf0be6cb3115a969c" + integrity sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.4" + +array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== @@ -3862,6 +3885,11 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +brcast@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brcast/-/brcast-2.0.2.tgz#2db16de44140e418dc37fab10beec0369e78dcef" + integrity sha512-Tfn5JSE7hrUlFcOoaLzVvkbgIemIorMIyoMr3TgvszWW7jFt2C9PdeMLtysYD9RU0MmU17b69+XJG1eRY2OBRg== + brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -4807,6 +4835,11 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== +"consolidated-events@^1.1.1 || ^2.0.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/consolidated-events/-/consolidated-events-2.0.2.tgz#da8d8f8c2b232831413d9e190dc11669c79f4a91" + integrity sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ== + constant-case@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" @@ -5468,6 +5501,11 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" + integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -5633,6 +5671,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +direction@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442" + integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ== + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -5675,6 +5718,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +document.contains@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/document.contains/-/document.contains-1.0.2.tgz#4260abad67a6ae9e135c1be83d68da0db169d5f0" + integrity sha512-YcvYFs15mX8m3AO1QNQy3BlIpSMfNRj3Ujk2BEJxsZG+HZf7/hZ6jr7mDpXrF8q+ff95Vef5yjhiZxm8CGJr6Q== + dependencies: + define-properties "^1.1.3" + dom-accessibility-api@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166" @@ -5950,6 +6000,14 @@ env-cmd@^10.1.0: commander "^4.0.0" cross-spawn "^7.0.0" +enzyme-shallow-equal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz#b9256cb25a5f430f9bfe073a84808c1d74fced2e" + integrity sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q== + dependencies: + has "^1.0.3" + object-is "^1.1.2" + equal-length@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/equal-length/-/equal-length-1.0.1.tgz#21ca112d48ab24b4e1e7ffc0e5339d31fdfc274c" @@ -5976,7 +6034,7 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" -es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: +es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: version "1.18.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== @@ -7096,11 +7154,26 @@ function-name-support@^0.2.0: resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071" integrity sha1-VdO/qm6v1QWlD5vIH99XVkoLsHE= +function.prototype.name@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.4.tgz#e4ea839b9d3672ae99d0efd9f38d9191c5eaac83" + integrity sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + functions-have-names "^1.2.2" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +functions-have-names@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" + integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== + gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -7251,6 +7324,14 @@ glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +global-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/global-cache/-/global-cache-1.2.1.tgz#39ca020d3dd7b3f0934c52b75363f8d53312c16d" + integrity sha512-EOeUaup5DgWKlCMhA9YFqNRIlZwoxt731jCh47WBV9fQqHgXhr3Fa55hfgIUqilIcPsfdNKN7LHjrNY+Km40KA== + dependencies: + define-properties "^1.1.2" + is-symbol "^1.0.1" + global-dirs@^0.1.0, global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -7590,7 +7671,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.1, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -8538,7 +8619,7 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= -is-regex@^1.0.4, is-regex@^1.1.2: +is-regex@^1.0.4, is-regex@^1.1.0, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== @@ -8600,7 +8681,7 @@ is-svg@^3.0.0: dependencies: html-comment-regex "^1.1.0" -is-symbol@^1.0.2, is-symbol@^1.0.3: +is-symbol@^1.0.1, is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== @@ -8614,6 +8695,11 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" +is-touch-device@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-touch-device/-/is-touch-device-1.0.1.tgz#9a2fd59f689e9a9bf6ae9a86924c4ba805a42eab" + integrity sha512-LAYzo9kMT1b2p19L/1ATGt2XcSilnzNlyvq6c0pbPRVisLbAPpLqr53tIJS00kvrTkj0HtR8U7+u8X0yR8lPSw== + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -9756,7 +9842,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.1.1, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.17.5: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10346,6 +10432,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +moment@>=1.6.0: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -10680,7 +10771,7 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== -object-is@^1.0.1: +object-is@^1.0.1, object-is@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== @@ -10772,7 +10863,7 @@ object.pick@^1.2.0, object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.0, object.values@^1.1.1: +object.values@^1.0.4, object.values@^1.1.0, object.values@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== @@ -12311,7 +12402,16 @@ prompts@2.4.0, prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types-exact@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869" + integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== + dependencies: + has "^1.0.3" + object.assign "^4.1.0" + reflect.ownkeys "^0.2.0" + +prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -12516,6 +12616,27 @@ react-app-polyfill@^2.0.0: regenerator-runtime "^0.13.7" whatwg-fetch "^3.4.1" +react-dates@^21.8.0: + version "21.8.0" + resolved "https://registry.yarnpkg.com/react-dates/-/react-dates-21.8.0.tgz#355c3c7a243a7c29568fe00aca96231e171a5e94" + integrity sha512-PPriGqi30CtzZmoHiGdhlA++YPYPYGCZrhydYmXXQ6RAvAsaONcPtYgXRTLozIOrsQ5mSo40+DiA5eOFHnZ6xw== + dependencies: + airbnb-prop-types "^2.15.0" + consolidated-events "^1.1.1 || ^2.0.0" + enzyme-shallow-equal "^1.0.0" + is-touch-device "^1.0.1" + lodash "^4.1.1" + object.assign "^4.1.0" + object.values "^1.1.0" + prop-types "^15.7.2" + raf "^3.4.1" + react-moment-proptypes "^1.6.0" + react-outside-click-handler "^1.2.4" + react-portal "^4.2.0" + react-with-direction "^1.3.1" + react-with-styles "^4.1.0" + react-with-styles-interface-css "^6.0.0" + react-dev-utils@^11.0.1: version "11.0.3" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.3.tgz#b61ed499c7d74f447d4faddcc547e5e671e97c08" @@ -12567,7 +12688,7 @@ react-icons@^3.11.0: dependencies: camelcase "^5.0.0" -react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -12582,11 +12703,36 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== +react-moment-proptypes@^1.6.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/react-moment-proptypes/-/react-moment-proptypes-1.8.1.tgz#7ba4076147f6b5998f0d4f51d302d6d8c62049fd" + integrity sha512-Er940DxWoObfIqPrZNfwXKugjxMIuk1LAuEzn23gytzV6hKS/sw108wibi9QubfMN4h+nrlje8eUCSbQRJo2fQ== + dependencies: + moment ">=1.6.0" + react-notifications-component@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/react-notifications-component/-/react-notifications-component-3.0.5.tgz#c31fad21cb827658063b32444b1061ad5d0d50d1" integrity sha512-75rg/Sa+8REX2lJ742OCXwKrc/ZBXfgcoJ70eIGkJ3naBGvYXkIkroRnIpo6VCrK4uKiT45dhHgK6TzJGU4ckw== +react-outside-click-handler@^1.2.4: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz#3831d541ac059deecd38ec5423f81e80ad60e115" + integrity sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ== + dependencies: + airbnb-prop-types "^2.15.0" + consolidated-events "^1.1.1 || ^2.0.0" + document.contains "^1.0.1" + object.values "^1.1.0" + prop-types "^15.7.2" + +react-portal@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.2.1.tgz#12c1599238c06fb08a9800f3070bea2a3f78b1a6" + integrity sha512-fE9kOBagwmTXZ3YGRYb4gcMy+kSA+yLO0xnPankjRlfBv4uCpFXqKPfkpsGQQR15wkZ9EssnvTOl1yMzbkxhPQ== + dependencies: + prop-types "^15.5.8" + react-refresh@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" @@ -12697,6 +12843,39 @@ react-transition-group@^4.4.0: loose-envify "^1.4.0" prop-types "^15.6.2" +react-with-direction@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/react-with-direction/-/react-with-direction-1.3.1.tgz#9fd414564f0ffe6947e5ff176f6132dd83f8b8df" + integrity sha512-aGcM21ZzhqeXFvDCfPj0rVNYuaVXfTz5D3Rbn0QMz/unZe+CCiLHthrjQWO7s6qdfXORgYFtmS7OVsRgSk5LXQ== + dependencies: + airbnb-prop-types "^2.10.0" + brcast "^2.0.2" + deepmerge "^1.5.2" + direction "^1.0.2" + hoist-non-react-statics "^3.3.0" + object.assign "^4.1.0" + object.values "^1.0.4" + prop-types "^15.6.2" + +react-with-styles-interface-css@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/react-with-styles-interface-css/-/react-with-styles-interface-css-6.0.0.tgz#b53da7fa8359d452cb934cface8738acaef7b5fe" + integrity sha512-6khSG1Trf4L/uXOge/ZAlBnq2O2PEXlQEqAhCRbvzaQU4sksIkdwpCPEl6d+DtP3+IdhyffTWuHDO9lhe1iYvA== + dependencies: + array.prototype.flat "^1.2.1" + global-cache "^1.2.1" + +react-with-styles@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/react-with-styles/-/react-with-styles-4.1.0.tgz#4bfc2daa92dd72033fc19fd861b90225a682a640" + integrity sha512-zp05fyA6XFetqr07ox/a0bCFyEj//gUozI9cC1GW59zaGJ38STnxYvzotutgpzMyHOd7TFW9ZiZeBKjsYaS+RQ== + dependencies: + airbnb-prop-types "^2.14.0" + hoist-non-react-statics "^3.2.1" + object.assign "^4.1.0" + prop-types "^15.7.2" + react-with-direction "^1.3.1" + react@^17.0.1: version "17.0.1" resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127" @@ -12826,6 +13005,11 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reflect.ownkeys@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" + integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" From bf06dbc3aeb58a6d4848050dcddd6d87c8623842 Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 14 Apr 2021 08:25:18 -0300 Subject: [PATCH 04/11] feat(generalstats): query strings are built from filter elements input --- src/pages/GeneralStats/GeneralStats.jsx | 77 ++++++++----------- src/pages/GeneralStats/index.jsx | 71 ----------------- .../Endpoints/GeneralStats/GeneralStats.js | 48 ++++++++++-- src/utils/utils.js | 16 ++-- 4 files changed, 84 insertions(+), 128 deletions(-) delete mode 100644 src/pages/GeneralStats/index.jsx diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index c4f6640..3b30a2d 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react' import 'react-dates/initialize' import 'react-dates/lib/css/_datepicker.css' import { DateRangePicker, SingleDatePicker } from 'react-dates' +import { useHistory } from 'react-router' import * as C from 'components' import PropTypes from 'prop-types' @@ -13,7 +14,6 @@ import * as S from './styles' const GeneralStats = ({ className, ...props }) => { const [generalStatsData, setGeneralStatsData] = useState('') const [searchString, setSearchString] = useState('') - const [generalStatsDataDefault, setGeneralStatsDataDefault] = useState('') const [startDate, setStartDate] = useState(null) const [endDate, setEndDate] = useState(null) @@ -27,82 +27,69 @@ const GeneralStats = ({ className, ...props }) => { { value: '2', text: 'Delphine' } ] - const loadData = async () => { - const generalStatsResponse = await API.loadGeneralStats() + const history = useHistory() + + const loadData = async (URLSearchParam) => { + const generalStatsResponse = await API.loadGeneralStats(URLSearchParam) UTIL.stringifyObjects(generalStatsResponse) + console.log('[GeneralStats] generalStatsResponse: ', generalStatsResponse) setGeneralStatsData(generalStatsResponse) - setGeneralStatsDataDefault(generalStatsResponse) - generalStatsResponse.map((el) => (el.createdAt = new Date())) } const onSearchbarChangeHandler = (enteredText) => { setSearchString(enteredText) - const searchStringRegex = new RegExp(enteredText, 'i') - const keys = Object.keys(generalStatsDataDefault[0]) if (enteredText !== '') { - setGeneralStatsData( - [...generalStatsDataDefault].filter( - (el) => - searchStringRegex.test(keys.map((key) => el[key])) || - searchStringRegex.test(JSON.stringify(el.createdAt)) - ) - ) - } else { - setGeneralStatsData(generalStatsDataDefault) + console.log('Searchbar') + const paramsString = `search=${enteredText}` + const searchParams = new URLSearchParams(paramsString) + loadData(searchParams) + history.push(`general_stats?${paramsString}`) } } const onDropdownChangeHandler = (value) => { - const searchStringRegex = new RegExp(options[value - 1]?.text, 'i') - const keys = Object.keys(generalStatsDataDefault[0]) if (options[value - 1]) { - setGeneralStatsData( - [...generalStatsDataDefault].filter((el) => - searchStringRegex.test(keys.map((key) => el[key])) - ) - ) - } else { - setGeneralStatsData(generalStatsDataDefault) + const paramsString = `username=${options[value - 1].text}` + const searchParams = new URLSearchParams(paramsString) + loadData(searchParams) + history.push(`general_stats?${paramsString}`) } } const onDatesChangeHandler = (dates) => { setStartDate(dates.startDate) setEndDate(dates.endDate) - if (dates.endDate) { - setGeneralStatsData( - [...generalStatsDataDefault].filter((el) => { - return UTIL.isDateBetweenDays( - dates.startDate?._d, - dates.endDate?._d, - el.createdAt - ) - }) - ) + const paramsString = `createdAt?start=${JSON.stringify( + dates.startDate?._d + )}&end=${JSON.stringify(dates.endDate?._d)}` + const searchParams = new URLSearchParams(paramsString) + loadData(searchParams) + + if (dates.startDate?._d && dates.endDate?._d) { + history.push(`general_stats?${paramsString}`) } } const onSingleDateChangeHandler = (date) => { setSingleDate(date.date) - - if (date.date) { - setGeneralStatsData( - [...generalStatsDataDefault].filter((el) => { - return UTIL.areDatesOnSameDay(date.date?._d, el.createdAt) - }) - ) - } + const paramsString = `createdAt=${JSON.stringify(date.date._d)}` + const searchParams = new URLSearchParams(paramsString) + loadData(searchParams) + history.push(`general_stats?${paramsString}`) } - useEffect(() => loadData(), []) + useEffect(() => { + loadData() + history.replace('/monitoring/general_stats', null) + }, []) return (

General Stats

onSearchbarChangeHandler(e.target.value)} value={searchString} diff --git a/src/pages/GeneralStats/index.jsx b/src/pages/GeneralStats/index.jsx deleted file mode 100644 index 2b72aff..0000000 --- a/src/pages/GeneralStats/index.jsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { useHistory } from 'react-router-dom' - -import axios from 'axios' -import Dropdown from 'components/Dropdown' -import GeneralStatsGrid from 'components/GeneralStatsGrid' -import Layout from 'components/Layout' -// import TextField from 'components/TextField' -import PropTypes from 'prop-types' - -import * as S from './styles' - -const GeneralStats = ({ className, ...props }) => { - const [gridData, setGridData] = useState('') - - const history = useHistory() - - const redirectPageHandler = () => { - history.push('edit_process') - } - - const stringifyObjects = (arr) => { - Object.keys(arr[0]).map((key) => { - if (typeof arr[0][key] === 'object') { - arr.map((el) => { - el[key] = JSON.stringify(el[key]) - }) - } - }) - } - - const getGridData = () => { - axios - .get('https://jsonplaceholder.typicode.com/users') - .then((response) => { - stringifyObjects(response.data) - setGridData(response.data) - }) - .catch((error) => console.log(error)) - } - - useEffect(() => getGridData(), []) - - const options = [ - { value: '1', text: 'option1' }, - { value: '2', text: 'option2' } - ] - return ( - -

General Stats

- {/* */} - - - redirectPageHandler()} - /> - -
- ) -} - -GeneralStats.propTypes = { - className: PropTypes.string -} - -GeneralStats.defaultProps = { - className: 'generalstats' -} - -export default GeneralStats diff --git a/src/services/Endpoints/GeneralStats/GeneralStats.js b/src/services/Endpoints/GeneralStats/GeneralStats.js index c7f636c..8210f37 100644 --- a/src/services/Endpoints/GeneralStats/GeneralStats.js +++ b/src/services/Endpoints/GeneralStats/GeneralStats.js @@ -1,9 +1,47 @@ import axios from 'axios' export const getGeneralStats = async (params = {}) => { - return axios.get('https://jsonplaceholder.typicode.com/users', { - params: { - ...params - } - }) + console.log('params: ', params) + const fields = ['id', 'name', 'username', 'email', 'address', 'createdAt'] + let queryString = null + + if (params instanceof URLSearchParams) { + fields.map((field) => { + if (params.has(field)) { + queryString = `https://604a26779251e100177ce0d3.mockapi.io/api/processes?${field}=${params.get( + field + )}` + } + }) + } + + if (queryString) { + return axios.get(queryString, { + params: { + ...params + } + }) + } else { + return axios.get( + `https://604a26779251e100177ce0d3.mockapi.io/api/processes`, + { + params: { + ...params + } + } + ) + } +} + +export const getEditProcess = async (params = {}) => { + if (params?.data) { + return axios.get( + `https://jsonplaceholder.typicode.com/users?id=${params.data.id}`, + { + params: { + ...params + } + } + ) + } } diff --git a/src/utils/utils.js b/src/utils/utils.js index d0ca64a..e93af98 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -8,13 +8,15 @@ export const isExternalUrl = (url) => { } export const stringifyObjects = (arr) => { - Object.keys(arr[0]).map((key) => { - if (typeof arr[0][key] === 'object') { - arr.map((el) => { - el[key] = JSON.stringify(el[key], null, 2) - }) - } - }) + if (arr[0]) { + Object.keys(arr[0]).map((key) => { + if (typeof arr[0][key] === 'object') { + arr.map((el) => { + el[key] = JSON.stringify(el[key], null, 2) + }) + } + }) + } } export const isDateBetweenDays = (first, last, date) => From 2b8836999d77f9704f6305fa1ac578fbabf07815 Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 14 Apr 2021 14:17:03 -0300 Subject: [PATCH 05/11] fix(editprocess): show query string on redirect and update url on page reload --- .../Grids/GeneralStatsGrid/GeneralStatsGrid.jsx | 4 ++-- src/pages/EditProcess/EditProcess.jsx | 13 +++++++------ src/pages/GeneralStats/GeneralStats.jsx | 2 -- .../Endpoints/EditProcess/EditProcess.js | 2 -- .../Endpoints/GeneralStats/GeneralStats.js | 16 +--------------- 5 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx index 858c98b..3ce9d25 100644 --- a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx +++ b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx @@ -23,8 +23,8 @@ const GeneralStatsGrid = ({ className, ...props }) => { const history = useHistory() const onCellClickedHandler = (event) => { - console.log('[GeneralStatsGrid] event: ', event) - history.push('edit_process', { data: event.data }) + const paramsString = `id=${event.data.id}` + history.push(`edit_process?${paramsString}`, { data: event.data }) } return ( diff --git a/src/pages/EditProcess/EditProcess.jsx b/src/pages/EditProcess/EditProcess.jsx index f8098cd..2a323fa 100644 --- a/src/pages/EditProcess/EditProcess.jsx +++ b/src/pages/EditProcess/EditProcess.jsx @@ -19,15 +19,16 @@ const EditProcess = ({ className, ...props }) => { ) UTIL.stringifyObjects(editProcessResponse) setProcessData(editProcessResponse) - history.replace('/monitoring/edit_process', null) } console.log('[EditProcess] props: ', props) - useEffect(() => loadData(props), []) - // console.log( - // '[EditProcess] props.location.state.data.id: ', - // props.location.state.data.id - // ) + loadData(props) + + useEffect(() => { + loadData(props) + // history.replace('/monitoring/edit_process', null) + history.replace(history.location, null) + }, []) return ( diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index 3b30a2d..2baedc8 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -32,7 +32,6 @@ const GeneralStats = ({ className, ...props }) => { const loadData = async (URLSearchParam) => { const generalStatsResponse = await API.loadGeneralStats(URLSearchParam) UTIL.stringifyObjects(generalStatsResponse) - console.log('[GeneralStats] generalStatsResponse: ', generalStatsResponse) setGeneralStatsData(generalStatsResponse) } @@ -40,7 +39,6 @@ const GeneralStats = ({ className, ...props }) => { setSearchString(enteredText) if (enteredText !== '') { - console.log('Searchbar') const paramsString = `search=${enteredText}` const searchParams = new URLSearchParams(paramsString) loadData(searchParams) diff --git a/src/services/Endpoints/EditProcess/EditProcess.js b/src/services/Endpoints/EditProcess/EditProcess.js index 72e594e..74ec146 100644 --- a/src/services/Endpoints/EditProcess/EditProcess.js +++ b/src/services/Endpoints/EditProcess/EditProcess.js @@ -2,7 +2,6 @@ import axios from 'axios' export const getEditProcess = async (params = {}) => { if (params?.data) { - // console.log('[EditProcess - Endpoints] state: ', params) return axios.get( `https://jsonplaceholder.typicode.com/users?id=${params.data.id}`, { @@ -12,7 +11,6 @@ export const getEditProcess = async (params = {}) => { } ) } else { - // console.log('[EditProcess - Endpoints] state: ', params) return axios.get('https://jsonplaceholder.typicode.com/users', { params: { ...params diff --git a/src/services/Endpoints/GeneralStats/GeneralStats.js b/src/services/Endpoints/GeneralStats/GeneralStats.js index 8210f37..295bc85 100644 --- a/src/services/Endpoints/GeneralStats/GeneralStats.js +++ b/src/services/Endpoints/GeneralStats/GeneralStats.js @@ -1,7 +1,6 @@ import axios from 'axios' export const getGeneralStats = async (params = {}) => { - console.log('params: ', params) const fields = ['id', 'name', 'username', 'email', 'address', 'createdAt'] let queryString = null @@ -23,20 +22,7 @@ export const getGeneralStats = async (params = {}) => { }) } else { return axios.get( - `https://604a26779251e100177ce0d3.mockapi.io/api/processes`, - { - params: { - ...params - } - } - ) - } -} - -export const getEditProcess = async (params = {}) => { - if (params?.data) { - return axios.get( - `https://jsonplaceholder.typicode.com/users?id=${params.data.id}`, + 'https://604a26779251e100177ce0d3.mockapi.io/api/processes', { params: { ...params From f5c6be35af5ae58c43125acec8510c8eed09a2d8 Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 14 Apr 2021 14:21:48 -0300 Subject: [PATCH 06/11] style(editprocess): removed comment --- src/pages/EditProcess/EditProcess.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/EditProcess/EditProcess.jsx b/src/pages/EditProcess/EditProcess.jsx index 2a323fa..53e38b9 100644 --- a/src/pages/EditProcess/EditProcess.jsx +++ b/src/pages/EditProcess/EditProcess.jsx @@ -26,7 +26,6 @@ const EditProcess = ({ className, ...props }) => { useEffect(() => { loadData(props) - // history.replace('/monitoring/edit_process', null) history.replace(history.location, null) }, []) From 3cffd6a87bcc0f2fc5ed803184cb26e4732bd863 Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 14 Apr 2021 16:40:48 -0300 Subject: [PATCH 07/11] fix(generalstats and editprocess): changed UTIL import path --- src/pages/EditProcess/EditProcess.jsx | 6 ++--- src/pages/GeneralStats/GeneralStats.jsx | 8 +++---- yarn.lock | 30 +++++++++++++++++++------ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/pages/EditProcess/EditProcess.jsx b/src/pages/EditProcess/EditProcess.jsx index 53e38b9..0e14258 100644 --- a/src/pages/EditProcess/EditProcess.jsx +++ b/src/pages/EditProcess/EditProcess.jsx @@ -4,7 +4,7 @@ import { useHistory } from 'react-router' import * as C from 'components' import PropTypes from 'prop-types' import * as API from 'services/Loaders' -import * as UTIL from 'utils' +import * as UTIL from 'utils/components/utils' import * as S from './styles' @@ -42,11 +42,11 @@ const EditProcess = ({ className, ...props }) => { EditProcess.propTypes = { className: PropTypes.string, location: PropTypes.object, - state: PropTypes.object + state: PropTypes.object, } EditProcess.defaultProps = { - className: 'editprocess' + className: 'editprocess', } export default EditProcess diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index 2baedc8..0f0f96e 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -7,7 +7,7 @@ import { useHistory } from 'react-router' import * as C from 'components' import PropTypes from 'prop-types' import * as API from 'services/Loaders' -import * as UTIL from 'utils' +import * as UTIL from 'utils/components/utils' import * as S from './styles' @@ -24,7 +24,7 @@ const GeneralStats = ({ className, ...props }) => { const options = [ { value: '1', text: 'Bret' }, - { value: '2', text: 'Delphine' } + { value: '2', text: 'Delphine' }, ] const history = useHistory() @@ -125,11 +125,11 @@ const GeneralStats = ({ className, ...props }) => { } GeneralStats.propTypes = { - className: PropTypes.string + className: PropTypes.string, } GeneralStats.defaultProps = { - className: 'generalstats' + className: 'generalstats', } export default GeneralStats diff --git a/yarn.lock b/yarn.lock index 2f0c051..1d1cd99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1409,6 +1409,17 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== +"@emotion/cache@^11.0.0", "@emotion/cache@^11.1.3": + version "11.1.3" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.1.3.tgz#c7683a9484bcd38d5562f2b9947873cf66829afd" + integrity sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.0.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "^4.0.3" + "@emotion/hash@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" @@ -10159,6 +10170,11 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memoize-one@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" + integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== + memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -12782,13 +12798,6 @@ react-outside-click-handler@^1.2.4: object.values "^1.1.0" prop-types "^15.7.2" -react-portal@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.2.1.tgz#12c1599238c06fb08a9800f3070bea2a3f78b1a6" - integrity sha512-fE9kOBagwmTXZ3YGRYb4gcMy+kSA+yLO0xnPankjRlfBv4uCpFXqKPfkpsGQQR15wkZ9EssnvTOl1yMzbkxhPQ== - dependencies: - prop-types "^15.5.8" - react-perfect-scrollbar@^1.5.8: version "1.5.8" resolved "https://registry.yarnpkg.com/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz#380959387a325c5c9d0268afc08b3f73ed5b3078" @@ -12797,6 +12806,13 @@ react-perfect-scrollbar@^1.5.8: perfect-scrollbar "^1.5.0" prop-types "^15.6.1" +react-portal@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.2.1.tgz#12c1599238c06fb08a9800f3070bea2a3f78b1a6" + integrity sha512-fE9kOBagwmTXZ3YGRYb4gcMy+kSA+yLO0xnPankjRlfBv4uCpFXqKPfkpsGQQR15wkZ9EssnvTOl1yMzbkxhPQ== + dependencies: + prop-types "^15.5.8" + react-refresh@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" From 083ff10096ff506825d368a904c356b0b700b1c5 Mon Sep 17 00:00:00 2001 From: Tito Date: Wed, 14 Apr 2021 23:17:10 -0300 Subject: [PATCH 08/11] fix(editprocess): removed call to loadData on every update --- .../GeneralStatsGrid/GeneralStatsGrid.jsx | 17 +++++------- src/pages/EditProcess/EditProcess.jsx | 27 +++++-------------- src/pages/GeneralStats/GeneralStats.jsx | 14 ++-------- 3 files changed, 14 insertions(+), 44 deletions(-) diff --git a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx index 3ce9d25..247dc74 100644 --- a/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx +++ b/src/components/Grids/GeneralStatsGrid/GeneralStatsGrid.jsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types' import * as S from './styles' -const GeneralStatsGrid = ({ className, ...props }) => { +const GeneralStatsGrid = ({ rowData }) => { const gridOptions = { columnDefs: [ { headerName: 'ID', field: 'id' }, @@ -16,8 +16,8 @@ const GeneralStatsGrid = ({ className, ...props }) => { { headerName: 'Username', field: 'username' }, { headerName: 'E-mail', field: 'email' }, { headerName: 'Address', field: 'address' }, - { headerName: 'Created at', field: 'createdAt' } - ] + { headerName: 'Created at', field: 'createdAt' }, + ], } const history = useHistory() @@ -28,10 +28,10 @@ const GeneralStatsGrid = ({ className, ...props }) => { } return ( - +
onCellClickedHandler(event)} /> @@ -41,12 +41,7 @@ const GeneralStatsGrid = ({ className, ...props }) => { } GeneralStatsGrid.propTypes = { - className: PropTypes.string, - rowData: PropTypes.any -} - -GeneralStatsGrid.defaultProps = { - className: 'generalstatsgrid' + rowData: PropTypes.any, } export default GeneralStatsGrid diff --git a/src/pages/EditProcess/EditProcess.jsx b/src/pages/EditProcess/EditProcess.jsx index 0e14258..bfba772 100644 --- a/src/pages/EditProcess/EditProcess.jsx +++ b/src/pages/EditProcess/EditProcess.jsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react' -import { useHistory } from 'react-router' import * as C from 'components' import PropTypes from 'prop-types' @@ -8,29 +7,21 @@ import * as UTIL from 'utils/components/utils' import * as S from './styles' -const EditProcess = ({ className, ...props }) => { +const EditProcess = ({ location }) => { const [processData, setProcessData] = useState('') - const history = useHistory() - - const loadData = async (props) => { - const editProcessResponse = await API.loadEditProcess( - props?.location?.state - ) + const loadData = async (location) => { + const editProcessResponse = await API.loadEditProcess(location?.state) UTIL.stringifyObjects(editProcessResponse) setProcessData(editProcessResponse) } - console.log('[EditProcess] props: ', props) - - loadData(props) useEffect(() => { - loadData(props) - history.replace(history.location, null) - }, []) + loadData(location) + }, [location]) return ( - +

Edit Process

@@ -40,13 +31,7 @@ const EditProcess = ({ className, ...props }) => { } EditProcess.propTypes = { - className: PropTypes.string, location: PropTypes.object, - state: PropTypes.object, -} - -EditProcess.defaultProps = { - className: 'editprocess', } export default EditProcess diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index 0f0f96e..d325990 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -5,13 +5,12 @@ import { DateRangePicker, SingleDatePicker } from 'react-dates' import { useHistory } from 'react-router' import * as C from 'components' -import PropTypes from 'prop-types' import * as API from 'services/Loaders' import * as UTIL from 'utils/components/utils' import * as S from './styles' -const GeneralStats = ({ className, ...props }) => { +const GeneralStats = () => { const [generalStatsData, setGeneralStatsData] = useState('') const [searchString, setSearchString] = useState('') @@ -79,7 +78,6 @@ const GeneralStats = ({ className, ...props }) => { useEffect(() => { loadData() - history.replace('/monitoring/general_stats', null) }, []) return ( @@ -117,19 +115,11 @@ const GeneralStats = ({ className, ...props }) => { id="unique_id" isOutsideRange={() => false} /> - +
) } -GeneralStats.propTypes = { - className: PropTypes.string, -} - -GeneralStats.defaultProps = { - className: 'generalstats', -} - export default GeneralStats From f97f2437cf8edf8233ce4fe99ea6e81f08fb2f99 Mon Sep 17 00:00:00 2001 From: Tito Date: Thu, 15 Apr 2021 09:06:31 -0300 Subject: [PATCH 09/11] refactor(generalstats): created state variable to store all the other states --- src/pages/GeneralStats/GeneralStats.jsx | 81 ++++++++++++++++++------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index d325990..87d2d7b 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -11,15 +11,15 @@ import * as UTIL from 'utils/components/utils' import * as S from './styles' const GeneralStats = () => { - const [generalStatsData, setGeneralStatsData] = useState('') - const [searchString, setSearchString] = useState('') - - const [startDate, setStartDate] = useState(null) - const [endDate, setEndDate] = useState(null) - const [focusedInput, setFocusedInput] = useState(null) - - const [singleDate, setSingleDate] = useState(null) - const [focused, setFocused] = useState(false) + const [state, setState] = useState({ + generalStatsData: [], + searchString: '', + startDate: null, + endDate: null, + focusedInput: null, + singleDate: null, + focused: false, + }) const options = [ { value: '1', text: 'Bret' }, @@ -31,11 +31,21 @@ const GeneralStats = () => { const loadData = async (URLSearchParam) => { const generalStatsResponse = await API.loadGeneralStats(URLSearchParam) UTIL.stringifyObjects(generalStatsResponse) - setGeneralStatsData(generalStatsResponse) + setState((prevState) => { + return { + ...prevState, + generalStatsData: generalStatsResponse, + } + }) } const onSearchbarChangeHandler = (enteredText) => { - setSearchString(enteredText) + setState((prevState) => { + return { + ...prevState, + searchString: enteredText, + } + }) if (enteredText !== '') { const paramsString = `search=${enteredText}` @@ -55,8 +65,14 @@ const GeneralStats = () => { } const onDatesChangeHandler = (dates) => { - setStartDate(dates.startDate) - setEndDate(dates.endDate) + setState((prevState) => { + return { + ...prevState, + startDate: dates.startDate, + endDate: dates.endDate, + } + }) + const paramsString = `createdAt?start=${JSON.stringify( dates.startDate?._d )}&end=${JSON.stringify(dates.endDate?._d)}` @@ -69,7 +85,12 @@ const GeneralStats = () => { } const onSingleDateChangeHandler = (date) => { - setSingleDate(date.date) + setState((prevState) => { + return { + ...prevState, + singleDate: date.date, + } + }) const paramsString = `createdAt=${JSON.stringify(date.date._d)}` const searchParams = new URLSearchParams(paramsString) loadData(searchParams) @@ -88,7 +109,7 @@ const GeneralStats = () => { placeholder="Searchbar" type="text" onChange={(e) => onSearchbarChangeHandler(e.target.value)} - value={searchString} + value={state.searchString} /> { { onDatesChangeHandler({ startDate, endDate }) }} - focusedInput={focusedInput} - onFocusChange={(focusedInput) => setFocusedInput(focusedInput)} + focusedInput={state.focusedInput} + onFocusChange={(focusedInput) => + setState((prevState) => { + return { + ...prevState, + focusedInput: focusedInput, + } + }) + } isOutsideRange={() => false} /> onSingleDateChangeHandler({ date })} - focused={focused} - onFocusChange={({ focused }) => setFocused(focused)} + focused={state.focused} + onFocusChange={({ focused }) => + setState((prevState) => { + return { + ...prevState, + focused: focused, + } + }) + } id="unique_id" isOutsideRange={() => false} /> - +
) From 0c3764cbcbd0fd200f216d1e1b80079500daeafd Mon Sep 17 00:00:00 2001 From: Tito Date: Fri, 16 Apr 2021 12:09:14 -0300 Subject: [PATCH 10/11] style: eslint/prettier changes in style --- src/components/UI/Dropdown/Dropdown.jsx | 4 ++-- src/services/Endpoints/EditProcess/EditProcess.js | 8 ++++---- src/services/Loaders/EditProcess/EditProcess.js | 2 +- src/services/Loaders/GeneralStats/GeneralStats.js | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/UI/Dropdown/Dropdown.jsx b/src/components/UI/Dropdown/Dropdown.jsx index 96551b6..6769a6c 100644 --- a/src/components/UI/Dropdown/Dropdown.jsx +++ b/src/components/UI/Dropdown/Dropdown.jsx @@ -29,11 +29,11 @@ const Dropdown = ({ className, label, options, ...props }) => { Dropdown.propTypes = { className: PropTypes.string, label: PropTypes.string, - options: PropTypes.array + options: PropTypes.array, } Dropdown.defaultProps = { - className: 'dropdown' + className: 'dropdown', } export default Dropdown diff --git a/src/services/Endpoints/EditProcess/EditProcess.js b/src/services/Endpoints/EditProcess/EditProcess.js index 74ec146..c0b0bd2 100644 --- a/src/services/Endpoints/EditProcess/EditProcess.js +++ b/src/services/Endpoints/EditProcess/EditProcess.js @@ -6,15 +6,15 @@ export const getEditProcess = async (params = {}) => { `https://jsonplaceholder.typicode.com/users?id=${params.data.id}`, { params: { - ...params - } + ...params, + }, } ) } else { return axios.get('https://jsonplaceholder.typicode.com/users', { params: { - ...params - } + ...params, + }, }) } } diff --git a/src/services/Loaders/EditProcess/EditProcess.js b/src/services/Loaders/EditProcess/EditProcess.js index 31d6381..3d8103f 100644 --- a/src/services/Loaders/EditProcess/EditProcess.js +++ b/src/services/Loaders/EditProcess/EditProcess.js @@ -11,7 +11,7 @@ export const loadEditProcess = async (params) => { console.error(err) UTIL.Notifications.createDangerNotification({ - message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT + message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT, }) return {} diff --git a/src/services/Loaders/GeneralStats/GeneralStats.js b/src/services/Loaders/GeneralStats/GeneralStats.js index fd0bea0..e766040 100644 --- a/src/services/Loaders/GeneralStats/GeneralStats.js +++ b/src/services/Loaders/GeneralStats/GeneralStats.js @@ -11,7 +11,7 @@ export const loadGeneralStats = async (params) => { console.error(err) UTIL.Notifications.createDangerNotification({ - message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT + message: err?.response?.data?.status_message || Messages.ERROR.DEFAULT, }) return {} From 3e9e44aae3e5c483812792c06c9dac1015be5923 Mon Sep 17 00:00:00 2001 From: Tito Date: Fri, 16 Apr 2021 14:28:18 -0300 Subject: [PATCH 11/11] refactor(generalstats): filters can be combined --- src/pages/GeneralStats/GeneralStats.jsx | 43 +++++++++---------- .../Endpoints/GeneralStats/GeneralStats.js | 35 ++++----------- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/pages/GeneralStats/GeneralStats.jsx b/src/pages/GeneralStats/GeneralStats.jsx index 87d2d7b..c441537 100644 --- a/src/pages/GeneralStats/GeneralStats.jsx +++ b/src/pages/GeneralStats/GeneralStats.jsx @@ -28,8 +28,18 @@ const GeneralStats = () => { const history = useHistory() - const loadData = async (URLSearchParam) => { - const generalStatsResponse = await API.loadGeneralStats(URLSearchParam) + const addQueryParam = (key, value) => { + const pathname = location.pathname + const searchParams = new URLSearchParams(location.search) + searchParams.set(key, value) + history.push({ + pathname: pathname, + search: searchParams.toString(), + }) + } + + const loadData = async (searchParam) => { + const generalStatsResponse = await API.loadGeneralStats(searchParam) UTIL.stringifyObjects(generalStatsResponse) setState((prevState) => { return { @@ -48,19 +58,13 @@ const GeneralStats = () => { }) if (enteredText !== '') { - const paramsString = `search=${enteredText}` - const searchParams = new URLSearchParams(paramsString) - loadData(searchParams) - history.push(`general_stats?${paramsString}`) + addQueryParam('search', enteredText) } } const onDropdownChangeHandler = (value) => { if (options[value - 1]) { - const paramsString = `username=${options[value - 1].text}` - const searchParams = new URLSearchParams(paramsString) - loadData(searchParams) - history.push(`general_stats?${paramsString}`) + addQueryParam('username', options[value - 1].text) } } @@ -73,14 +77,9 @@ const GeneralStats = () => { } }) - const paramsString = `createdAt?start=${JSON.stringify( - dates.startDate?._d - )}&end=${JSON.stringify(dates.endDate?._d)}` - const searchParams = new URLSearchParams(paramsString) - loadData(searchParams) - if (dates.startDate?._d && dates.endDate?._d) { - history.push(`general_stats?${paramsString}`) + addQueryParam('start', JSON.stringify(dates.startDate?._d)) + addQueryParam('end', JSON.stringify(dates.endDate?._d)) } } @@ -91,15 +90,13 @@ const GeneralStats = () => { singleDate: date.date, } }) - const paramsString = `createdAt=${JSON.stringify(date.date._d)}` - const searchParams = new URLSearchParams(paramsString) - loadData(searchParams) - history.push(`general_stats?${paramsString}`) + + addQueryParam('createdAt', JSON.stringify(date.date._d)) } useEffect(() => { - loadData() - }, []) + loadData(location.search) + }, [location.search]) return ( diff --git a/src/services/Endpoints/GeneralStats/GeneralStats.js b/src/services/Endpoints/GeneralStats/GeneralStats.js index 295bc85..3c323ed 100644 --- a/src/services/Endpoints/GeneralStats/GeneralStats.js +++ b/src/services/Endpoints/GeneralStats/GeneralStats.js @@ -1,33 +1,16 @@ import axios from 'axios' export const getGeneralStats = async (params = {}) => { - const fields = ['id', 'name', 'username', 'email', 'address', 'createdAt'] - let queryString = null + let endpoint = 'https://604a26779251e100177ce0d3.mockapi.io/api/processes' - if (params instanceof URLSearchParams) { - fields.map((field) => { - if (params.has(field)) { - queryString = `https://604a26779251e100177ce0d3.mockapi.io/api/processes?${field}=${params.get( - field - )}` - } - }) + if (Object.entries(params).length > 0) { + const search = new URLSearchParams(params) + endpoint = `${endpoint}?${search}` } - if (queryString) { - return axios.get(queryString, { - params: { - ...params - } - }) - } else { - return axios.get( - 'https://604a26779251e100177ce0d3.mockapi.io/api/processes', - { - params: { - ...params - } - } - ) - } + return axios.get(endpoint, { + params: { + ...params, + }, + }) }