Typescriptify components
This commit is contained in:
parent
08ae6d42bc
commit
51df6abd81
|
|
@ -1,17 +1,16 @@
|
|||
import React, {Component} from 'react';
|
||||
import Button from 'material-ui/Button';
|
||||
import Dialog, {DialogActions, DialogContent, DialogContentText, DialogTitle} from 'material-ui/Dialog';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {Component} from 'react';
|
||||
|
||||
export default class ConfirmDialog extends Component {
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
fClose: PropTypes.func.isRequired,
|
||||
fOnSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
interface IProps {
|
||||
title: string
|
||||
text: string
|
||||
fClose: VoidFunction
|
||||
fOnSubmit: VoidFunction
|
||||
}
|
||||
|
||||
render() {
|
||||
export default class ConfirmDialog extends Component<IProps> {
|
||||
public render() {
|
||||
const {title, text, fClose, fOnSubmit} = this.props;
|
||||
const submitAndClose = () => {
|
||||
fOnSubmit();
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React, {Component} from 'react';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import {WithStyles} from "material-ui";
|
||||
import Paper from 'material-ui/Paper';
|
||||
import PropTypes from 'prop-types';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import * as React from 'react';
|
||||
|
||||
const styles = () => ({
|
||||
paper: {
|
||||
|
|
@ -9,14 +9,12 @@ const styles = () => ({
|
|||
},
|
||||
});
|
||||
|
||||
class Container extends Component {
|
||||
static propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
children: PropTypes.node,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
interface IProps {
|
||||
style?: object,
|
||||
}
|
||||
|
||||
render() {
|
||||
class Container extends React.Component<IProps & WithStyles<'paper'>, {}> {
|
||||
public render() {
|
||||
const {classes, children, style} = this.props;
|
||||
return (
|
||||
<Paper elevation={6} className={classes.paper} style={style}>
|
||||
|
|
@ -26,4 +24,4 @@ class Container extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Container);
|
||||
export default withStyles(styles)<IProps>(Container);
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import React, {Component} from 'react';
|
||||
import Button from 'material-ui/Button';
|
||||
import Grid from 'material-ui/Grid';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class DefaultPage extends Component {
|
||||
static defaultProps = {
|
||||
buttonDisabled: false,
|
||||
hideButton: false,
|
||||
maxWidth: 700,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
buttonTitle: PropTypes.string,
|
||||
fButton: PropTypes.func,
|
||||
buttonDisabled: PropTypes.bool.isRequired,
|
||||
maxWidth: PropTypes.number.isRequired,
|
||||
hideButton: PropTypes.bool.isRequired,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {title, buttonTitle, fButton, buttonDisabled, maxWidth, hideButton, children} = this.props;
|
||||
return (
|
||||
<main style={{margin: '0 auto', maxWidth}}>
|
||||
<Grid container spacing={24}>
|
||||
<Grid item xs={12} style={{display: 'flex'}}>
|
||||
<Typography variant="display1" style={{flex: 1}}>
|
||||
{title}
|
||||
</Typography>
|
||||
{hideButton ? null : <Button variant="raised" color="primary" disabled={buttonDisabled}
|
||||
onClick={fButton}>{buttonTitle}</Button>}
|
||||
</Grid>
|
||||
{children}
|
||||
</Grid>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import Button from 'material-ui/Button';
|
||||
import Grid from 'material-ui/Grid';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import React, {SFC} from 'react';
|
||||
|
||||
interface IProps {
|
||||
title: string
|
||||
buttonTitle?: string
|
||||
fButton?: VoidFunction
|
||||
buttonDisabled?: boolean
|
||||
maxWidth?: number
|
||||
hideButton?: boolean
|
||||
}
|
||||
|
||||
const DefaultPage: SFC<IProps> = ({title, buttonTitle, fButton, buttonDisabled = false, maxWidth = 700, hideButton, children}) => (
|
||||
<main style={{margin: '0 auto', maxWidth}}>
|
||||
<Grid container spacing={24}>
|
||||
<Grid item xs={12} style={{display: 'flex'}}>
|
||||
<Typography variant="display1" style={{flex: 1}}>
|
||||
{title}
|
||||
</Typography>
|
||||
{hideButton ? null : <Button variant="raised" color="primary" disabled={buttonDisabled}
|
||||
onClick={fButton}>{buttonTitle}</Button>}
|
||||
</Grid>
|
||||
{children}
|
||||
</Grid>
|
||||
</main>
|
||||
);
|
||||
export default DefaultPage;
|
||||
|
|
@ -1,33 +1,41 @@
|
|||
// @ts-ignore
|
||||
import ReactList from 'react-list';
|
||||
|
||||
// See also https://github.com/coderiety/react-list/blob/master/react-list.es6
|
||||
class FixedReactList extends ReactList {
|
||||
// deleting a messages or adding a message (per shift) requires invalidating the cache, react-list sucks as it does
|
||||
// not provide such functionality, therefore we need to hack it inside there :(
|
||||
ignoreNextCacheUpdate = false;
|
||||
public ignoreNextCacheUpdate = false;
|
||||
|
||||
cacheSizes() {
|
||||
public cacheSizes(): void {
|
||||
if (this.ignoreNextCacheUpdate) {
|
||||
this.ignoreNextCacheUpdate = false;
|
||||
return;
|
||||
}
|
||||
// @ts-ignore accessing private member
|
||||
super.cacheSizes();
|
||||
}
|
||||
|
||||
clearCacheFromIndex(startIndex) {
|
||||
|
||||
public clearCacheFromIndex(startIndex: number): void {
|
||||
this.ignoreNextCacheUpdate = true;
|
||||
|
||||
if (startIndex === 0) {
|
||||
// @ts-ignore accessing private member
|
||||
this.cache = {};
|
||||
} else {
|
||||
// @ts-ignore accessing private member
|
||||
Object.keys(this.cache).filter((index) => index >= startIndex).forEach((index) => {
|
||||
// @ts-ignore accessing private member
|
||||
delete this.cache[index];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
componentDidUpdate() {
|
||||
public componentDidUpdate() {
|
||||
// @ts-ignore accessing private member
|
||||
const hasCacheForLastRenderedItem = Object.keys(this.cache).length && this.cache[this.getVisibleRange()[1]];
|
||||
// @ts-ignore accessing private member
|
||||
super.componentDidUpdate();
|
||||
if (!hasCacheForLastRenderedItem) {
|
||||
// when there is no cache for the last rendered item, then its a new item, react-list doesn't know it size
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
import React, {Component} from 'react';
|
||||
import AppBar from 'material-ui/AppBar';
|
||||
import Button from 'material-ui/Button';
|
||||
import Toolbar from 'material-ui/Toolbar';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import * as UserAction from '../actions/UserAction';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {Theme, WithStyles} from "material-ui";
|
||||
import AccountCircle from 'material-ui-icons/AccountCircle';
|
||||
import Chat from 'material-ui-icons/Chat';
|
||||
import SupervisorAccount from 'material-ui-icons/SupervisorAccount';
|
||||
import DevicesOther from 'material-ui-icons/DevicesOther';
|
||||
import ExitToApp from 'material-ui-icons/ExitToApp';
|
||||
import AccountCircle from 'material-ui-icons/AccountCircle';
|
||||
import LightbulbOutline from 'material-ui-icons/LightbulbOutline';
|
||||
import SupervisorAccount from 'material-ui-icons/SupervisorAccount';
|
||||
import AppBar from 'material-ui/AppBar';
|
||||
import Button from 'material-ui/Button';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import Toolbar from 'material-ui/Toolbar';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import React, {Component} from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import * as UserAction from '../actions/UserAction';
|
||||
|
||||
const styles = (theme) => ({
|
||||
const styles = (theme: Theme) => ({
|
||||
appBar: {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
},
|
||||
|
|
@ -33,38 +33,19 @@ const styles = (theme) => ({
|
|||
},
|
||||
});
|
||||
|
||||
class Header extends Component {
|
||||
static propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
loggedIn: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
admin: PropTypes.bool.isRequired,
|
||||
version: PropTypes.string.isRequired,
|
||||
toggleTheme: PropTypes.func.isRequired,
|
||||
showSettings: PropTypes.func.isRequired,
|
||||
};
|
||||
type Styles = WithStyles<'link' | 'titleName' | 'title' | 'appBar'>
|
||||
|
||||
renderButtons(name, admin) {
|
||||
const {classes, showSettings} = this.props;
|
||||
return (
|
||||
<div>
|
||||
{admin
|
||||
? <Link className={classes.link} to="/users">
|
||||
<Button color="inherit"><SupervisorAccount/> users</Button></Link>
|
||||
: ''}
|
||||
<Link className={classes.link} to="/applications">
|
||||
<Button color="inherit"><Chat/> apps</Button>
|
||||
</Link>
|
||||
<Link className={classes.link} to="/clients"><Button color="inherit">
|
||||
<DevicesOther/> clients</Button>
|
||||
</Link>
|
||||
<Button color="inherit" onClick={showSettings}><AccountCircle/> {name}</Button>
|
||||
<Button color="inherit" onClick={UserAction.logout}><ExitToApp/> Logout</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
interface IProps {
|
||||
loggedIn: boolean
|
||||
name: string
|
||||
admin: boolean
|
||||
version: string
|
||||
toggleTheme: VoidFunction
|
||||
showSettings: VoidFunction
|
||||
}
|
||||
|
||||
render() {
|
||||
class Header extends Component<IProps & Styles> {
|
||||
public render() {
|
||||
const {classes, version, name, loggedIn, admin, toggleTheme} = this.props;
|
||||
|
||||
return (
|
||||
|
|
@ -88,6 +69,26 @@ class Header extends Component {
|
|||
</AppBar>
|
||||
);
|
||||
}
|
||||
|
||||
private renderButtons(name: string, admin: boolean) {
|
||||
const {classes, showSettings} = this.props;
|
||||
return (
|
||||
<div>
|
||||
{admin
|
||||
? <Link className={classes.link} to="/users">
|
||||
<Button color="inherit"><SupervisorAccount/> users</Button></Link>
|
||||
: ''}
|
||||
<Link className={classes.link} to="/applications">
|
||||
<Button color="inherit"><Chat/> apps</Button>
|
||||
</Link>
|
||||
<Link className={classes.link} to="/clients"><Button color="inherit">
|
||||
<DevicesOther/> clients</Button>
|
||||
</Link>
|
||||
<Button color="inherit" onClick={showSettings}><AccountCircle/> {name}</Button>
|
||||
<Button color="inherit" onClick={UserAction.logout}><ExitToApp/> Logout</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles, {withTheme: true})(Header);
|
||||
export default withStyles(styles, {withTheme: true})<IProps>(Header);
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import React, {Component} from 'react';
|
||||
import {CircularProgress} from 'material-ui/Progress';
|
||||
import DefaultPage from './DefaultPage';
|
||||
import Grid from 'material-ui/Grid';
|
||||
import {CircularProgress} from 'material-ui/Progress';
|
||||
import React, {Component} from 'react';
|
||||
import DefaultPage from './DefaultPage';
|
||||
|
||||
class LoadingSpinner extends Component {
|
||||
render() {
|
||||
public render() {
|
||||
return (
|
||||
<DefaultPage title="" maxWidth={250} hideButton={true}>
|
||||
<Grid item xs={12} style={{textAlign: 'center'}}>
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import React, {Component} from 'react';
|
||||
import {WithStyles} from "material-ui";
|
||||
import Delete from 'material-ui-icons/Delete';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import PropTypes from 'prop-types';
|
||||
import Container from './Container';
|
||||
import React, {Component} from 'react';
|
||||
import TimeAgo from 'react-timeago';
|
||||
import Delete from 'material-ui-icons/Delete';
|
||||
import Container from './Container';
|
||||
|
||||
const styles = () => ({
|
||||
header: {
|
||||
|
|
@ -32,16 +32,18 @@ const styles = () => ({
|
|||
},
|
||||
});
|
||||
|
||||
class Message extends Component {
|
||||
static propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
image: PropTypes.string,
|
||||
date: PropTypes.string.isRequired,
|
||||
content: PropTypes.string.isRequired,
|
||||
fDelete: PropTypes.func.isRequired,
|
||||
};
|
||||
render() {
|
||||
type Style = WithStyles<'header' | 'headerTitle' | 'trash' | 'wrapperPadding' | 'messageContentWrapper' | 'image' | 'imageWrapper'>;
|
||||
|
||||
interface IProps {
|
||||
title: string
|
||||
image?: string
|
||||
date: string
|
||||
content: string
|
||||
fDelete: VoidFunction
|
||||
}
|
||||
|
||||
class Message extends Component<IProps & Style> {
|
||||
public render() {
|
||||
const {fDelete, classes, title, date, content, image} = this.props;
|
||||
|
||||
return (
|
||||
|
|
@ -68,4 +70,4 @@ class Message extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(Message);
|
||||
export default withStyles(styles)<IProps>(Message);
|
||||
|
|
@ -1,47 +1,47 @@
|
|||
import React, {Component} from 'react';
|
||||
import {Theme, WithStyles} from "material-ui";
|
||||
import Divider from 'material-ui/Divider';
|
||||
import Drawer from 'material-ui/Drawer';
|
||||
import {ListItem, ListItemText} from 'material-ui/List';
|
||||
import {withStyles} from 'material-ui/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
import AppStore from '../stores/AppStore';
|
||||
import React, {Component} from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import AppStore from '../stores/AppStore';
|
||||
|
||||
const styles = (theme) => ({
|
||||
const styles = (theme: Theme) => ({
|
||||
drawerPaper: {
|
||||
position: 'relative',
|
||||
position: 'relative' as 'relative',
|
||||
width: 250,
|
||||
minHeight: '100%',
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
toolbar: theme.mixins.toolbar as any,
|
||||
link: {
|
||||
color: 'inherit',
|
||||
textDecoration: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
class Navigation extends Component {
|
||||
static propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
loggedIn: PropTypes.bool.isRequired,
|
||||
};
|
||||
type Styles = WithStyles<'drawerPaper' | 'toolbar' | 'link'>
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {apps: []};
|
||||
}
|
||||
interface IProps {
|
||||
loggedIn: boolean
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
interface IState {
|
||||
apps: IApplication[]
|
||||
}
|
||||
|
||||
class Navigation extends Component<IProps & Styles, IState> {
|
||||
public state: IState = {apps: []};
|
||||
|
||||
public componentWillMount() {
|
||||
AppStore.on('change', this.updateApps);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
public componentWillUnmount() {
|
||||
AppStore.removeListener('change', this.updateApps);
|
||||
}
|
||||
|
||||
updateApps = () => this.setState({apps: AppStore.get()});
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {classes, loggedIn} = this.props;
|
||||
const {apps} = this.state;
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ class Navigation extends Component {
|
|||
<ListItemText primary="you have no applications :("/>
|
||||
</ListItem>);
|
||||
|
||||
const userApps = apps.length === 0 ? empty : apps.map(function(app) {
|
||||
const userApps = apps.length === 0 ? empty : apps.map((app) => {
|
||||
return (
|
||||
<Link className={classes.link} to={'/messages/' + app.id} key={app.id}>
|
||||
<ListItem button>
|
||||
|
|
@ -82,6 +82,8 @@ class Navigation extends Component {
|
|||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
private updateApps = () => this.setState({apps: AppStore.get()});
|
||||
}
|
||||
|
||||
export default withStyles(styles, {withTheme: true})(Navigation);
|
||||
export default withStyles(styles,{withTheme: true})<IProps>(Navigation);
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
import React, {Component} from 'react';
|
||||
import Button from 'material-ui/Button';
|
||||
import KeyboardArrowUp from 'material-ui-icons/KeyboardArrowUp';
|
||||
import Button from 'material-ui/Button';
|
||||
import React, {Component} from 'react';
|
||||
|
||||
class ScrollUpButton extends Component {
|
||||
render() {
|
||||
public render() {
|
||||
return (
|
||||
<Button variant="fab" color="primary"
|
||||
style={{position: 'fixed', bottom: '30px', right: '30px', zIndex: 100000}}
|
||||
onClick={() => window.scrollTo(0, 0)}>
|
||||
onClick={this.scrollUp}>
|
||||
<KeyboardArrowUp/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
private scrollUp = () => window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
export default ScrollUpButton;
|
||||
|
|
@ -1,28 +1,22 @@
|
|||
import React, {Component} from 'react';
|
||||
import Button from 'material-ui/Button';
|
||||
import Dialog, {DialogActions, DialogContent, DialogTitle} from 'material-ui/Dialog';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import Tooltip from 'material-ui/Tooltip';
|
||||
import Dialog, {DialogActions, DialogContent, DialogTitle} from 'material-ui/Dialog';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, {ChangeEvent, Component} from 'react';
|
||||
import * as UserAction from '../actions/UserAction';
|
||||
|
||||
export default class SettingsDialog extends Component {
|
||||
static propTypes = {
|
||||
fClose: PropTypes.func.isRequired,
|
||||
};
|
||||
interface IState {
|
||||
pass: string
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {pass: ''};
|
||||
}
|
||||
interface IProps {
|
||||
fClose: VoidFunction
|
||||
}
|
||||
|
||||
handleChange(propertyName, event) {
|
||||
const state = this.state;
|
||||
state[propertyName] = event.target.value;
|
||||
this.setState(state);
|
||||
}
|
||||
export default class SettingsDialog extends Component<IProps, IState> {
|
||||
public state = {pass: ''};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {pass} = this.state;
|
||||
const {fClose} = this.props;
|
||||
const submitAndClose = () => {
|
||||
|
|
@ -50,4 +44,10 @@ export default class SettingsDialog extends Component {
|
|||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
private handleChange(propertyName: string, event: ChangeEvent<HTMLInputElement>) {
|
||||
const state = this.state;
|
||||
state[propertyName] = event.target.value;
|
||||
this.setState(state);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +1,37 @@
|
|||
import Close from 'material-ui-icons/Close';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import Snackbar from 'material-ui/Snackbar';
|
||||
import React, {Component} from 'react';
|
||||
import SnackBarStore from '../stores/SnackBarStore';
|
||||
import Snackbar from 'material-ui/Snackbar';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import Close from 'material-ui-icons/Close';
|
||||
|
||||
class SnackBarHandler extends Component {
|
||||
static MAX_VISIBLE_SNACK_TIME_IN_MS = 6000;
|
||||
static MIN_VISIBLE_SNACK_TIME_IN_MS = 1000;
|
||||
|
||||
state = {
|
||||
interface IState {
|
||||
current: string
|
||||
hasNext: boolean
|
||||
open: boolean
|
||||
openWhen: number
|
||||
}
|
||||
|
||||
class SnackBarHandler extends Component<{}, IState> {
|
||||
private static MAX_VISIBLE_SNACK_TIME_IN_MS = 6000;
|
||||
private static MIN_VISIBLE_SNACK_TIME_IN_MS = 1000;
|
||||
|
||||
public state = {
|
||||
current: '',
|
||||
hasNext: false,
|
||||
open: false,
|
||||
openWhen: 0,
|
||||
};
|
||||
|
||||
componentWillMount = () => SnackBarStore.on('change', this.onNewSnack);
|
||||
componentWillUnmount = () => SnackBarStore.removeListener('change', this.onNewSnack);
|
||||
public componentWillMount() {
|
||||
SnackBarStore.on('change', this.onNewSnack);
|
||||
}
|
||||
|
||||
onNewSnack = () => {
|
||||
const {open, openWhen} = this.state;
|
||||
public componentWillUnmount() {
|
||||
SnackBarStore.removeListener('change', this.onNewSnack);
|
||||
}
|
||||
|
||||
if (!open) {
|
||||
this.openNextSnack();
|
||||
return;
|
||||
}
|
||||
|
||||
const snackOpenSince = Date.now() - openWhen;
|
||||
if (snackOpenSince > SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS) {
|
||||
this.closeCurrentSnack();
|
||||
} else {
|
||||
setTimeout(this.closeCurrentSnack, SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS - snackOpenSince);
|
||||
}
|
||||
};
|
||||
|
||||
openNextSnack = () => {
|
||||
if (SnackBarStore.hasNext()) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
open: true,
|
||||
openWhen: Date.now(),
|
||||
current: SnackBarStore.next(),
|
||||
hasNext: SnackBarStore.hasNext(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
closeCurrentSnack = () => this.setState({...this.state, open: false});
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {open, current, hasNext} = this.state;
|
||||
const duration = hasNext
|
||||
? SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS
|
||||
|
|
@ -68,6 +51,36 @@ class SnackBarHandler extends Component {
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private onNewSnack = () => {
|
||||
const {open, openWhen} = this.state;
|
||||
|
||||
if (!open) {
|
||||
this.openNextSnack();
|
||||
return;
|
||||
}
|
||||
|
||||
const snackOpenSince = Date.now() - openWhen;
|
||||
if (snackOpenSince > SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS) {
|
||||
this.closeCurrentSnack();
|
||||
} else {
|
||||
setTimeout(this.closeCurrentSnack, SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS - snackOpenSince);
|
||||
}
|
||||
};
|
||||
|
||||
private openNextSnack = () => {
|
||||
if (SnackBarStore.hasNext()) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
open: true,
|
||||
openWhen: Date.now(),
|
||||
current: SnackBarStore.next(),
|
||||
hasNext: SnackBarStore.hasNext(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private closeCurrentSnack = () => this.setState({...this.state, open: false});
|
||||
}
|
||||
|
||||
export default SnackBarHandler;
|
||||
|
|
@ -1,24 +1,22 @@
|
|||
import React, {Component} from 'react';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import VisibilityOff from 'material-ui-icons/VisibilityOff';
|
||||
import Visibility from 'material-ui-icons/Visibility';
|
||||
import PropTypes from 'prop-types';
|
||||
import VisibilityOff from 'material-ui-icons/VisibilityOff';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import Typography from 'material-ui/Typography';
|
||||
import React, {Component} from 'react';
|
||||
|
||||
class ToggleVisibility extends Component {
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
interface IProps {
|
||||
value: string
|
||||
style?: object
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {visible: false};
|
||||
}
|
||||
interface IState {
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
toggleVisibility = () => this.setState({visible: !this.state.visible});
|
||||
class ToggleVisibility extends Component<IProps, IState> {
|
||||
public state = {visible: false};
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {value, style} = this.props;
|
||||
const text = this.state.visible ? value : '•••••••••••••••';
|
||||
return (
|
||||
|
|
@ -32,6 +30,8 @@ class ToggleVisibility extends Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleVisibility = () => this.setState({visible: !this.state.visible});
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue