import React, { useRef, useState } from 'react'; import copy from 'copy-to-clipboard'; import cn from 'classnames'; import { Icon, TextEllipsis, Tooltip } from 'UI'; import { TYPES } from 'Types/session/event'; import { prorata } from 'App/utils'; import withOverlay from 'Components/hocs/withOverlay'; import LoadInfo from './LoadInfo'; import cls from './event.module.css'; import { numberWithCommas } from 'App/utils'; type Props = { event: any; selected?: boolean; isCurrent?: boolean; onClick?: () => void; showSelection?: boolean; showLoadInfo?: boolean; toggleLoadInfo?: () => void; isRed?: boolean; presentInSearch?: boolean; whiteBg?: boolean; }; const isFrustrationEvent = (evt: any): boolean => { if (evt.type === 'mouse_thrashing' || evt.type === TYPES.CLICKRAGE || evt.type === TYPES.TAPRAGE) { return true; } if (evt.type === TYPES.CLICK || evt.type === TYPES.INPUT) { return evt.hesitation > 1000; } return false; }; const Event: React.FC = ({ event, selected = false, isCurrent = false, onClick, showSelection = false, showLoadInfo, toggleLoadInfo, isRed = false, presentInSearch = false, whiteBg }) => { const wrapperRef = useRef(null); const [menuOpen, setMenuOpen] = useState(false); const isLocation = event.type === TYPES.LOCATION; const onContextMenu = (e: React.MouseEvent) => { e.preventDefault(); setMenuOpen(true); }; const onMouseLeave = () => setMenuOpen(false); const copyHandler = (e: React.MouseEvent) => { e.stopPropagation(); const path = event.getIn(['target', 'path']) || event.url || ''; copy(path); setMenuOpen(false); }; const renderBody = () => { let title = event.type; let body; let icon; const isFrustration = isFrustrationEvent(event); const tooltip = { disabled: true, text: '' }; switch (event.type) { case TYPES.LOCATION: title = 'Visited'; body = event.url; icon = 'event/location'; break; case TYPES.SWIPE: title = 'Swipe'; body = event.direction; icon = `chevron-${event.direction}` break; case TYPES.TOUCH: title = 'Tapped'; body = event.label; icon = 'event/click'; break; case TYPES.CLICK: title = 'Clicked'; body = event.label; icon = isFrustration ? 'event/click_hesitation' : 'event/click'; isFrustration ? Object.assign(tooltip, { disabled: false, text: `User hesitated ${Math.round(event.hesitation / 1000)}s to perform this event` }) : null; break; case TYPES.INPUT: title = 'Input'; body = event.value; icon = isFrustration ? 'event/input_hesitation' : 'event/input'; isFrustration ? Object.assign(tooltip, { disabled: false, text: `User hesitated ${Math.round(event.hesitation / 1000)}s to enter a value in this input field.` }) : null; break; case TYPES.CLICKRAGE: case TYPES.TAPRAGE: title = event.count ? `${event.count} Clicks` : 'Click Rage'; body = event.label; icon = 'event/clickrage'; break; case TYPES.IOS_VIEW: title = 'View'; body = event.name; icon = 'event/ios_view'; break; case 'mouse_thrashing': title = 'Mouse Thrashing'; icon = 'event/mouse_thrashing'; break; } return (
{event.type && }
{title} {body && !isLocation && ( )}
{isLocation && event.speedIndex != null && (
{'Speed Index'}
{numberWithCommas(event.speedIndex || 0)}
)}
{event.target && event.target.label && (
{event.target.label}
)}
{isLocation && (
{body}
)}
); }; const isFrustration = isFrustrationEvent(event); const mobileTypes = [TYPES.TOUCH, TYPES.SWIPE, TYPES.TAPRAGE] return (
{menuOpen && ( )}
{renderBody()}
{isLocation && (event.fcpTime || event.visuallyComplete || event.timeToInteractive) && ( elements / 1.2, divisorFn: (elements, parts) => elements / (2 * parts + 1) })} /> )}
); }; export default withOverlay()(Event);