Skip to content

Commit

Permalink
More flow
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmatter committed Jan 7, 2017
1 parent 31f8420 commit cba318a
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 39 deletions.
14 changes: 8 additions & 6 deletions .eslintrc
Expand Up @@ -44,10 +44,12 @@
"react/require-extension": ["error", {"extensions": [".js"]}],
"react/sort-comp": "off", // Flow type definition of props in a React class confuses it
"spaced-comment": "off",
},
"globals": {
"SyntheticEvent": false,
"SyntheticKeyboardEvent": false,
"SyntheticInputEvent": false
}
},
"globals": {
"$Diff": false,
"Class": false,
"SyntheticEvent": false,
"SyntheticKeyboardEvent": false,
"SyntheticInputEvent": false
}
}
2 changes: 0 additions & 2 deletions TODO
Expand Up @@ -16,9 +16,7 @@ flow
React components: proptype validation only works for class-based ones. for functions, need proptypes and flow. even for class-based components, flow can give more flexibility, but does not do runtime checking. https://github.com/gcanti/babel-plugin-tcomb could help with that, but seems to create too many false positives. until there is a better solution, it's not urgent to port React components to flow.
https://codemix.github.io/flow-runtime/
views: thru live
views/components: thru NagModal
views/views
views/wrappers

replace owner message text with numbers/chart

Expand Down
1 change: 1 addition & 0 deletions src/.htaccess
Expand Up @@ -10,6 +10,7 @@ RewriteBase /

