5 changed files with 171 additions and 78 deletions
@ -0,0 +1,129 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
import { connect } from 'react-redux' |
||||
|
import Box from 'components/base/Box' |
||||
|
import { radii } from 'styles/theme' |
||||
|
import IconCross from 'icons/Cross' |
||||
|
import { createStructuredSelector } from 'reselect' |
||||
|
import { dismissBanner } from '../actions/settings' |
||||
|
import { dismissedBannersSelector } from '../reducers/settings' |
||||
|
|
||||
|
export type Content = { |
||||
|
Icon?: React$ComponentType<*>, |
||||
|
message: React$Node, |
||||
|
right?: React$Node, |
||||
|
} |
||||
|
|
||||
|
type Props = { |
||||
|
content?: Content, |
||||
|
status: string, |
||||
|
dismissable: boolean, |
||||
|
bannerId?: string, |
||||
|
dismissedBanners: string[], |
||||
|
dismissBanner: string => void, |
||||
|
} |
||||
|
|
||||
|
const mapStateToProps = createStructuredSelector({ |
||||
|
dismissedBanners: dismissedBannersSelector, |
||||
|
}) |
||||
|
|
||||
|
const mapDispatchToProps = { |
||||
|
dismissBanner, |
||||
|
} |
||||
|
|
||||
|
class TopBanner extends PureComponent<Props> { |
||||
|
static defaultProps = { |
||||
|
status: '', |
||||
|
dismissable: false, |
||||
|
} |
||||
|
|
||||
|
onDismiss = () => { |
||||
|
const { bannerId, dismissBanner } = this.props |
||||
|
|
||||
|
if (bannerId) { |
||||
|
dismissBanner(bannerId) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { dismissedBanners, bannerId, dismissable, content, status } = this.props |
||||
|
|
||||
|
if (!content || (bannerId && dismissedBanners.includes(bannerId))) return null |
||||
|
|
||||
|
const { Icon, message, right } = content |
||||
|
|
||||
|
return ( |
||||
|
<Container status={status}> |
||||
|
{Icon && ( |
||||
|
<IconContainer> |
||||
|
<Icon size={16} /> |
||||
|
</IconContainer> |
||||
|
)} |
||||
|
{message} |
||||
|
<RightContainer>{right}</RightContainer> |
||||
|
{dismissable && ( |
||||
|
<CloseContainer onClick={this.onDismiss}> |
||||
|
<IconCross size={16} /> |
||||
|
</CloseContainer> |
||||
|
)} |
||||
|
</Container> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect( |
||||
|
mapStateToProps, |
||||
|
mapDispatchToProps, |
||||
|
)(TopBanner) |
||||
|
|
||||
|
const IconContainer = styled.div` |
||||
|
margin-right: 15px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
` |
||||
|
|
||||
|
const colorForStatus = { |
||||
|
error: 'alertRed', |
||||
|
} |
||||
|
|
||||
|
const Container = styled(Box).attrs({ |
||||
|
horizontal: true, |
||||
|
align: 'center', |
||||
|
py: '8px', |
||||
|
px: 3, |
||||
|
bg: p => colorForStatus[p.status] || 'wallet', |
||||
|
color: 'white', |
||||
|
mt: -20, |
||||
|
mb: 20, |
||||
|
fontSize: 4, |
||||
|
ff: 'Open Sans|SemiBold', |
||||
|
})` |
||||
|
border-radius: ${radii[1]}px; |
||||
|
` |
||||
|
|
||||
|
const RightContainer = styled.div` |
||||
|
margin-left: auto; |
||||
|
` |
||||
|
|
||||
|
export const FakeLink = styled.span` |
||||
|
color: white; |
||||
|
text-decoration: underline; |
||||
|
cursor: pointer; |
||||
|
` |
||||
|
|
||||
|
const CloseContainer = styled(Box).attrs({ |
||||
|
color: 'white', |
||||
|
})` |
||||
|
z-index: 1; |
||||
|
margin-left: 10px; |
||||
|
cursor: pointer; |
||||
|
&:hover { |
||||
|
color: ${p => p.theme.colors.graphite}; |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
color: ${p => p.theme.colors.graphite}; |
||||
|
} |
||||
|
` |
Loading…
Reference in new issue