diff --git a/components/common/Pagination.js b/components/common/Pagination.js new file mode 100644 index 00000000..78f5f0e5 --- /dev/null +++ b/components/common/Pagination.js @@ -0,0 +1,61 @@ +import React from 'react'; + +export default function Pagination({ + gotoPage, + canPreviousPage, + previousPage, + canNextPage, + nextPage, + pageCount, + pageIndex, + pageOptions, + pageSize, + setPageSize, +}) { + return ( +
+ {' '} + {' '} + {' '} + {' '} + + Page{' '} + + {pageIndex + 1} of {pageOptions.length} + {' '} + + + | Go to page:{' '} + { + const page = e.target.value ? Number(e.target.value) - 1 : 0; + gotoPage(page); + }} + style={{ width: '100px' }} + /> + {' '} + +
+ ); +} diff --git a/components/common/TableNew.js b/components/common/TableNew.js new file mode 100644 index 00000000..e3773a12 --- /dev/null +++ b/components/common/TableNew.js @@ -0,0 +1,41 @@ +import React from 'react'; + +export default function TableNew({ + getTableProps, + getTableBodyProps, + headerGroups, + prepareRow, + page, +}) { + return ( + + + {headerGroups.map(headerGroup => ( + + {headerGroup.headers.map(column => ( + + ))} + + ))} + + + {page.map(row => { + prepareRow(row); + return ( + + {row.cells.map(cell => { + return ( + + ); + })} + + ); + })} + +
+ {column.render('Header')} +
+ {cell.render('Cell', { ...row.original })} +
+ ); +} diff --git a/components/pages/WebsiteList.js b/components/pages/WebsiteList.js index 747ad24f..6c2ae784 100644 --- a/components/pages/WebsiteList.js +++ b/components/pages/WebsiteList.js @@ -1,7 +1,10 @@ -import React, { useLayoutEffect, useMemo, useState } from 'react'; +import React, { useLayoutEffect, useMemo, useState, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import Link from 'components/common/Link'; import DateFilter from 'components/common/DateFilter'; +import TableNew from 'components/common/TableNew'; +import Pagination from 'components/common/Pagination'; import Page from 'components/layout/Page'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import useFetch from 'hooks/useFetch'; @@ -12,13 +15,18 @@ import { get } from 'lib/web'; import { TOKEN_HEADER } from 'lib/constants'; import { useRouter } from 'next/router'; import { useTable, usePagination } from 'react-table'; +import { setWebsitesData } from 'redux/actions/websites'; import find from 'lodash.find'; +import Loader from 'react-loader-spinner'; +import styles from './WebsiteList.module.css'; export default function WebsiteList({ userId }) { const [stats, setStats] = useState([]); + const dispatch = useDispatch(); const fetchedData = useFetch('/api/websites', { params: { user_id: userId } }); const { basePath } = useRouter(); const shareToken = useShareToken(); + const websites = useSelector(state => state.websites); const [dateRange, setDateRange] = useDateRange(); const { startDate, endDate, value } = dateRange; @@ -27,17 +35,6 @@ export default function WebsiteList({ userId }) { return fetchedData.data.map(site => site.website_id); }, [fetchedData.data]); - const tableData = useMemo(() => { - if (!fetchedData.data || !stats.length) return []; - - const _data = []; - fetchedData.data.forEach(i => { - const stat = find(stats, { id: i.website_id }) || {}; - _data.push({ ...i, ...stat.data }); - }); - return _data; - }, [fetchedData.data, stats.length]); - const getStats = async () => { const websitesData = []; for (let id of websitesIds) { @@ -64,6 +61,18 @@ export default function WebsiteList({ userId }) { getStats(); }, [fetchedData.data, stats.length]); + useEffect(() => { + if (!fetchedData.data || !stats.length) return []; + + const _data = []; + fetchedData.data.forEach(i => { + const stat = find(stats, { id: i.website_id }) || {}; + _data.push({ ...i, ...stat.data }); + }); + + dispatch(setWebsitesData(_data)); + }, [fetchedData.data, stats.length]); + const tableColumns = useMemo( () => [ { @@ -123,95 +132,43 @@ export default function WebsiteList({ userId }) { } = useTable( { columns: tableColumns, - data: tableData, - initialState: { pageIndex: 0, pageSize: 10 }, + data: websites, + initialState: { pageIndex: 0, pageSize: 50 }, }, usePagination, ); return ( - - - - - {headerGroups.map(headerGroup => ( - - {headerGroup.headers.map(column => ( - - ))} - - ))} - - - {page.map(row => { - prepareRow(row); - return ( - - {row.cells.map(cell => { - return ( - - ); - })} - - ); - })} - -
- {column.render('Header')} -
- {cell.render('Cell', { ...row.original })} -
-
- {' '} - {' '} - {' '} - {' '} - - Page{' '} - - {pageIndex + 1} of {pageOptions.length} - {' '} - - - | Go to page:{' '} - { - const page = e.target.value ? Number(e.target.value) - 1 : 0; - gotoPage(page); - }} - style={{ width: '100px' }} - /> - {' '} - + +
+ Range: +
- {/* */} - {/* {data.map(({ website_id, name, domain }) => ( -
- + + {stats.length === 0 && ( +
+
- ))} */} - {fetchedData.data?.length === 0 && ( + )} + + {fetchedData.status === 200 && fetchedData.data.length === 0 && stats.length === 0 && ( { + return dispatch(updateWebsites([...data])); + }; +} diff --git a/yarn.lock b/yarn.lock index 0fb8f8ed..c09ff98e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2151,6 +2151,14 @@ babel-plugin-transform-react-remove-prop-types@0.4.24: resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -2918,6 +2926,11 @@ core-js-compat@^3.6.2: browserslist "^4.8.5" semver "7.0.0" +core-js@^2.4.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -7486,6 +7499,14 @@ react-is@16.13.1, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-loader-spinner@^3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/react-loader-spinner/-/react-loader-spinner-3.1.14.tgz#2a201f07379c492766175609903c0f2ced57c720" + integrity sha512-7V+upnW+RVA/O94LIB/EQLK2uaz/TpZBHG5uNXlOXgvxvALxlxVYeEDmus5Oex2C58fiwrsRvSyu/4VRmLbZ9Q== + dependencies: + babel-runtime "^6.26.0" + prop-types "^15.7.2" + react-redux@^7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz#03862e803a30b6b9ef8582dadcc810947f74b736" @@ -7670,6 +7691,11 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"