diff options
author | Anthony Bellew <anthonyreflected@gmail.com> | 2017-01-25 20:53:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-25 20:53:57 -0700 |
commit | 3d890c407356c8e0e7dd9b64e8e232ededcff8e8 (patch) | |
tree | a22df9a8737250f97a6024943af3445a163917b3 /app/assets/javascripts/components/features/notifications | |
parent | febe2449bb14f3d877fb934ceb6d52e320712bac (diff) | |
parent | 905c82917959a5afe24cb85c62c0b0ba13f0da8b (diff) |
Merge pull request #3 from tootsuite/master
Updating to current
Diffstat (limited to 'app/assets/javascripts/components/features/notifications')
5 files changed, 94 insertions, 127 deletions
diff --git a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx b/app/assets/javascripts/components/features/notifications/components/column_settings.jsx index b4035c20d..b63c1881a 100644 --- a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx +++ b/app/assets/javascripts/components/features/notifications/components/column_settings.jsx @@ -1,37 +1,14 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import Toggle from 'react-toggle'; -import { Motion, spring } from 'react-motion'; import { FormattedMessage } from 'react-intl'; +import ColumnCollapsable from '../../../components/column_collapsable'; +import SettingToggle from './setting_toggle'; const outerStyle = { background: '#373b4a', padding: '15px' }; -const iconStyle = { - fontSize: '16px', - padding: '15px', - position: 'absolute', - right: '0', - top: '-48px', - cursor: 'pointer' -}; - -const labelStyle = { - display: 'block', - lineHeight: '24px', - verticalAlign: 'middle' -}; - -const labelSpanStyle = { - display: 'inline-block', - verticalAlign: 'middle', - marginBottom: '14px', - marginLeft: '8px', - color: '#9baec8' -}; - const sectionStyle = { cursor: 'default', display: 'block', @@ -48,100 +25,55 @@ const ColumnSettings = React.createClass({ propTypes: { settings: ImmutablePropTypes.map.isRequired, - onChange: React.PropTypes.func.isRequired - }, - - getInitialState () { - return { - collapsed: true - }; + onChange: React.PropTypes.func.isRequired, + onSave: React.PropTypes.func.isRequired }, mixins: [PureRenderMixin], - handleToggleCollapsed () { - this.setState({ collapsed: !this.state.collapsed }); - }, - - handleChange (key, e) { - this.props.onChange(key, e.target.checked); - }, - render () { - const { settings } = this.props; - const { collapsed } = this.state; + const { settings, onChange, onSave } = this.props; const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />; const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />; + const soundStr = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />; return ( - <div style={{ position: 'relative' }}> - <div style={{...iconStyle, color: collapsed ? '#9baec8' : '#fff', background: collapsed ? '#2f3441' : '#373b4a' }} onClick={this.handleToggleCollapsed}><i className='fa fa-sliders' /></div> - - <Motion defaultStyle={{ opacity: 0, height: 0 }} style={{ opacity: spring(collapsed ? 0 : 100), height: spring(collapsed ? 0 : 458) }}> - {({ opacity, height }) => - <div style={{ overflow: 'hidden', height: `${height}px`, opacity: opacity / 100 }}> - <div style={outerStyle}> - <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span> - - <div style={rowStyle}> - <label style={labelStyle}> - <Toggle checked={settings.getIn(['alerts', 'follow'])} onChange={this.handleChange.bind(this, ['alerts', 'follow'])} /> - <span style={labelSpanStyle}>{alertStr}</span> - </label> - - <label style={labelStyle}> - <Toggle checked={settings.getIn(['shows', 'follow'])} onChange={this.handleChange.bind(this, ['shows', 'follow'])} /> - <span style={labelSpanStyle}>{showStr}</span> - </label> - </div> - - <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span> - - <div style={rowStyle}> - <label style={labelStyle}> - <Toggle checked={settings.getIn(['alerts', 'favourite'])} onChange={this.handleChange.bind(this, ['alerts', 'favourite'])} /> - <span style={labelSpanStyle}>{alertStr}</span> - </label> - - <label style={labelStyle}> - <Toggle checked={settings.getIn(['shows', 'favourite'])} onChange={this.handleChange.bind(this, ['shows', 'favourite'])} /> - <span style={labelSpanStyle}>{showStr}</span> - </label> - </div> - - <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span> - - <div style={rowStyle}> - <label style={labelStyle}> - <Toggle checked={settings.getIn(['alerts', 'mention'])} onChange={this.handleChange.bind(this, ['alerts', 'mention'])} /> - <span style={labelSpanStyle}>{alertStr}</span> - </label> - - <label style={labelStyle}> - <Toggle checked={settings.getIn(['shows', 'mention'])} onChange={this.handleChange.bind(this, ['shows', 'mention'])} /> - <span style={labelSpanStyle}>{showStr}</span> - </label> - </div> - - <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span> - - <div style={rowStyle}> - <label style={labelStyle}> - <Toggle checked={settings.getIn(['alerts', 'reblog'])} onChange={this.handleChange.bind(this, ['alerts', 'reblog'])} /> - <span style={labelSpanStyle}>{alertStr}</span> - </label> - - <label style={labelStyle}> - <Toggle checked={settings.getIn(['shows', 'reblog'])} onChange={this.handleChange.bind(this, ['shows', 'reblog'])} /> - <span style={labelSpanStyle}>{showStr}</span> - </label> - </div> - </div> - </div> - } - </Motion> - </div> + <ColumnCollapsable icon='sliders' fullHeight={616} onCollapse={onSave}> + <div style={outerStyle}> + <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span> + + <div style={rowStyle}> + <SettingToggle settings={settings} settingKey={['alerts', 'follow']} onChange={onChange} label={alertStr} /> + <SettingToggle settings={settings} settingKey={['shows', 'follow']} onChange={onChange} label={showStr} /> + <SettingToggle settings={settings} settingKey={['sounds', 'follow']} onChange={onChange} label={soundStr} /> + </div> + + <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span> + + <div style={rowStyle}> + <SettingToggle settings={settings} settingKey={['alerts', 'favourite']} onChange={onChange} label={alertStr} /> + <SettingToggle settings={settings} settingKey={['shows', 'favourite']} onChange={onChange} label={showStr} /> + <SettingToggle settings={settings} settingKey={['sounds', 'favourite']} onChange={onChange} label={soundStr} /> + </div> + + <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span> + + <div style={rowStyle}> + <SettingToggle settings={settings} settingKey={['alerts', 'mention']} onChange={onChange} label={alertStr} /> + <SettingToggle settings={settings} settingKey={['shows', 'mention']} onChange={onChange} label={showStr} /> + <SettingToggle settings={settings} settingKey={['sounds', 'mention']} onChange={onChange} label={soundStr} /> + </div> + + <span style={sectionStyle}><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span> + + <div style={rowStyle}> + <SettingToggle settings={settings} settingKey={['alerts', 'reblog']} onChange={onChange} label={alertStr} /> + <SettingToggle settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={showStr} /> + <SettingToggle settings={settings} settingKey={['sounds', 'reblog']} onChange={onChange} label={soundStr} /> + </div> + </div> + </ColumnCollapsable> ); } diff --git a/app/assets/javascripts/components/features/notifications/components/notification.jsx b/app/assets/javascripts/components/features/notifications/components/notification.jsx index 9f4cf9e4d..140ba9134 100644 --- a/app/assets/javascripts/components/features/notifications/components/notification.jsx +++ b/app/assets/javascripts/components/features/notifications/components/notification.jsx @@ -4,6 +4,8 @@ import StatusContainer from '../../../containers/status_container'; import AccountContainer from '../../../containers/account_container'; import { FormattedMessage } from 'react-intl'; import Permalink from '../../../components/permalink'; +import emojify from '../../../emoji'; +import escapeTextContentForBrowser from 'react/lib/escapeTextContentForBrowser'; const messageStyle = { marginLeft: '68px', @@ -71,7 +73,7 @@ const Notification = React.createClass({ <i className='fa fa-fw fa-retweet' style={{ color: '#2b90d9' }} /> </div> - <FormattedMessage id='notification.reblog' defaultMessage='{name} reblogged your status' values={{ name: link }} /> + <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} /> </div> <StatusContainer id={notification.get('status')} muted={true} /> @@ -83,7 +85,8 @@ const Notification = React.createClass({ const { notification } = this.props; const account = notification.get('account'); const displayName = account.get('display_name').length > 0 ? account.get('display_name') : account.get('username'); - const link = <Permalink className='notification__display-name' style={linkStyle} href={account.get('url')} to={`/accounts/${account.get('id')}`}>{displayName}</Permalink>; + const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; + const link = <Permalink className='notification__display-name' style={linkStyle} href={account.get('url')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHTML} />; switch(notification.get('type')) { case 'follow': diff --git a/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx b/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx new file mode 100644 index 000000000..c2438f716 --- /dev/null +++ b/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx @@ -0,0 +1,32 @@ +import ImmutablePropTypes from 'react-immutable-proptypes'; +import Toggle from 'react-toggle'; + +const labelStyle = { + display: 'block', + lineHeight: '24px', + verticalAlign: 'middle' +}; + +const labelSpanStyle = { + display: 'inline-block', + verticalAlign: 'middle', + marginBottom: '14px', + marginLeft: '8px', + color: '#9baec8' +}; + +const SettingToggle = ({ settings, settingKey, label, onChange }) => ( + <label style={labelStyle}> + <Toggle checked={settings.getIn(settingKey)} onChange={(e) => onChange(settingKey, e.target.checked)} /> + <span style={labelSpanStyle}>{label}</span> + </label> +); + +SettingToggle.propTypes = { + settings: ImmutablePropTypes.map.isRequired, + settingKey: React.PropTypes.array.isRequired, + label: React.PropTypes.node.isRequired, + onChange: React.PropTypes.func.isRequired +}; + +export default SettingToggle; diff --git a/app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx b/app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx index 6907fd351..bc24c75e0 100644 --- a/app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx +++ b/app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx @@ -1,15 +1,19 @@ import { connect } from 'react-redux'; import ColumnSettings from '../components/column_settings'; -import { changeNotificationsSetting } from '../../../actions/notifications'; +import { changeSetting, saveSettings } from '../../../actions/settings'; const mapStateToProps = state => ({ - settings: state.getIn(['notifications', 'settings']) + settings: state.getIn(['settings', 'notifications']) }); const mapDispatchToProps = dispatch => ({ onChange (key, checked) { - dispatch(changeNotificationsSetting(key, checked)); + dispatch(changeSetting(['notifications', ...key], checked)); + }, + + onSave () { + dispatch(saveSettings()); } }); diff --git a/app/assets/javascripts/components/features/notifications/index.jsx b/app/assets/javascripts/components/features/notifications/index.jsx index 7e706ad6a..b4593aaff 100644 --- a/app/assets/javascripts/components/features/notifications/index.jsx +++ b/app/assets/javascripts/components/features/notifications/index.jsx @@ -2,10 +2,7 @@ import { connect } from 'react-redux'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; import Column from '../ui/components/column'; -import { - refreshNotifications, - expandNotifications -} from '../../actions/notifications'; +import { expandNotifications } from '../../actions/notifications'; import NotificationContainer from './containers/notification_container'; import { ScrollContainer } from 'react-router-scroll'; import { defineMessages, injectIntl } from 'react-intl'; @@ -18,12 +15,13 @@ const messages = defineMessages({ }); const getNotifications = createSelector([ - state => Immutable.List(state.getIn(['notifications', 'settings', 'shows']).filter(item => !item).keys()), + state => Immutable.List(state.getIn(['settings', 'notifications', 'shows']).filter(item => !item).keys()), state => state.getIn(['notifications', 'items']) ], (excludedTypes, notifications) => notifications.filterNot(item => excludedTypes.includes(item.get('type')))); const mapStateToProps = state => ({ - notifications: getNotifications(state) + notifications: getNotifications(state), + isLoading: state.getIn(['notifications', 'isLoading'], true) }); const Notifications = React.createClass({ @@ -32,7 +30,8 @@ const Notifications = React.createClass({ notifications: ImmutablePropTypes.list.isRequired, dispatch: React.PropTypes.func.isRequired, trackScroll: React.PropTypes.bool, - intl: React.PropTypes.object.isRequired + intl: React.PropTypes.object.isRequired, + isLoading: React.PropTypes.bool }, getDefaultProps () { @@ -43,15 +42,11 @@ const Notifications = React.createClass({ mixins: [PureRenderMixin], - componentWillMount () { - const { dispatch } = this.props; - dispatch(refreshNotifications()); - }, - handleScroll (e) { const { scrollTop, scrollHeight, clientHeight } = e.target; + const offset = scrollHeight - scrollTop - clientHeight; - if (scrollTop === scrollHeight - clientHeight) { + if (250 > offset && !this.props.isLoading) { this.props.dispatch(expandNotifications()); } }, @@ -70,6 +65,7 @@ const Notifications = React.createClass({ if (trackScroll) { return ( <Column icon='bell' heading={intl.formatMessage(messages.title)}> + <ColumnSettingsContainer /> <ScrollContainer scrollKey='notifications'> {scrollableArea} </ScrollContainer> |