From f5bf5ebb82e3af420dcd23d602b1be6cc86838e1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 3 May 2017 02:04:16 +0200 Subject: Replace sprockets/browserify with Webpack (#2617) * Replace browserify with webpack * Add react-intl-translations-manager * Do not minify in development, add offline-plugin for ServiceWorker background cache updates * Adjust tests and dependencies * Fix production deployments * Fix tests * More optimizations * Improve travis cache for npm stuff * Re-run travis * Add back support for custom.scss as before * Remove offline-plugin and babili * Fix issue with Immutable.List().unshift(...values) not working as expected * Make travis load schema instead of running all migrations in sequence * Fix missing React import in WarningContainer. Optimize rendering performance by using ImmutablePureComponent instead of React.PureComponent. ImmutablePureComponent uses Immutable.is() to compare props. Replace dynamic callback bindings in * Add react definitions to places that use JSX * Add Procfile.dev for running rails, webpack and streaming API at the same time --- .../features/account/components/action_bar.jsx | 92 ------- .../features/account/components/header.jsx | 148 ------------ .../account_timeline/components/header.jsx | 81 ------- .../containers/header_container.jsx | 75 ------ .../components/features/account_timeline/index.jsx | 87 ------- .../components/features/blocks/index.jsx | 72 ------ .../features/community_timeline/index.jsx | 95 -------- .../compose/components/autosuggest_account.jsx | 16 -- .../compose/components/autosuggest_status.jsx | 15 -- .../compose/components/character_counter.jsx | 26 -- .../features/compose/components/compose_form.jsx | 209 ---------------- .../compose/components/emoji_picker_dropdown.jsx | 114 --------- .../features/compose/components/navigation_bar.jsx | 32 --- .../compose/components/privacy_dropdown.jsx | 104 -------- .../compose/components/reply_indicator.jsx | 69 ------ .../features/compose/components/search.jsx | 82 ------- .../features/compose/components/search_results.jsx | 65 ----- .../compose/components/text_icon_button.jsx | 35 --- .../features/compose/components/upload_button.jsx | 60 ----- .../features/compose/components/upload_form.jsx | 45 ---- .../compose/components/upload_progress.jsx | 42 ---- .../features/compose/components/warning.jsx | 25 -- .../containers/autosuggest_account_container.jsx | 15 -- .../containers/autosuggest_status_container.jsx | 15 -- .../compose/containers/compose_form_container.jsx | 64 ----- .../compose/containers/navigation_container.jsx | 10 - .../containers/privacy_dropdown_container.jsx | 17 -- .../containers/reply_indicator_container.jsx | 24 -- .../compose/containers/search_container.jsx | 35 --- .../containers/search_results_container.jsx | 8 - .../containers/sensitive_button_container.jsx | 50 ---- .../containers/spoiler_button_container.jsx | 25 -- .../compose/containers/upload_button_container.jsx | 18 -- .../compose/containers/upload_form_container.jsx | 17 -- .../containers/upload_progress_container.jsx | 9 - .../compose/containers/warning_container.jsx | 48 ---- .../components/features/compose/index.jsx | 85 ------- .../features/favourited_statuses/index.jsx | 66 ------ .../components/features/favourites/index.jsx | 59 ----- .../components/account_authorize.jsx | 44 ---- .../containers/account_authorize_container.jsx | 26 -- .../components/features/follow_requests/index.jsx | 72 ------ .../components/features/followers/index.jsx | 90 ------- .../components/features/following/index.jsx | 90 ------- .../features/generic_not_found/index.jsx | 10 - .../components/features/getting_started/index.jsx | 66 ------ .../components/features/hashtag_timeline/index.jsx | 89 ------- .../home_timeline/components/column_settings.jsx | 50 ---- .../home_timeline/components/setting_text.jsx | 37 --- .../containers/column_settings_container.jsx | 21 -- .../components/features/home_timeline/index.jsx | 37 --- .../components/features/mutes/index.jsx | 73 ------ .../components/clear_column_button.jsx | 26 -- .../notifications/components/column_settings.jsx | 70 ------ .../notifications/components/notification.jsx | 88 ------- .../notifications/components/setting_toggle.jsx | 20 -- .../containers/column_settings_container.jsx | 21 -- .../containers/notification_container.jsx | 15 -- .../components/features/notifications/index.jsx | 142 ----------- .../components/features/public_timeline/index.jsx | 95 -------- .../components/features/reblogs/index.jsx | 59 ----- .../report/components/status_check_box.jsx | 39 --- .../containers/status_check_box_container.jsx | 19 -- .../components/features/report/index.jsx | 130 ---------- .../features/status/components/action_bar.jsx | 101 -------- .../components/features/status/components/card.jsx | 95 -------- .../features/status/components/detailed_status.jsx | 94 -------- .../features/status/containers/card_container.jsx | 8 - .../components/features/status/index.jsx | 197 --------------- .../features/ui/components/boost_modal.jsx | 82 ------- .../components/features/ui/components/column.jsx | 82 ------- .../features/ui/components/column_header.jsx | 42 ---- .../features/ui/components/column_link.jsx | 31 --- .../features/ui/components/column_subheading.jsx | 15 -- .../features/ui/components/columns_area.jsx | 19 -- .../features/ui/components/confirmation_modal.jsx | 50 ---- .../features/ui/components/media_modal.jsx | 101 -------- .../features/ui/components/modal_root.jsx | 92 ------- .../features/ui/components/onboarding_modal.jsx | 263 --------------------- .../components/features/ui/components/tabs_bar.jsx | 23 -- .../features/ui/components/upload_area.jsx | 59 ----- .../features/ui/components/video_modal.jsx | 38 --- .../ui/containers/loading_bar_container.jsx | 8 - .../features/ui/containers/modal_container.jsx | 16 -- .../ui/containers/notifications_container.jsx | 21 -- .../ui/containers/status_list_container.jsx | 74 ------ .../javascripts/components/features/ui/index.jsx | 166 ------------- 87 files changed, 5260 deletions(-) delete mode 100644 app/assets/javascripts/components/features/account/components/action_bar.jsx delete mode 100644 app/assets/javascripts/components/features/account/components/header.jsx delete mode 100644 app/assets/javascripts/components/features/account_timeline/components/header.jsx delete mode 100644 app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx delete mode 100644 app/assets/javascripts/components/features/account_timeline/index.jsx delete mode 100644 app/assets/javascripts/components/features/blocks/index.jsx delete mode 100644 app/assets/javascripts/components/features/community_timeline/index.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/autosuggest_account.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/autosuggest_status.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/character_counter.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/compose_form.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/emoji_picker_dropdown.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/navigation_bar.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/privacy_dropdown.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/reply_indicator.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/search.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/search_results.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/text_icon_button.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/upload_button.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/upload_form.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/upload_progress.jsx delete mode 100644 app/assets/javascripts/components/features/compose/components/warning.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/autosuggest_account_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/autosuggest_status_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/navigation_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/privacy_dropdown_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/reply_indicator_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/search_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/search_results_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/sensitive_button_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/spoiler_button_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/upload_button_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/upload_form_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/upload_progress_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/containers/warning_container.jsx delete mode 100644 app/assets/javascripts/components/features/compose/index.jsx delete mode 100644 app/assets/javascripts/components/features/favourited_statuses/index.jsx delete mode 100644 app/assets/javascripts/components/features/favourites/index.jsx delete mode 100644 app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx delete mode 100644 app/assets/javascripts/components/features/follow_requests/containers/account_authorize_container.jsx delete mode 100644 app/assets/javascripts/components/features/follow_requests/index.jsx delete mode 100644 app/assets/javascripts/components/features/followers/index.jsx delete mode 100644 app/assets/javascripts/components/features/following/index.jsx delete mode 100644 app/assets/javascripts/components/features/generic_not_found/index.jsx delete mode 100644 app/assets/javascripts/components/features/getting_started/index.jsx delete mode 100644 app/assets/javascripts/components/features/hashtag_timeline/index.jsx delete mode 100644 app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx delete mode 100644 app/assets/javascripts/components/features/home_timeline/components/setting_text.jsx delete mode 100644 app/assets/javascripts/components/features/home_timeline/containers/column_settings_container.jsx delete mode 100644 app/assets/javascripts/components/features/home_timeline/index.jsx delete mode 100644 app/assets/javascripts/components/features/mutes/index.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/components/column_settings.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/components/notification.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/containers/notification_container.jsx delete mode 100644 app/assets/javascripts/components/features/notifications/index.jsx delete mode 100644 app/assets/javascripts/components/features/public_timeline/index.jsx delete mode 100644 app/assets/javascripts/components/features/reblogs/index.jsx delete mode 100644 app/assets/javascripts/components/features/report/components/status_check_box.jsx delete mode 100644 app/assets/javascripts/components/features/report/containers/status_check_box_container.jsx delete mode 100644 app/assets/javascripts/components/features/report/index.jsx delete mode 100644 app/assets/javascripts/components/features/status/components/action_bar.jsx delete mode 100644 app/assets/javascripts/components/features/status/components/card.jsx delete mode 100644 app/assets/javascripts/components/features/status/components/detailed_status.jsx delete mode 100644 app/assets/javascripts/components/features/status/containers/card_container.jsx delete mode 100644 app/assets/javascripts/components/features/status/index.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/boost_modal.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/column.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/column_header.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/column_link.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/column_subheading.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/columns_area.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/confirmation_modal.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/media_modal.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/modal_root.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/onboarding_modal.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/tabs_bar.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/upload_area.jsx delete mode 100644 app/assets/javascripts/components/features/ui/components/video_modal.jsx delete mode 100644 app/assets/javascripts/components/features/ui/containers/loading_bar_container.jsx delete mode 100644 app/assets/javascripts/components/features/ui/containers/modal_container.jsx delete mode 100644 app/assets/javascripts/components/features/ui/containers/notifications_container.jsx delete mode 100644 app/assets/javascripts/components/features/ui/containers/status_list_container.jsx delete mode 100644 app/assets/javascripts/components/features/ui/index.jsx (limited to 'app/assets/javascripts/components/features') diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx deleted file mode 100644 index 772ea3a38..000000000 --- a/app/assets/javascripts/components/features/account/components/action_bar.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import DropdownMenu from '../../../components/dropdown_menu'; -import { Link } from 'react-router'; -import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl'; - -const messages = defineMessages({ - mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' }, - edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, - unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, - unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' }, - block: { id: 'account.block', defaultMessage: 'Block @{name}' }, - mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - report: { id: 'account.report', defaultMessage: 'Report @{name}' }, - disclaimer: { id: 'account.disclaimer', defaultMessage: 'This user is from another instance. This number may be larger.' } -}); - -class ActionBar extends React.PureComponent { - - render () { - const { account, me, intl } = this.props; - - let menu = []; - let extraInfo = ''; - - menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention }); - menu.push(null); - - if (account.get('id') === me) { - menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' }); - } else { - if (account.getIn(['relationship', 'muting'])) { - menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.props.onMute }); - } else { - menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.props.onMute }); - } - - if (account.getIn(['relationship', 'blocking'])) { - menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.props.onBlock }); - } else { - menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.props.onBlock }); - } - - menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.props.onReport }); - } - - if (account.get('acct') !== account.get('username')) { - extraInfo = *; - } - - return ( -
-
- -
- -
- - - {extraInfo} - - - - - {extraInfo} - - - - - {extraInfo} - -
-
- ); - } - -} - -ActionBar.propTypes = { - account: ImmutablePropTypes.map.isRequired, - me: PropTypes.number.isRequired, - onFollow: PropTypes.func, - onBlock: PropTypes.func.isRequired, - onMention: PropTypes.func.isRequired, - onReport: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(ActionBar); diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx deleted file mode 100644 index 958a5206b..000000000 --- a/app/assets/javascripts/components/features/account/components/header.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import emojify from '../../../emoji'; -import escapeTextContentForBrowser from 'escape-html'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import IconButton from '../../../components/icon_button'; -import { Motion, spring } from 'react-motion'; -import { connect } from 'react-redux'; - -const messages = defineMessages({ - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' } -}); - -const makeMapStateToProps = () => { - const mapStateToProps = (state, props) => ({ - autoPlayGif: state.getIn(['meta', 'auto_play_gif']) - }); - - return mapStateToProps; -}; - -class Avatar extends React.PureComponent { - - constructor (props, context) { - super(props, context); - - this.state = { - isHovered: false - }; - - this.handleMouseOver = this.handleMouseOver.bind(this); - this.handleMouseOut = this.handleMouseOut.bind(this); - } - - handleMouseOver () { - if (this.state.isHovered) return; - this.setState({ isHovered: true }); - } - - handleMouseOut () { - if (!this.state.isHovered) return; - this.setState({ isHovered: false }); - } - - render () { - const { account, autoPlayGif } = this.props; - const { isHovered } = this.state; - - return ( - - {({ radius }) => - - } - - ); - } - -} - -Avatar.propTypes = { - account: ImmutablePropTypes.map.isRequired, - autoPlayGif: PropTypes.bool.isRequired -}; - -class Header extends React.Component { - - render () { - const { account, me, intl } = this.props; - - if (!account) { - return null; - } - - let displayName = account.get('display_name'); - let info = ''; - let actionBtn = ''; - let lockedIcon = ''; - - if (displayName.length === 0) { - displayName = account.get('username'); - } - - if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) { - info = - } - - if (me !== account.get('id')) { - if (account.getIn(['relationship', 'requested'])) { - actionBtn = ( -
- -
- ); - } else if (!account.getIn(['relationship', 'blocking'])) { - actionBtn = ( -
- -
- ); - } - } - - if (account.get('locked')) { - lockedIcon = ; - } - - const content = { __html: emojify(account.get('note')) }; - const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; - - return ( -
-
- - - - @{account.get('acct')} {lockedIcon} -
- - {info} - {actionBtn} -
-
- ); - } - -} - -Header.propTypes = { - account: ImmutablePropTypes.map, - me: PropTypes.number.isRequired, - onFollow: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - autoPlayGif: PropTypes.bool.isRequired -}; - -export default connect(makeMapStateToProps)(injectIntl(Header)); diff --git a/app/assets/javascripts/components/features/account_timeline/components/header.jsx b/app/assets/javascripts/components/features/account_timeline/components/header.jsx deleted file mode 100644 index fd66c13e0..000000000 --- a/app/assets/javascripts/components/features/account_timeline/components/header.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import InnerHeader from '../../account/components/header'; -import ActionBar from '../../account/components/action_bar'; -import MissingIndicator from '../../../components/missing_indicator'; - -class Header extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleFollow = this.handleFollow.bind(this); - this.handleBlock = this.handleBlock.bind(this); - this.handleMention = this.handleMention.bind(this); - this.handleReport = this.handleReport.bind(this); - this.handleMute = this.handleMute.bind(this); - } - - handleFollow () { - this.props.onFollow(this.props.account); - } - - handleBlock () { - this.props.onBlock(this.props.account); - } - - handleMention () { - this.props.onMention(this.props.account, this.context.router); - } - - handleReport () { - this.props.onReport(this.props.account); - this.context.router.push('/report'); - } - - handleMute() { - this.props.onMute(this.props.account); - } - - render () { - const { account, me } = this.props; - - if (account === null) { - return ; - } - - return ( -
- - - -
- ); - } -} - -Header.propTypes = { - account: ImmutablePropTypes.map, - me: PropTypes.number.isRequired, - onFollow: PropTypes.func.isRequired, - onBlock: PropTypes.func.isRequired, - onMention: PropTypes.func.isRequired, - onReport: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired -}; - -Header.contextTypes = { - router: PropTypes.object -}; - -export default Header; diff --git a/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx b/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx deleted file mode 100644 index f924e7f5e..000000000 --- a/app/assets/javascripts/components/features/account_timeline/containers/header_container.jsx +++ /dev/null @@ -1,75 +0,0 @@ -import { connect } from 'react-redux'; -import { makeGetAccount } from '../../../selectors'; -import Header from '../components/header'; -import { - followAccount, - unfollowAccount, - blockAccount, - unblockAccount, - muteAccount, - unmuteAccount -} 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(); - - const mapStateToProps = (state, { accountId }) => ({ - account: getAccount(state, Number(accountId)), - me: state.getIn(['meta', 'me']) - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch, { intl }) => ({ - onFollow (account) { - if (account.getIn(['relationship', 'following'])) { - dispatch(unfollowAccount(account.get('id'))); - } else { - dispatch(followAccount(account.get('id'))); - } - }, - - onBlock (account) { - if (account.getIn(['relationship', 'blocking'])) { - dispatch(unblockAccount(account.get('id'))); - } else { - dispatch(openModal('CONFIRM', { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.blockConfirm), - onConfirm: () => dispatch(blockAccount(account.get('id'))) - })); - } - }, - - onMention (account, router) { - dispatch(mentionCompose(account, router)); - }, - - onReport (account) { - dispatch(initReport(account)); - }, - - onMute (account) { - if (account.getIn(['relationship', 'muting'])) { - dispatch(unmuteAccount(account.get('id'))); - } else { - dispatch(openModal('CONFIRM', { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.muteConfirm), - onConfirm: () => dispatch(muteAccount(account.get('id'))) - })); - } - } -}); - -export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header)); diff --git a/app/assets/javascripts/components/features/account_timeline/index.jsx b/app/assets/javascripts/components/features/account_timeline/index.jsx deleted file mode 100644 index a06de3d21..000000000 --- a/app/assets/javascripts/components/features/account_timeline/index.jsx +++ /dev/null @@ -1,87 +0,0 @@ -import { connect } from 'react-redux'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import { - fetchAccount, - fetchAccountTimeline, - expandAccountTimeline -} from '../../actions/accounts'; -import StatusList from '../../components/status_list'; -import LoadingIndicator from '../../components/loading_indicator'; -import Column from '../ui/components/column'; -import HeaderContainer from './containers/header_container'; -import ColumnBackButton from '../../components/column_back_button'; -import Immutable from 'immutable'; - -const mapStateToProps = (state, props) => ({ - statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId), 'items'], Immutable.List()), - isLoading: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId), 'isLoading']), - hasMore: !!state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId), 'next']), - me: state.getIn(['meta', 'me']) -}); - -class AccountTimeline extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScrollToBottom = this.handleScrollToBottom.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchAccount(Number(this.props.params.accountId))); - this.props.dispatch(fetchAccountTimeline(Number(this.props.params.accountId))); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(Number(nextProps.params.accountId))); - this.props.dispatch(fetchAccountTimeline(Number(nextProps.params.accountId))); - } - } - - handleScrollToBottom () { - if (!this.props.isLoading && this.props.hasMore) { - this.props.dispatch(expandAccountTimeline(Number(this.props.params.accountId))); - } - } - - render () { - const { statusIds, isLoading, hasMore, me } = this.props; - - if (!statusIds && isLoading) { - return ( - - - - ); - } - - return ( - - - - } - scrollKey='account_timeline' - statusIds={statusIds} - isLoading={isLoading} - hasMore={hasMore} - me={me} - onScrollToBottom={this.handleScrollToBottom} - /> - - ); - } - -} - -AccountTimeline.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list, - isLoading: PropTypes.bool, - hasMore: PropTypes.bool, - me: PropTypes.number.isRequired -}; - -export default connect(mapStateToProps)(AccountTimeline); diff --git a/app/assets/javascripts/components/features/blocks/index.jsx b/app/assets/javascripts/components/features/blocks/index.jsx deleted file mode 100644 index 8b973ebb1..000000000 --- a/app/assets/javascripts/components/features/blocks/index.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import { connect } from 'react-redux'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import LoadingIndicator from '../../components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll'; -import Column from '../ui/components/column'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import AccountContainer from '../../containers/account_container'; -import { fetchBlocks, expandBlocks } from '../../actions/blocks'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - heading: { id: 'column.blocks', defaultMessage: 'Blocked users' } -}); - -const mapStateToProps = state => ({ - accountIds: state.getIn(['user_lists', 'blocks', 'items']) -}); - -class Blocks extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchBlocks()); - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandBlocks()); - } - } - - render () { - const { intl, accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - -
- {accountIds.map(id => - - )} -
-
-
- ); - } -} - -Blocks.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list, - intl: PropTypes.object.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(Blocks)); diff --git a/app/assets/javascripts/components/features/community_timeline/index.jsx b/app/assets/javascripts/components/features/community_timeline/index.jsx deleted file mode 100644 index 3877888ba..000000000 --- a/app/assets/javascripts/components/features/community_timeline/index.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; -import { - refreshTimeline, - updateTimeline, - deleteFromTimelines, - connectTimeline, - disconnectTimeline -} from '../../actions/timelines'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import createStream from '../../stream'; - -const messages = defineMessages({ - title: { id: 'column.community', defaultMessage: 'Local timeline' } -}); - -const mapStateToProps = state => ({ - hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0, - streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']), - accessToken: state.getIn(['meta', 'access_token']) -}); - -let subscription; - -class CommunityTimeline extends React.PureComponent { - - componentDidMount () { - const { dispatch, streamingAPIBaseURL, accessToken } = this.props; - - dispatch(refreshTimeline('community')); - - if (typeof subscription !== 'undefined') { - return; - } - - subscription = createStream(streamingAPIBaseURL, accessToken, 'public:local', { - - connected () { - dispatch(connectTimeline('community')); - }, - - reconnected () { - dispatch(connectTimeline('community')); - }, - - disconnected () { - dispatch(disconnectTimeline('community')); - }, - - received (data) { - switch(data.event) { - case 'update': - dispatch(updateTimeline('community', JSON.parse(data.payload))); - break; - case 'delete': - dispatch(deleteFromTimelines(data.payload)); - break; - } - } - - }); - } - - componentWillUnmount () { - // if (typeof subscription !== 'undefined') { - // subscription.close(); - // subscription = null; - // } - } - - render () { - const { intl, hasUnread } = this.props; - - return ( - - - } /> - - ); - } - -} - -CommunityTimeline.propTypes = { - dispatch: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - streamingAPIBaseURL: PropTypes.string.isRequired, - accessToken: PropTypes.string.isRequired, - hasUnread: PropTypes.bool -}; - -export default connect(mapStateToProps)(injectIntl(CommunityTimeline)); diff --git a/app/assets/javascripts/components/features/compose/components/autosuggest_account.jsx b/app/assets/javascripts/components/features/compose/components/autosuggest_account.jsx deleted file mode 100644 index bf6a15e5d..000000000 --- a/app/assets/javascripts/components/features/compose/components/autosuggest_account.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; -import ImmutablePropTypes from 'react-immutable-proptypes'; - -const AutosuggestAccount = ({ account }) => ( -
-
- -
-); - -AutosuggestAccount.propTypes = { - account: ImmutablePropTypes.map.isRequired -}; - -export default AutosuggestAccount; diff --git a/app/assets/javascripts/components/features/compose/components/autosuggest_status.jsx b/app/assets/javascripts/components/features/compose/components/autosuggest_status.jsx deleted file mode 100644 index 275b3d5a6..000000000 --- a/app/assets/javascripts/components/features/compose/components/autosuggest_status.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { FormattedMessage } from 'react-intl'; -import DisplayName from '../../../components/display_name'; -import ImmutablePropTypes from 'react-immutable-proptypes'; - -const AutosuggestStatus = ({ status }) => ( -
- @{status.getIn(['account', 'acct'])} }} /> -
-); - -AutosuggestStatus.propTypes = { - status: ImmutablePropTypes.map.isRequired -}; - -export default AutosuggestStatus; diff --git a/app/assets/javascripts/components/features/compose/components/character_counter.jsx b/app/assets/javascripts/components/features/compose/components/character_counter.jsx deleted file mode 100644 index 08d2ac4d1..000000000 --- a/app/assets/javascripts/components/features/compose/components/character_counter.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import PropTypes from 'prop-types'; -import { length } from 'stringz'; - -class CharacterCounter extends React.PureComponent { - - checkRemainingText (diff) { - if (diff < 0) { - return {diff}; - } - return {diff}; - } - - render () { - const diff = this.props.max - length(this.props.text); - - return this.checkRemainingText(diff); - } - -} - -CharacterCounter.propTypes = { - text: PropTypes.string.isRequired, - max: PropTypes.number.isRequired -} - -export default CharacterCounter; diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx deleted file mode 100644 index 6bc811160..000000000 --- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx +++ /dev/null @@ -1,209 +0,0 @@ -import CharacterCounter from './character_counter'; -import Button from '../../../components/button'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import ReplyIndicatorContainer from '../containers/reply_indicator_container'; -import AutosuggestTextarea from '../../../components/autosuggest_textarea'; -import { debounce } from 'react-decoration'; -import UploadButtonContainer from '../containers/upload_button_container'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import Toggle from 'react-toggle'; -import Collapsable from '../../../components/collapsable'; -import SpoilerButtonContainer from '../containers/spoiler_button_container'; -import PrivacyDropdownContainer from '../containers/privacy_dropdown_container'; -import SensitiveButtonContainer from '../containers/sensitive_button_container'; -import EmojiPickerDropdown from './emoji_picker_dropdown'; -import UploadFormContainer from '../containers/upload_form_container'; -import TextIconButton from './text_icon_button'; -import WarningContainer from '../containers/warning_container'; - -const messages = defineMessages({ - placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' }, - spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Content warning' }, - publish: { id: 'compose_form.publish', defaultMessage: 'Toot' } -}); - -class ComposeForm extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleChange = this.handleChange.bind(this); - this.handleKeyDown = this.handleKeyDown.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - this.onSuggestionsClearRequested = this.onSuggestionsClearRequested.bind(this); - this.onSuggestionsFetchRequested = this.onSuggestionsFetchRequested.bind(this); - this.onSuggestionSelected = this.onSuggestionSelected.bind(this); - this.handleChangeSpoilerText = this.handleChangeSpoilerText.bind(this); - this.setAutosuggestTextarea = this.setAutosuggestTextarea.bind(this); - this.handleEmojiPick = this.handleEmojiPick.bind(this); - } - - handleChange (e) { - this.props.onChange(e.target.value); - } - - handleKeyDown (e) { - if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { - this.handleSubmit(); - } - } - - handleSubmit () { - this.autosuggestTextarea.reset(); - this.props.onSubmit(); - } - - onSuggestionsClearRequested () { - this.props.onClearSuggestions(); - } - - @debounce(500) - onSuggestionsFetchRequested (token) { - this.props.onFetchSuggestions(token); - } - - onSuggestionSelected (tokenStart, token, value) { - this._restoreCaret = null; - this.props.onSuggestionSelected(tokenStart, token, value); - } - - handleChangeSpoilerText (e) { - this.props.onChangeSpoilerText(e.target.value); - } - - componentWillReceiveProps (nextProps) { - // If this is the update where we've finished uploading, - // save the last caret position so we can restore it below! - if (!nextProps.is_uploading && this.props.is_uploading) { - this._restoreCaret = this.autosuggestTextarea.textarea.selectionStart; - } - } - - componentDidUpdate (prevProps) { - // This statement does several things: - // - If we're beginning a reply, and, - // - Replying to zero or one users, places the cursor at the end of the textbox. - // - Replying to more than one user, selects any usernames past the first; - // this provides a convenient shortcut to drop everyone else from the conversation. - // - If we've just finished uploading an image, and have a saved caret position, - // restores the cursor to that position after the text changes! - if (this.props.focusDate !== prevProps.focusDate || (prevProps.is_uploading && !this.props.is_uploading && typeof this._restoreCaret === 'number')) { - let selectionEnd, selectionStart; - - if (this.props.preselectDate !== prevProps.preselectDate) { - selectionEnd = this.props.text.length; - selectionStart = this.props.text.search(/\s/) + 1; - } else if (typeof this._restoreCaret === 'number') { - selectionStart = this._restoreCaret; - selectionEnd = this._restoreCaret; - } else { - selectionEnd = this.props.text.length; - selectionStart = selectionEnd; - } - - this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd); - this.autosuggestTextarea.textarea.focus(); - } - } - - setAutosuggestTextarea (c) { - this.autosuggestTextarea = c; - } - - handleEmojiPick (data) { - const position = this.autosuggestTextarea.textarea.selectionStart; - this._restoreCaret = position + data.shortname.length + 1; - this.props.onPickEmoji(position, data); - } - - render () { - const { intl, onPaste } = this.props; - const disabled = this.props.is_submitting; - const text = [this.props.spoiler_text, this.props.text].join(''); - - let publishText = ''; - let reply_to_other = false; - - if (this.props.privacy === 'private' || this.props.privacy === 'direct') { - publishText = {intl.formatMessage(messages.publish)}; - } else { - publishText = intl.formatMessage(messages.publish) + (this.props.privacy !== 'unlisted' ? '!' : ''); - } - - return ( -
- -
- -
-
- - - - - -
- - - -
- -
- -
- -
-
- - - - -
- -
-
-
-
-
-
- ); - } - -} - -ComposeForm.propTypes = { - intl: PropTypes.object.isRequired, - text: PropTypes.string.isRequired, - suggestion_token: PropTypes.string, - suggestions: ImmutablePropTypes.list, - spoiler: PropTypes.bool, - privacy: PropTypes.string, - spoiler_text: PropTypes.string, - focusDate: PropTypes.instanceOf(Date), - preselectDate: PropTypes.instanceOf(Date), - is_submitting: PropTypes.bool, - is_uploading: PropTypes.bool, - me: PropTypes.number, - onChange: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onClearSuggestions: PropTypes.func.isRequired, - onFetchSuggestions: PropTypes.func.isRequired, - onSuggestionSelected: PropTypes.func.isRequired, - onChangeSpoilerText: PropTypes.func.isRequired, - onPaste: PropTypes.func.isRequired, - onPickEmoji: PropTypes.func.isRequired -}; - -export default injectIntl(ComposeForm); diff --git a/app/assets/javascripts/components/features/compose/components/emoji_picker_dropdown.jsx b/app/assets/javascripts/components/features/compose/components/emoji_picker_dropdown.jsx deleted file mode 100644 index bc22b074d..000000000 --- a/app/assets/javascripts/components/features/compose/components/emoji_picker_dropdown.jsx +++ /dev/null @@ -1,114 +0,0 @@ -import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown'; -import EmojiPicker from 'emojione-picker'; -import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, - emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' }, - people: { id: 'emoji_button.people', defaultMessage: 'People' }, - nature: { id: 'emoji_button.nature', defaultMessage: 'Nature' }, - food: { id: 'emoji_button.food', defaultMessage: 'Food & Drink' }, - activity: { id: 'emoji_button.activity', defaultMessage: 'Activity' }, - travel: { id: 'emoji_button.travel', defaultMessage: 'Travel & Places' }, - objects: { id: 'emoji_button.objects', defaultMessage: 'Objects' }, - symbols: { id: 'emoji_button.symbols', defaultMessage: 'Symbols' }, - flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' } -}); - -const settings = { - imageType: 'png', - sprites: false, - imagePathPNG: '/emoji/' -}; - -const dropdownStyle = { - position: 'absolute', - right: '5px', - top: '5px' -}; - -const dropdownTriggerStyle = { - display: 'block', - fontSize: '24px', - lineHeight: '24px', - marginLeft: '2px', - width: '24px' -} - -class EmojiPickerDropdown extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.setRef = this.setRef.bind(this); - this.handleChange = this.handleChange.bind(this); - } - - setRef (c) { - this.dropdown = c; - } - - handleChange (data) { - this.dropdown.hide(); - this.props.onPickEmoji(data); - } - - render () { - const { intl } = this.props; - - const categories = { - people: { - title: intl.formatMessage(messages.people), - emoji: 'smile', - }, - nature: { - title: intl.formatMessage(messages.nature), - emoji: 'hamster', - }, - food: { - title: intl.formatMessage(messages.food), - emoji: 'pizza', - }, - activity: { - title: intl.formatMessage(messages.activity), - emoji: 'soccer', - }, - travel: { - title: intl.formatMessage(messages.travel), - emoji: 'earth_americas', - }, - objects: { - title: intl.formatMessage(messages.objects), - emoji: 'bulb', - }, - symbols: { - title: intl.formatMessage(messages.symbols), - emoji: 'clock9', - }, - flags: { - title: intl.formatMessage(messages.flags), - emoji: 'flag_gb', - } - } - - return ( - - - 🙂 - - - - - - - ); - } - -} - -EmojiPickerDropdown.propTypes = { - intl: PropTypes.object.isRequired, - onPickEmoji: PropTypes.func.isRequired -}; - -export default injectIntl(EmojiPickerDropdown); diff --git a/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx b/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx deleted file mode 100644 index aae0592c6..000000000 --- a/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Avatar from '../../../components/avatar'; -import IconButton from '../../../components/icon_button'; -import DisplayName from '../../../components/display_name'; -import Permalink from '../../../components/permalink'; -import { FormattedMessage } from 'react-intl'; -import { Link } from 'react-router'; - -class NavigationBar extends React.PureComponent { - - render () { - return ( -
- ); - } - -} - -NavigationBar.propTypes = { - account: ImmutablePropTypes.map.isRequired -}; - -export default NavigationBar; diff --git a/app/assets/javascripts/components/features/compose/components/privacy_dropdown.jsx b/app/assets/javascripts/components/features/compose/components/privacy_dropdown.jsx deleted file mode 100644 index 82b3454c6..000000000 --- a/app/assets/javascripts/components/features/compose/components/privacy_dropdown.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import PropTypes from 'prop-types'; -import { injectIntl, defineMessages } from 'react-intl'; -import IconButton from '../../../components/icon_button'; - -const messages = defineMessages({ - public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, - public_long: { id: 'privacy.public.long', defaultMessage: 'Post to public timelines' }, - unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' }, - unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Do not show in public timelines' }, - private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' }, - private_long: { id: 'privacy.private.long', defaultMessage: 'Post to followers only' }, - direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' }, - direct_long: { id: 'privacy.direct.long', defaultMessage: 'Post to mentioned users only' }, - change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' } -}); - -const iconStyle = { - height: null, - lineHeight: '27px' -} - -class PrivacyDropdown extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.state = { - open: false - }; - this.handleToggle = this.handleToggle.bind(this); - this.handleClick = this.handleClick.bind(this); - this.onGlobalClick = this.onGlobalClick.bind(this); - this.setRef = this.setRef.bind(this); - } - - handleToggle () { - this.setState({ open: !this.state.open }); - } - - handleClick (value, e) { - e.preventDefault(); - this.setState({ open: false }); - this.props.onChange(value); - } - - onGlobalClick (e) { - if (e.target !== this.node && !this.node.contains(e.target) && this.state.open) { - this.setState({ open: false }); - } - } - - componentDidMount () { - window.addEventListener('click', this.onGlobalClick); - window.addEventListener('touchstart', this.onGlobalClick); - } - - componentWillUnmount () { - window.removeEventListener('click', this.onGlobalClick); - window.removeEventListener('touchstart', this.onGlobalClick); - } - - setRef (c) { - this.node = c; - } - - render () { - const { value, onChange, intl } = this.props; - const { open } = this.state; - - const options = [ - { icon: 'globe', value: 'public', shortText: intl.formatMessage(messages.public_short), longText: intl.formatMessage(messages.public_long) }, - { icon: 'unlock-alt', value: 'unlisted', shortText: intl.formatMessage(messages.unlisted_short), longText: intl.formatMessage(messages.unlisted_long) }, - { icon: 'lock', value: 'private', shortText: intl.formatMessage(messages.private_short), longText: intl.formatMessage(messages.private_long) }, - { icon: 'envelope', value: 'direct', shortText: intl.formatMessage(messages.direct_short), longText: intl.formatMessage(messages.direct_long) } - ]; - - const valueOption = options.find(item => item.value === value); - - return ( -
-
-
- {options.map(item => -
-
-
- {item.shortText} - {item.longText} -
-
- )} -
-
- ); - } - -} - -PrivacyDropdown.propTypes = { - value: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(PrivacyDropdown); diff --git a/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx b/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx deleted file mode 100644 index 442ed5a35..000000000 --- a/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import Avatar from '../../../components/avatar'; -import IconButton from '../../../components/icon_button'; -import DisplayName from '../../../components/display_name'; -import emojify from '../../../emoji'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' } -}); - -class ReplyIndicator extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleClick = this.handleClick.bind(this); - this.handleAccountClick = this.handleAccountClick.bind(this); - } - - handleClick () { - this.props.onCancel(); - } - - handleAccountClick (e) { - if (e.button === 0) { - e.preventDefault(); - this.context.router.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`); - } - } - - render () { - const { status, intl } = this.props; - - if (!status) { - return null; - } - - const content = { __html: emojify(status.get('content')) }; - - return ( -
-
-
- - -
- -
-
- -
-
- ); - } - -} - -ReplyIndicator.contextTypes = { - router: PropTypes.object -}; - -ReplyIndicator.propTypes = { - status: ImmutablePropTypes.map, - onCancel: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(ReplyIndicator); diff --git a/app/assets/javascripts/components/features/compose/components/search.jsx b/app/assets/javascripts/components/features/compose/components/search.jsx deleted file mode 100644 index f62248a33..000000000 --- a/app/assets/javascripts/components/features/compose/components/search.jsx +++ /dev/null @@ -1,82 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -const messages = defineMessages({ - placeholder: { id: 'search.placeholder', defaultMessage: 'Search' } -}); - -class Search extends React.PureComponent { - - constructor (props, context) { - super(props, context); - 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) { - this.props.onChange(e.target.value); - } - - handleClear (e) { - e.preventDefault(); - - if (this.props.value.length > 0 || this.props.submitted) { - this.props.onClear(); - } - } - - handleKeyDown (e) { - if (e.key === 'Enter') { - e.preventDefault(); - this.props.onSubmit(); - } - } - - noop () { - - } - - handleFocus () { - this.props.onShow(); - } - - render () { - const { intl, value, submitted } = this.props; - const hasValue = value.length > 0 || submitted; - - return ( -
- - -
- - -
-
- ); - } - -} - -Search.propTypes = { - value: PropTypes.string.isRequired, - submitted: PropTypes.bool, - onChange: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onClear: PropTypes.func.isRequired, - onShow: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(Search); diff --git a/app/assets/javascripts/components/features/compose/components/search_results.jsx b/app/assets/javascripts/components/features/compose/components/search_results.jsx deleted file mode 100644 index 00bfd1786..000000000 --- a/app/assets/javascripts/components/features/compose/components/search_results.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import AccountContainer from '../../../containers/account_container'; -import StatusContainer from '../../../containers/status_container'; -import { Link } from 'react-router'; - -class SearchResults extends React.PureComponent { - - render () { - const { results } = this.props; - - let accounts, statuses, hashtags; - let count = 0; - - if (results.get('accounts') && results.get('accounts').size > 0) { - count += results.get('accounts').size; - accounts = ( -
- {results.get('accounts').map(accountId => )} -
- ); - } - - if (results.get('statuses') && results.get('statuses').size > 0) { - count += results.get('statuses').size; - statuses = ( -
- {results.get('statuses').map(statusId => )} -
- ); - } - - if (results.get('hashtags') && results.get('hashtags').size > 0) { - count += results.get('hashtags').size; - hashtags = ( -
- {results.get('hashtags').map(hashtag => - - #{hashtag} - - )} -
- ); - } - - return ( -
-
- -
- - {accounts} - {statuses} - {hashtags} -
- ); - } - -} - -SearchResults.propTypes = { - results: ImmutablePropTypes.map.isRequired -}; - -export default SearchResults; diff --git a/app/assets/javascripts/components/features/compose/components/text_icon_button.jsx b/app/assets/javascripts/components/features/compose/components/text_icon_button.jsx deleted file mode 100644 index 4252596c2..000000000 --- a/app/assets/javascripts/components/features/compose/components/text_icon_button.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import PropTypes from 'prop-types'; - -class TextIconButton extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleClick = this.handleClick.bind(this); - } - - handleClick (e) { - e.preventDefault(); - this.props.onClick(); - } - - render () { - const { label, title, active, ariaControls } = this.props; - - return ( - - ); - } - -} - -TextIconButton.propTypes = { - label: PropTypes.string.isRequired, - title: PropTypes.string, - active: PropTypes.bool, - onClick: PropTypes.func.isRequired, - ariaControls: PropTypes.string -}; - -export default TextIconButton; diff --git a/app/assets/javascripts/components/features/compose/components/upload_button.jsx b/app/assets/javascripts/components/features/compose/components/upload_button.jsx deleted file mode 100644 index 9b2de0332..000000000 --- a/app/assets/javascripts/components/features/compose/components/upload_button.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import IconButton from '../../../components/icon_button'; -import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - upload: { id: 'upload_button.label', defaultMessage: 'Add media' } -}); - - -const iconStyle = { - height: null, - lineHeight: '27px' -} - -class UploadButton extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleChange = this.handleChange.bind(this); - this.handleClick = this.handleClick.bind(this); - this.setRef = this.setRef.bind(this); - } - - handleChange (e) { - if (e.target.files.length > 0) { - this.props.onSelectFile(e.target.files); - } - } - - handleClick () { - this.fileElement.click(); - } - - setRef (c) { - this.fileElement = c; - } - - render () { - - const { intl, resetFileKey, disabled } = this.props; - - return ( -
- - -
- ); - } - -} - -UploadButton.propTypes = { - disabled: PropTypes.bool, - onSelectFile: PropTypes.func.isRequired, - style: PropTypes.object, - resetFileKey: PropTypes.number, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(UploadButton); diff --git a/app/assets/javascripts/components/features/compose/components/upload_form.jsx b/app/assets/javascripts/components/features/compose/components/upload_form.jsx deleted file mode 100644 index a2fb7cfe0..000000000 --- a/app/assets/javascripts/components/features/compose/components/upload_form.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import IconButton from '../../../components/icon_button'; -import { defineMessages, injectIntl } from 'react-intl'; -import UploadProgressContainer from '../containers/upload_progress_container'; -import { Motion, spring } from 'react-motion'; - -const messages = defineMessages({ - undo: { id: 'upload_form.undo', defaultMessage: 'Undo' } -}); - -class UploadForm extends React.PureComponent { - - render () { - const { intl, media } = this.props; - - const uploads = media.map(attachment => -
- - {({ scale }) => -
- -
- } -
-
- ); - - return ( -
- -
{uploads}
-
- ); - } - -} - -UploadForm.propTypes = { - media: ImmutablePropTypes.list.isRequired, - onRemoveFile: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(UploadForm); diff --git a/app/assets/javascripts/components/features/compose/components/upload_progress.jsx b/app/assets/javascripts/components/features/compose/components/upload_progress.jsx deleted file mode 100644 index 8f03bb76a..000000000 --- a/app/assets/javascripts/components/features/compose/components/upload_progress.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import PropTypes from 'prop-types'; -import { Motion, spring } from 'react-motion'; -import { FormattedMessage } from 'react-intl'; - -class UploadProgress extends React.PureComponent { - - render () { - const { active, progress } = this.props; - - if (!active) { - return null; - } - - return ( -
-
- -
- -
- - -
- - {({ width }) => -
- } - -
-
-
- ); - } - -} - -UploadProgress.propTypes = { - active: PropTypes.bool, - progress: PropTypes.number -}; - -export default UploadProgress; diff --git a/app/assets/javascripts/components/features/compose/components/warning.jsx b/app/assets/javascripts/components/features/compose/components/warning.jsx deleted file mode 100644 index ff1989755..000000000 --- a/app/assets/javascripts/components/features/compose/components/warning.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import PropTypes from 'prop-types'; - -class Warning extends React.PureComponent { - - constructor (props) { - super(props); - } - - render () { - const { message } = this.props; - - return ( -
- {message} -
- ); - } - -} - -Warning.propTypes = { - message: PropTypes.node.isRequired -}; - -export default Warning; diff --git a/app/assets/javascripts/components/features/compose/containers/autosuggest_account_container.jsx b/app/assets/javascripts/components/features/compose/containers/autosuggest_account_container.jsx deleted file mode 100644 index de76a364d..000000000 --- a/app/assets/javascripts/components/features/compose/containers/autosuggest_account_container.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux'; -import AutosuggestAccount from '../components/autosuggest_account'; -import { makeGetAccount } from '../../../selectors'; - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, { id }) => ({ - account: getAccount(state, id) - }); - - return mapStateToProps; -}; - -export default connect(makeMapStateToProps)(AutosuggestAccount); diff --git a/app/assets/javascripts/components/features/compose/containers/autosuggest_status_container.jsx b/app/assets/javascripts/components/features/compose/containers/autosuggest_status_container.jsx deleted file mode 100644 index ef46eb09c..000000000 --- a/app/assets/javascripts/components/features/compose/containers/autosuggest_status_container.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux'; -import AutosuggestStatus from '../components/autosuggest_status'; -import { makeGetStatus } from '../../../selectors'; - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - const mapStateToProps = (state, { id }) => ({ - status: getStatus(state, id) - }); - - return mapStateToProps; -}; - -export default connect(makeMapStateToProps)(AutosuggestStatus); diff --git a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx b/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx deleted file mode 100644 index 892183b83..000000000 --- a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import { connect } from 'react-redux'; -import ComposeForm from '../components/compose_form'; -import { uploadCompose } from '../../../actions/compose'; -import { - changeCompose, - submitCompose, - clearComposeSuggestions, - fetchComposeSuggestions, - selectComposeSuggestion, - changeComposeSpoilerText, - insertEmojiCompose -} from '../../../actions/compose'; - -const mapStateToProps = state => ({ - text: state.getIn(['compose', 'text']), - suggestion_token: state.getIn(['compose', 'suggestion_token']), - suggestions: state.getIn(['compose', 'suggestions']), - spoiler: state.getIn(['compose', 'spoiler']), - spoiler_text: state.getIn(['compose', 'spoiler_text']), - privacy: state.getIn(['compose', 'privacy']), - focusDate: state.getIn(['compose', 'focusDate']), - preselectDate: state.getIn(['compose', 'preselectDate']), - is_submitting: state.getIn(['compose', 'is_submitting']), - is_uploading: state.getIn(['compose', 'is_uploading']), - me: state.getIn(['compose', 'me']) -}); - -const mapDispatchToProps = (dispatch) => ({ - - onChange (text) { - dispatch(changeCompose(text)); - }, - - onSubmit () { - dispatch(submitCompose()); - }, - - onClearSuggestions () { - dispatch(clearComposeSuggestions()); - }, - - onFetchSuggestions (token) { - dispatch(fetchComposeSuggestions(token)); - }, - - onSuggestionSelected (position, token, accountId) { - dispatch(selectComposeSuggestion(position, token, accountId)); - }, - - onChangeSpoilerText (checked) { - dispatch(changeComposeSpoilerText(checked)); - }, - - onPaste (files) { - dispatch(uploadCompose(files)); - }, - - onPickEmoji (position, data) { - dispatch(insertEmojiCompose(position, data)); - }, - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm); diff --git a/app/assets/javascripts/components/features/compose/containers/navigation_container.jsx b/app/assets/javascripts/components/features/compose/containers/navigation_container.jsx deleted file mode 100644 index 0006608da..000000000 --- a/app/assets/javascripts/components/features/compose/containers/navigation_container.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import { connect } from 'react-redux'; -import NavigationBar from '../components/navigation_bar'; - -const mapStateToProps = (state, props) => { - return { - account: state.getIn(['accounts', state.getIn(['meta', 'me'])]) - }; -}; - -export default connect(mapStateToProps)(NavigationBar); diff --git a/app/assets/javascripts/components/features/compose/containers/privacy_dropdown_container.jsx b/app/assets/javascripts/components/features/compose/containers/privacy_dropdown_container.jsx deleted file mode 100644 index 1eee8f84c..000000000 --- a/app/assets/javascripts/components/features/compose/containers/privacy_dropdown_container.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import { connect } from 'react-redux'; -import PrivacyDropdown from '../components/privacy_dropdown'; -import { changeComposeVisibility } from '../../../actions/compose'; - -const mapStateToProps = state => ({ - value: state.getIn(['compose', 'privacy']) -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (value) { - dispatch(changeComposeVisibility(value)); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(PrivacyDropdown); diff --git a/app/assets/javascripts/components/features/compose/containers/reply_indicator_container.jsx b/app/assets/javascripts/components/features/compose/containers/reply_indicator_container.jsx deleted file mode 100644 index 39b48f3b6..000000000 --- a/app/assets/javascripts/components/features/compose/containers/reply_indicator_container.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import { connect } from 'react-redux'; -import { cancelReplyCompose } from '../../../actions/compose'; -import { makeGetStatus } from '../../../selectors'; -import ReplyIndicator from '../components/reply_indicator'; - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - const mapStateToProps = (state, props) => ({ - status: getStatus(state, state.getIn(['compose', 'in_reply_to'])), - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = dispatch => ({ - - onCancel () { - dispatch(cancelReplyCompose()); - } - -}); - -export default connect(makeMapStateToProps, mapDispatchToProps)(ReplyIndicator); diff --git a/app/assets/javascripts/components/features/compose/containers/search_container.jsx b/app/assets/javascripts/components/features/compose/containers/search_container.jsx deleted file mode 100644 index 906c0c28c..000000000 --- a/app/assets/javascripts/components/features/compose/containers/search_container.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { connect } from 'react-redux'; -import { - changeSearch, - clearSearch, - submitSearch, - showSearch -} from '../../../actions/search'; -import Search from '../components/search'; - -const mapStateToProps = state => ({ - value: state.getIn(['search', 'value']), - submitted: state.getIn(['search', 'submitted']) -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (value) { - dispatch(changeSearch(value)); - }, - - onClear () { - dispatch(clearSearch()); - }, - - onSubmit () { - dispatch(submitSearch()); - }, - - onShow () { - dispatch(showSearch()); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Search); diff --git a/app/assets/javascripts/components/features/compose/containers/search_results_container.jsx b/app/assets/javascripts/components/features/compose/containers/search_results_container.jsx deleted file mode 100644 index e5911fd38..000000000 --- a/app/assets/javascripts/components/features/compose/containers/search_results_container.jsx +++ /dev/null @@ -1,8 +0,0 @@ -import { connect } from 'react-redux'; -import SearchResults from '../components/search_results'; - -const mapStateToProps = state => ({ - results: state.getIn(['search', 'results']) -}); - -export default connect(mapStateToProps)(SearchResults); diff --git a/app/assets/javascripts/components/features/compose/containers/sensitive_button_container.jsx b/app/assets/javascripts/components/features/compose/containers/sensitive_button_container.jsx deleted file mode 100644 index c83598a7d..000000000 --- a/app/assets/javascripts/components/features/compose/containers/sensitive_button_container.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import TextIconButton from '../components/text_icon_button'; -import { changeComposeSensitivity } from '../../../actions/compose'; -import { Motion, spring } from 'react-motion'; -import { injectIntl, defineMessages } from 'react-intl'; - -const messages = defineMessages({ - title: { id: 'compose_form.sensitive', defaultMessage: 'Mark media as sensitive' } -}); - -const mapStateToProps = state => ({ - visible: state.getIn(['compose', 'media_attachments']).size > 0, - active: state.getIn(['compose', 'sensitive']) -}); - -const mapDispatchToProps = dispatch => ({ - - onClick () { - dispatch(changeComposeSensitivity()); - } - -}); - -class SensitiveButton extends React.PureComponent { - - render () { - const { visible, active, onClick, intl } = this.props; - - return ( - - {({ scale }) => -
- -
- } -
- ); - } - -} - -SensitiveButton.propTypes = { - visible: PropTypes.bool, - active: PropTypes.bool, - onClick: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(SensitiveButton)); diff --git a/app/assets/javascripts/components/features/compose/containers/spoiler_button_container.jsx b/app/assets/javascripts/components/features/compose/containers/spoiler_button_container.jsx deleted file mode 100644 index b1c80fe19..000000000 --- a/app/assets/javascripts/components/features/compose/containers/spoiler_button_container.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import { connect } from 'react-redux'; -import TextIconButton from '../components/text_icon_button'; -import { changeComposeSpoilerness } from '../../../actions/compose'; -import { injectIntl, defineMessages } from 'react-intl'; - -const messages = defineMessages({ - title: { id: 'compose_form.spoiler', defaultMessage: 'Hide text behind warning' } -}); - -const mapStateToProps = (state, { intl }) => ({ - label: 'CW', - title: intl.formatMessage(messages.title), - active: state.getIn(['compose', 'spoiler']), - ariaControls: 'cw-spoiler-input' -}); - -const mapDispatchToProps = dispatch => ({ - - onClick () { - dispatch(changeComposeSpoilerness()); - } - -}); - -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(TextIconButton)); diff --git a/app/assets/javascripts/components/features/compose/containers/upload_button_container.jsx b/app/assets/javascripts/components/features/compose/containers/upload_button_container.jsx deleted file mode 100644 index 78e5312f5..000000000 --- a/app/assets/javascripts/components/features/compose/containers/upload_button_container.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import { connect } from 'react-redux'; -import UploadButton from '../components/upload_button'; -import { uploadCompose } from '../../../actions/compose'; - -const mapStateToProps = state => ({ - disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')), - resetFileKey: state.getIn(['compose', 'resetFileKey']) -}); - -const mapDispatchToProps = dispatch => ({ - - onSelectFile (files) { - dispatch(uploadCompose(files)); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(UploadButton); diff --git a/app/assets/javascripts/components/features/compose/containers/upload_form_container.jsx b/app/assets/javascripts/components/features/compose/containers/upload_form_container.jsx deleted file mode 100644 index a6a202e17..000000000 --- a/app/assets/javascripts/components/features/compose/containers/upload_form_container.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import { connect } from 'react-redux'; -import UploadForm from '../components/upload_form'; -import { undoUploadCompose } from '../../../actions/compose'; - -const mapStateToProps = (state, props) => ({ - media: state.getIn(['compose', 'media_attachments']), -}); - -const mapDispatchToProps = dispatch => ({ - - onRemoveFile (media_id) { - dispatch(undoUploadCompose(media_id)); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(UploadForm); diff --git a/app/assets/javascripts/components/features/compose/containers/upload_progress_container.jsx b/app/assets/javascripts/components/features/compose/containers/upload_progress_container.jsx deleted file mode 100644 index b0f1d4d19..000000000 --- a/app/assets/javascripts/components/features/compose/containers/upload_progress_container.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { connect } from 'react-redux'; -import UploadProgress from '../components/upload_progress'; - -const mapStateToProps = (state, props) => ({ - active: state.getIn(['compose', 'is_uploading']), - progress: state.getIn(['compose', 'progress']) -}); - -export default connect(mapStateToProps)(UploadProgress); diff --git a/app/assets/javascripts/components/features/compose/containers/warning_container.jsx b/app/assets/javascripts/components/features/compose/containers/warning_container.jsx deleted file mode 100644 index cd744ed82..000000000 --- a/app/assets/javascripts/components/features/compose/containers/warning_container.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { connect } from 'react-redux'; -import Warning from '../components/warning'; -import { createSelector } from 'reselect'; -import PropTypes from 'prop-types'; -import { FormattedMessage } from 'react-intl'; - -const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig)); - -const getMentionedDomains = createSelector(getMentionedUsernames, mentionedUsernamesWithDomains => { - return mentionedUsernamesWithDomains !== null ? [...new Set(mentionedUsernamesWithDomains.map(item => item.split('@')[2]))] : []; -}); - -const mapStateToProps = state => { - const mentionedUsernames = getMentionedUsernames(state); - const mentionedUsernamesWithDomains = getMentionedDomains(state); - - return { - needsLeakWarning: (state.getIn(['compose', 'privacy']) === 'private' || state.getIn(['compose', 'privacy']) === 'direct') && mentionedUsernames !== null, - mentionedDomains: mentionedUsernamesWithDomains, - needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', state.getIn(['meta', 'me']), 'locked']) - }; -}; - -const WarningWrapper = ({ needsLeakWarning, needsLockWarning, mentionedDomains }) => { - if (needsLockWarning) { - return }} />} />; - } else if (needsLeakWarning) { - return ( - {mentionedDomains.join(', ')}, domainsCount: mentionedDomains.length }} - />} - /> - ); - } - - return null; -}; - -WarningWrapper.propTypes = { - needsLeakWarning: PropTypes.bool, - needsLockWarning: PropTypes.bool, - mentionedDomains: PropTypes.array.isRequired, -}; - -export default connect(mapStateToProps)(WarningWrapper); diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx deleted file mode 100644 index ae1b52ca0..000000000 --- a/app/assets/javascripts/components/features/compose/index.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import ComposeFormContainer from './containers/compose_form_container'; -import UploadFormContainer from './containers/upload_form_container'; -import NavigationContainer from './containers/navigation_container'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { mountCompose, unmountCompose } from '../../actions/compose'; -import { Link } from 'react-router'; -import { injectIntl, defineMessages } from 'react-intl'; -import SearchContainer from './containers/search_container'; -import { Motion, spring } from 'react-motion'; -import SearchResultsContainer from './containers/search_results_container'; - -const messages = defineMessages({ - start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, - public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, - community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, - preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, - logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' } -}); - -const mapStateToProps = state => ({ - showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) -}); - -class Compose extends React.PureComponent { - - componentDidMount () { - this.props.dispatch(mountCompose()); - } - - componentWillUnmount () { - this.props.dispatch(unmountCompose()); - } - - render () { - const { withHeader, showSearch, intl } = this.props; - - let header = ''; - - if (withHeader) { - header = ( -
- - - - - -
- ); - } - - return ( -
- {header} - - - -
-
- - -
- - - {({ x }) => -
- -
- } -
-
-
- ); - } - -} - -Compose.propTypes = { - dispatch: PropTypes.func.isRequired, - withHeader: PropTypes.bool, - showSearch: PropTypes.bool, - intl: PropTypes.object.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(Compose)); diff --git a/app/assets/javascripts/components/features/favourited_statuses/index.jsx b/app/assets/javascripts/components/features/favourited_statuses/index.jsx deleted file mode 100644 index bc45ace51..000000000 --- a/app/assets/javascripts/components/features/favourited_statuses/index.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchFavouritedStatuses, expandFavouritedStatuses } from '../../actions/favourites'; -import Column from '../ui/components/column'; -import StatusList from '../../components/status_list'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - heading: { id: 'column.favourites', defaultMessage: 'Favourites' } -}); - -const mapStateToProps = state => ({ - statusIds: state.getIn(['status_lists', 'favourites', 'items']), - loaded: state.getIn(['status_lists', 'favourites', 'loaded']), - me: state.getIn(['meta', 'me']) -}); - -class Favourites extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScrollToBottom = this.handleScrollToBottom.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchFavouritedStatuses()); - } - - handleScrollToBottom () { - this.props.dispatch(expandFavouritedStatuses()); - } - - render () { - const { statusIds, loaded, intl, me } = this.props; - - if (!loaded) { - return ( - - - - ); - } - - return ( - - - - - ); - } - -} - -Favourites.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - statusIds: ImmutablePropTypes.list.isRequired, - loaded: PropTypes.bool, - intl: PropTypes.object.isRequired, - me: PropTypes.number.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(Favourites)); diff --git a/app/assets/javascripts/components/features/favourites/index.jsx b/app/assets/javascripts/components/features/favourites/index.jsx deleted file mode 100644 index bd6cf8a90..000000000 --- a/app/assets/javascripts/components/features/favourites/index.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchFavourites } from '../../actions/interactions'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../../containers/account_container'; -import Column from '../ui/components/column'; -import ColumnBackButton from '../../components/column_back_button'; - -const mapStateToProps = (state, props) => ({ - accountIds: state.getIn(['user_lists', 'favourited_by', Number(props.params.statusId)]) -}); - -class Favourites extends React.PureComponent { - - componentWillMount () { - this.props.dispatch(fetchFavourites(Number(this.props.params.statusId))); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { - this.props.dispatch(fetchFavourites(Number(nextProps.params.statusId))); - } - } - - render () { - const { accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - - -
- {accountIds.map(id => )} -
-
-
- ); - } - -} - -Favourites.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list -}; - -export default connect(mapStateToProps)(Favourites); diff --git a/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx b/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx deleted file mode 100644 index d35a54c12..000000000 --- a/app/assets/javascripts/components/features/follow_requests/components/account_authorize.jsx +++ /dev/null @@ -1,44 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Permalink from '../../../components/permalink'; -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; -import emojify from '../../../emoji'; -import IconButton from '../../../components/icon_button'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' }, - reject: { id: 'follow_request.reject', defaultMessage: 'Reject' } -}); - -const AccountAuthorize = ({ intl, account, onAuthorize, onReject }) => { - const content = { __html: emojify(account.get('note')) }; - - return ( -
-
- -
- -
- -
-
- -
-
-
-
-
- ) -}; - -AccountAuthorize.propTypes = { - account: ImmutablePropTypes.map.isRequired, - onAuthorize: PropTypes.func.isRequired, - onReject: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(AccountAuthorize); diff --git a/app/assets/javascripts/components/features/follow_requests/containers/account_authorize_container.jsx b/app/assets/javascripts/components/features/follow_requests/containers/account_authorize_container.jsx deleted file mode 100644 index da1e5eaa1..000000000 --- a/app/assets/javascripts/components/features/follow_requests/containers/account_authorize_container.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux'; -import { makeGetAccount } from '../../../selectors'; -import AccountAuthorize from '../components/account_authorize'; -import { authorizeFollowRequest, rejectFollowRequest } from '../../../actions/accounts'; - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, props) => ({ - account: getAccount(state, props.id) - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch, { id }) => ({ - onAuthorize (account) { - dispatch(authorizeFollowRequest(id)); - }, - - onReject (account) { - dispatch(rejectFollowRequest(id)); - } -}); - -export default connect(makeMapStateToProps, mapDispatchToProps)(AccountAuthorize); diff --git a/app/assets/javascripts/components/features/follow_requests/index.jsx b/app/assets/javascripts/components/features/follow_requests/index.jsx deleted file mode 100644 index 3dc709654..000000000 --- a/app/assets/javascripts/components/features/follow_requests/index.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll'; -import Column from '../ui/components/column'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import AccountAuthorizeContainer from './containers/account_authorize_container'; -import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' } -}); - -const mapStateToProps = state => ({ - accountIds: state.getIn(['user_lists', 'follow_requests', 'items']) -}); - -class FollowRequests extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchFollowRequests()); - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandFollowRequests()); - } - } - - render () { - const { intl, accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - -
- {accountIds.map(id => - - )} -
-
-
- ); - } -} - -FollowRequests.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list, - intl: PropTypes.object.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(FollowRequests)); diff --git a/app/assets/javascripts/components/features/followers/index.jsx b/app/assets/javascripts/components/features/followers/index.jsx deleted file mode 100644 index 2b1e3719e..000000000 --- a/app/assets/javascripts/components/features/followers/index.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { - fetchAccount, - fetchFollowers, - expandFollowers -} from '../../actions/accounts'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../../containers/account_container'; -import Column from '../ui/components/column'; -import HeaderContainer from '../account_timeline/containers/header_container'; -import LoadMore from '../../components/load_more'; -import ColumnBackButton from '../../components/column_back_button'; - -const mapStateToProps = (state, props) => ({ - accountIds: state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'items']) -}); - -class Followers extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - this.handleLoadMore = this.handleLoadMore.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchAccount(Number(this.props.params.accountId))); - this.props.dispatch(fetchFollowers(Number(this.props.params.accountId))); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(Number(nextProps.params.accountId))); - this.props.dispatch(fetchFollowers(Number(nextProps.params.accountId))); - } - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandFollowers(Number(this.props.params.accountId))); - } - } - - handleLoadMore (e) { - e.preventDefault(); - this.props.dispatch(expandFollowers(Number(this.props.params.accountId))); - } - - render () { - const { accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - - -
-
- - {accountIds.map(id => )} - -
-
-
-
- ); - } - -} - -Followers.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list -}; - -export default connect(mapStateToProps)(Followers); diff --git a/app/assets/javascripts/components/features/following/index.jsx b/app/assets/javascripts/components/features/following/index.jsx deleted file mode 100644 index 30b320917..000000000 --- a/app/assets/javascripts/components/features/following/index.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { - fetchAccount, - fetchFollowing, - expandFollowing -} from '../../actions/accounts'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../../containers/account_container'; -import Column from '../ui/components/column'; -import HeaderContainer from '../account_timeline/containers/header_container'; -import LoadMore from '../../components/load_more'; -import ColumnBackButton from '../../components/column_back_button'; - -const mapStateToProps = (state, props) => ({ - accountIds: state.getIn(['user_lists', 'following', Number(props.params.accountId), 'items']) -}); - -class Following extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - this.handleLoadMore = this.handleLoadMore.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchAccount(Number(this.props.params.accountId))); - this.props.dispatch(fetchFollowing(Number(this.props.params.accountId))); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { - this.props.dispatch(fetchAccount(Number(nextProps.params.accountId))); - this.props.dispatch(fetchFollowing(Number(nextProps.params.accountId))); - } - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandFollowing(Number(this.props.params.accountId))); - } - } - - handleLoadMore (e) { - e.preventDefault(); - this.props.dispatch(expandFollowing(Number(this.props.params.accountId))); - } - - render () { - const { accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - - -
-
- - {accountIds.map(id => )} - -
-
-
-
- ); - } - -} - -Following.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list -}; - -export default connect(mapStateToProps)(Following); diff --git a/app/assets/javascripts/components/features/generic_not_found/index.jsx b/app/assets/javascripts/components/features/generic_not_found/index.jsx deleted file mode 100644 index a7afe29b0..000000000 --- a/app/assets/javascripts/components/features/generic_not_found/index.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import Column from '../ui/components/column'; -import MissingIndicator from '../../components/missing_indicator'; - -const GenericNotFound = () => ( - - - -); - -export default GenericNotFound; diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx deleted file mode 100644 index bd4920c94..000000000 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import Column from '../ui/components/column'; -import ColumnLink from '../ui/components/column_link'; -import ColumnSubheading from '../ui/components/column_subheading'; -import { Link } from 'react-router'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; - -const messages = defineMessages({ - heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, - public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' }, - navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation'}, - settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings'}, - community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, - preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, - follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, - sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, - favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, - blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, - mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, - info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' } -}); - -const mapStateToProps = state => ({ - me: state.getIn(['accounts', state.getIn(['meta', 'me'])]) -}); - -const GettingStarted = ({ intl, me }) => { - let followRequests = ''; - - if (me.get('locked')) { - followRequests = ; - } - - return ( - -
- - - - - {followRequests} - - - - - - -
- -
-
-

tootsuite/mastodon, apps: }} />