RewriteCond %{HTTP:X-Forwarded-SSL} !on
RewriteCond %{HTTP_HOST} !=localhost
RewriteCond %{HTTP_HOST} !\.dev$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteRule ^manifest_hack$ manifest_hack.html
Expand Down
1 change: 1 addition & 0 deletions src/js/util/logEvent.js
Expand Up @@ -32,6 +32,7 @@ type LogEventOptions = {
'refuseToSign' |
'release' |
'retired' |
'screenshot' |
'trade' |
'tragedy'
),
Expand Down
6 changes: 6 additions & 0 deletions src/js/util/types.js
Expand Up @@ -123,6 +123,12 @@ export type Message = {

export type MessageWithMid = Message & {mid: number};

export type Option = {
id: string,
label: string,
url?: string,
};

export type OwnerMoodDeltas = {
money: number,
playoffs: number,
Expand Down
10 changes: 1 addition & 9 deletions src/js/views/components/Controller.js
Expand Up @@ -7,7 +7,7 @@ import * as ui from '../../ui';
import * as ads from '../../util/ads';
import {beforeLeague, beforeNonLeague} from '../../util/viewHelpers';
import {Footer, Header, LeagueWrapper, MultiTeamMenu, NagModal, NavBar} from './index';
import type {GetOutput, PageCtx, RunFunction, UpdateEvents} from '../../util/types';
import type {GetOutput, Option, PageCtx, RunFunction, UpdateEvents} from '../../util/types';

class LeagueContent extends React.Component {
// eslint-disable-next-line class-methods-use-this
Expand Down Expand Up @@ -37,14 +37,6 @@ type Args = {
runWhenever: RunFunction[],
};

type Option = {
[key: string]: {
id: string,
label: string,
url?: string,
}
};

type State = {
Component: any,
idLoaded?: string,
Expand Down
4 changes: 2 additions & 2 deletions src/js/views/components/DataTable.js
Expand Up @@ -82,12 +82,12 @@ const Row = clickable(({clicked, row, toggleClicked}) => {
</tr>;
});

Row.propTypes = {
/*Row.propTypes = {
row: React.PropTypes.shape({
classNames: React.PropTypes.object,
data: React.PropTypes.array.isRequired,
}).isRequired,
};
};*/

const getSearchVal = val => {
try {
Expand Down
80 changes: 66 additions & 14 deletions src/js/views/components/NavBar.js
@@ -1,3 +1,5 @@
// @flow

/* eslint react/no-find-dom-node: "off" */

import Promise from 'bluebird';
Expand All @@ -16,30 +18,44 @@ import html2canvas from '../../lib/html2canvas';
import * as actions from '../../util/actions';
import * as helpers from '../../util/helpers';
import logEvent from '../../util/logEvent';
import type {Option} from '../../util/types';

const toggleDebugMode = () => {
if (localStorage.debug === "debug") {
localStorage.debug = "";
if (localStorage.getItem('debug') === 'debug') {
localStorage.setItem('debug', '');
} else {
localStorage.debug = "debug";
localStorage.setItem('debug', 'debug');
}
window.location.reload();
};

type TopMenuToggleProps = {
long: string,
onClick?: (SyntheticEvent) => void, // From react-bootstrap Dropdown
openId?: string,
short: string,
};

class TopMenuToggle extends React.Component {
constructor(props, context) {
props: TopMenuToggleProps;
handleClick: Function;
handleMouseEnter: Function;

constructor(props: TopMenuToggleProps, context) {
super(props, context);
this.handleClick = this.handleClick.bind(this);
this.handleMouseEnter = this.handleMouseEnter.bind(this);
}

handleClick(e) {
e.preventDefault();
this.props.onClick(e);
if (this.props.onClick) {
this.props.onClick(e);
}
}

handleMouseEnter(e) {
if (this.props.openId !== undefined && this.props.openId !== this.props.long) {
if (this.props.openId !== undefined && this.props.openId !== this.props.long && this.props.onClick) {
this.props.onClick(e);
}
}
Expand Down Expand Up @@ -94,7 +110,11 @@ const handleScreenshotClick = e => {

// Add watermark
const watermark = document.createElement("div");
watermark.innerHTML = `<nav class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header">${document.getElementsByClassName("navbar-brand")[0].parentNode.innerHTML}</div><p class="navbar-text navbar-right" style="color: #000; font-weight: bold">Play your own league free at basketball-gm.com</p></div></nav>`;
const navbarBrands = document.getElementsByClassName("navbar-brand");
if (navbarBrands.length === 0 || !navbarBrands[0].parentNode || !navbarBrands[0].parentNode.innerHTML) {
return;
}
watermark.innerHTML = `<nav class="navbar navbar-default"><div class="container-fluid"><div class="navbar-header">${String(navbarBrands[0].parentNode.innerHTML)}</div><p class="navbar-text navbar-right" style="color: #000; font-weight: bold">Play your own league free at basketball-gm.com</p></div></nav>`;
contentEl.insertBefore(watermark, contentEl.firstChild);
contentEl.style.padding = "8px";

Expand All @@ -103,7 +123,10 @@ const handleScreenshotClick = e => {
notifications.classList.remove('notification-container');
for (let i = 0; i < notifications.childNodes.length; i++) {
// Otherwise screeenshot is taken before fade in is complete
notifications.childNodes[0].classList.remove('notification-fadein');
const el = notifications.childNodes[0];
if (el.classList && typeof el.classList.remove === 'function') {
el.classList.remove('notification-fadein');
}
}
contentEl.appendChild(notifications);

Expand Down Expand Up @@ -164,7 +187,14 @@ const handleToolsClick = (id, e) => {
actions.toolsMenu[id]();
};

type DropdownLinksState = {
openId?: string,
};

class DropdownLinks extends React.Component {
state: DropdownLinksState;
handleTopMenuToggle: Function;

constructor(props) {
super(props);
this.state = {
Expand All @@ -173,7 +203,7 @@ class DropdownLinks extends React.Component {
this.handleTopMenuToggle = this.handleTopMenuToggle.bind(this);
}

shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps, nextState: DropdownLinksState) {
return this.state.openId !== nextState.openId || this.props.lid !== nextProps.lid || this.props.godMode !== nextProps.godMode;
}

Expand Down Expand Up @@ -244,7 +274,7 @@ class DropdownLinks extends React.Component {
{lid !== undefined ? <MenuItem onClick={e => handleToolsClick('skipToPreseason', e)}>Skip To Preseason</MenuItem> : null}
{lid !== undefined ? <MenuItem onClick={e => handleToolsClick('forceResumeDraft', e)}>Force Resume Draft</MenuItem> : null}
<MenuItem href="" onClick={toggleDebugMode} id="toggle-debug-mode">
{localStorage.debug === "debug" ? 'Disable Debug Mode' : 'Enable Debug Mode'}
{localStorage.getItem('debug') === 'debug' ? 'Disable Debug Mode' : 'Enable Debug Mode'}
</MenuItem>
<MenuItem onClick={e => handleToolsClick('resetDb', e)}>Reset DB</MenuItem>
</TopMenuDropdown>
Expand Down Expand Up @@ -302,6 +332,8 @@ const handleOptionClick = (option, e) => {
};

class PlayMenu extends React.Component {
handleAltP: Function;

constructor(props) {
super(props);
this.handleAltP = this.handleAltP.bind(this);
Expand All @@ -312,10 +344,10 @@ class PlayMenu extends React.Component {
}

componentWillUnmount() {
document.removeListener('keyup', this.handleAltP);
document.removeEventListener('keyup', this.handleAltP);
}

handleAltP(e) {
handleAltP(e: SyntheticKeyboardEvent) {
// alt + p
if (e.altKey && e.keyCode === 80) {
const option = this.props.options[0];
Expand Down Expand Up @@ -370,8 +402,28 @@ PlayMenu.propTypes = {
})).isRequired,
};

type Props = {
hasViewedALeague: boolean,
lid?: number,
godMode: boolean,
options: Option[],
phaseText: string,
popup: boolean,
statusText: string,
updating: boolean,
username?: string,
};

type State = {
hasViewedALeague: boolean,
};

class NavBar extends React.Component {
constructor(props) {
props: Props;
state: State;
playMenu: PlayMenu;

constructor(props: Props) {
super(props);
this.state = {
hasViewedALeague: props.hasViewedALeague,
Expand Down Expand Up @@ -426,7 +478,7 @@ class NavBar extends React.Component {
<Overlay
onHide={() => {
this.setState({hasViewedALeague: true});
localStorage.hasViewedALeague = 'true';
localStorage.setItem('hasViewedALeague', 'true');
}}
placement="bottom"
rootClose
Expand Down
12 changes: 11 additions & 1 deletion src/js/views/components/PlayerNameLabels.js
@@ -1,9 +1,19 @@
// @flow

import React from 'react';
import * as helpers from '../../util/helpers';
import SkillsBlock from './SkillsBlock';
import WatchBlock from './WatchBlock';
import type {PlayerInjury, PlayerSkill} from '../../util/types';

const PlayerNameLabels = ({children, injury, pid, skills, style, watch}) => {
const PlayerNameLabels = ({children, injury, pid, skills, style, watch}: {
children: string,
injury?: PlayerInjury,
pid: number,
skills?: PlayerSkill[],
style?: {[key: string]: string},
watch?: boolean | Function, // For Firefox's Object.watch
}) => {
let injuryIcon = null;
if (injury !== undefined) {
if (injury.gamesRemaining > 0) {
Expand Down
16 changes: 15 additions & 1 deletion src/js/views/components/PlayoffMatchup.js
@@ -1,8 +1,22 @@
// @flow

import React from 'react';
import g from '../../globals';
import * as helpers from '../../util/helpers';

const PlayoffMatchup = ({season, series}) => {
type SeriesTeam = {
seed: number,
tid: number,
won?: number,
};

const PlayoffMatchup = ({season, series}: {
season: number,
series?: {
away: SeriesTeam,
home: SeriesTeam,
},
}) => {
if (series === undefined || series.home === undefined || series.home.tid === undefined) {
return null;
}
Expand Down
19 changes: 15 additions & 4 deletions src/js/views/wrappers/clickable.js
@@ -1,18 +1,29 @@
// @flow

import React from 'react';

export default Component => {
// I have no idea what's going on here
export default <Props, C: React.Component<*, Props, *>>(
Component: Class<C>,
): Class<React.Component<*, $Diff<Props, {toggleClicked: () => void}>, *>> => {
return class Clickable extends React.Component {
state: {
clicked: boolean,
};
toggleClicked: Function;

constructor(props) {
super(props);
this.state = {
clicked: false,
};
this.toggleClicked = this.toggleClicked.bind(this);
}

toggleClicked(event) {
toggleClicked(event: SyntheticEvent) {
// Don't toggle the row if a link was clicked.
const ignoredElements = ['A', 'BUTTON', 'INPUT', 'SELECT'];
if (ignoredElements.includes(event.target.nodeName)) {
if (event.target.nodeName && ignoredElements.includes(event.target.nodeName)) {
return;
}

Expand All @@ -22,7 +33,7 @@ export default Component => {
}

render() {
return <Component {...this.props} {...this.state} toggleClicked={event => this.toggleClicked(event)} />;
return <Component {...this.props} {...this.state} toggleClicked={this.toggleClicked} />;
}
};
};

0 comments on commit cba318a

Please sign in to comment.