import { isEmpty, propEq, values } from 'ramda'; import React, { useState, useEffect, useMemo } from 'react'; import { Button, Card, Collapse } from 'reactstrap'; import PropTypes from 'prop-types'; import qs from 'qs'; import classNames from 'classnames'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown as chevronDown } from '@fortawesome/free-solid-svg-icons'; import DateRangeRow from '../utils/DateRangeRow'; import Message from '../utils/Message'; import { formatDate } from '../utils/helpers/date'; import { useToggle } from '../utils/helpers/hooks'; import SortableBarGraph from './SortableBarGraph'; import { shortUrlVisitsType } from './reducers/shortUrlVisits'; import VisitsHeader from './VisitsHeader'; import GraphCard from './GraphCard'; import { shortUrlDetailType } from './reducers/shortUrlDetail'; import VisitsTable from './VisitsTable'; const propTypes = { match: PropTypes.shape({ params: PropTypes.object, }), location: PropTypes.shape({ search: PropTypes.string, }), getShortUrlVisits: PropTypes.func, shortUrlVisits: shortUrlVisitsType, getShortUrlDetail: PropTypes.func, shortUrlDetail: shortUrlDetailType, cancelGetShortUrlVisits: PropTypes.func, matchMedia: PropTypes.func, }; const highlightedVisitsToStats = (highlightedVisits, prop) => highlightedVisits.reduce((acc, highlightedVisit) => { if (!acc[highlightedVisit[prop]]) { acc[highlightedVisit[prop]] = 0; } acc[highlightedVisit[prop]] += 1; return acc; }, {}); const format = formatDate(); let selectedBar; const ShortUrlVisits = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBtn) => { const ShortUrlVisitsComp = ({ match, location, shortUrlVisits, shortUrlDetail, getShortUrlVisits, getShortUrlDetail, cancelGetShortUrlVisits, matchMedia = window.matchMedia, }) => { const [ startDate, setStartDate ] = useState(undefined); const [ endDate, setEndDate ] = useState(undefined); const [ showTable, toggleTable ] = useToggle(); const [ tableIsSticky, , setSticky, unsetSticky ] = useToggle(); const [ highlightedVisits, setHighlightedVisits ] = useState([]); const [ isMobileDevice, setIsMobileDevice ] = useState(false); const determineIsMobileDevice = () => setIsMobileDevice(matchMedia('(max-width: 991px)').matches); const setSelectedVisits = (selectedVisits) => { selectedBar = undefined; setHighlightedVisits(selectedVisits); }; const highlightVisitsForProp = (prop) => (value) => { const newSelectedBar = `${prop}_${value}`; if (selectedBar === newSelectedBar) { setHighlightedVisits([]); selectedBar = undefined; } else { setHighlightedVisits(normalizedVisits.filter(propEq(prop, value))); selectedBar = newSelectedBar; } }; const { params } = match; const { shortCode } = params; const { search } = location; const { domain } = qs.parse(search, { ignoreQueryPrefix: true }); const { visits, loading, loadingLarge, error } = shortUrlVisits; const showTableControls = !loading && visits.length > 0; const normalizedVisits = useMemo(() => normalizeVisits(visits), [ visits ]); const { os, browsers, referrers, countries, cities, citiesForMap } = useMemo( () => processStatsFromVisits(visits), [ visits ] ); const mapLocations = values(citiesForMap); const loadVisits = () => getShortUrlVisits(shortCode, { startDate: format(startDate), endDate: format(endDate), domain }); useEffect(() => { getShortUrlDetail(shortCode, domain); determineIsMobileDevice(); window.addEventListener('resize', determineIsMobileDevice); return () => { cancelGetShortUrlVisits(); window.removeEventListener('resize', determineIsMobileDevice); }; }, []); useEffect(() => { loadVisits(); }, [ startDate, endDate ]); const renderVisitsContent = () => { if (loading) { const message = loadingLarge ? 'This is going to take a while... :S' : 'Loading...'; return {message}; } if (error) { return ( An error occurred while loading visits :( ); } if (isEmpty(visits)) { return There are no visits matching current filter :(; } return (
mapLocations.length > 0 && } sortingItems={{ name: 'City name', amount: 'Visits amount', }} onClick={highlightVisitsForProp('city')} />
); }; return (
{showTableControls && ( )}
{showTableControls && ( )}
{renderVisitsContent()}
); }; ShortUrlVisitsComp.propTypes = propTypes; return ShortUrlVisitsComp; }; export default ShortUrlVisits;