playball
Version:
Watch MLB games from the comfort of your terminal
167 lines • 6.18 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React, { useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from "react-redux/lib/alternate-renderers.js";
import PropTypes from 'prop-types';
import { format } from 'date-fns';
import { fetchSchedule, nextDay, prevDay, selectData, selectLoading, selectScheduleDate, setDate } from "../features/schedule.js";
import { teamFavoriteStar } from "../utils.js";
import Grid from "./Grid.js";
import useKey from "../hooks/useKey.js";
const formatGame = game => {
const startTime = game.status.startTimeTBD ? 'TBD' : format(new Date(game.gameDate), 'p');
const start = game.doubleHeader === 'Y' && game.gameNumber > 1 ? 'Game ' + game.gameNumber : startTime;
const teamName = team => {
const star = teamFavoriteStar(team.team);
return star + `${team.team.teamName} (${team.leagueRecord.wins}-${team.leagueRecord.losses})`.padEnd(star ? 18 : 20);
};
let content = [start, teamName(game.teams.away), teamName(game.teams.home)];
const gameState = game.status.abstractGameCode;
const detailedState = game.status.detailedState;
switch (gameState) {
case 'P':
break;
case 'L':
if (detailedState === 'Warmup') {
content[0] = detailedState;
} else {
content[0] = game.linescore.inningState + ' ' + game.linescore.currentInningOrdinal;
if (detailedState !== 'In Progress') {
content[0] += ' | ' + detailedState;
}
}
if (game.linescore) {
content[0] = content[0].padEnd(20) + ' R H E';
content[1] += game.linescore.teams.away.runs.toString().padStart(2) + game.linescore.teams.away.hits.toString().padStart(3) + game.linescore.teams.away.errors.toString().padStart(3);
content[2] += game.linescore.teams.home.runs.toString().padStart(2) + game.linescore.teams.home.hits.toString().padStart(3) + game.linescore.teams.home.errors.toString().padStart(3);
}
break;
case 'F':
content[0] = detailedState;
if (game.status.reason) {
content[0] += ' | ' + game.status.reason;
}
if (game.linescore) {
if (game.linescore.currentInning !== game.scheduledInnings) {
content[0] += '/' + game.linescore.currentInning;
}
content[0] = content[0].padEnd(20) + ' R H E';
content[1] += game.linescore.teams.away.runs.toString().padStart(2) + game.linescore.teams.away.hits.toString().padStart(3) + game.linescore.teams.away.errors.toString().padStart(3);
content[2] += game.linescore.teams.home.runs.toString().padStart(2) + game.linescore.teams.home.hits.toString().padStart(3) + game.linescore.teams.home.errors.toString().padStart(3);
if (game.teams.away.isWinner) {
content[1] = `{bold}${content[1]}{/bold}`;
}
if (game.teams.home.isWinner) {
content[2] = `{bold}${content[2]}{/bold}`;
}
}
break;
}
return content.map(s => ' ' + s).join('\n');
};
const GAME_STATE_ORDER = {
L: 0,
P: 1,
F: 2
};
function compareGameState(a, b) {
return GAME_STATE_ORDER[a.status.abstractGameCode] - GAME_STATE_ORDER[b.status.abstractGameCode];
}
function compareGameInnings(a, b) {
const inningCompare = b.linescore.currentInning - a.linescore.currentInning;
if (inningCompare !== 0) {
return inningCompare;
}
if (a.isTopInning && !b.isTopInning) {
return -1;
}
if (b.isTopInning && !a.isTopInning) {
return 1;
}
return 0;
}
function compareGames(a, b) {
const stateCompare = compareGameState(a, b);
if (stateCompare !== 0) {
return stateCompare;
}
if (a.status.abstractGameCode === 'L') {
const inningCompare = compareGameInnings(a, b);
if (inningCompare !== 0) {
return inningCompare;
}
}
return 0;
}
function GameList({
onGameSelect
}) {
const dispatch = useDispatch();
const schedule = useSelector(selectData);
const loading = useSelector(selectLoading);
const date = useSelector(selectScheduleDate);
const timerRef = useRef(null);
let games = [];
if (schedule && schedule.dates.length > 0) {
games = schedule.dates[0].games.slice().sort(compareGames);
}
useEffect(() => {
dispatch(fetchSchedule(date));
timerRef.current = setInterval(() => dispatch(fetchSchedule(date)), 30000);
return () => clearInterval(timerRef.current);
}, [date]);
useKey('p', useCallback(() => dispatch(prevDay()), []), {
key: 'P',
label: 'Prev Day'
});
useKey('n', useCallback(() => dispatch(nextDay()), []), {
key: 'N',
label: 'Next Day'
});
useKey('t', useCallback(() => dispatch(setDate(new Date())), []), {
key: 'T',
label: 'Today'
});
const handleGameSelect = idx => {
const selected = games[idx];
onGameSelect(selected);
};
const messageStyle = {
left: 0,
top: 0,
height: '100%',
width: '100%',
align: 'center',
valign: 'middle'
};
return /*#__PURE__*/React.createElement("element", null, /*#__PURE__*/React.createElement("box", {
top: 0,
left: 0,
width: "100%",
height: 1,
align: "center",
valign: "middle",
style: {
bg: 'white',
fg: 'black'
},
content: format(date, 'PPPP')
}), /*#__PURE__*/React.createElement("element", {
top: 2,
left: 0,
width: "100%",
height: "100%-2"
}, !schedule && loading && /*#__PURE__*/React.createElement("box", _extends({}, messageStyle, {
content: "Loading..."
})), schedule && games.length === 0 && /*#__PURE__*/React.createElement("box", _extends({}, messageStyle, {
content: "No games today"
})), schedule && games.length > 0 && /*#__PURE__*/React.createElement(Grid, {
items: games.map(formatGame),
itemHeight: 5,
itemMinWidth: 34,
onSelect: handleGameSelect
})));
}
GameList.propTypes = {
onGameSelect: PropTypes.func
};
export default GameList;