Skip to content

Commit

Permalink
Converts NotificationBar and NotificationItem into redux components
Browse files Browse the repository at this point in the history
Resolves brave#9451

Auditors: @bsclifton @bridiver

Test Plan:
  • Loading branch information
NejcZdovc committed Jun 19, 2017
1 parent fab48e2 commit 9738f41
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 48 deletions.
11 changes: 5 additions & 6 deletions app/renderer/components/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,12 +679,12 @@ class Main extends ImmutableComponent {
const customTitlebar = this.customTitlebar
const contextMenuDetail = this.props.windowState.get('contextMenuDetail')
const shouldAllowWindowDrag = windowState.shouldAllowWindowDrag(this.props.appState, this.props.windowState, activeFrame, isFocused())
const activeOrigin = activeFrame ? siteUtil.getOrigin(activeFrame.get('location')) : null
const notificationBarIsVisible = activeOrigin && this.props.appState.get('notifications').filter((item) =>
item.get('frameOrigin') ? activeOrigin === item.get('frameOrigin') : true).size > 0

const appStateSites = this.props.appState.get('sites')

const notifications = this.props.appState.get('notifications')
const hasNotifications = notifications && notifications.size

return <div id='window'
className={cx({
isFullScreen: activeFrame && activeFrame.get('isFullScreen'),
Expand Down Expand Up @@ -824,11 +824,10 @@ class Main extends ImmutableComponent {
</div>
<TabsToolbar key='tab-bar' />
{
hasNotifications && activeFrame
? <NotificationBar notifications={notifications} activeFrame={activeFrame} />
notificationBarIsVisible
? <NotificationBar />
: null
}

{
activeFrame && activeFrame.get('findbarShown') && !activeFrame.get('isFullScreen')
? <FindBar
Expand Down
42 changes: 26 additions & 16 deletions app/renderer/components/main/notificationBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,52 @@

const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
const Immutable = require('immutable')

// Components
const ImmutableComponent = require('../immutableComponent')
const ReduxComponent = require('../reduxComponent')
const NotificationItem = require('./notificationItem')

// Utils
const {getOrigin} = require('../../../../js/state/siteUtil')
const frameStateUtil = require('../../../../js/state/frameStateUtil')

// Styles
const commonStyles = require('../styles/commonStyles')
const globalStyles = require('../styles/global')

class NotificationBar extends ImmutableComponent {
render () {
const activeOrigin = getOrigin(this.props.activeFrame.get('location'))
if (!activeOrigin) {
return null
}
const activeNotifications = this.props.notifications.filter((item) =>
item.get('frameOrigin') ? activeOrigin === item.get('frameOrigin') : true)
class NotificationBar extends React.Component {
mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const activeFrame = frameStateUtil.getActiveFrame(currentWindow) || Immutable.Map()
const activeOrigin = getOrigin(activeFrame.get('location'))
const notifications = state.get('notifications')

if (!activeNotifications.size) {
return null
}
const props = {}
props.activeNotifications = notifications
.filter((item) => {
return item.get('frameOrigin')
? activeOrigin === item.get('frameOrigin')
: true
})
.takeLast(3)
.map((notification) => notification.get('message'))

return props
}

render () {
return <div className={css(commonStyles.notificationBar)} data-test-id='notificationBar'>
{
activeNotifications.takeLast(3).map((notificationDetail) =>
<NotificationItem detail={notificationDetail} />
this.props.activeNotifications.map((message) =>
<NotificationItem message={message} />
)
}
</div>
}
}

class NotificationBarCaret extends ImmutableComponent {
class NotificationBarCaret extends React.Component {
render () {
return <div className={css(styles.caretWrapper)}>
<div className={css(styles.caretWrapper__caret)} />
Expand Down Expand Up @@ -75,6 +85,6 @@ const styles = StyleSheet.create({
})

module.exports = {
NotificationBar,
NotificationBar: ReduxComponent.connect(NotificationBar),
NotificationBarCaret
}
82 changes: 56 additions & 26 deletions app/renderer/components/main/notificationItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const Immutable = require('immutable')
const ipc = require('electron').ipcRenderer
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
const ImmutableComponent = require('../immutableComponent')
const ReduxComponent = require('../reduxComponent')
const BrowserButton = require('../common/browserButton')

// Constants
Expand All @@ -22,70 +23,99 @@ const cx = require('../../../../js/lib/classSet')
// Styles
const commonStyles = require('../styles/commonStyles')

class NotificationItem extends ImmutableComponent {
clickHandler (buttonIndex, e) {
const nonce = this.props.detail.get('options').get('nonce')
if (nonce) {
ipc.emit(messages.NOTIFICATION_RESPONSE + nonce, {},
this.props.detail.get('message'),
buttonIndex, this.checkbox ? this.checkbox.checked : false)
class NotificationItem extends React.Component {
constructor (props) {
super(props)
this.openAdvanced = this.openAdvanced.bind(this)
this.toggleCheckbox = this.toggleCheckbox.bind(this)
}

clickHandler (buttonIndex) {
if (this.props.nonce) {
ipc.emit(
messages.NOTIFICATION_RESPONSE + this.props.nonce,
{},
this.props.message,
buttonIndex,
this.checkbox ? this.checkbox.checked : false
)
} else {
ipc.send(messages.NOTIFICATION_RESPONSE, this.props.detail.get('message'),
buttonIndex, this.checkbox ? this.checkbox.checked : false)
ipc.send(
messages.NOTIFICATION_RESPONSE,
this.props.message,
buttonIndex,
this.checkbox ? this.checkbox.checked : false
)
}
}

openAdvanced () {
appActions.createTabRequested({
url: this.props.detail.get('options').get('advancedLink')
url: this.props.advancedLink
})
}

toggleCheckbox () {
this.checkbox.checked = !this.checkbox.checked
}

mergeProps (state, ownProps) {
const notification = state.get('notifications')
.find((notification) => {
return notification.get('message') === ownProps.message
}) || Immutable.Map()

const props = {}
props.message = ownProps.message
props.greeting = notification.get('greeting')
props.buttons = notification.get('buttons') // TODO (nejc) only primitives
props.style = notification.getIn(['options', 'style'])
props.advancedText = notification.getIn(['options', 'advancedText'])
props.advancedLink = notification.getIn(['options', 'advancedLink'])
props.persist = notification.getIn(['options', 'persist'])
props.nonce = notification.getIn(['options', 'nonce'])

return props
}

render () {
let i = 0
const options = this.props.detail.get('options')
const greeting = this.props.detail.get('greeting')
return <div className={cx({
notificationItem: true,
[css(commonStyles.notificationBar__notificationItem)]: true,
[options.get('style')]: options.get('style')
[this.props.style]: this.props.style
})}>
<div className={css(styles.flexJustifyBetween, styles.flexAlignCenter)}>
<div className={css(styles.marginRight)}>
{
greeting
? <span className={css(commonStyles.notificationItem__greeting)} data-test-id='greeting'>{greeting}</span>
this.props.greeting
? <span className={css(commonStyles.notificationItem__greeting)} data-test-id='greeting'>{this.props.greeting}</span>
: null
}
<span className={css(commonStyles.notificationItem__message)}>{this.props.detail.get('message')}</span>
<span className={css(commonStyles.notificationItem__message)}>{this.props.message}</span>
<span className={css(styles.advanced)}>
{
options.get('advancedText') && options.get('advancedLink')
? <span onClick={this.openAdvanced.bind(this)}>{options.get('advancedText')}</span>
this.props.advancedText && this.props.advancedLink
? <span onClick={this.openAdvanced}>{this.props.advancedText}</span>
: null
}
</span>
</div>
<span className={css(styles.flexAlignCenter)} data-test-id='notificationOptions'>
{
options.get('persist')
this.props.persist
? <span id='rememberOption'>
<input className={css(styles.checkbox)} type='checkbox' ref={(node) => { this.checkbox = node }} />
<label className={css(styles.label)} htmlFor='rememberOption' data-l10n-id='rememberDecision' onClick={this.toggleCheckbox.bind(this)} />
<label className={css(styles.label)} htmlFor='rememberOption' data-l10n-id='rememberDecision' onClick={this.toggleCheckbox} />
</span>
: null
}
{
this.props.detail.get('buttons').map((button) =>
this.props.buttons.map((button, i) =>
<BrowserButton groupedItem secondaryColor notificationItem
iconClass={button.get('className')}
testId='notificationButton'
label={button.get('text')}
onClick={this.clickHandler.bind(this, i++)}
onClick={this.clickHandler.bind(this, i)}
/>
)
}
Expand All @@ -95,6 +125,8 @@ class NotificationItem extends ImmutableComponent {
}
}

module.exports = ReduxComponent.connect(NotificationItem)

const styles = StyleSheet.create({
flexJustifyBetween: {
display: 'flex',
Expand Down Expand Up @@ -124,5 +156,3 @@ const styles = StyleSheet.create({
margin: '5px'
}
})

module.exports = NotificationItem

0 comments on commit 9738f41

Please sign in to comment.