import React, { MouseEvent, MouseEventHandler, PureComponent } from 'react'; import PropTypes from 'prop-types'; import dateformat from 'dateformat'; import type { DebouncedFunc } from 'lodash'; import debounce from 'lodash.debounce'; import { StylingFunction } from 'react-base16-styling'; import { Action } from 'redux'; import RightSlider from './RightSlider'; const BUTTON_SKIP = 'Skip'; const BUTTON_JUMP = 'Jump'; type Button = typeof BUTTON_SKIP | typeof BUTTON_JUMP; interface Props> { styling: StylingFunction; actionId: number; isInitAction: boolean; isSelected: boolean; isInFuture: boolean; onSelect: MouseEventHandler; timestamps: { current: number; previous: number }; action: A; onToggleClick: () => void; onJumpClick: () => void; onCommitClick: () => void; hideActionButtons: boolean | undefined; isSkipped: boolean; } interface State { hover: boolean; } export default class ActionListRow< A extends Action, > extends PureComponent, State> { state: State = { hover: false }; static propTypes = { styling: PropTypes.func.isRequired, isSelected: PropTypes.bool.isRequired, action: PropTypes.object.isRequired, isInFuture: PropTypes.bool.isRequired, isInitAction: PropTypes.bool.isRequired, onSelect: PropTypes.func.isRequired, timestamps: PropTypes.shape({ current: PropTypes.number.isRequired, previous: PropTypes.number.isRequired, }).isRequired, isSkipped: PropTypes.bool.isRequired, }; render() { const { styling, isSelected, action, actionId, isInitAction, onSelect, timestamps, isSkipped, isInFuture, hideActionButtons, } = this.props; const { hover } = this.state; const timeDelta = timestamps.current - timestamps.previous; const showButtons = (hover && !isInitAction) || isSkipped; const isButtonSelected = (btn: Button) => btn === BUTTON_SKIP && isSkipped; let actionType = action.type; if (typeof actionType === 'undefined') actionType = ''; else if (actionType === null) actionType = ''; else actionType = (actionType as string).toString() || ''; return (
} onMouseLeave={ (!hideActionButtons && this.handleMouseLeave) as MouseEventHandler } onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseEnter} data-id={actionId} {...styling( [ 'actionListItem', isSelected && 'actionListItemSelected', isSkipped && 'actionListItemSkipped', isInFuture && 'actionListFromFuture', ], isSelected, action, )} >
{actionType as string}
{hideActionButtons ? (
{timeDelta === 0 ? '+00:00:00' : dateformat( timeDelta, timestamps.previous ? '+MM:ss.L' : 'h:MM:ss.L', )}
) : (
{timeDelta === 0 ? '+00:00:00' : dateformat( timeDelta, timestamps.previous ? '+MM:ss.L' : 'h:MM:ss.L', )}
{([BUTTON_JUMP, BUTTON_SKIP] as const).map( (btn) => (!isInitAction || btn !== BUTTON_SKIP) && (
this.handleButtonClick(btn, e)} {...styling( [ 'selectorButton', isButtonSelected(btn) && 'selectorButtonSelected', 'selectorButtonSmall', ], isButtonSelected(btn), true, )} > {btn}
), )}
)}
); } handleButtonClick(btn: Button, e: MouseEvent) { e.stopPropagation(); switch (btn) { case BUTTON_SKIP: this.props.onToggleClick(); break; case BUTTON_JUMP: this.props.onJumpClick(); break; } } handleMouseEnter = (e: MouseEvent) => { if (this.state.hover) return; this.handleMouseLeave.cancel(); this.handleMouseEnterDebounced(e.buttons); }; handleMouseEnterDebounced: DebouncedFunc<(buttons: number) => void> = debounce((buttons) => { if (buttons) return; this.setState({ hover: true }); }, 150); handleMouseLeave: DebouncedFunc<() => void> = debounce(() => { this.handleMouseEnterDebounced.cancel(); if (this.state.hover) this.setState({ hover: false }); }, 100); handleMouseDown = (e: MouseEvent) => { if ( (e.target as unknown as { className: string[] }).className.indexOf( 'selectorButton', ) === 0 ) return; this.handleMouseLeave(); }; }