Implemented some improvements and fixes on how visits table is split and calculated

This commit is contained in:
Alejandro Celaya
2020-04-05 18:04:15 +02:00
parent b79333393b
commit 8a486d991b

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Moment from 'react-moment'; import Moment from 'react-moment';
import classNames from 'classnames'; import classNames from 'classnames';
import { map, min } from 'ramda'; import { map, min, splitEvery } from 'ramda';
import { import {
faCaretDown as caretDownIcon, faCaretDown as caretDownIcon,
faCaretUp as caretUpIcon, faCaretUp as caretUpIcon,
@@ -27,25 +27,20 @@ const propTypes = {
const PAGE_SIZE = 20; const PAGE_SIZE = 20;
const visitMatchesSearch = ({ browser, os, referer, country, city }, searchTerm) => const visitMatchesSearch = ({ browser, os, referer, country, city }, searchTerm) =>
`${browser} ${os} ${referer} ${country} ${city}`.toLowerCase().includes(searchTerm.toLowerCase()); `${browser} ${os} ${referer} ${country} ${city}`.toLowerCase().includes(searchTerm.toLowerCase());
const calculateVisits = (allVisits, page, searchTerm, { field, dir }) => { const searchVisits = (searchTerm, visits) => visits.filter((visit) => visitMatchesSearch(visit, searchTerm));
const end = page * PAGE_SIZE; const sortVisits = ({ field, dir }, visits) => visits.sort((a, b) => {
const start = end - PAGE_SIZE; const greaterThan = dir === 'ASC' ? 1 : -1;
const filteredVisits = searchTerm ? allVisits.filter((visit) => visitMatchesSearch(visit, searchTerm)) : allVisits; const smallerThan = dir === 'ASC' ? -1 : 1;
const total = filteredVisits.length;
const visits = filteredVisits
.sort((a, b) => {
if (!dir) {
return 0;
}
const greaterThan = dir === 'ASC' ? 1 : -1; return a[field] > b[field] ? greaterThan : smallerThan;
const smallerThan = dir === 'ASC' ? -1 : 1; });
const calculateVisits = (allVisits, searchTerm, order) => {
const filteredVisits = searchTerm ? searchVisits(searchTerm, allVisits) : allVisits;
const sortedVisits = order.dir ? sortVisits(order, filteredVisits) : filteredVisits;
const total = sortedVisits.length;
const visitsGroups = splitEvery(PAGE_SIZE, sortedVisits);
return a[field] > b[field] ? greaterThan : smallerThan; return { visitsGroups, total };
})
.slice(start, end);
return { visits, start, end, total };
}; };
const normalizeVisits = map(({ userAgent, date, referer, visitLocation }) => ({ const normalizeVisits = map(({ userAgent, date, referer, visitLocation }) => ({
date, date,
@@ -57,6 +52,7 @@ const normalizeVisits = map(({ userAgent, date, referer, visitLocation }) => ({
})); }));
const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = window.matchMedia }) => { const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = window.matchMedia }) => {
const allVisits = normalizeVisits(visits);
const headerCellsClass = classNames('visits-table__header-cell', { const headerCellsClass = classNames('visits-table__header-cell', {
'visits-table__sticky': isSticky, 'visits-table__sticky': isSticky,
}); });
@@ -64,11 +60,13 @@ const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = w
const [ selectedVisit, setSelectedVisit ] = useState(undefined); const [ selectedVisit, setSelectedVisit ] = useState(undefined);
const [ isMobileDevice, setIsMobileDevice ] = useState(matchMobile()); const [ isMobileDevice, setIsMobileDevice ] = useState(matchMobile());
const [ page, setPage ] = useState(1);
const [ searchTerm, setSearchTerm ] = useState(undefined); const [ searchTerm, setSearchTerm ] = useState(undefined);
const [ order, setOrder ] = useState({ field: undefined, dir: undefined }); const [ order, setOrder ] = useState({ field: undefined, dir: undefined });
const allVisits = useMemo(() => normalizeVisits(visits), [ visits ]); const resultSet = useMemo(() => calculateVisits(allVisits, searchTerm, order), [ searchTerm, order ]);
const currentPage = useMemo(() => calculateVisits(allVisits, page, searchTerm, order), [ page, searchTerm, order ]);
const [ page, setPage ] = useState(1);
const end = page * PAGE_SIZE;
const start = end - PAGE_SIZE;
const orderByColumn = (field) => () => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) }); const orderByColumn = (field) => () => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) });
const renderOrderIcon = (field) => order.dir && order.field === field && ( const renderOrderIcon = (field) => order.dir && order.field === field && (
@@ -88,6 +86,9 @@ const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = w
return () => window.removeEventListener('resize', listener); return () => window.removeEventListener('resize', listener);
}, []); }, []);
useEffect(() => {
setPage(1);
}, [ searchTerm ]);
return ( return (
<table className="table table-striped table-bordered table-hover table-sm visits-table"> <table className="table table-striped table-bordered table-hover table-sm visits-table">
@@ -132,14 +133,14 @@ const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = w
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{currentPage.visits.length === 0 && ( {(!resultSet.visitsGroups[page - 1] || resultSet.visitsGroups[page - 1].length === 0) && (
<tr> <tr>
<td colSpan={7} className="text-center"> <td colSpan={7} className="text-center">
No visits found with current filtering No visits found with current filtering
</td> </td>
</tr> </tr>
)} )}
{currentPage.visits.map((visit, index) => ( {resultSet.visitsGroups[page - 1] && resultSet.visitsGroups[page - 1].map((visit, index) => (
<tr <tr
key={index} key={index}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
@@ -160,14 +161,14 @@ const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = w
</tr> </tr>
))} ))}
</tbody> </tbody>
{currentPage.total >= PAGE_SIZE && ( {resultSet.total >= PAGE_SIZE && (
<tfoot> <tfoot>
<tr> <tr>
<td colSpan={7} className={classNames('visits-table__footer-cell', { 'visits-table__sticky': isSticky })}> <td colSpan={7} className={classNames('visits-table__footer-cell', { 'visits-table__sticky': isSticky })}>
<div className="row"> <div className="row">
<div className="col-md-6"> <div className="col-md-6">
<SimplePaginator <SimplePaginator
pagesCount={Math.ceil(currentPage.total / PAGE_SIZE)} pagesCount={Math.ceil(resultSet.total / PAGE_SIZE)}
currentPage={page} currentPage={page}
setCurrentPage={setPage} setCurrentPage={setPage}
centered={isMobileDevice} centered={isMobileDevice}
@@ -180,9 +181,9 @@ const VisitsTable = ({ visits, onVisitSelected, isSticky = false, matchMedia = w
})} })}
> >
<div> <div>
Visits <b>{prettify(currentPage.start + 1)}</b> to{' '} Visits <b>{prettify(start + 1)}</b> to{' '}
<b>{prettify(min(currentPage.end, currentPage.total))}</b> of{' '} <b>{prettify(min(end, resultSet.total))}</b> of{' '}
<b>{prettify(currentPage.total)}</b> <b>{prettify(resultSet.total)}</b>
</div> </div>
</div> </div>
</div> </div>