import { openModal } from '../actions/modal';
import { createSelector } from 'reselect'
import { isMobile } from '../is_mobile'
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+
+const messages = defineMessages({
+ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
+ deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
+ blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
+ muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
+});
const makeMapStateToProps = () => {
const getStatus = makeGetStatus();
return mapStateToProps;
};
-const mapDispatchToProps = (dispatch) => ({
+const mapDispatchToProps = (dispatch, { intl }) => ({
onReply (status, router) {
dispatch(replyCompose(status, router));
},
onDelete (status) {
- dispatch(deleteStatus(status.get('id')));
+ dispatch(openModal('CONFIRM', {
+ message: intl.formatMessage(messages.deleteMessage),
+ confirm: intl.formatMessage(messages.deleteConfirm),
+ onConfirm: () => dispatch(deleteStatus(status.get('id')))
+ }));
},
onMention (account, router) {
},
onBlock (account) {
- dispatch(blockAccount(account.get('id')));
+ dispatch(openModal('CONFIRM', {
+ message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
+ confirm: intl.formatMessage(messages.blockConfirm),
+ onConfirm: () => dispatch(blockAccount(account.get('id')))
+ }));
},
onReport (status) {
},
onMute (account) {
- dispatch(muteAccount(account.get('id')));
+ dispatch(openModal('CONFIRM', {
+ message: <FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
+ confirm: intl.formatMessage(messages.muteConfirm),
+ onConfirm: () => dispatch(muteAccount(account.get('id')))
+ }));
},
});
-export default connect(makeMapStateToProps, mapDispatchToProps)(Status);
+export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status));
} from '../../../actions/accounts';
import { mentionCompose } from '../../../actions/compose';
import { initReport } from '../../../actions/reports';
+import { openModal } from '../../../actions/modal';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+
+const messages = defineMessages({
+ blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
+ muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' }
+});
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
return mapStateToProps;
};
-const mapDispatchToProps = dispatch => ({
+const mapDispatchToProps = (dispatch, { intl }) => ({
onFollow (account) {
if (account.getIn(['relationship', 'following'])) {
dispatch(unfollowAccount(account.get('id')));
if (account.getIn(['relationship', 'blocking'])) {
dispatch(unblockAccount(account.get('id')));
} else {
- dispatch(blockAccount(account.get('id')));
+ dispatch(openModal('CONFIRM', {
+ message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
+ confirm: intl.formatMessage(messages.blockConfirm),
+ onConfirm: () => dispatch(blockAccount(account.get('id')))
+ }));
}
},
if (account.getIn(['relationship', 'muting'])) {
dispatch(unmuteAccount(account.get('id')));
} else {
- dispatch(muteAccount(account.get('id')));
+ dispatch(openModal('CONFIRM', {
+ message: <FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
+ confirm: intl.formatMessage(messages.muteConfirm),
+ onConfirm: () => dispatch(muteAccount(account.get('id')))
+ }));
}
}
});
-export default connect(makeMapStateToProps, mapDispatchToProps)(Header);
+export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));
this.handleChange = this.handleChange.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleFocus = this.handleFocus.bind(this);
+ this.handleClear = this.handleClear.bind(this);
}
handleChange (e) {
handleClear (e) {
e.preventDefault();
- this.props.onClear();
+
+ if (this.props.value.length > 0 || this.props.submitted) {
+ this.props.onClear();
+ }
}
handleKeyDown (e) {
onFocus={this.handleFocus}
/>
- <div role='button' tabIndex='0' className='search__icon' onClick={hasValue ? this.handleClear : this.noop}>
+ <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
<i className={`fa fa-search ${hasValue ? '' : 'active'}`} />
- <i aria-label="Clear search" className={`fa fa-times-circle ${hasValue ? 'active' : ''}`} />
+ <i aria-label={intl.formatMessage(messages.placeholder)} className={`fa fa-times-circle ${hasValue ? 'active' : ''}`} />
</div>
</div>
);
import Immutable from 'immutable';
import LoadMore from '../../components/load_more';
import ClearColumnButton from './components/clear_column_button';
+import { openModal } from '../../actions/modal';
const messages = defineMessages({
title: { id: 'column.notifications', defaultMessage: 'Notifications' },
- confirm: { id: 'notifications.clear_confirmation', defaultMessage: 'Are you sure you want to clear all your notifications?' }
+ clearMessage: { id: 'notifications.clear_confirmation', defaultMessage: 'Are you sure you want to permanently clear all your notifications?' },
+ clearConfirm: { id: 'notifications.clear', defaultMessage: 'Clear notifications' }
});
const getNotifications = createSelector([
}
handleClear () {
- if (window.confirm(this.props.intl.formatMessage(messages.confirm))) {
- this.props.dispatch(clearNotifications());
- }
+ const { dispatch, intl } = this.props;
+
+ dispatch(openModal('CONFIRM', {
+ message: intl.formatMessage(messages.clearMessage),
+ confirm: intl.formatMessage(messages.clearConfirm),
+ onConfirm: () => dispatch(clearNotifications())
+ }));
}
setRef (c) {
import StatusContainer from '../../containers/status_container';
import { openModal } from '../../actions/modal';
import { isMobile } from '../../is_mobile'
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+
+const messages = defineMessages({
+ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
+ deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }
+});
const makeMapStateToProps = () => {
const getStatus = makeGetStatus();
}
handleDeleteClick (status) {
- this.props.dispatch(deleteStatus(status.get('id')));
+ const { dispatch, intl } = this.props;
+
+ dispatch(openModal('CONFIRM', {
+ message: intl.formatMessage(messages.deleteMessage),
+ confirm: intl.formatMessage(messages.deleteConfirm),
+ onConfirm: () => dispatch(deleteStatus(status.get('id')))
+ }));
}
handleMentionClick (account, router) {
descendantsIds: ImmutablePropTypes.list,
me: PropTypes.number,
boostModal: PropTypes.bool,
- autoPlayGif: PropTypes.bool
+ autoPlayGif: PropTypes.bool,
+ intl: PropTypes.object.isRequired
};
-export default connect(makeMapStateToProps)(Status);
+export default injectIntl(connect(makeMapStateToProps)(Status));
--- /dev/null
+import PropTypes from 'prop-types';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import Button from '../../../components/button';
+
+class ConfirmationModal extends React.PureComponent {
+
+ constructor (props, context) {
+ super(props, context);
+ this.handleClick = this.handleClick.bind(this);
+ this.handleCancel = this.handleCancel.bind(this);
+ }
+
+ handleClick () {
+ this.props.onClose();
+ this.props.onConfirm();
+ }
+
+ handleCancel (e) {
+ e.preventDefault();
+ this.props.onClose();
+ }
+
+ render () {
+ const { intl, message, confirm, onConfirm, onClose } = this.props;
+
+ return (
+ <div className='modal-root__modal confirmation-modal'>
+ <div className='confirmation-modal__container'>
+ {message}
+ </div>
+
+ <div className='confirmation-modal__action-bar'>
+ <div><a href='#' onClick={this.handleCancel}><FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' /></a></div>
+ <Button text={confirm} onClick={this.handleClick} />
+ </div>
+ </div>
+ );
+ }
+
+}
+
+ConfirmationModal.propTypes = {
+ message: PropTypes.node.isRequired,
+ confirm: PropTypes.string.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onConfirm: PropTypes.func.isRequired,
+ intl: PropTypes.object.isRequired
+};
+
+export default injectIntl(ConfirmationModal);
import OnboardingModal from './onboarding_modal';
import VideoModal from './video_modal';
import BoostModal from './boost_modal';
+import ConfirmationModal from './confirmation_modal';
import { TransitionMotion, spring } from 'react-motion';
const MODAL_COMPONENTS = {
'MEDIA': MediaModal,
'ONBOARDING': OnboardingModal,
'VIDEO': VideoModal,
- 'BOOST': BoostModal
+ 'BOOST': BoostModal,
+ 'CONFIRM': ConfirmationModal
};
class ModalRoot extends React.PureComponent {
"notification.follow": "{name} followed you",
"notification.mention": "{name} mentioned you",
"notification.reblog": "{name} boosted your status",
- "notifications.clear_confirmation": "Are you sure you want to clear all your notifications?",
+ "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
"notifications.clear": "Clear notifications",
"notifications.column_settings.alert": "Desktop notifications",
"notifications.column_settings.favourite": "Favourites:",
margin-left: 10px;
}
-.boost-modal {
+.boost-modal, .confirmation-modal {
background: lighten($color2, 8%);
color: $color1;
border-radius: 8px;
}
}
-.boost-modal__action-bar {
+.boost-modal__action-bar, .confirmation-modal__action-bar {
display: flex;
background: $color2;
padding: 10px;
font-size: 14px;
}
+.confirmation-modal {
+ max-width: 380px;
+}
+
+.confirmation-modal__action-bar {
+ & > div {
+ text-align: left;
+ padding: 0 16px;
+ }
+
+ a {
+ color: darken($color2, 34%);
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: 500;
+
+ &:hover, &:focus, &:active {
+ color: darken($color2, 38%);
+ }
+ }
+}
+
+.confirmation-modal__container {
+ padding: 30px;
+ font-size: 16px;
+ text-align: center;
+
+ strong {
+ font-weight: 500;
+ }
+}
+
.loading-bar {
background-color: $color4;
height: 3px;
:'zh-TW',
]
- config.i18n.default_locale = :en
+ config.i18n.default_locale = :en
# config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
# config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
config.middleware.use Rack::Attack
config.middleware.use Rack::Deflater
- config.browserify_rails.source_map_environments << 'development'
config.browserify_rails.commandline_options = '--transform [ babelify --presets [ es2015 react ] --plugins [ transform-decorators-legacy ] ] --extension=".jsx"'
config.browserify_rails.evaluate_node_modules = true