zepio/app/components/status-pill.js

147 lines
3.9 KiB
JavaScript

// @flow
import React, { PureComponent } from 'react';
import styled, { keyframes, withTheme } from 'styled-components';
import { TextComponent } from './text';
import { DARK } from '../constants/themes';
import { NODE_SYNC_TYPES } from '../constants/node-sync-types';
import readyIconDark from '../assets/images/green_check_dark.png';
import readyIconLight from '../assets/images/green_check_light.png';
import syncIconDark from '../assets/images/sync_icon_dark.png';
import syncIconLight from '../assets/images/sync_icon_light.png';
import errorIconDark from '../assets/images/error_icon_dark.png';
import errorIconLight from '../assets/images/error_icon_light.png';
import type { MapDispatchToProps, MapStateToProps } from '../containers/status-pill';
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const Wrapper = styled.div`
align-items: center;
display: flex;
background: ${props => props.theme.colors.statusPillBg};
border: 1px solid ${props => props.theme.colors.statusPillBorder}
border-radius: 27px;
padding: 8px 16px;
`;
const Icon = styled.img`
width: 12px;
height: 12px;
margin-right: 8px;
animation: 2s linear infinite;
animation-name: ${/** $FlowFixMe */
(props: PropsWithTheme<{ animated: boolean }>) => (props.animated ? rotate : 'none')};
`;
const StatusPillLabel = styled(TextComponent)`
color: ${props => props.theme.colors.statusPillLabel};
font-weight: ${props => String(props.theme.fontWeight.bold)};
text-transform: uppercase;
font-size: 10px;
padding-top: 1px;
user-select: none;
`;
type Props = {
theme: AppTheme,
} & MapStateToProps &
MapDispatchToProps;
const MINUTE_IN_MILI = 60000;
class Component extends PureComponent<Props> {
timer: ?IntervalID = null;
componentDidMount() {
const { getBlockchainStatus } = this.props;
this.timer = setInterval(() => getBlockchainStatus(), 2000);
}
componentDidUpdate(prevProps: Props) {
const { getBlockchainStatus, nodeSyncType } = this.props;
if (
prevProps.nodeSyncType === NODE_SYNC_TYPES.SYNCING
&& nodeSyncType === NODE_SYNC_TYPES.READY
) {
// if the status is "ready", we can increase the interval to avoid useless rpc calls
this.cleanUpdateInterval();
this.timer = setInterval(() => getBlockchainStatus(), MINUTE_IN_MILI);
}
}
componentWillUnmount() {
this.cleanUpdateInterval();
}
cleanUpdateInterval = () => {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
};
isSyncing = () => {
const { nodeSyncType } = this.props;
return nodeSyncType === NODE_SYNC_TYPES.SYNCING;
};
getReadyIcon = () => {
const { theme } = this.props;
return theme.mode === DARK ? readyIconDark : readyIconLight;
};
getErrorIcon = () => {
const { theme } = this.props;
return theme.mode === DARK ? errorIconDark : errorIconLight;
};
getSyncingIcon = () => {
const { theme } = this.props;
return theme.mode === DARK ? syncIconDark : syncIconLight;
};
getIcon = () => {
const { nodeSyncType } = this.props;
switch (nodeSyncType) {
case NODE_SYNC_TYPES.SYNCING:
return this.getSyncingIcon();
case NODE_SYNC_TYPES.READY:
return this.getReadyIcon();
case NODE_SYNC_TYPES.ERROR:
return this.getErrorIcon();
default:
return null;
}
};
render() {
const icon = this.getIcon();
const { nodeSyncType, nodeSyncProgress } = this.props;
const percent = nodeSyncType === NODE_SYNC_TYPES.SYNCING ? `(${nodeSyncProgress.toFixed(2)}%)` : '';
const typeText = nodeSyncType === NODE_SYNC_TYPES.READY ? 'Synced' : nodeSyncType;
return (
<Wrapper id='status-pill'>
{icon && <Icon src={icon} animated={this.isSyncing()} />}
<StatusPillLabel value={`${typeText} ${percent}`} />
</Wrapper>
);
}
}
export const StatusPill = withTheme(Component);