-
-
-
- ); -}; - -GettingStarted.propTypes = { - intl: PropTypes.object.isRequired, - me: ImmutablePropTypes.map.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(GettingStarted)); diff --git a/app/assets/javascripts/components/features/hashtag_timeline/index.jsx b/app/assets/javascripts/components/features/hashtag_timeline/index.jsx deleted file mode 100644 index 0575e9214..000000000 --- a/app/assets/javascripts/components/features/hashtag_timeline/index.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; -import { - refreshTimeline, - updateTimeline, - deleteFromTimelines -} from '../../actions/timelines'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import { FormattedMessage } from 'react-intl'; -import createStream from '../../stream'; - -const mapStateToProps = state => ({ - hasUnread: state.getIn(['timelines', 'tag', 'unread']) > 0, - streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']), - accessToken: state.getIn(['meta', 'access_token']) -}); - -class HashtagTimeline extends React.PureComponent { - - _subscribe (dispatch, id) { - const { streamingAPIBaseURL, accessToken } = this.props; - - this.subscription = createStream(streamingAPIBaseURL, accessToken, `hashtag&tag=${id}`, { - - received (data) { - switch(data.event) { - case 'update': - dispatch(updateTimeline('tag', JSON.parse(data.payload))); - break; - case 'delete': - dispatch(deleteFromTimelines(data.payload)); - break; - } - } - - }); - } - - _unsubscribe () { - if (typeof this.subscription !== 'undefined') { - this.subscription.close(); - this.subscription = null; - } - } - - componentDidMount () { - const { dispatch } = this.props; - const { id } = this.props.params; - - dispatch(refreshTimeline('tag', id)); - this._subscribe(dispatch, id); - } - - componentWillReceiveProps (nextProps) { - if (nextProps.params.id !== this.props.params.id) { - this.props.dispatch(refreshTimeline('tag', nextProps.params.id)); - this._unsubscribe(); - this._subscribe(this.props.dispatch, nextProps.params.id); - } - } - - componentWillUnmount () { - this._unsubscribe(); - } - - render () { - const { id, hasUnread } = this.props.params; - - return ( - - - } /> - - ); - } - -} - -HashtagTimeline.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - streamingAPIBaseURL: PropTypes.string.isRequired, - accessToken: PropTypes.string.isRequired, - hasUnread: PropTypes.bool -}; - -export default connect(mapStateToProps)(HashtagTimeline); diff --git a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx b/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx deleted file mode 100644 index 81a1a0e5b..000000000 --- a/app/assets/javascripts/components/features/home_timeline/components/column_settings.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnCollapsable from '../../../components/column_collapsable'; -import SettingToggle from '../../notifications/components/setting_toggle'; -import SettingText from './setting_text'; - -const messages = defineMessages({ - filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' }, - settings: { id: 'home.settings', defaultMessage: 'Column settings' } -}); - -class ColumnSettings extends React.PureComponent { - - render () { - const { settings, onChange, onSave, intl } = this.props; - - return ( - -
- - -
- } /> -
- -
- } /> -
- - - -
- -
-
-
- ); - } - -} - -ColumnSettings.propTypes = { - settings: ImmutablePropTypes.map.isRequired, - onChange: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -} - -export default injectIntl(ColumnSettings); diff --git a/app/assets/javascripts/components/features/home_timeline/components/setting_text.jsx b/app/assets/javascripts/components/features/home_timeline/components/setting_text.jsx deleted file mode 100644 index 90b4aeb94..000000000 --- a/app/assets/javascripts/components/features/home_timeline/components/setting_text.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; - -class SettingText extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleChange = this.handleChange.bind(this); - } - - handleChange (e) { - this.props.onChange(this.props.settingKey, e.target.value) - } - - render () { - const { settings, settingKey, label } = this.props; - - return ( - - ); - } - -} - -SettingText.propTypes = { - settings: ImmutablePropTypes.map.isRequired, - settingKey: PropTypes.array.isRequired, - label: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired -}; - -export default SettingText; diff --git a/app/assets/javascripts/components/features/home_timeline/containers/column_settings_container.jsx b/app/assets/javascripts/components/features/home_timeline/containers/column_settings_container.jsx deleted file mode 100644 index 3b3ce19bc..000000000 --- a/app/assets/javascripts/components/features/home_timeline/containers/column_settings_container.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import { connect } from 'react-redux'; -import ColumnSettings from '../components/column_settings'; -import { changeSetting, saveSettings } from '../../../actions/settings'; - -const mapStateToProps = state => ({ - settings: state.getIn(['settings', 'home']) -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (key, checked) { - dispatch(changeSetting(['home', ...key], checked)); - }, - - onSave () { - dispatch(saveSettings()); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings); diff --git a/app/assets/javascripts/components/features/home_timeline/index.jsx b/app/assets/javascripts/components/features/home_timeline/index.jsx deleted file mode 100644 index 52b94690d..000000000 --- a/app/assets/javascripts/components/features/home_timeline/index.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnSettingsContainer from './containers/column_settings_container'; -import { Link } from 'react-router'; - -const messages = defineMessages({ - title: { id: 'column.home', defaultMessage: 'Home' } -}); - -const mapStateToProps = state => ({ - hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0 -}); - -class HomeTimeline extends React.PureComponent { - - render () { - const { intl, hasUnread } = this.props; - - return ( - - - }} />} /> - - ); - } - -} - -HomeTimeline.propTypes = { - intl: PropTypes.object.isRequired, - hasUnread: PropTypes.bool -}; - -export default connect(mapStateToProps)(injectIntl(HomeTimeline)); diff --git a/app/assets/javascripts/components/features/mutes/index.jsx b/app/assets/javascripts/components/features/mutes/index.jsx deleted file mode 100644 index 0310fa7f2..000000000 --- a/app/assets/javascripts/components/features/mutes/index.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { ScrollContainer } from 'react-router-scroll'; -import Column from '../ui/components/column'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import AccountContainer from '../../containers/account_container'; -import { fetchMutes, expandMutes } from '../../actions/mutes'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - heading: { id: 'column.mutes', defaultMessage: 'Muted users' } -}); - -const mapStateToProps = state => ({ - accountIds: state.getIn(['user_lists', 'mutes', 'items']) -}); - -class Mutes extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchMutes()); - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - - if (scrollTop === scrollHeight - clientHeight) { - this.props.dispatch(expandMutes()); - } - } - - render () { - const { intl, accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - -
- {accountIds.map(id => - - )} -
-
-
- ); - } - -} - -Mutes.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list, - intl: PropTypes.object.isRequired -}; - -export default connect(mapStateToProps)(injectIntl(Mutes)); diff --git a/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx b/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx deleted file mode 100644 index 206b05f91..000000000 --- a/app/assets/javascripts/components/features/notifications/components/clear_column_button.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - clear: { id: 'notifications.clear', defaultMessage: 'Clear notifications' } -}); - -class ClearColumnButton extends React.Component { - - render () { - const { intl } = this.props; - - return ( -
- -
- ); - } -} - -ClearColumnButton.propTypes = { - onClick: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(ClearColumnButton); diff --git a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx b/app/assets/javascripts/components/features/notifications/components/column_settings.jsx deleted file mode 100644 index 30063010c..000000000 --- a/app/assets/javascripts/components/features/notifications/components/column_settings.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnCollapsable from '../../../components/column_collapsable'; -import SettingToggle from './setting_toggle'; - -const messages = defineMessages({ - settings: { id: 'notifications.settings', defaultMessage: 'Column settings' } -}); - -class ColumnSettings extends React.PureComponent { - - render () { - const { settings, intl, onChange, onSave } = this.props; - - const alertStr = ; - const showStr = ; - const soundStr = ; - - return ( - -
- - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
-
-
- ); - } - -} - -ColumnSettings.propTypes = { - settings: ImmutablePropTypes.map.isRequired, - onChange: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired, - intl: PropTypes.shape({ - formatMessage: PropTypes.func.isRequired - }).isRequired -}; - -export default injectIntl(ColumnSettings); diff --git a/app/assets/javascripts/components/features/notifications/components/notification.jsx b/app/assets/javascripts/components/features/notifications/components/notification.jsx deleted file mode 100644 index 34dd76bb7..000000000 --- a/app/assets/javascripts/components/features/notifications/components/notification.jsx +++ /dev/null @@ -1,88 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; -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 'escape-html'; - -class Notification extends React.PureComponent { - - renderFollow (account, link) { - return ( -
-
-
- -
- - -
- - -
- ); - } - - renderMention (notification) { - return ; - } - - renderFavourite (notification, link) { - return ( -
-
-
- -
- - -
- - -
- ); - } - - renderReblog (notification, link) { - return ( -
-
-
- -
- - -
- - -
- ); - } - - render () { // eslint-disable-line consistent-return - 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 displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) }; - const link = ; - - switch(notification.get('type')) { - case 'follow': - return this.renderFollow(account, link); - case 'mention': - return this.renderMention(notification); - case 'favourite': - return this.renderFavourite(notification, link); - case 'reblog': - return this.renderReblog(notification, link); - } - } - -} - -Notification.propTypes = { - notification: ImmutablePropTypes.map.isRequired -}; - -export default Notification; diff --git a/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx b/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx deleted file mode 100644 index e9bca5928..000000000 --- a/app/assets/javascripts/components/features/notifications/components/setting_toggle.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Toggle from 'react-toggle'; - -const SettingToggle = ({ settings, settingKey, label, onChange, htmlFor = '' }) => ( - -); - -SettingToggle.propTypes = { - settings: ImmutablePropTypes.map.isRequired, - settingKey: PropTypes.array.isRequired, - label: PropTypes.node.isRequired, - onChange: PropTypes.func.isRequired, - htmlFor: PropTypes.string -}; - -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 deleted file mode 100644 index bc24c75e0..000000000 --- a/app/assets/javascripts/components/features/notifications/containers/column_settings_container.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import { connect } from 'react-redux'; -import ColumnSettings from '../components/column_settings'; -import { changeSetting, saveSettings } from '../../../actions/settings'; - -const mapStateToProps = state => ({ - settings: state.getIn(['settings', 'notifications']) -}); - -const mapDispatchToProps = dispatch => ({ - - onChange (key, checked) { - dispatch(changeSetting(['notifications', ...key], checked)); - }, - - onSave () { - dispatch(saveSettings()); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings); diff --git a/app/assets/javascripts/components/features/notifications/containers/notification_container.jsx b/app/assets/javascripts/components/features/notifications/containers/notification_container.jsx deleted file mode 100644 index 4ca1b1b7b..000000000 --- a/app/assets/javascripts/components/features/notifications/containers/notification_container.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux'; -import { makeGetNotification } from '../../../selectors'; -import Notification from '../components/notification'; - -const makeMapStateToProps = () => { - const getNotification = makeGetNotification(); - - const mapStateToProps = (state, props) => ({ - notification: getNotification(state, props.notification, props.accountId) - }); - - return mapStateToProps; -}; - -export default connect(makeMapStateToProps)(Notification); diff --git a/app/assets/javascripts/components/features/notifications/index.jsx b/app/assets/javascripts/components/features/notifications/index.jsx deleted file mode 100644 index da3ce2f62..000000000 --- a/app/assets/javascripts/components/features/notifications/index.jsx +++ /dev/null @@ -1,142 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Column from '../ui/components/column'; -import { expandNotifications, clearNotifications, scrollTopNotifications } from '../../actions/notifications'; -import NotificationContainer from './containers/notification_container'; -import { ScrollContainer } from 'react-router-scroll'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnSettingsContainer from './containers/column_settings_container'; -import { createSelector } from 'reselect'; -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' }, - 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([ - 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), - isLoading: state.getIn(['notifications', 'isLoading'], true), - isUnread: state.getIn(['notifications', 'unread']) > 0 -}); - -class Notifications extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleScroll = this.handleScroll.bind(this); - this.handleLoadMore = this.handleLoadMore.bind(this); - this.handleClear = this.handleClear.bind(this); - this.setRef = this.setRef.bind(this); - } - - handleScroll (e) { - const { scrollTop, scrollHeight, clientHeight } = e.target; - const offset = scrollHeight - scrollTop - clientHeight; - this._oldScrollPosition = scrollHeight - scrollTop; - - if (250 > offset && !this.props.isLoading) { - this.props.dispatch(expandNotifications()); - } else if (scrollTop < 100) { - this.props.dispatch(scrollTopNotifications(true)); - } else { - this.props.dispatch(scrollTopNotifications(false)); - } - } - - componentDidUpdate (prevProps) { - if (this.node.scrollTop > 0 && (prevProps.notifications.size < this.props.notifications.size && prevProps.notifications.first() !== this.props.notifications.first() && !!this._oldScrollPosition)) { - this.node.scrollTop = this.node.scrollHeight - this._oldScrollPosition; - } - } - - handleLoadMore (e) { - e.preventDefault(); - this.props.dispatch(expandNotifications()); - } - - handleClear () { - const { dispatch, intl } = this.props; - - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.clearMessage), - confirm: intl.formatMessage(messages.clearConfirm), - onConfirm: () => dispatch(clearNotifications()) - })); - } - - setRef (c) { - this.node = c; - } - - render () { - const { intl, notifications, shouldUpdateScroll, isLoading, isUnread } = this.props; - - let loadMore = ''; - let scrollableArea = ''; - let unread = ''; - - if (!isLoading && notifications.size > 0) { - loadMore = ; - } - - if (isUnread) { - unread =
; - } - - if (isLoading || notifications.size > 0) { - scrollableArea = ( -
- {unread} - -
- {notifications.map(item => )} - {loadMore} -
-
- ); - } else { - scrollableArea = ( -
- -
- ); - } - - return ( - - - - - {scrollableArea} - - - ); - } - -} - -Notifications.propTypes = { - notifications: ImmutablePropTypes.list.isRequired, - dispatch: PropTypes.func.isRequired, - shouldUpdateScroll: PropTypes.func, - intl: PropTypes.object.isRequired, - isLoading: PropTypes.bool, - isUnread: PropTypes.bool -}; - -Notifications.defaultProps = { - trackScroll: true -}; - -export default connect(mapStateToProps)(injectIntl(Notifications)); diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx deleted file mode 100644 index 53be13686..000000000 --- a/app/assets/javascripts/components/features/public_timeline/index.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; -import { - refreshTimeline, - updateTimeline, - deleteFromTimelines, - connectTimeline, - disconnectTimeline -} from '../../actions/timelines'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; -import createStream from '../../stream'; - -const messages = defineMessages({ - title: { id: 'column.public', defaultMessage: 'Federated timeline' } -}); - -const mapStateToProps = state => ({ - hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0, - streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']), - accessToken: state.getIn(['meta', 'access_token']) -}); - -let subscription; - -class PublicTimeline extends React.PureComponent { - - componentDidMount () { - const { dispatch, streamingAPIBaseURL, accessToken } = this.props; - - dispatch(refreshTimeline('public')); - - if (typeof subscription !== 'undefined') { - return; - } - - subscription = createStream(streamingAPIBaseURL, accessToken, 'public', { - - connected () { - dispatch(connectTimeline('public')); - }, - - reconnected () { - dispatch(connectTimeline('public')); - }, - - disconnected () { - dispatch(disconnectTimeline('public')); - }, - - received (data) { - switch(data.event) { - case 'update': - dispatch(updateTimeline('public', JSON.parse(data.payload))); - break; - case 'delete': - dispatch(deleteFromTimelines(data.payload)); - break; - } - } - - }); - } - - componentWillUnmount () { - // if (typeof subscription !== 'undefined') { - // subscription.close(); - // subscription = null; - // } - } - - render () { - const { intl, hasUnread } = this.props; - - return ( - - - } /> - - ); - } - -} - -PublicTimeline.propTypes = { - dispatch: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - streamingAPIBaseURL: PropTypes.string.isRequired, - accessToken: PropTypes.string.isRequired, - hasUnread: PropTypes.bool -}; - -export default connect(mapStateToProps)(injectIntl(PublicTimeline)); diff --git a/app/assets/javascripts/components/features/reblogs/index.jsx b/app/assets/javascripts/components/features/reblogs/index.jsx deleted file mode 100644 index 5e5671422..000000000 --- a/app/assets/javascripts/components/features/reblogs/index.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchReblogs } from '../../actions/interactions'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../../containers/account_container'; -import Column from '../ui/components/column'; -import ColumnBackButton from '../../components/column_back_button'; - -const mapStateToProps = (state, props) => ({ - accountIds: state.getIn(['user_lists', 'reblogged_by', Number(props.params.statusId)]) -}); - -class Reblogs extends React.PureComponent { - - componentWillMount () { - this.props.dispatch(fetchReblogs(Number(this.props.params.statusId))); - } - - componentWillReceiveProps(nextProps) { - if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { - this.props.dispatch(fetchReblogs(Number(nextProps.params.statusId))); - } - } - - render () { - const { accountIds } = this.props; - - if (!accountIds) { - return ( - - - - ); - } - - return ( - - - - -
- {accountIds.map(id => )} -
-
-
- ); - } - -} - -Reblogs.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - accountIds: ImmutablePropTypes.list -}; - -export default connect(mapStateToProps)(Reblogs); diff --git a/app/assets/javascripts/components/features/report/components/status_check_box.jsx b/app/assets/javascripts/components/features/report/components/status_check_box.jsx deleted file mode 100644 index bc866616a..000000000 --- a/app/assets/javascripts/components/features/report/components/status_check_box.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import emojify from '../../../emoji'; -import Toggle from 'react-toggle'; - -class StatusCheckBox extends React.PureComponent { - - render () { - const { status, checked, onToggle, disabled } = this.props; - const content = { __html: emojify(status.get('content')) }; - - if (status.get('reblog')) { - return null; - } - - return ( -
-
- -
- -
-
- ); - } - -} - -StatusCheckBox.propTypes = { - status: ImmutablePropTypes.map.isRequired, - checked: PropTypes.bool, - onToggle: PropTypes.func.isRequired, - disabled: PropTypes.bool -}; - -export default StatusCheckBox; diff --git a/app/assets/javascripts/components/features/report/containers/status_check_box_container.jsx b/app/assets/javascripts/components/features/report/containers/status_check_box_container.jsx deleted file mode 100644 index 67ce9d9f3..000000000 --- a/app/assets/javascripts/components/features/report/containers/status_check_box_container.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import { connect } from 'react-redux'; -import StatusCheckBox from '../components/status_check_box'; -import { toggleStatusReport } from '../../../actions/reports'; -import Immutable from 'immutable'; - -const mapStateToProps = (state, { id }) => ({ - status: state.getIn(['statuses', id]), - checked: state.getIn(['reports', 'new', 'status_ids'], Immutable.Set()).includes(id) -}); - -const mapDispatchToProps = (dispatch, { id }) => ({ - - onToggle (e) { - dispatch(toggleStatusReport(id, e.target.checked)); - } - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(StatusCheckBox); diff --git a/app/assets/javascripts/components/features/report/index.jsx b/app/assets/javascripts/components/features/report/index.jsx deleted file mode 100644 index 6e3cfcb2a..000000000 --- a/app/assets/javascripts/components/features/report/index.jsx +++ /dev/null @@ -1,130 +0,0 @@ -import { connect } from 'react-redux'; -import { cancelReport, changeReportComment, submitReport } from '../../actions/reports'; -import { fetchAccountTimeline } from '../../actions/accounts'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Column from '../ui/components/column'; -import Button from '../../components/button'; -import { makeGetAccount } from '../../selectors'; -import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; -import StatusCheckBox from './containers/status_check_box_container'; -import Immutable from 'immutable'; -import ColumnBackButtonSlim from '../../components/column_back_button_slim'; - -const messages = defineMessages({ - heading: { id: 'report.heading', defaultMessage: 'New report' }, - placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' }, - submit: { id: 'report.submit', defaultMessage: 'Submit' } -}); - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = state => { - const accountId = state.getIn(['reports', 'new', 'account_id']); - - return { - isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']), - account: getAccount(state, accountId), - comment: state.getIn(['reports', 'new', 'comment']), - statusIds: Immutable.OrderedSet(state.getIn(['timelines', 'accounts_timelines', accountId, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])) - }; - }; - - return mapStateToProps; -}; - -class Report extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleCommentChange = this.handleCommentChange.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - } - - componentWillMount () { - if (!this.props.account) { - this.context.router.replace('/'); - } - } - - componentDidMount () { - if (!this.props.account) { - return; - } - - this.props.dispatch(fetchAccountTimeline(this.props.account.get('id'))); - } - - componentWillReceiveProps (nextProps) { - if (this.props.account !== nextProps.account && nextProps.account) { - this.props.dispatch(fetchAccountTimeline(nextProps.account.get('id'))); - } - } - - handleCommentChange (e) { - this.props.dispatch(changeReportComment(e.target.value)); - } - - handleSubmit () { - this.props.dispatch(submitReport()); - this.context.router.replace('/'); - } - - render () { - const { account, comment, intl, statusIds, isSubmitting } = this.props; - - if (!account) { - return null; - } - - return ( - - - -
-
- - {account.get('acct')} -
- -
-
- {statusIds.map(statusId => )} -
-
- -
-