Continuing updating the reformatting of propTypes and set redux, intl functions to end of component

• Removing:
- the reformatting of propTypes and set redux, intl functions to end of component
This commit is contained in:
mgabdev 2020-08-17 19:57:35 -05:00
parent 46a0cbca7d
commit ddca693cfc
101 changed files with 2053 additions and 2140 deletions

View File

@ -23,81 +23,8 @@ import Avatar from './avatar'
import DisplayName from './display_name' import DisplayName from './display_name'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
const makeMapStateToProps = (state, props) => ({
account: makeGetAccount()(state, props.id),
})
const mapDispatchToProps = (dispatch) => ({
onFollow (account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
account,
}))
} else {
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(blockAccount(account.get('id')))
}
},
onMute (account) {
if (account.getIn(['relationship', 'muting'])) {
dispatch(unmuteAccount(account.get('id')))
} else {
dispatch(initMuteModal(account))
}
},
onMuteNotifications (account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
})
export default
@injectIntl
@connect(makeMapStateToProps, mapDispatchToProps)
class Account extends ImmutablePureComponent { class Account extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onMuteNotifications: PropTypes.func,
intl: PropTypes.object.isRequired,
isHidden: PropTypes.bool,
actionIcon: PropTypes.string,
actionTitle: PropTypes.string,
onActionClick: PropTypes.func,
compact: PropTypes.bool,
expanded: PropTypes.bool,
showDismiss: PropTypes.bool,
dismissAction: PropTypes.func,
withBio: PropTypes.bool,
}
updateOnProps = [
'account',
'isHidden',
'compact',
'expanded',
'showDismiss',
'withBio',
]
handleAction = (e) => { handleAction = (e) => {
this.props.onActionClick(this.props.account, e) this.props.onActionClick(this.props.account, e)
} }
@ -206,3 +133,66 @@ class Account extends ImmutablePureComponent {
} }
} }
const makeMapStateToProps = (state, props) => ({
account: makeGetAccount()(state, props.id),
})
const mapDispatchToProps = (dispatch) => ({
onFollow (account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
account,
}))
} else {
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(blockAccount(account.get('id')))
}
},
onMute (account) {
if (account.getIn(['relationship', 'muting'])) {
dispatch(unmuteAccount(account.get('id')))
} else {
dispatch(initMuteModal(account))
}
},
onMuteNotifications (account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
})
Account.propTypes = {
account: ImmutablePropTypes.map.isRequired,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onMuteNotifications: PropTypes.func,
intl: PropTypes.object.isRequired,
isHidden: PropTypes.bool,
actionIcon: PropTypes.string,
actionTitle: PropTypes.string,
onActionClick: PropTypes.func,
compact: PropTypes.bool,
expanded: PropTypes.bool,
showDismiss: PropTypes.bool,
dismissAction: PropTypes.func,
withBio: PropTypes.bool,
}
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Account))

View File

@ -15,70 +15,8 @@ import { MODAL_EDIT_PROFILE } from '../constants'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
// : todo :
const messages = defineMessages({
follow: { id: 'follow', defaultMessage: 'Follow' },
following: { id: 'following', defaultMessage: 'Following' },
unfollow: { id: 'unfollow', defaultMessage: 'Unfollow' },
requested: { id: 'requested', defaultMessage: 'Requested' },
unblock: { id: 'unblock', defaultMessage: 'Unblock' },
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
})
const mapDispatchToProps = (dispatch) => ({
onFollow(account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
account,
}));
} else {
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('BLOCK_ACCOUNT', {
accountId: account.get('id'),
}));
}
},
onOpenEditProfile() {
dispatch(openModal(MODAL_EDIT_PROFILE))
},
});
export default
@injectIntl
@connect(null, mapDispatchToProps)
class AccountActionButton extends ImmutablePureComponent { class AccountActionButton extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
isSmall: PropTypes.bool,
onBlock: PropTypes.func.isRequired,
onFollow: PropTypes.func.isRequired,
onOpenEditProfile: PropTypes.func.isRequired,
}
updateOnProps = [
'account',
]
handleFollow = () => { handleFollow = () => {
this.props.onFollow(this.props.account) this.props.onFollow(this.props.account)
} }
@ -181,3 +119,58 @@ class AccountActionButton extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
follow: { id: 'follow', defaultMessage: 'Follow' },
following: { id: 'following', defaultMessage: 'Following' },
unfollow: { id: 'unfollow', defaultMessage: 'Unfollow' },
requested: { id: 'requested', defaultMessage: 'Requested' },
unblock: { id: 'unblock', defaultMessage: 'Unblock' },
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
})
const mapDispatchToProps = (dispatch) => ({
onFollow(account) {
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
if (unfollowModal) {
dispatch(openModal('UNFOLLOW', {
account,
}))
} else {
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('BLOCK_ACCOUNT', {
accountId: account.get('id'),
}))
}
},
onOpenEditProfile() {
dispatch(openModal(MODAL_EDIT_PROFILE))
},
})
AccountActionButton.propTypes = {
account: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
isSmall: PropTypes.bool,
onBlock: PropTypes.func.isRequired,
onFollow: PropTypes.func.isRequired,
onOpenEditProfile: PropTypes.func.isRequired,
}
export default injectIntl(connect(null, mapDispatchToProps)(AccountActionButton))

View File

@ -8,36 +8,8 @@ import { authorizeFollowRequest, rejectFollowRequest } from '../actions/accounts
import { makeGetAccount } from '../selectors' import { makeGetAccount } from '../selectors'
import Account from './account' import Account from './account'
const messages = defineMessages({
authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' },
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
})
const makeMapStateToProps = (state, props) => ({
account: makeGetAccount()(state, props.id),
})
const mapDispatchToProps = (dispatch, { id }) => ({
onAuthorize() {
dispatch(authorizeFollowRequest(id))
},
onReject() {
dispatch(rejectFollowRequest(id))
},
})
export default
@connect(makeMapStateToProps, mapDispatchToProps)
@injectIntl
class AccountAuthorize extends ImmutablePureComponent { class AccountAuthorize extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
intl: PropTypes.object.isRequired,
onAuthorize: PropTypes.func.isRequired,
onReject: PropTypes.func.isRequired,
}
render () { render () {
const { const {
intl, intl,
@ -62,3 +34,30 @@ class AccountAuthorize extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
authorize: { id: 'follow_request.authorize', defaultMessage: 'Authorize' },
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
})
const makeMapStateToProps = (state, props) => ({
account: makeGetAccount()(state, props.id),
})
const mapDispatchToProps = (dispatch, { id }) => ({
onAuthorize() {
dispatch(authorizeFollowRequest(id))
},
onReject() {
dispatch(rejectFollowRequest(id))
},
})
AccountAuthorize.propTypes = {
account: ImmutablePropTypes.map.isRequired,
intl: PropTypes.object.isRequired,
onAuthorize: PropTypes.func.isRequired,
onReject: PropTypes.func.isRequired,
}
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(AccountAuthorize))

View File

@ -7,24 +7,8 @@ import { makeGetAccount } from '../selectors'
import Avatar from './avatar' import Avatar from './avatar'
import DisplayName from './display_name' import DisplayName from './display_name'
const makeMapStateToProps = () => {
const getAccount = makeGetAccount()
const mapStateToProps = (state, { id }) => ({
account: getAccount(state, id),
})
return mapStateToProps
}
export default
@connect(makeMapStateToProps)
class AutosuggestAccount extends ImmutablePureComponent { class AutosuggestAccount extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
}
render () { render () {
const { account } = this.props const { account } = this.props
@ -42,3 +26,13 @@ class AutosuggestAccount extends ImmutablePureComponent {
} }
} }
const mapStateToProps = () => ({
account: makeGetAccount()(state, id),
})
AutosuggestAccount.propTypes = {
account: ImmutablePropTypes.map.isRequired,
}
export default connect(mapStateToProps)(AutosuggestAccount)

View File

@ -5,11 +5,7 @@ import Text from './text'
const assetHost = process.env.CDN_HOST || '' const assetHost = process.env.CDN_HOST || ''
export default class AutosuggestEmoji extends React.PureComponent { class AutosuggestEmoji extends React.PureComponent {
static propTypes = {
emoji: PropTypes.object.isRequired,
}
render () { render () {
const { emoji } = this.props const { emoji } = this.props
@ -36,3 +32,9 @@ export default class AutosuggestEmoji extends React.PureComponent {
} }
} }
AutosuggestEmoji.propTypes = {
emoji: PropTypes.object.isRequired,
}
export default AutosuggestEmoji

View File

@ -16,34 +16,7 @@ import AutosuggestEmoji from './autosuggest_emoji'
import Input from './input' import Input from './input'
import Composer from './composer' import Composer from './composer'
export default class AutosuggestTextbox extends ImmutablePureComponent { class AutosuggestTextbox extends ImmutablePureComponent {
static propTypes = {
value: PropTypes.string,
valueMarkdown: PropTypes.string,
suggestions: ImmutablePropTypes.list,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
onSuggestionSelected: PropTypes.func.isRequired,
onSuggestionsClearRequested: PropTypes.func.isRequired,
onSuggestionsFetchRequested: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func,
id: PropTypes.string,
searchTokens: PropTypes.arrayOf(PropTypes.string),
onPaste: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
textarea: PropTypes.bool,
small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
}
static defaultProps = {
searchTokens: ['@', ':'],
}
state = { state = {
suggestionsHidden: true, suggestionsHidden: true,
@ -308,3 +281,32 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
} }
} }
AutosuggestTextbox.propTypes = {
value: PropTypes.string,
valueMarkdown: PropTypes.string,
suggestions: ImmutablePropTypes.list,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
onSuggestionSelected: PropTypes.func.isRequired,
onSuggestionsClearRequested: PropTypes.func.isRequired,
onSuggestionsFetchRequested: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func,
id: PropTypes.string,
searchTokens: PropTypes.arrayOf(PropTypes.string),
onPaste: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
textarea: PropTypes.bool,
small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
}
AutosuggestTextbox.defaultProps = {
searchTokens: ['@', ':'],
}
export default AutosuggestTextbox

View File

@ -8,46 +8,19 @@ import { autoPlayGif } from '../initial_state'
import { openPopover, closePopover } from '../actions/popover' import { openPopover, closePopover } from '../actions/popover'
import Image from './image' import Image from './image'
const mapDispatchToProps = (dispatch) => ({
openUserInfoPopover(props) {
dispatch(openPopover('USER_INFO', props))
},
closeUserInfoPopover() {
dispatch(closePopover('USER_INFO'))
}
})
/** /**
* Renders an avatar component * Renders an avatar component
* @param {map} [props.account] - the account for image * @param {map} [props.account] - the account for image
* @param {number} [props.size=40] - the size of the avatar * @param {number} [props.size=40] - the size of the avatar
*/ */
export default
@connect(null, mapDispatchToProps)
class Avatar extends ImmutablePureComponent { class Avatar extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
noHover: PropTypes.bool,
openUserInfoPopover: PropTypes.func.isRequired,
size: PropTypes.number,
}
static defaultProps = {
size: 40,
}
state = { state = {
hovering: false, hovering: false,
sameImg: !this.props.account ? false : this.props.account.get('avatar') === this.props.account.get('avatar_static'), sameImg: !this.props.account ? false : this.props.account.get('avatar') === this.props.account.get('avatar_static'),
} }
updateOnProps = [
'account',
'noHover',
'size',
]
mouseOverTimeout = null mouseOverTimeout = null
componentDidUpdate (prevProps) { componentDidUpdate (prevProps) {
@ -143,3 +116,25 @@ class Avatar extends ImmutablePureComponent {
} }
} }
const mapDispatchToProps = (dispatch) => ({
openUserInfoPopover(props) {
dispatch(openPopover('USER_INFO', props))
},
closeUserInfoPopover() {
dispatch(closePopover('USER_INFO'))
}
})
Avatar.propTypes = {
account: ImmutablePropTypes.map,
noHover: PropTypes.bool,
openUserInfoPopover: PropTypes.func.isRequired,
size: PropTypes.number,
}
Avatar.defaultProps = {
size: 40,
}
export default connect(null, mapDispatchToProps)(Avatar)

View File

@ -3,20 +3,12 @@ import PropTypes from 'prop-types'
import { CX } from '../constants' import { CX } from '../constants'
import Button from './button' import Button from './button'
export default class BackButton extends React.PureComponent { class BackButton extends React.PureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
className: PropTypes.string,
icon: PropTypes.string,
iconClassName: PropTypes.string,
iconSize: PropTypes.string,
toHome: PropTypes.bool,
}
historyBack = () => { historyBack = () => {
if (window.history && window.history.length === 1 || this.props.toHome) { if (window.history && window.history.length === 1 || this.props.toHome) {
this.context.router.history.push('/home') this.context.router.history.push('/home')
@ -62,3 +54,13 @@ export default class BackButton extends React.PureComponent {
} }
} }
BackButton.propTypes = {
className: PropTypes.string,
icon: PropTypes.string,
iconClassName: PropTypes.string,
iconSize: PropTypes.string,
toHome: PropTypes.bool,
}
export default BackButton

View File

@ -4,11 +4,7 @@ import PropTypes from 'prop-types'
/** /**
* Renders a block component * Renders a block component
*/ */
export default class Block extends React.PureComponent { class Block extends React.PureComponent {
static propTypes = {
children: PropTypes.any,
}
render() { render() {
const { children } = this.props const { children } = this.props
@ -21,3 +17,9 @@ export default class Block extends React.PureComponent {
} }
} }
Block.propTypes = {
children: PropTypes.any,
}
export default Block

View File

@ -2,11 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Heading from './heading' import Heading from './heading'
export default class BlockHeading extends React.PureComponent { class BlockHeading extends React.PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
}
render() { render() {
const { title } = this.props const { title } = this.props
@ -21,3 +17,9 @@ export default class BlockHeading extends React.PureComponent {
} }
} }
BlockHeading.propTypes = {
title: PropTypes.string.isRequired,
}
export default BlockHeading

View File

@ -14,21 +14,8 @@ import Divider from './divider'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
const messages = defineMessages({
title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },
body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' },
retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },
})
export default
@injectIntl
class BundleColumnError extends React.PureComponent { class BundleColumnError extends React.PureComponent {
static propTypes = {
onRetry: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
}
handleRetry = () => { handleRetry = () => {
this.props.onRetry() this.props.onRetry()
} }
@ -107,3 +94,16 @@ class BundleColumnError extends React.PureComponent {
} }
} }
const messages = defineMessages({
title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },
body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' },
retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' },
})
BundleColumnError.propTypes = {
onRetry: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
}
export default injectIntl(BundleColumnError)

View File

@ -46,43 +46,7 @@ const COLORS = {
* @param {bool} [props.type] - `type` attribute for button * @param {bool} [props.type] - `type` attribute for button
* @param {bool} [props.underlineOnHover] - if the button has underline on hover * @param {bool} [props.underlineOnHover] - if the button has underline on hover
*/ */
export default class Button extends React.PureComponent { class Button extends React.PureComponent {
static propTypes = {
backgroundColor: PropTypes.string,
buttonRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.node,
]),
children: PropTypes.node,
className: PropTypes.string,
color: PropTypes.string,
href: PropTypes.string,
icon: PropTypes.string,
iconClassName: PropTypes.string,
iconSize: PropTypes.string,
isBlock: PropTypes.bool,
isDisabled: PropTypes.bool,
isNarrow: PropTypes.bool,
isText: PropTypes.bool,
noClasses: PropTypes.bool,
onClick: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
isOutline: PropTypes.bool,
radiusSmall: PropTypes.bool,
rel: PropTypes.string,
target: PropTypes.string,
title: PropTypes.string,
to: PropTypes.string,
type: PropTypes.string,
underlineOnHover: PropTypes.bool,
}
static defaultProps = {
color: COLORS.white,
backgroundColor: COLORS.brand,
}
handleClick = (e) => { handleClick = (e) => {
if (!this.props.isDisabled && this.props.onClick) { if (!this.props.isDisabled && this.props.onClick) {
@ -252,3 +216,41 @@ export default class Button extends React.PureComponent {
} }
} }
Button.propTypes = {
backgroundColor: PropTypes.string,
buttonRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.node,
]),
children: PropTypes.node,
className: PropTypes.string,
color: PropTypes.string,
href: PropTypes.string,
icon: PropTypes.string,
iconClassName: PropTypes.string,
iconSize: PropTypes.string,
isBlock: PropTypes.bool,
isDisabled: PropTypes.bool,
isNarrow: PropTypes.bool,
isText: PropTypes.bool,
noClasses: PropTypes.bool,
onClick: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
isOutline: PropTypes.bool,
radiusSmall: PropTypes.bool,
rel: PropTypes.string,
target: PropTypes.string,
title: PropTypes.string,
to: PropTypes.string,
type: PropTypes.string,
underlineOnHover: PropTypes.bool,
}
Button.defaultProps = {
color: COLORS.white,
backgroundColor: COLORS.brand,
}
export default Button

View File

@ -7,12 +7,7 @@ import { length } from 'stringz'
* @param {string} props.text - text to use to measure * @param {string} props.text - text to use to measure
* @param {number} props.max - max text allowed * @param {number} props.max - max text allowed
*/ */
export default class CharacterCounter extends React.PureComponent { class CharacterCounter extends React.PureComponent {
static propTypes = {
text: PropTypes.string.isRequired,
max: PropTypes.number.isRequired,
}
render() { render() {
const { text, max } = this.props const { text, max } = this.props
@ -58,3 +53,10 @@ export default class CharacterCounter extends React.PureComponent {
} }
} }
CharacterCounter.propTypes = {
text: PropTypes.string.isRequired,
max: PropTypes.number.isRequired,
}
export default CharacterCounter

View File

@ -4,28 +4,8 @@ import { defineMessages, injectIntl } from 'react-intl'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
const messages = defineMessages({
loading: { id: 'loading_indicator.label', defaultMessage: 'Loading..' },
missing: { id: 'missing_indicator.sublabel', defaultMessage: 'This resource could not be found.' },
})
export default
@injectIntl
class ColumnIndicator extends React.PureComponent { class ColumnIndicator extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
type: PropTypes.oneOf([
'loading',
'missing',
'error',
]),
message: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
}
render() { render() {
const { type, message, intl } = this.props const { type, message, intl } = this.props
@ -49,3 +29,23 @@ class ColumnIndicator extends React.PureComponent {
} }
} }
const messages = defineMessages({
loading: { id: 'loading_indicator.label', defaultMessage: 'Loading..' },
missing: { id: 'missing_indicator.sublabel', defaultMessage: 'This resource could not be found.' },
})
ColumnIndicator.propTypes = {
intl: PropTypes.object.isRequired,
type: PropTypes.oneOf([
'loading',
'missing',
'error',
]),
message: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
}
export default injectIntl(ColumnIndicator)

View File

@ -25,99 +25,12 @@ import StatusMedia from './status_media'
import { defaultMediaVisibility } from './status' import { defaultMediaVisibility } from './status'
import Text from './text' import Text from './text'
const messages = defineMessages({
reply: { id: 'status.reply', defaultMessage: 'Reply' },
like: { id: 'status.like', defaultMessage: 'Like' },
unlike: { id: 'status.unlike', defaultMessage: 'Unlike' },
})
const makeMapStateToProps = (state, props) => ({
status: makeGetStatus()(state, props)
})
const mapDispatchToProps = (dispatch) => ({
onReply(status, router) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch((_, getState) => {
const state = getState();
if (state.getIn(['compose', 'text']).trim().length !== 0) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.reply.message' defaultMessage='Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' />,
confirm: <FormattedMessage id='confirmations.reply.confirm' defaultMessage='Reply' />,
onConfirm: () => dispatch(replyCompose(status, router)),
}))
} else {
dispatch(replyCompose(status, router, true))
}
})
},
onFavorite(status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
if (status.get('favourited')) {
dispatch(unfavorite(status))
} else {
dispatch(favorite(status))
}
},
onOpenStatusOptions(targetRef, status) {
dispatch(openPopover('STATUS_OPTIONS', {
targetRef,
status,
position: 'top',
}))
},
onOpenLikes(status) {
dispatch(openModal('STATUS_LIKES', { status }))
},
onOpenReposts(status) {
dispatch(openModal('STATUS_REPOSTS', { status }))
},
onOpenStatusRevisionsPopover(status) {
dispatch(openModal('STATUS_REVISIONS', {
status,
}))
},
onOpenMedia (media, index) {
dispatch(openModal('MEDIA', { media, index }));
},
})
export default
@injectIntl
@connect(makeMapStateToProps, mapDispatchToProps)
class Comment extends ImmutablePureComponent { class Comment extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
indent: PropTypes.number,
intl: PropTypes.object.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
status: ImmutablePropTypes.map.isRequired,
isHidden: PropTypes.bool,
isIntersecting: PropTypes.bool,
isHighlighted: PropTypes.bool,
onReply: PropTypes.func.isRequired,
onFavorite: PropTypes.func.isRequired,
onOpenStatusOptions: PropTypes.func.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onOpenStatusRevisionsPopover: PropTypes.func.isRequired,
onOpenMedia: PropTypes.func.isRequired
}
updateOnProps = [
'status',
'indent',
'isHidden',
'isIntersecting',
'isHighlighted',
]
state = { state = {
showMedia: defaultMediaVisibility(this.props.status), showMedia: defaultMediaVisibility(this.props.status),
statusId: undefined, statusId: undefined,
@ -277,3 +190,81 @@ class CommentButton extends React.PureComponent {
} }
} }
const messages = defineMessages({
reply: { id: 'status.reply', defaultMessage: 'Reply' },
like: { id: 'status.like', defaultMessage: 'Like' },
unlike: { id: 'status.unlike', defaultMessage: 'Unlike' },
})
const makeMapStateToProps = (state, props) => ({
status: makeGetStatus()(state, props)
})
const mapDispatchToProps = (dispatch) => ({
onReply(status, router) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch((_, getState) => {
const state = getState();
if (state.getIn(['compose', 'text']).trim().length !== 0) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.reply.message' defaultMessage='Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' />,
confirm: <FormattedMessage id='confirmations.reply.confirm' defaultMessage='Reply' />,
onConfirm: () => dispatch(replyCompose(status, router)),
}))
} else {
dispatch(replyCompose(status, router, true))
}
})
},
onFavorite(status) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
if (status.get('favourited')) {
dispatch(unfavorite(status))
} else {
dispatch(favorite(status))
}
},
onOpenStatusOptions(targetRef, status) {
dispatch(openPopover('STATUS_OPTIONS', {
targetRef,
status,
position: 'top',
}))
},
onOpenLikes(status) {
dispatch(openModal('STATUS_LIKES', { status }))
},
onOpenReposts(status) {
dispatch(openModal('STATUS_REPOSTS', { status }))
},
onOpenStatusRevisionsPopover(status) {
dispatch(openModal('STATUS_REVISIONS', {
status,
}))
},
onOpenMedia (media, index) {
dispatch(openModal('MEDIA', { media, index }));
},
})
Comment.propTypes = {
indent: PropTypes.number,
intl: PropTypes.object.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
status: ImmutablePropTypes.map.isRequired,
isHidden: PropTypes.bool,
isIntersecting: PropTypes.bool,
isHighlighted: PropTypes.bool,
onReply: PropTypes.func.isRequired,
onFavorite: PropTypes.func.isRequired,
onOpenStatusOptions: PropTypes.func.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onOpenStatusRevisionsPopover: PropTypes.func.isRequired,
onOpenMedia: PropTypes.func.isRequired
}
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Comment))

View File

@ -12,26 +12,8 @@ import Icon from './icon'
import RelativeTimestamp from './relative_timestamp' import RelativeTimestamp from './relative_timestamp'
import Text from './text' import Text from './text'
const messages = defineMessages({
edited: { id: 'status.edited', defaultMessage: 'Edited' },
likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' },
repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' },
original: { id: 'original_gabber', defaultMessage: 'Original Gabber' },
})
export default
@injectIntl
class CommentHeader extends ImmutablePureComponent { class CommentHeader extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
status: ImmutablePropTypes.map.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onOpenRevisions: PropTypes.func.isRequired,
}
openLikesList = () => { openLikesList = () => {
this.props.onOpenLikes(this.props.status) this.props.onOpenLikes(this.props.status)
} }
@ -187,3 +169,21 @@ class CommentHeader extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
edited: { id: 'status.edited', defaultMessage: 'Edited' },
likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' },
repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' },
original: { id: 'original_gabber', defaultMessage: 'Original Gabber' },
})
CommentHeader.propTypes = {
intl: PropTypes.object.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
status: ImmutablePropTypes.map.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onOpenRevisions: PropTypes.func.isRequired,
}
export default injectIntl(CommentHeader)

View File

@ -8,14 +8,7 @@ import ScrollableList from './scrollable_list'
import Text from './text' import Text from './text'
import Dummy from './dummy' import Dummy from './dummy'
export default class CommentList extends ImmutablePureComponent { class CommentList extends ImmutablePureComponent {
static propTypes = {
commentsLimited: PropTypes.bool,
descendants: ImmutablePropTypes.list,
onViewComments: PropTypes.func.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
}
render() { render() {
const { const {
@ -73,3 +66,12 @@ export default class CommentList extends ImmutablePureComponent {
} }
} }
CommentList.propTypes = {
commentsLimited: PropTypes.bool,
descendants: ImmutablePropTypes.list,
onViewComments: PropTypes.func.isRequired,
ancestorAccountId: PropTypes.string.isRequired,
}
export default CommentList

View File

@ -112,23 +112,7 @@ const GROUP_HANDLE_REGEX = /\g\/[\w]+/g
const HANDLE_REGEX = /\@[\w]+/g const HANDLE_REGEX = /\@[\w]+/g
const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g
export default class Composer extends React.PureComponent { class Composer extends React.PureComponent {
static propTypes = {
inputRef: PropTypes.func,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
value: PropTypes.string,
valueMarkdown: PropTypes.string,
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onPaste: PropTypes.func,
small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
}
state = { state = {
active: false, active: false,
@ -302,3 +286,21 @@ export default class Composer extends React.PureComponent {
} }
} }
Composer.propTypes = {
inputRef: PropTypes.func,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
value: PropTypes.string,
valueMarkdown: PropTypes.string,
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onPaste: PropTypes.func,
small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
}
export default Composer

View File

@ -13,45 +13,8 @@ import { openPopover, closePopover } from '../actions/popover'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
const mapDispatchToProps = (dispatch) => ({
openUserInfoPopover(props) {
dispatch(openPopover(POPOVER_USER_INFO, props))
},
closeUserInfoPopover() {
dispatch(closePopover(POPOVER_USER_INFO))
}
})
export default
@connect(null, mapDispatchToProps)
class DisplayName extends ImmutablePureComponent { class DisplayName extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
openUserInfoPopover: PropTypes.func.isRequired,
closeUserInfoPopover: PropTypes.func.isRequired,
isLarge: PropTypes.bool,
isMultiline: PropTypes.bool,
isSmall: PropTypes.bool,
noHover: PropTypes.bool,
noRelationship: PropTypes.bool,
noUsername: PropTypes.bool,
isComment: PropTypes.bool,
isCentered: PropTypes.bool,
}
updateOnProps = [
'account',
'isMultiline',
'isSmall',
'isLarge',
'noHover',
'noRelationship',
'noUsername',
'isComment',
'isCentered',
]
mouseOverTimeout = null mouseOverTimeout = null
componentWillUnmount () { componentWillUnmount () {
@ -224,3 +187,28 @@ class DisplayName extends ImmutablePureComponent {
} }
} }
const mapDispatchToProps = (dispatch) => ({
openUserInfoPopover(props) {
dispatch(openPopover(POPOVER_USER_INFO, props))
},
closeUserInfoPopover() {
dispatch(closePopover(POPOVER_USER_INFO))
}
})
DisplayName.propTypes = {
account: ImmutablePropTypes.map,
openUserInfoPopover: PropTypes.func.isRequired,
closeUserInfoPopover: PropTypes.func.isRequired,
isLarge: PropTypes.bool,
isMultiline: PropTypes.bool,
isSmall: PropTypes.bool,
noHover: PropTypes.bool,
noRelationship: PropTypes.bool,
noUsername: PropTypes.bool,
isComment: PropTypes.bool,
isCentered: PropTypes.bool,
}
export default (connect(null, mapDispatchToProps)(DisplayName))

View File

@ -7,12 +7,7 @@ import { CX } from '../constants'
* @param {bool} [props.isInvisible] - to style the tab bar larger * @param {bool} [props.isInvisible] - to style the tab bar larger
* @param {bool} [props.isSmall] - if item is active * @param {bool} [props.isSmall] - if item is active
*/ */
export default class Divider extends React.PureComponent { class Divider extends React.PureComponent {
static propTypes = {
isInvisible: PropTypes.bool,
isSmall: PropTypes.bool,
}
render() { render() {
const { isSmall, isInvisible } = this.props const { isSmall, isInvisible } = this.props
@ -30,3 +25,10 @@ export default class Divider extends React.PureComponent {
} }
} }
Divider.propTypes = {
isInvisible: PropTypes.bool,
isSmall: PropTypes.bool,
}
export default Divider

View File

@ -15,11 +15,7 @@ import Divider from './divider'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
export default class ErrorBoundary extends React.PureComponent { class ErrorBoundary extends React.PureComponent {
static propTypes = {
children: PropTypes.node,
}
state = { state = {
hasError: false, hasError: false,
@ -162,3 +158,9 @@ export default class ErrorBoundary extends React.PureComponent {
} }
} }
ErrorBoundary.propTypes = {
children: PropTypes.node,
}
export default ErrorBoundary

View File

@ -1,18 +1,7 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
export default class ExtendedVideoPlayer extends React.PureComponent { class ExtendedVideoPlayer extends React.PureComponent {
static propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
time: PropTypes.number,
controls: PropTypes.bool.isRequired,
muted: PropTypes.bool.isRequired,
onClick: PropTypes.func,
}
handleLoadedData = () => { handleLoadedData = () => {
if (this.props.time) { if (this.props.time) {
@ -62,3 +51,16 @@ export default class ExtendedVideoPlayer extends React.PureComponent {
} }
} }
ExtendedVideoPlayer.propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
time: PropTypes.number,
controls: PropTypes.bool.isRequired,
muted: PropTypes.bool.isRequired,
onClick: PropTypes.func,
}
export default ExtendedVideoPlayer

View File

@ -5,25 +5,7 @@ import Icon from './icon'
import Image from './image' import Image from './image'
import Text from './text' import Text from './text'
export default class FileInput extends React.PureComponent { class FileInput extends React.PureComponent {
static propTypes = {
onChange: PropTypes.func,
file: PropTypes.any,
fileType: PropTypes.string,
disabled: PropTypes.bool,
title: PropTypes.string,
id: PropTypes.string.isRequired,
height: PropTypes.string,
width: PropTypes.string,
isBordered: PropTypes.bool,
className: PropTypes.string,
}
static defaultProps = {
fileType: 'image',
isBordered: false,
}
state = { state = {
file: this.props.file, file: this.props.file,
@ -125,3 +107,23 @@ export default class FileInput extends React.PureComponent {
} }
} }
FileInput.propTypes = {
onChange: PropTypes.func,
file: PropTypes.any,
fileType: PropTypes.string,
disabled: PropTypes.bool,
title: PropTypes.string,
id: PropTypes.string.isRequired,
height: PropTypes.string,
width: PropTypes.string,
isBordered: PropTypes.bool,
className: PropTypes.string,
}
FileInput.defaultProps = {
fileType: 'image',
isBordered: false,
}
export default FileInput

View File

@ -7,25 +7,8 @@ import { CX } from '../constants'
import { openModal } from '../actions/modal' import { openModal } from '../actions/modal'
import Button from './button' import Button from './button'
const messages = defineMessages({
gab: { id: 'gab', defaultMessage: 'Gab' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenCompose: () => dispatch(openModal('COMPOSE')),
})
export default
@injectIntl
@connect(null, mapDispatchToProps)
class FloatingActionButton extends React.PureComponent { class FloatingActionButton extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
onOpenCompose: PropTypes.func.isRequired,
isDesktop: PropTypes.bool,
}
render() { render() {
const { const {
intl, intl,
@ -67,3 +50,19 @@ class FloatingActionButton extends React.PureComponent {
} }
} }
const messages = defineMessages({
gab: { id: 'gab', defaultMessage: 'Gab' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenCompose: () => dispatch(openModal('COMPOSE')),
})
FloatingActionButton.propTypes = {
intl: PropTypes.object.isRequired,
onOpenCompose: PropTypes.func.isRequired,
isDesktop: PropTypes.bool,
}
export default injectIntl(connect(null, mapDispatchToProps)(FloatingActionButton))

View File

@ -6,25 +6,12 @@ import { me } from '../initial_state'
import { CX } from '../constants' import { CX } from '../constants'
import Button from './button' import Button from './button'
const mapStateToProps = (state) => ({
notificationCount: !!me ? state.getIn(['notifications', 'unread']) : 0,
homeItemsQueueCount: !!me ? state.getIn(['timelines', 'home', 'totalQueuedItemsCount']) : 0,
})
export default
@withRouter
@connect(mapStateToProps)
class FooterBar extends React.PureComponent { class FooterBar extends React.PureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
notificationCount: PropTypes.number.isRequired,
homeItemsQueueCount: PropTypes.number.isRequired,
}
render() { render() {
const { const {
notificationCount, notificationCount,
@ -133,3 +120,15 @@ class FooterBar extends React.PureComponent {
} }
} }
const mapStateToProps = (state) => ({
notificationCount: !!me ? state.getIn(['notifications', 'unread']) : 0,
homeItemsQueueCount: !!me ? state.getIn(['timelines', 'home', 'totalQueuedItemsCount']) : 0,
})
FooterBar.propTypes = {
notificationCount: PropTypes.number.isRequired,
homeItemsQueueCount: PropTypes.number.isRequired,
}
export default withRouter(connect(mapStateToProps)(FooterBar))

View File

@ -2,17 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Text from './text' import Text from './text'
export default class Form extends React.PureComponent { class Form extends React.PureComponent {
static propTypes = {
children: PropTypes.any,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired,
}
componentDidUpdate (prevProps) {
}
render() { render() {
const { const {
@ -37,3 +27,11 @@ export default class Form extends React.PureComponent {
} }
} }
Form.propTypes = {
children: PropTypes.any,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired,
}
export default Form

View File

@ -11,31 +11,10 @@ import { shortNumberFormat } from '../utils/numbers'
import Image from './image' import Image from './image'
import Text from './text' import Text from './text'
const messages = defineMessages({
members: { id: 'groups.card.members', defaultMessage: 'Members' },
viewGroup: { id: 'view_group', defaultMessage: 'View Group' },
member: { id: 'member', defaultMessage: 'Member' },
admin: { id: 'admin', defaultMessage: 'Admin' },
})
const mapStateToProps = (state, { id }) => ({
group: state.getIn(['groups', id]),
relationships: state.getIn(['group_relationships', id]),
})
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default
@connect(mapStateToProps)
@injectIntl
class GroupCollectionItem extends ImmutablePureComponent { class GroupCollectionItem extends ImmutablePureComponent {
static propTypes = {
group: ImmutablePropTypes.map,
relationships: ImmutablePropTypes.map,
isHidden: PropTypes.bool,
}
render() { render() {
const { const {
intl, intl,
@ -145,3 +124,23 @@ class GroupCollectionItem extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
members: { id: 'groups.card.members', defaultMessage: 'Members' },
viewGroup: { id: 'view_group', defaultMessage: 'View Group' },
member: { id: 'member', defaultMessage: 'Member' },
admin: { id: 'admin', defaultMessage: 'Admin' },
})
const mapStateToProps = (state, { id }) => ({
group: state.getIn(['groups', id]),
relationships: state.getIn(['group_relationships', id]),
})
GroupCollectionItem.propTypes = {
group: ImmutablePropTypes.map,
relationships: ImmutablePropTypes.map,
isHidden: PropTypes.bool,
}
export default injectIntl(connect(mapStateToProps)(GroupCollectionItem))

View File

@ -22,50 +22,8 @@ import TabBar from './tab_bar'
import Pills from './pills' import Pills from './pills'
import Text from './text' import Text from './text'
const messages = defineMessages({
join: { id: 'groups.join', defaultMessage: 'Join group' },
member: { id: 'groups.member', defaultMessage: 'Member' },
removed_accounts: { id: 'groups.removed_accounts', defaultMessage: 'Removed Accounts' },
group_archived: { id: 'group.detail.archived_group', defaultMessage: 'Archived group' },
group_admin: { id: 'groups.detail.role_admin', defaultMessage: 'You\'re an admin' }
})
const mapDispatchToProps = (dispatch, { intl }) => ({
onToggleMembership(group, relationships) {
if (relationships.get('member')) {
dispatch(leaveGroup(group.get('id')));
} else {
dispatch(joinGroup(group.get('id')));
}
},
onOpenGroupOptions(targetRef, group, isAdmin) {
dispatch(openPopover('GROUP_OPTIONS', {
targetRef,
group,
isAdmin,
position: 'left',
}))
},
});
export default
@connect(null, mapDispatchToProps)
@injectIntl
class GroupHeader extends ImmutablePureComponent { class GroupHeader extends ImmutablePureComponent {
static propTypes = {
group: ImmutablePropTypes.map,
children: PropTypes.any,
intl: PropTypes.object.isRequired,
isXS: PropTypes.bool,
onToggleMembership: PropTypes.func.isRequired,
onOpenGroupOptions: PropTypes.func.isRequired,
relationships: ImmutablePropTypes.map,
}
handleOnToggleMembership = () => { handleOnToggleMembership = () => {
const { group, relationships } = this.props const { group, relationships } = this.props
this.props.onToggleMembership(group, relationships); this.props.onToggleMembership(group, relationships);
@ -273,3 +231,44 @@ class GroupHeader extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
join: { id: 'groups.join', defaultMessage: 'Join group' },
member: { id: 'groups.member', defaultMessage: 'Member' },
removed_accounts: { id: 'groups.removed_accounts', defaultMessage: 'Removed Accounts' },
group_archived: { id: 'group.detail.archived_group', defaultMessage: 'Archived group' },
group_admin: { id: 'groups.detail.role_admin', defaultMessage: 'You\'re an admin' }
})
const mapDispatchToProps = (dispatch, { intl }) => ({
onToggleMembership(group, relationships) {
if (relationships.get('member')) {
dispatch(leaveGroup(group.get('id')))
} else {
dispatch(joinGroup(group.get('id')))
}
},
onOpenGroupOptions(targetRef, group, isAdmin) {
dispatch(openPopover('GROUP_OPTIONS', {
targetRef,
group,
isAdmin,
position: 'left',
}))
},
})
GroupHeader.propTypes = {
group: ImmutablePropTypes.map,
children: PropTypes.any,
intl: PropTypes.object.isRequired,
isXS: PropTypes.bool,
onToggleMembership: PropTypes.func.isRequired,
onOpenGroupOptions: PropTypes.func.isRequired,
relationships: ImmutablePropTypes.map,
}
export default injectIntl(connect(null, mapDispatchToProps)(GroupHeader))

View File

@ -14,44 +14,8 @@ import Image from './image'
import Text from './text' import Text from './text'
import Dummy from './dummy' import Dummy from './dummy'
const messages = defineMessages({
members: { id: 'groups.card.members', defaultMessage: 'Members' },
})
const mapStateToProps = (state, { id }) => ({
group: state.getIn(['groups', id]),
relationships: state.getIn(['group_relationships', id]),
})
const mapDispatchToProps = (dispatch) => ({
onToggleMembership(groupId, relationships) {
if (relationships.get('member')) {
dispatch(leaveGroup(groupId))
} else {
dispatch(joinGroup(groupId))
}
},
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class GroupListItem extends ImmutablePureComponent { class GroupListItem extends ImmutablePureComponent {
static propTypes = {
group: ImmutablePropTypes.map,
isAddable: PropTypes.bool,
isHidden: PropTypes.bool,
isLast: PropTypes.bool,
isStatic: PropTypes.bool,
onToggleMembership: PropTypes.func.isRequired,
relationships: ImmutablePropTypes.map,
}
static defaultProps = {
isLast: false,
}
state = { state = {
hovering: false, hovering: false,
} }
@ -171,3 +135,38 @@ class GroupListItem extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
members: { id: 'groups.card.members', defaultMessage: 'Members' },
})
const mapStateToProps = (state, { id }) => ({
group: state.getIn(['groups', id]),
relationships: state.getIn(['group_relationships', id]),
})
const mapDispatchToProps = (dispatch) => ({
onToggleMembership(groupId, relationships) {
if (relationships.get('member')) {
dispatch(leaveGroup(groupId))
} else {
dispatch(joinGroup(groupId))
}
},
})
GroupListItem.propTypes = {
group: ImmutablePropTypes.map,
isAddable: PropTypes.bool,
isHidden: PropTypes.bool,
isLast: PropTypes.bool,
isStatic: PropTypes.bool,
onToggleMembership: PropTypes.func.isRequired,
relationships: ImmutablePropTypes.map,
}
GroupListItem.defaultProps = {
isLast: false,
}
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(GroupListItem))

View File

@ -18,55 +18,8 @@ import {
} from '../constants' } from '../constants'
import SortBlock from '../components/sort_block' import SortBlock from '../components/sort_block'
const messages = defineMessages({
sortBy: { id: 'comment_sort.title', defaultMessage: 'Sort by' },
hotTitle: { id: 'group_timeline_sorting.hot_title', defaultMessage: 'Hot Posts' },
topTitle: { id: 'group_timeline_sorting.top_title', defaultMessage: 'Top Posts' },
topTodayTitle: { id: 'group_timeline_sorting.top_today_title', defaultMessage: 'Today' },
topWeekTitle: { id: 'group_timeline_sorting.top_week_title', defaultMessage: 'This Week' },
topMonthTitle: { id: 'group_timeline_sorting.top_month_title', defaultMessage: 'This Month' },
topYearTitle: { id: 'group_timeline_sorting.top_year_title', defaultMessage: 'This Year' },
topAllTitle: { id: 'group_timeline_sorting.top_all_title', defaultMessage: 'All Time' },
recentTitle: { id: 'group_timeline_sorting.recent_title', defaultMessage: 'Recent Activity' },
newTitle: { id: 'group_timeline_sorting.new_title', defaultMessage: 'New Posts' },
})
const mapStateToProps = (state) => ({
sortByValue: state.getIn(['group_lists', 'sortByValue']),
sortByTopValue: state.getIn(['group_lists', 'sortByTopValue']),
})
const mapDispatchToProps = (dispatch) => ({
onOpenSortingOptions(targetRef, options) {
dispatch(openPopover(POPOVER_GROUP_TIMELINE_SORT_OPTIONS, {
targetRef,
options,
position: 'bottom',
}))
},
onOpenSortingTopOptions(targetRef, options) {
dispatch(openPopover(POPOVER_GROUP_TIMELINE_SORT_TOP_OPTIONS, {
targetRef,
options,
position: 'bottom',
}))
},
})
export default
@injectIntl
@connect(mapStateToProps, mapDispatchToProps)
class GroupSortBlock extends React.PureComponent { class GroupSortBlock extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
collectionType: PropTypes.string,
sortByValue: PropTypes.string.isRequired,
sortByTopValue: PropTypes.string,
onOpenSortingOptions: PropTypes.func.isRequired,
onOpenSortingTopOptions: PropTypes.func,
}
handleOnClickValue = (btn) => { handleOnClickValue = (btn) => {
this.props.onOpenSortingOptions(btn, { this.props.onOpenSortingOptions(btn, {
collectionType: this.props.collectionType, collectionType: this.props.collectionType,
@ -137,3 +90,50 @@ class GroupSortBlock extends React.PureComponent {
} }
} }
const messages = defineMessages({
sortBy: { id: 'comment_sort.title', defaultMessage: 'Sort by' },
hotTitle: { id: 'group_timeline_sorting.hot_title', defaultMessage: 'Hot Posts' },
topTitle: { id: 'group_timeline_sorting.top_title', defaultMessage: 'Top Posts' },
topTodayTitle: { id: 'group_timeline_sorting.top_today_title', defaultMessage: 'Today' },
topWeekTitle: { id: 'group_timeline_sorting.top_week_title', defaultMessage: 'This Week' },
topMonthTitle: { id: 'group_timeline_sorting.top_month_title', defaultMessage: 'This Month' },
topYearTitle: { id: 'group_timeline_sorting.top_year_title', defaultMessage: 'This Year' },
topAllTitle: { id: 'group_timeline_sorting.top_all_title', defaultMessage: 'All Time' },
recentTitle: { id: 'group_timeline_sorting.recent_title', defaultMessage: 'Recent Activity' },
newTitle: { id: 'group_timeline_sorting.new_title', defaultMessage: 'New Posts' },
})
const mapStateToProps = (state) => ({
sortByValue: state.getIn(['group_lists', 'sortByValue']),
sortByTopValue: state.getIn(['group_lists', 'sortByTopValue']),
})
const mapDispatchToProps = (dispatch) => ({
onOpenSortingOptions(targetRef, options) {
dispatch(openPopover(POPOVER_GROUP_TIMELINE_SORT_OPTIONS, {
targetRef,
options,
position: 'bottom',
}))
},
onOpenSortingTopOptions(targetRef, options) {
dispatch(openPopover(POPOVER_GROUP_TIMELINE_SORT_TOP_OPTIONS, {
targetRef,
options,
position: 'bottom',
}))
},
})
GroupSortBlock.propTypes = {
intl: PropTypes.object.isRequired,
collectionType: PropTypes.string,
sortByValue: PropTypes.string.isRequired,
sortByTopValue: PropTypes.string,
onOpenSortingOptions: PropTypes.func.isRequired,
onOpenSortingTopOptions: PropTypes.func,
}
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(GroupSortBlock))

View File

@ -7,14 +7,7 @@ import { NavLink } from 'react-router-dom'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
export default class HashtagItem extends ImmutablePureComponent { class HashtagItem extends ImmutablePureComponent {
static propTypes = {
hashtag: ImmutablePropTypes.map.isRequired,
isCompact: PropTypes.bool,
}
updateOnProps = ['hashtag']
render() { render() {
const { hashtag, isCompact } = this.props const { hashtag, isCompact } = this.props
@ -61,3 +54,10 @@ export default class HashtagItem extends ImmutablePureComponent {
} }
} }
HashtagItem.propTypes = {
hashtag: ImmutablePropTypes.map.isRequired,
isCompact: PropTypes.bool,
}
export default HashtagItem

View File

@ -29,17 +29,7 @@ const ARIA_LEVELS = {
* @param {bool} [props.isCentered] - if text is centered within the element * @param {bool} [props.isCentered] - if text is centered within the element
* @param {string} [props.size='h1'] - the size of the heading * @param {string} [props.size='h1'] - the size of the heading
*/ */
export default class Heading extends React.PureComponent { class Heading extends React.PureComponent {
static propTypes = {
children: PropTypes.any,
isCentered: PropTypes.bool,
size: PropTypes.oneOf(Object.keys(SIZES)),
}
static defaultProps = {
size: SIZES.h1,
}
render() { render() {
const { children, size, isCentered } = this.props const { children, size, isCentered } = this.props
@ -80,3 +70,15 @@ export default class Heading extends React.PureComponent {
} }
} }
Heading.propTypes = {
children: PropTypes.any,
isCentered: PropTypes.bool,
size: PropTypes.oneOf(Object.keys(SIZES)),
}
Heading.defaultProps = {
size: SIZES.h1,
}
export default Heading

View File

@ -2,13 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { CX } from '../constants' import { CX } from '../constants'
export default class Icon extends React.PureComponent { class Icon extends React.PureComponent {
static propTypes = {
className: PropTypes.string,
id: PropTypes.string.isRequired,
size: PropTypes.string,
}
render() { render() {
const { const {
@ -28,3 +22,11 @@ export default class Icon extends React.PureComponent {
} }
} }
Icon.propTypes = {
className: PropTypes.string,
id: PropTypes.string.isRequired,
size: PropTypes.string,
}
export default Icon

View File

@ -4,30 +4,7 @@ import classNames from 'classnames/bind'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class Image extends React.PureComponent { class Image extends React.PureComponent {
static propTypes = {
alt: PropTypes.string.isRequired,
isLazy: PropTypes.string,
className: PropTypes.string,
width: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
height: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
fit: PropTypes.oneOf(['contain', 'cover', 'tile', 'none']),
nullable: PropTypes.bool,
lazy: PropTypes.bool,
imageRef: PropTypes.func,
}
static defaultProps = {
width: '100%',
fit: 'cover',
}
state = { state = {
error: false, error: false,
@ -81,3 +58,28 @@ export default class Image extends React.PureComponent {
} }
} }
Image.propTypes = {
alt: PropTypes.string.isRequired,
isLazy: PropTypes.string,
className: PropTypes.string,
width: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
height: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
fit: PropTypes.oneOf(['contain', 'cover', 'tile', 'none']),
nullable: PropTypes.bool,
lazy: PropTypes.bool,
imageRef: PropTypes.func,
}
Image.defaultProps = {
width: '100%',
fit: 'cover',
}
export default Image

View File

@ -4,22 +4,7 @@ import { LoadingBar } from 'react-redux-loading-bar'
import { CX } from '../constants' import { CX } from '../constants'
import ZoomableImage from './zoomable_image' import ZoomableImage from './zoomable_image'
export default class ImageLoader extends React.PureComponent { class ImageLoader extends React.PureComponent {
static propTypes = {
alt: PropTypes.string,
src: PropTypes.string.isRequired,
previewSrc: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
}
static defaultProps = {
alt: '',
width: null,
height: null,
};
state = { state = {
loading: true, loading: true,
@ -186,3 +171,20 @@ export default class ImageLoader extends React.PureComponent {
} }
} }
ImageLoader.propTypes = {
alt: PropTypes.string,
src: PropTypes.string.isRequired,
previewSrc: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
}
ImageLoader.defaultProps = {
alt: '',
width: null,
height: null,
}
export default ImageLoader

View File

@ -7,26 +7,7 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class Input extends React.PureComponent { class Input extends React.PureComponent {
static propTypes = {
placeholder: PropTypes.string,
prependIcon: PropTypes.string,
value: PropTypes.string,
hasClear: PropTypes.bool,
onChange: PropTypes.func,
onKeyUp: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onClear: PropTypes.func,
title: PropTypes.string,
small: PropTypes.bool,
readOnly: PropTypes.string,
inputRef: PropTypes.func,
id: PropTypes.string.isRequired,
hideLabel: PropTypes.bool,
maxLength: PropTypes.number,
}
handleOnChange = (e) => { handleOnChange = (e) => {
this.props.onChange(e.target.value) this.props.onChange(e.target.value)
@ -133,3 +114,24 @@ export default class Input extends React.PureComponent {
) )
} }
} }
Input.propTypes = {
placeholder: PropTypes.string,
prependIcon: PropTypes.string,
value: PropTypes.string,
hasClear: PropTypes.bool,
onChange: PropTypes.func,
onKeyUp: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onClear: PropTypes.func,
title: PropTypes.string,
small: PropTypes.bool,
readOnly: PropTypes.string,
inputRef: PropTypes.func,
id: PropTypes.string.isRequired,
hideLabel: PropTypes.bool,
maxLength: PropTypes.number,
}
export default Input

View File

@ -11,42 +11,8 @@ const updateOnPropsForRendered = ['id', 'index', 'listLength']
// Diff these props in the "unrendered" state // Diff these props in the "unrendered" state
const updateOnPropsForUnrendered = ['id', 'index', 'listLength', 'cachedHeight'] const updateOnPropsForUnrendered = ['id', 'index', 'listLength', 'cachedHeight']
const makeMapStateToProps = (state, props) => ({
cachedHeight: state.getIn(['height_cache', props.saveHeightKey, props.id]),
})
const mapDispatchToProps = (dispatch) => ({
onHeightChange(key, id, height) {
dispatch(setHeight(key, id, height))
},
})
export default
@connect(makeMapStateToProps, mapDispatchToProps)
class IntersectionObserverArticle extends React.Component { class IntersectionObserverArticle extends React.Component {
static propTypes = {
intersectionObserverWrapper: PropTypes.object.isRequired,
id: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
index: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
listLength: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
saveHeightKey: PropTypes.string,
cachedHeight: PropTypes.number,
onHeightChange: PropTypes.func,
children: PropTypes.node,
}
state = { state = {
isIntersecting: false, isIntersecting: false,
isHidden: false, isHidden: false,
@ -165,3 +131,37 @@ class IntersectionObserverArticle extends React.Component {
} }
} }
const makeMapStateToProps = (state, props) => ({
cachedHeight: state.getIn(['height_cache', props.saveHeightKey, props.id]),
})
const mapDispatchToProps = (dispatch) => ({
onHeightChange(key, id, height) {
dispatch(setHeight(key, id, height))
},
})
IntersectionObserverArticle.propTypes = {
intersectionObserverWrapper: PropTypes.object.isRequired,
id: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
index: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
listLength: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
saveHeightKey: PropTypes.string,
cachedHeight: PropTypes.number,
onHeightChange: PropTypes.func,
children: PropTypes.node,
}
export default connect(makeMapStateToProps, mapDispatchToProps)(IntersectionObserverArticle)

View File

@ -16,37 +16,8 @@ import { CX, DEFAULT_REL } from '../constants'
import Text from './text' import Text from './text'
import Button from './button' import Button from './button'
const messages = defineMessages({
help: { id: 'getting_started.help', defaultMessage: 'Help' },
invite: { id: 'getting_started.invite', defaultMessage: 'Invite people' },
hotkeys: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Hotkeys' },
security: { id: 'getting_started.security', defaultMessage: 'Security' },
about: { id: 'navigation_bar.info', defaultMessage: 'About' },
developers: { id: 'getting_started.developers', defaultMessage: 'Developers' },
terms: { id: 'getting_started.terms', defaultMessage: 'Terms of Service' },
dmca: { id: 'getting_started.dmca', defaultMessage: 'DMCA' },
salesTerms: { id: 'getting_started.terms_of_sale', defaultMessage: 'Terms of Sale' },
privacy: { id: 'getting_started.privacy', defaultMessage: 'Privacy Policy' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenHotkeys() {
dispatch(openModal('HOTKEYS'))
},
})
export default
@connect(null, mapDispatchToProps)
@injectIntl
class LinkFooter extends React.PureComponent { class LinkFooter extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
noPadding: PropTypes.bool,
onOpenHotkeys: PropTypes.func.isRequired,
}
render() { render() {
const { const {
intl, intl,
@ -157,3 +128,31 @@ class LinkFooter extends React.PureComponent {
} }
} }
const messages = defineMessages({
help: { id: 'getting_started.help', defaultMessage: 'Help' },
invite: { id: 'getting_started.invite', defaultMessage: 'Invite people' },
hotkeys: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Hotkeys' },
security: { id: 'getting_started.security', defaultMessage: 'Security' },
about: { id: 'navigation_bar.info', defaultMessage: 'About' },
developers: { id: 'getting_started.developers', defaultMessage: 'Developers' },
terms: { id: 'getting_started.terms', defaultMessage: 'Terms of Service' },
dmca: { id: 'getting_started.dmca', defaultMessage: 'DMCA' },
salesTerms: { id: 'getting_started.terms_of_sale', defaultMessage: 'Terms of Sale' },
privacy: { id: 'getting_started.privacy', defaultMessage: 'Privacy Policy' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenHotkeys() {
dispatch(openModal('HOTKEYS'))
},
})
LinkFooter.propTypes = {
intl: PropTypes.object.isRequired,
noPadding: PropTypes.bool,
onOpenHotkeys: PropTypes.func.isRequired,
}
export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter))

View File

@ -8,24 +8,7 @@ import ListItem from './list_item'
import Dummy from './dummy' import Dummy from './dummy'
import ListItemPlaceholder from './placeholder/list_item_placeholder' import ListItemPlaceholder from './placeholder/list_item_placeholder'
export default class List extends ImmutablePureComponent { class List extends ImmutablePureComponent {
static propTypes = {
items: PropTypes.oneOfType([
PropTypes.array,
ImmutablePropTypes.map,
ImmutablePropTypes.list,
]),
scrollKey: PropTypes.string,
emptyMessage: PropTypes.any,
size: PropTypes.oneOf([
'small',
'large'
]),
onLoadMore: PropTypes.func,
hasMore: PropTypes.bool,
showLoading: PropTypes.bool,
}
render() { render() {
const { const {
@ -67,3 +50,22 @@ export default class List extends ImmutablePureComponent {
} }
} }
List.propTypes = {
items: PropTypes.oneOfType([
PropTypes.array,
ImmutablePropTypes.map,
ImmutablePropTypes.list,
]),
scrollKey: PropTypes.string,
emptyMessage: PropTypes.any,
size: PropTypes.oneOf([
'small',
'large'
]),
onLoadMore: PropTypes.func,
hasMore: PropTypes.bool,
showLoading: PropTypes.bool,
}
export default List

View File

@ -8,26 +8,7 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class ListItem extends React.PureComponent { class ListItem extends React.PureComponent {
static propTypes = {
icon: PropTypes.string,
image: PropTypes.string,
isLast: PropTypes.bool,
isHidden: PropTypes.bool,
to: PropTypes.string,
href: PropTypes.string,
title: PropTypes.string,
subtitle: PropTypes.string,
isActive: PropTypes.bool,
actionIcon: PropTypes.bool,
onClick: PropTypes.func,
size: PropTypes.oneOf([
'small',
'large',
]),
hideArrow: PropTypes.bool,
}
handleOnClick = (e) => { handleOnClick = (e) => {
if (!!this.props.onClick) { if (!!this.props.onClick) {
@ -168,3 +149,24 @@ export default class ListItem extends React.PureComponent {
} }
} }
ListItem.propTypes = {
icon: PropTypes.string,
image: PropTypes.string,
isLast: PropTypes.bool,
isHidden: PropTypes.bool,
to: PropTypes.string,
href: PropTypes.string,
title: PropTypes.string,
subtitle: PropTypes.string,
isActive: PropTypes.bool,
actionIcon: PropTypes.bool,
onClick: PropTypes.func,
size: PropTypes.oneOf([
'small',
'large',
]),
hideArrow: PropTypes.bool,
}
export default ListItem

View File

@ -4,25 +4,8 @@ import { injectIntl, defineMessages } from 'react-intl'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
const messages = defineMessages({
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
})
export default
@injectIntl
class LoadMore extends React.PureComponent { class LoadMore extends React.PureComponent {
static propTypes = {
onClick: PropTypes.func,
disabled: PropTypes.bool,
visible: PropTypes.bool,
intl: PropTypes.object.isRequired,
}
static defaultProps = {
visible: true,
}
handleClick = (e) => { handleClick = (e) => {
this.props.onClick(e) this.props.onClick(e)
} }
@ -59,3 +42,21 @@ class LoadMore extends React.PureComponent {
} }
} }
const messages = defineMessages({
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
})
LoadMore.propTypes = {
onClick: PropTypes.func,
disabled: PropTypes.bool,
visible: PropTypes.bool,
intl: PropTypes.object.isRequired,
}
LoadMore.defaultProps = {
visible: true,
}
export default injectIntl(LoadMore)

View File

@ -8,13 +8,7 @@ import Text from './text'
import ResponsiveComponent from '../features/ui/util/responsive_component' import ResponsiveComponent from '../features/ui/util/responsive_component'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component' import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
export default class LoggedOutNavigationBar extends React.PureComponent { class LoggedOutNavigationBar extends React.PureComponent {
static propTypes = {
isProfile: PropTypes.bool,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
}
render() { render() {
const { isProfile } = this.props const { isProfile } = this.props
@ -100,3 +94,11 @@ export default class LoggedOutNavigationBar extends React.PureComponent {
} }
} }
LoggedOutNavigationBar.propTypes = {
isProfile: PropTypes.bool,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
}
export default LoggedOutNavigationBar

View File

@ -7,21 +7,8 @@ import SidebarSectionItem from './sidebar_section_item'
import Heading from './heading' import Heading from './heading'
import LinkFooter from './link_footer' import LinkFooter from './link_footer'
const messages = defineMessages({
explore: { id: 'explore', defaultMessage: 'Explore' },
menu: { id: 'menu', defaultMessage: 'Menu' },
})
export default
@injectIntl
class Sidebar extends React.PureComponent { class Sidebar extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
showLinkFooter: PropTypes.bool,
title: PropTypes.string,
}
render() { render() {
const { const {
intl, intl,
@ -122,3 +109,16 @@ class Sidebar extends React.PureComponent {
} }
} }
const messages = defineMessages({
explore: { id: 'explore', defaultMessage: 'Explore' },
menu: { id: 'menu', defaultMessage: 'Menu' },
})
Sidebar.propTypes = {
intl: PropTypes.object.isRequired,
showLinkFooter: PropTypes.bool,
title: PropTypes.string,
}
export default injectIntl(Sidebar)

View File

@ -13,33 +13,10 @@ import Button from './button'
import SensitiveMediaItem from './sensitive_media_item' import SensitiveMediaItem from './sensitive_media_item'
import Text from './text' import Text from './text'
const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide media' },
warning: { id: 'status.sensitive_warning', defaultMessage: 'Sensitive content' },
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
});
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
class Item extends ImmutablePureComponent { class Item extends ImmutablePureComponent {
static propTypes = {
attachment: ImmutablePropTypes.map.isRequired,
standalone: PropTypes.bool,
index: PropTypes.number.isRequired,
size: PropTypes.number.isRequired,
onClick: PropTypes.func.isRequired,
displayWidth: PropTypes.number,
visible: PropTypes.bool.isRequired,
dimensions: PropTypes.object,
}
static defaultProps = {
standalone: false,
index: 0,
size: 1,
}
state = { state = {
loaded: false, loaded: false,
} }
@ -239,31 +216,25 @@ class Item extends ImmutablePureComponent {
} }
export default Item.propTypes = {
@injectIntl attachment: ImmutablePropTypes.map.isRequired,
standalone: PropTypes.bool,
index: PropTypes.number.isRequired,
size: PropTypes.number.isRequired,
onClick: PropTypes.func.isRequired,
displayWidth: PropTypes.number,
visible: PropTypes.bool.isRequired,
dimensions: PropTypes.object,
}
Item.defaultProps = {
standalone: false,
index: 0,
size: 1,
}
class MediaGallery extends React.PureComponent { class MediaGallery extends React.PureComponent {
static propTypes = {
sensitive: PropTypes.bool,
standalone: PropTypes.bool,
media: ImmutablePropTypes.list.isRequired,
size: PropTypes.object,
height: PropTypes.number.isRequired,
onOpenMedia: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
reduced: PropTypes.bool,
isComment: PropTypes.bool,
};
static defaultProps = {
standalone: false,
height: 110,
};
state = { state = {
visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'), visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
width: this.props.defaultWidth, width: this.props.defaultWidth,
@ -589,3 +560,32 @@ class MediaGallery extends React.PureComponent {
} }
} }
const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide media' },
warning: { id: 'status.sensitive_warning', defaultMessage: 'Sensitive content' },
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
})
MediaGallery.propTypes = {
sensitive: PropTypes.bool,
standalone: PropTypes.bool,
media: ImmutablePropTypes.list.isRequired,
size: PropTypes.object,
height: PropTypes.number.isRequired,
onOpenMedia: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
reduced: PropTypes.bool,
isComment: PropTypes.bool,
}
MediaGallery.defaultProps = {
standalone: false,
height: 110,
}
export default injectIntl(MediaGallery)

View File

@ -12,13 +12,7 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class MediaItem extends ImmutablePureComponent { class MediaItem extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
attachment: ImmutablePropTypes.map.isRequired,
isSmall: PropTypes.bool,
}
state = { state = {
loaded: false, loaded: false,
@ -161,3 +155,11 @@ export default class MediaItem extends ImmutablePureComponent {
} }
} }
MediaItem.propTypes = {
account: ImmutablePropTypes.map.isRequired,
attachment: ImmutablePropTypes.map.isRequired,
isSmall: PropTypes.bool,
}
export default MediaItem

View File

@ -48,12 +48,6 @@ class DisplayOptionsModal extends ImmutablePureComponent {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
} }
updateOnProps = [
'fontSize',
'displayOptionsSettings',
'theme',
]
handleOnFontSizeChange = (e) => { handleOnFontSizeChange = (e) => {
const fontSizeNames = Object.keys(FONT_SIZES) const fontSizeNames = Object.keys(FONT_SIZES)
const index = fontSizeNames[e.target.value] const index = fontSizeNames[e.target.value]

View File

@ -41,12 +41,6 @@ class MediaModal extends ImmutablePureComponent {
navigationHidden: false, navigationHidden: false,
} }
updateOnProps = [
'media',
'status',
'index',
]
handleSwipe = (index) => { handleSwipe = (index) => {
this.setState({ index: index % this.props.media.size }) this.setState({ index: index % this.props.media.size })
} }

View File

@ -1,51 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { FormattedMessage } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { NavLink } from 'react-router-dom'
import DisplayName from './display_name'
import Icon from './icon'
// : todo :
export default class MovedNote extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,
}
static propTypes = {
fromAcct: ImmutablePropTypes.map.isRequired,
to: ImmutablePropTypes.map.isRequired,
}
render () {
const { fromAcct, toAcct } = this.props;
const displayNameHtml = { __html: fromAcct.get('display_name_html') }
return (
<div className='moved-note'>
<div className='moved-note__message'>
<div className='moved-note__icon-wrapper'>
<Icon id='suitcase' className='moved-note__icon' fixedWidth />
</div>
<FormattedMessage
id='account.moved_to'
defaultMessage='{name} has moved to:'
values={{
name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi>
}}
/>
</div>
<NavLink to={`/${toAcct.get('acct')}`} className='moved-note__display-name'>
<div className='moved-note__display-avatar'>
<Avatar account={toAcct} />
</div>
<DisplayName account={toAcct} />
</NavLink>
</div>
);
}
}

View File

@ -22,39 +22,8 @@ import NavigationBarButton from './navigation_bar_button'
import Search from './search' import Search from './search'
import Text from './text' import Text from './text'
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
})
const mapDispatchToProps = (dispatch) => ({
onOpenSidebar() {
dispatch(openSidebar())
},
onOpenNavSettingsPopover(targetRef) {
dispatch(openPopover(POPOVER_NAV_SETTINGS, {
targetRef,
position: 'left-end',
}))
}
})
export default
@connect(mapStateToProps, mapDispatchToProps)
class NavigationBar extends ImmutablePureComponent { class NavigationBar extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
actions: PropTypes.array,
tabs: PropTypes.array,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
onOpenSidebar: PropTypes.func.isRequired,
onOpenNavSettingsPopover: PropTypes.func.isRequired,
noActions: PropTypes.bool,
noSearch: PropTypes.bool,
}
handleOnOpenNavSettingsPopover = () => { handleOnOpenNavSettingsPopover = () => {
this.props.onOpenNavSettingsPopover(this.avatarNode) this.props.onOpenNavSettingsPopover(this.avatarNode)
} }
@ -118,12 +87,12 @@ class NavigationBar extends ImmutablePureComponent {
<NavigationBarButton title='Explore' icon='explore' to='/explore' /> <NavigationBarButton title='Explore' icon='explore' to='/explore' />
<NavigationBarButton title='News' icon='news' to='/news' /> <NavigationBarButton title='News' icon='news' to='/news' />
<NavigationBarButtonDivider /> <div className={[_s.default, _s.height20PX, _s.width1PX, _s.mr10, _s.ml10, _s.bgNavigationBlend].join(' ')} />
<NavigationBarButton attrTitle='Notifications' icon='notifications' to='/notifications' /> <NavigationBarButton attrTitle='Notifications' icon='notifications' to='/notifications' />
<NavigationBarButton attrTitle='Settings' icon='cog' href='/settings/preferences' /> <NavigationBarButton attrTitle='Settings' icon='cog' href='/settings/preferences' />
<NavigationBarButtonDivider /> <div className={[_s.default, _s.height20PX, _s.width1PX, _s.mr10, _s.ml10, _s.bgNavigationBlend].join(' ')} />
{ {
!!account && !!account &&
@ -236,12 +205,33 @@ class NavigationBar extends ImmutablePureComponent {
} }
class NavigationBarButtonDivider extends React.PureComponent { const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
})
render() { const mapDispatchToProps = (dispatch) => ({
return ( onOpenSidebar() {
<div className={[_s.default, _s.height20PX, _s.width1PX, _s.mr10, _s.ml10, _s.bgNavigationBlend].join(' ')} /> dispatch(openSidebar())
) },
onOpenNavSettingsPopover(targetRef) {
dispatch(openPopover(POPOVER_NAV_SETTINGS, {
targetRef,
position: 'left-end',
}))
} }
})
NavigationBar.propTypes = {
account: ImmutablePropTypes.map,
actions: PropTypes.array,
tabs: PropTypes.array,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
onOpenSidebar: PropTypes.func.isRequired,
onOpenNavSettingsPopover: PropTypes.func.isRequired,
noActions: PropTypes.bool,
noSearch: PropTypes.bool,
} }
export default connect(mapStateToProps, mapDispatchToProps)(NavigationBar)

View File

@ -5,15 +5,7 @@ import Button from './button'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
export default class NavigationBarButton extends React.PureComponent { class NavigationBarButton extends React.PureComponent {
static propTypes = {
title: PropTypes.string,
icon: PropTypes.string,
to: PropTypes.string,
href: PropTypes.string,
attrTitle: PropTypes.string,
}
render() { render() {
const { const {
@ -72,3 +64,13 @@ export default class NavigationBarButton extends React.PureComponent {
} }
} }
NavigationBarButton.propTypes = {
title: PropTypes.string,
icon: PropTypes.string,
to: PropTypes.string,
href: PropTypes.string,
attrTitle: PropTypes.string,
}
export default NavigationBarButton

View File

@ -18,37 +18,12 @@ import DotTextSeperator from './dot_text_seperator'
import RelativeTimestamp from './relative_timestamp' import RelativeTimestamp from './relative_timestamp'
import DisplayName from './display_name' import DisplayName from './display_name'
const messages = defineMessages({
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
ownPoll: { id: 'notification.own_poll', defaultMessage: 'Your poll has ended' },
mentionedInPost: { id: 'mentioned_in_post', defaultMessage: 'mentioned you in their post' },
mentionedInComment: { id: 'mentioned_in_comment', defaultMessage: 'mentioned you in their comment' },
followedYouOne: { id: 'followed_you_one', defaultMessage: 'followed you' },
followedYouMultiple: { id: 'followed_you_multiple', defaultMessage: 'and {count} others followed you' },
likedStatusOne: { id: 'liked_status_one', defaultMessage: 'liked your status' },
likedStatusMultiple: { id: 'liked_status_multiple', defaultMessage: 'and {count} others liked your status' },
repostedStatusOne: { id: 'reposted_status_one', defaultMessage: 'reposted your status' },
repostedStatusMultiple: { id: 'reposted_status_multiple', defaultMessage: 'and {count} others reposted your status' },
})
export default
@injectIntl
class Notification extends ImmutablePureComponent { class Notification extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
intl: PropTypes.object.isRequired,
accounts: ImmutablePropTypes.list.isRequired,
createdAt: PropTypes.string,
statusId: PropTypes.string,
type: PropTypes.string.isRequired,
isHidden: PropTypes.bool,
isUnread: PropTypes.bool,
}
render() { render() {
const { const {
intl, intl,
@ -194,3 +169,28 @@ class Notification extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
ownPoll: { id: 'notification.own_poll', defaultMessage: 'Your poll has ended' },
mentionedInPost: { id: 'mentioned_in_post', defaultMessage: 'mentioned you in their post' },
mentionedInComment: { id: 'mentioned_in_comment', defaultMessage: 'mentioned you in their comment' },
followedYouOne: { id: 'followed_you_one', defaultMessage: 'followed you' },
followedYouMultiple: { id: 'followed_you_multiple', defaultMessage: 'and {count} others followed you' },
likedStatusOne: { id: 'liked_status_one', defaultMessage: 'liked your status' },
likedStatusMultiple: { id: 'liked_status_multiple', defaultMessage: 'and {count} others liked your status' },
repostedStatusOne: { id: 'reposted_status_one', defaultMessage: 'reposted your status' },
repostedStatusMultiple: { id: 'reposted_status_multiple', defaultMessage: 'and {count} others reposted your status' },
})
Notification.propTypes = {
intl: PropTypes.object.isRequired,
accounts: ImmutablePropTypes.list.isRequired,
createdAt: PropTypes.string,
statusId: PropTypes.string,
type: PropTypes.string.isRequired,
isHidden: PropTypes.bool,
isUnread: PropTypes.bool,
}
export default injectIntl(Notification)

View File

@ -25,10 +25,6 @@ class ListDetailsPanel extends ImmutablePureComponent {
onEdit: PropTypes.func.isRequired, onEdit: PropTypes.func.isRequired,
} }
updateOnProps = [
'list',
]
render() { render() {
const { const {
intl, intl,

View File

@ -40,12 +40,6 @@ class ListsPanel extends ImmutablePureComponent {
fetched: false, fetched: false,
} }
updateOnProps = [
'lists',
'isLazy',
'shouldLoad',
]
static getDerivedStateFromProps(nextProps, prevState) { static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.shouldLoad && !prevState.fetched) { if (nextProps.shouldLoad && !prevState.fetched) {
return { fetched: true } return { fetched: true }

View File

@ -5,18 +5,8 @@ import { CX } from '../constants'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
export default
@withRouter
class PillItem extends React.PureComponent { class PillItem extends React.PureComponent {
static propTypes = {
icon: PropTypes.string,
isActive: PropTypes.bool,
onClick: PropTypes.func,
title: PropTypes.string,
to: PropTypes.string,
}
state = { state = {
isCurrent: false, isCurrent: false,
} }
@ -103,3 +93,13 @@ class PillItem extends React.PureComponent {
) )
} }
} }
PillItem.propTypes = {
icon: PropTypes.string,
isActive: PropTypes.bool,
onClick: PropTypes.func,
title: PropTypes.string,
to: PropTypes.string,
}
export default withRouter(PillItem)

View File

@ -7,11 +7,7 @@ import PillItem from './pill_item'
* Renders pills components * Renders pills components
* @param {array} [props.pills] - tab bar data for creating `TabBarItem` * @param {array} [props.pills] - tab bar data for creating `TabBarItem`
*/ */
export default class Pills extends React.PureComponent { class Pills extends React.PureComponent {
static propTypes = {
pills: PropTypes.array,
}
render() { render() {
const { pills } = this.props const { pills } = this.props
@ -38,3 +34,9 @@ export default class Pills extends React.PureComponent {
} }
} }
Pills.propTypes = {
pills: PropTypes.array,
}
export default Pills

View File

@ -18,33 +18,13 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
const mapStateToProps = (state, { pollId }) => ({
poll: state.getIn(['polls', pollId]),
})
const messages = defineMessages({
closed: { id: 'poll.closed', defaultMessage: 'Closed' },
vote: { id: 'poll.vote', defaultMessage: 'Vote' },
refresh: { id: 'poll.refresh', defaultMessage: 'Refresh' },
})
const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => { const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
obj[`:${emoji.get('shortcode')}:`] = emoji.toJS() obj[`:${emoji.get('shortcode')}:`] = emoji.toJS()
return obj return obj
}, {}) }, {})
export default
@connect(mapStateToProps)
@injectIntl
class Poll extends ImmutablePureComponent { class Poll extends ImmutablePureComponent {
static propTypes = {
poll: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func,
disabled: PropTypes.bool,
}
state = { state = {
selected: {}, selected: {},
} }
@ -242,3 +222,22 @@ class Poll extends ImmutablePureComponent {
} }
} }
const mapStateToProps = (state, { pollId }) => ({
poll: state.getIn(['polls', pollId]),
})
const messages = defineMessages({
closed: { id: 'poll.closed', defaultMessage: 'Closed' },
vote: { id: 'poll.vote', defaultMessage: 'Vote' },
refresh: { id: 'poll.refresh', defaultMessage: 'Refresh' },
})
Poll.propTypes = {
poll: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func,
disabled: PropTypes.bool,
}
export default injectIntl(connect(mapStateToProps)(Poll))

View File

@ -20,53 +20,14 @@ import Avatar from './avatar'
import Button from './button' import Button from './button'
import DisplayName from './display_name' import DisplayName from './display_name'
import Image from './image' import Image from './image'
import MovedNote from './moved_note'
import TabBar from './tab_bar' import TabBar from './tab_bar'
import Pills from './pills' import Pills from './pills'
import Text from './text' import Text from './text'
import Responsive from '../features/ui/util/responsive_component'; import Responsive from '../features/ui/util/responsive_component';
import ProfileHeaderXSPlaceholder from './placeholder/profile_header_xs_placeholder' import ProfileHeaderXSPlaceholder from './placeholder/profile_header_xs_placeholder'
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
headerPhoto: { id: 'header_photo', defaultMessage: 'Header photo' },
timeline: { id: 'timeline', defaultMessage: 'Timeline' },
comments: { id: 'comments', defaultMessage: 'Comments' },
photos: { id: 'photos', defaultMessage: 'Photos' },
videos: { id: 'videos', defaultMessage: 'Videos' },
bookmarks: { id: 'bookmarks', defaultMessage: 'Bookmarks' },
accountFollowsYou: { id: 'account.follows_you', defaultMessage: 'Follows you' },
editProfile: { id: "account.edit_profile", defaultMessage: "Edit profile" },
})
const mapDispatchToProps = (dispatch) => ({
openProfileOptionsPopover(props) {
dispatch(openPopover(POPOVER_PROFILE_OPTIONS, props))
},
onEditProfile() {
dispatch(openModal(MODAL_EDIT_PROFILE))
},
});
export default
@connect(null, mapDispatchToProps)
@injectIntl
class ProfileHeader extends ImmutablePureComponent { class ProfileHeader extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
children: PropTypes.any,
intl: PropTypes.object.isRequired,
onEditProfile: PropTypes.func.isRequired,
openProfileOptionsPopover: PropTypes.func.isRequired,
isXS: PropTypes.bool,
}
state = { state = {
stickied: false, stickied: false,
} }
@ -397,3 +358,40 @@ class ProfileHeader extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
headerPhoto: { id: 'header_photo', defaultMessage: 'Header photo' },
timeline: { id: 'timeline', defaultMessage: 'Timeline' },
comments: { id: 'comments', defaultMessage: 'Comments' },
photos: { id: 'photos', defaultMessage: 'Photos' },
videos: { id: 'videos', defaultMessage: 'Videos' },
bookmarks: { id: 'bookmarks', defaultMessage: 'Bookmarks' },
accountFollowsYou: { id: 'account.follows_you', defaultMessage: 'Follows you' },
editProfile: { id: "account.edit_profile", defaultMessage: "Edit profile" },
})
const mapDispatchToProps = (dispatch) => ({
openProfileOptionsPopover(props) {
dispatch(openPopover(POPOVER_PROFILE_OPTIONS, props))
},
onEditProfile() {
dispatch(openModal(MODAL_EDIT_PROFILE))
},
});
ProfileHeader.propTypes = {
account: ImmutablePropTypes.map,
children: PropTypes.any,
intl: PropTypes.object.isRequired,
onEditProfile: PropTypes.func.isRequired,
openProfileOptionsPopover: PropTypes.func.isRequired,
isXS: PropTypes.bool,
}
export default injectIntl(connect(null, mapDispatchToProps)(ProfileHeader))

View File

@ -3,12 +3,7 @@ import PropTypes from 'prop-types'
import BackButton from './back_button' import BackButton from './back_button'
import Heading from './heading' import Heading from './heading'
export default class ProfileNavigationBar extends React.PureComponent { class ProfileNavigationBar extends React.PureComponent {
static propTypes = {
titleHTML: PropTypes.string,
showBackBtn: PropTypes.bool,
}
render() { render() {
const { titleHTML } = this.props const { titleHTML } = this.props
@ -41,3 +36,10 @@ export default class ProfileNavigationBar extends React.PureComponent {
} }
} }
ProfileNavigationBar.propTypes = {
titleHTML: PropTypes.string,
showBackBtn: PropTypes.bool,
}
export default ProfileNavigationBar

View File

@ -4,17 +4,7 @@ import { CX } from '../constants'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
export default class ProgressBar extends React.PureComponent { class ProgressBar extends React.PureComponent {
static propTypes = {
progress: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
]).isRequired,
small: PropTypes.bool,
title: PropTypes.string,
href: PropTypes.string,
}
render() { render() {
const { const {
@ -60,3 +50,15 @@ export default class ProgressBar extends React.PureComponent {
) )
} }
} }
ProgressBar.propTypes = {
progress: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
]).isRequired,
small: PropTypes.bool,
title: PropTypes.string,
href: PropTypes.string,
}
export default ProgressBar

View File

@ -2,7 +2,6 @@ import React from 'react'
import { BREAKPOINT_EXTRA_SMALL } from '../constants' import { BREAKPOINT_EXTRA_SMALL } from '../constants'
import Responsive from '../features/ui//util/responsive_component' import Responsive from '../features/ui//util/responsive_component'
import Icon from './icon' import Icon from './icon'
import Text from './text'
export default class PullToRefresher extends React.PureComponent { export default class PullToRefresher extends React.PureComponent {

View File

@ -15,6 +15,32 @@ import RelativeTimestamp from './relative_timestamp'
import Text from './text' import Text from './text'
import StatusContent from './status_content' import StatusContent from './status_content'
class Comment extends ImmutablePureComponent {
constructListItem = (item) => {
if (item.nestedItems) {
return (
<List key={item.key}>
{item.nestedItems.map(this.constructListItem)}
</List>
)
} else {
return <ListItem key={item.key} item={item} />
}
}
render() {
const { listItems } = this.props
return (
<List>
{listItems.map(this.constructListItem)}
</List>
)
}
}
const messages = defineMessages({ const messages = defineMessages({
follow: { id: 'follow', defaultMessage: 'Follow' }, follow: { id: 'follow', defaultMessage: 'Follow' },
}) })
@ -57,37 +83,9 @@ const makeMapStateToProps = () => {
return mapStateToProps return mapStateToProps
} }
export default Comment.propTypes = {
@injectIntl status: ImmutablePropTypes.map.isRequired,
@connect(makeMapStateToProps) descendantsIds: ImmutablePropTypes.list,
class Comment extends ImmutablePureComponent {
static propTypes = {
status: ImmutablePropTypes.map.isRequired,
descendantsIds: ImmutablePropTypes.list,
}
constructListItem = (item) => {
if (item.nestedItems) {
return (
<List key={item.key}>
{item.nestedItems.map(this.constructListItem)}
</List>
)
} else {
return <ListItem key={item.key} item={item} />
}
}
render() {
const { listItems } = this.props
return (
<List>
{listItems.map(this.constructListItem)}
</List>
)
}
} }
export default injectIntl(connect(makeMapStateToProps)(Comment))

View File

@ -2,19 +2,6 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { injectIntl, defineMessages } from 'react-intl' import { injectIntl, defineMessages } from 'react-intl'
const messages = defineMessages({
just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },
minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
days: { id: 'relative_time.days', defaultMessage: '{number}d' },
moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
})
const dateFormatOptions = { const dateFormatOptions = {
hour12: false, hour12: false,
year: 'numeric', year: 'numeric',
@ -103,17 +90,8 @@ const timeRemainingString = (intl, date, now) => {
return intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) }) return intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) })
} }
export default
@injectIntl
class RelativeTimestamp extends React.Component { class RelativeTimestamp extends React.Component {
static propTypes = {
intl: PropTypes.object.isRequired,
timestamp: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
futureDate: PropTypes.bool,
}
state = { state = {
now: this.props.intl.now(), now: this.props.intl.now(),
} }
@ -177,3 +155,25 @@ class RelativeTimestamp extends React.Component {
} }
} }
const messages = defineMessages({
just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },
minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
days: { id: 'relative_time.days', defaultMessage: '{number}d' },
moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
})
RelativeTimestamp.propTypes = {
intl: PropTypes.object.isRequired,
timestamp: PropTypes.string.isRequired,
year: PropTypes.number.isRequired,
futureDate: PropTypes.bool,
}
export default injectIntl(RelativeTimestamp)

View File

@ -72,28 +72,8 @@ const RTE_ITEMS = [
// }, // },
] ]
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
const account = getAccount(state, me)
const isPro = account.get('is_pro')
return {
isPro,
rteControlsVisible: state.getIn(['compose', 'rte_controls_visible']),
}
}
export default
@connect(mapStateToProps)
class RichTextEditorBar extends React.PureComponent { class RichTextEditorBar extends React.PureComponent {
static propTypes = {
editorState: PropTypes.object.isRequired,
isPro: PropTypes.bool.isRequired,
rteControlsVisible: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
}
toggleEditorStyle = (style, type) => { toggleEditorStyle = (style, type) => {
if (type === 'style') { if (type === 'style') {
this.props.onChange( this.props.onChange(
@ -199,3 +179,22 @@ class StyleButton extends React.PureComponent {
} }
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
const account = getAccount(state, me)
const isPro = account.get('is_pro')
return {
isPro,
rteControlsVisible: state.getIn(['compose', 'rte_controls_visible']),
}
}
RichTextEditorBar.propTypes = {
editorState: PropTypes.object.isRequired,
isPro: PropTypes.bool.isRequired,
rteControlsVisible: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
}
export default connect(mapStateToProps)(RichTextEditorBar)

View File

@ -10,30 +10,12 @@ import LoadMore from './load_more'
const MOUSE_IDLE_DELAY = 300 const MOUSE_IDLE_DELAY = 300
export default class ScrollableList extends React.PureComponent { class ScrollableList extends React.PureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
scrollKey: PropTypes.string.isRequired,
onLoadMore: PropTypes.func,
onReload: PropTypes.func,
isLoading: PropTypes.bool,
showLoading: PropTypes.bool,
hasMore: PropTypes.bool,
emptyMessage: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
children: PropTypes.node,
onScrollToTop: PropTypes.func,
onScroll: PropTypes.func,
placeholderComponent: PropTypes.node,
placeholderCount: PropTypes.node,
}
state = { state = {
pullToRefreshTriggered: false, pullToRefreshTriggered: false,
cachedMediaWidth: 250, // Default media/card width using default Gab Social theme cachedMediaWidth: 250, // Default media/card width using default Gab Social theme
@ -298,3 +280,22 @@ export default class ScrollableList extends React.PureComponent {
} }
ScrollableList.propTypes = {
scrollKey: PropTypes.string.isRequired,
onLoadMore: PropTypes.func,
onReload: PropTypes.func,
isLoading: PropTypes.bool,
showLoading: PropTypes.bool,
hasMore: PropTypes.bool,
emptyMessage: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
children: PropTypes.node,
onScrollToTop: PropTypes.func,
onScroll: PropTypes.func,
placeholderComponent: PropTypes.node,
placeholderCount: PropTypes.node,
}
export default ScrollableList

View File

@ -13,40 +13,12 @@ import {
} from '../actions/search' } from '../actions/search'
import Button from './button' import Button from './button'
const mapStateToProps = (state) => ({
value: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']),
theme: state.getIn(['settings', 'displayOptions', 'theme']),
})
const mapDispatchToProps = (dispatch) => ({
onChange: (value) => dispatch(changeSearch(value)),
onClear: () => dispatch(clearSearch()),
onSubmit: () => dispatch(submitSearch()),
onShow: () => dispatch(showSearch()),
})
export default
@withRouter
@connect(mapStateToProps, mapDispatchToProps)
class Search extends React.PureComponent { class Search extends React.PureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object.isRequired, router: PropTypes.object.isRequired,
} }
static propTypes = {
value: PropTypes.string.isRequired,
submitted: PropTypes.bool,
onShow: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
withOverlay: PropTypes.bool,
onClear: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
isInNav: PropTypes.bool.isRequired,
theme: PropTypes.string,
}
state = { state = {
focused: false, focused: false,
} }
@ -177,3 +149,30 @@ class Search extends React.PureComponent {
} }
} }
const mapStateToProps = (state) => ({
value: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']),
theme: state.getIn(['settings', 'displayOptions', 'theme']),
})
const mapDispatchToProps = (dispatch) => ({
onChange: (value) => dispatch(changeSearch(value)),
onClear: () => dispatch(clearSearch()),
onSubmit: () => dispatch(submitSearch()),
onShow: () => dispatch(showSearch()),
})
Search.propTypes = {
value: PropTypes.string.isRequired,
submitted: PropTypes.bool,
onShow: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
withOverlay: PropTypes.bool,
onClear: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
isInNav: PropTypes.bool.isRequired,
theme: PropTypes.string,
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Search))

View File

@ -10,16 +10,7 @@ import Icon from './icon'
* @param {object} props.options - options for selection * @param {object} props.options - options for selection
* @param {string} [props.value] - value to set selected * @param {string} [props.value] - value to set selected
*/ */
export default class Select extends ImmutablePureComponent { class Select extends ImmutablePureComponent {
static propTypes = {
onChange: PropTypes.func.isRequired,
options: PropTypes.oneOf([
ImmutablePropTypes.map,
PropTypes.object,
]).isRequired,
value: PropTypes.string,
}
updateOnProps = [ updateOnProps = [
'options', 'options',
@ -58,3 +49,14 @@ export default class Select extends ImmutablePureComponent {
} }
} }
Select.propTypes = {
onChange: PropTypes.func.isRequired,
options: PropTypes.oneOf([
ImmutablePropTypes.map,
PropTypes.object,
]).isRequired,
value: PropTypes.string,
}
export default Select

View File

@ -4,20 +4,8 @@ import { injectIntl, defineMessages } from 'react-intl'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
const messages = defineMessages({
warning: { id: 'status.sensitive_warning_2', defaultMessage: 'The following media includes potentially sensitive content.' },
view: { id: 'view', defaultMessage: 'View' },
});
export default
@injectIntl
class SensitiveMediaItem extends React.PureComponent { class SensitiveMediaItem extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired,
}
render() { render() {
const { const {
intl, intl,
@ -50,3 +38,15 @@ class SensitiveMediaItem extends React.PureComponent {
} }
} }
const messages = defineMessages({
warning: { id: 'status.sensitive_warning_2', defaultMessage: 'The following media includes potentially sensitive content.' },
view: { id: 'view', defaultMessage: 'View' },
});
SensitiveMediaItem.propTypes = {
intl: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired,
}
export default injectIntl(SensitiveMediaItem)

View File

@ -4,19 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import Switch from './switch' import Switch from './switch'
export default class SettingSwitch extends ImmutablePureComponent { class SettingSwitch extends ImmutablePureComponent {
static propTypes = {
prefix: PropTypes.string,
settings: ImmutablePropTypes.map.isRequired,
settingPath: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string,
]).isRequired,
description: PropTypes.string,
label: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
updateOnProps = [ updateOnProps = [
'prefix', 'prefix',
@ -57,3 +45,17 @@ export default class SettingSwitch extends ImmutablePureComponent {
} }
} }
SettingSwitch.propTypes = {
prefix: PropTypes.string,
settings: ImmutablePropTypes.map.isRequired,
settingPath: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string,
]).isRequired,
description: PropTypes.string,
label: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
}
export default SettingSwitch

View File

@ -11,28 +11,8 @@ import SidebarSectionItem from './sidebar_section_item'
import Heading from './heading' import Heading from './heading'
import BackButton from './back_button' import BackButton from './back_button'
const messages = defineMessages({
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
menu: { id: 'menu', defaultMessage: 'Menu' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
})
export default
@connect(mapStateToProps)
@injectIntl
class Sidebar extends ImmutablePureComponent { class Sidebar extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
title: PropTypes.string,
}
render() { render() {
const { const {
intl, intl,
@ -95,3 +75,22 @@ class Sidebar extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
menu: { id: 'menu', defaultMessage: 'Menu' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
})
Sidebar.propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
title: PropTypes.string,
}
export default injectIntl(connect(mapStateToProps)(Sidebar))

View File

@ -22,77 +22,8 @@ import BackButton from './back_button'
import Pills from './pills' import Pills from './pills'
import Text from './text' import Text from './text'
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
lists: { id: 'column.lists', defaultMessage: 'Lists' },
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
more: { id: 'sidebar.more', defaultMessage: 'More' },
explore: { id: 'explore', defaultMessage: 'Explore' },
news: { id: 'news', defaultMessage: 'News' },
menu: { id: 'menu', defaultMessage: 'Menu' },
pro: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
trends: { id: 'promo.trends', defaultMessage: 'Trends' },
search: { id: 'tabs_bar.search', defaultMessage: 'Search' },
shop: { id: 'tabs_bar.shop', defaultMessage: 'Store - Buy Merch' },
donate: { id: 'tabs_bar.donate', defaultMessage: 'Make a Donation' },
shortcuts: { id: 'navigation_bar.shortcuts', defaultMessage: 'Shortcuts' },
all: { id: 'all', defaultMessage: 'All' },
edit: { id: 'edit', defaultMessage: 'Edit' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
shortcuts: state.getIn(['shortcuts', 'items']),
moreOpen: state.getIn(['popover', 'popoverType']) === 'SIDEBAR_MORE',
notificationCount: state.getIn(['notifications', 'unread']),
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
})
const mapDispatchToProps = (dispatch) => ({
onClose() {
dispatch(closeSidebar())
},
openSidebarMorePopover(props) {
dispatch(openPopover('SIDEBAR_MORE', props))
},
onOpenComposeModal() {
dispatch(openModal('COMPOSE'))
},
onFetchShortcuts() {
dispatch(fetchShortcuts())
},
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class Sidebar extends ImmutablePureComponent { class Sidebar extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
moreOpen: PropTypes.bool,
onClose: PropTypes.func.isRequired,
onOpenComposeModal: PropTypes.func.isRequired,
onFetchShortcuts: PropTypes.func.isRequired,
openSidebarMorePopover: PropTypes.func.isRequired,
notificationCount: PropTypes.number.isRequired,
homeItemsQueueCount: PropTypes.number.isRequired,
actions: PropTypes.array,
tabs: PropTypes.array,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
shortcuts: ImmutablePropTypes.list,
}
state = { state = {
hoveringShortcuts: false, hoveringShortcuts: false,
} }
@ -356,3 +287,71 @@ class Sidebar extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
lists: { id: 'column.lists', defaultMessage: 'Lists' },
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
more: { id: 'sidebar.more', defaultMessage: 'More' },
explore: { id: 'explore', defaultMessage: 'Explore' },
news: { id: 'news', defaultMessage: 'News' },
menu: { id: 'menu', defaultMessage: 'Menu' },
pro: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
trends: { id: 'promo.trends', defaultMessage: 'Trends' },
search: { id: 'tabs_bar.search', defaultMessage: 'Search' },
shop: { id: 'tabs_bar.shop', defaultMessage: 'Store - Buy Merch' },
donate: { id: 'tabs_bar.donate', defaultMessage: 'Make a Donation' },
shortcuts: { id: 'navigation_bar.shortcuts', defaultMessage: 'Shortcuts' },
all: { id: 'all', defaultMessage: 'All' },
edit: { id: 'edit', defaultMessage: 'Edit' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
shortcuts: state.getIn(['shortcuts', 'items']),
moreOpen: state.getIn(['popover', 'popoverType']) === 'SIDEBAR_MORE',
notificationCount: state.getIn(['notifications', 'unread']),
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
})
const mapDispatchToProps = (dispatch) => ({
onClose() {
dispatch(closeSidebar())
},
openSidebarMorePopover(props) {
dispatch(openPopover('SIDEBAR_MORE', props))
},
onOpenComposeModal() {
dispatch(openModal('COMPOSE'))
},
onFetchShortcuts() {
dispatch(fetchShortcuts())
},
})
Sidebar.propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
moreOpen: PropTypes.bool,
onClose: PropTypes.func.isRequired,
onOpenComposeModal: PropTypes.func.isRequired,
onFetchShortcuts: PropTypes.func.isRequired,
openSidebarMorePopover: PropTypes.func.isRequired,
notificationCount: PropTypes.number.isRequired,
homeItemsQueueCount: PropTypes.number.isRequired,
actions: PropTypes.array,
tabs: PropTypes.array,
title: PropTypes.string,
showBackBtn: PropTypes.bool,
shortcuts: ImmutablePropTypes.list,
}
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Sidebar))

View File

@ -7,13 +7,7 @@ import {
StatusPromotionPanel StatusPromotionPanel
} from '../features/ui/util/async_components' } from '../features/ui/util/async_components'
export default class SidebarPanelGroup extends React.PureComponent { class SidebarPanelGroup extends React.PureComponent {
static propTypes = {
layout: PropTypes.array.isRequired,
page: PropTypes.string.isRequired,
promotion: PropTypes.object,
}
render() { render() {
const { layout, page } = this.props const { layout, page } = this.props
@ -57,3 +51,11 @@ export default class SidebarPanelGroup extends React.PureComponent {
} }
} }
SidebarPanelGroup.propTypes = {
layout: PropTypes.array.isRequired,
page: PropTypes.string.isRequired,
promotion: PropTypes.object,
}
export default SidebarPanelGroup

View File

@ -8,25 +8,12 @@ import Icon from './icon'
import Image from './image' import Image from './image'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component' import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
export default class SidebarSectionItem extends React.PureComponent { class SidebarSectionItem extends React.PureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
to: PropTypes.string,
href: PropTypes.string,
onClick: PropTypes.func,
active: PropTypes.bool,
icon: PropTypes.string,
image: PropTypes.string,
title: PropTypes.string,
me: PropTypes.bool,
suffix: PropTypes.node,
buttonRef: PropTypes.func,
}
state = { state = {
hovering: false, hovering: false,
} }
@ -141,3 +128,18 @@ export default class SidebarSectionItem extends React.PureComponent {
} }
} }
SidebarSectionItem.propTypes = {
to: PropTypes.string,
href: PropTypes.string,
onClick: PropTypes.func,
active: PropTypes.bool,
icon: PropTypes.string,
image: PropTypes.string,
title: PropTypes.string,
me: PropTypes.bool,
suffix: PropTypes.node,
buttonRef: PropTypes.func,
}
export default SidebarSectionItem

View File

@ -2,11 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Text from './text' import Text from './text'
export default class SidebarSectionTitle extends React.PureComponent { class SidebarSectionTitle extends React.PureComponent {
static propTypes = {
children: PropTypes.string.isRequired,
}
render() { render() {
const { children } = this.props const { children } = this.props
@ -21,3 +17,9 @@ export default class SidebarSectionTitle extends React.PureComponent {
} }
} }
SidebarSectionTitle.propTypes = {
children: PropTypes.string.isRequired,
}
export default SidebarSectionTitle

View File

@ -22,55 +22,8 @@ import {
ProgressPanel, ProgressPanel,
} from '../features/ui/util/async_components' } from '../features/ui/util/async_components'
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
lists: { id: 'column.lists', defaultMessage: 'Lists', },
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
more: { id: 'sidebar.more', defaultMessage: 'More' },
pro: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
trends: { id: 'promo.trends', defaultMessage: 'Trends' },
search: { id: 'tabs_bar.search', defaultMessage: 'Search' },
shop: { id: 'tabs_bar.shop', defaultMessage: 'Store - Buy Merch' },
chat: { id: 'tabs_bar.chat', defaultMessage: 'Chat' },
help: { id: 'getting_started.help', defaultMessage: 'Help' },
display: { id: 'display_options', defaultMessage: 'Display Options' },
proFeed: { id: 'pro_feed', defaultMessage: 'Pro Feed' },
shortcuts: { id: 'shortcuts', defaultMessage: 'Shortcuts' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
sidebarOpen: state.get('sidebar').open,
})
const mapDispatchToProps = (dispatch) => ({
onCloseSidebar: () => dispatch(closeSidebar()),
onOpenDisplayModel() {
dispatch(closeSidebar())
dispatch(openModal('DISPLAY_OPTIONS'))
}
})
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class SidebarXS extends ImmutablePureComponent { class SidebarXS extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
sidebarOpen: PropTypes.bool,
onCloseSidebar: PropTypes.func.isRequired,
onOpenDisplayModel: PropTypes.func.isRequired,
}
componentDidUpdate () { componentDidUpdate () {
if (!me) return if (!me) return
@ -267,3 +220,50 @@ class SidebarXS extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
follows: { id: 'account.follows', defaultMessage: 'Following' },
profile: { id: 'account.profile', defaultMessage: 'Profile' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
lists: { id: 'column.lists', defaultMessage: 'Lists', },
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
more: { id: 'sidebar.more', defaultMessage: 'More' },
pro: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
trends: { id: 'promo.trends', defaultMessage: 'Trends' },
search: { id: 'tabs_bar.search', defaultMessage: 'Search' },
shop: { id: 'tabs_bar.shop', defaultMessage: 'Store - Buy Merch' },
chat: { id: 'tabs_bar.chat', defaultMessage: 'Chat' },
help: { id: 'getting_started.help', defaultMessage: 'Help' },
display: { id: 'display_options', defaultMessage: 'Display Options' },
proFeed: { id: 'pro_feed', defaultMessage: 'Pro Feed' },
shortcuts: { id: 'shortcuts', defaultMessage: 'Shortcuts' },
})
const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
sidebarOpen: state.get('sidebar').open,
})
const mapDispatchToProps = (dispatch) => ({
onCloseSidebar: () => dispatch(closeSidebar()),
onOpenDisplayModel() {
dispatch(closeSidebar())
dispatch(openModal('DISPLAY_OPTIONS'))
}
})
SidebarXS.propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map,
sidebarOpen: PropTypes.bool,
onCloseSidebar: PropTypes.func.isRequired,
onOpenDisplayModel: PropTypes.func.isRequired,
}
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SidebarXS))

View File

@ -6,22 +6,8 @@ import DotTextSeperator from '../components/dot_text_seperator'
import Icon from '../components/icon' import Icon from '../components/icon'
import Text from '../components/text' import Text from '../components/text'
const messages = defineMessages({
sortBy: { id: 'comment_sort.title', defaultMessage: 'Sort by' },
})
export default
@injectIntl
class SortBlock extends React.PureComponent { class SortBlock extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
value: PropTypes.string.isRequired,
subValue: PropTypes.string,
onClickValue: PropTypes.func.isRequired,
onClickSubValue: PropTypes.func,
}
handleOnClickValue = () => { handleOnClickValue = () => {
this.props.onClickValue(this.valueBtn) this.props.onClickValue(this.valueBtn)
} }
@ -91,3 +77,17 @@ class SortBlock extends React.PureComponent {
} }
} }
const messages = defineMessages({
sortBy: { id: 'comment_sort.title', defaultMessage: 'Sort by' },
})
SortBlock.propTypes = {
intl: PropTypes.object.isRequired,
value: PropTypes.string.isRequired,
subValue: PropTypes.string,
onClickValue: PropTypes.func.isRequired,
onClickSubValue: PropTypes.func,
}
export default injectIntl(SortBlock)

View File

@ -68,55 +68,12 @@ export const defaultMediaVisibility = (status) => {
return (displayMedia !== 'hide_all' && !status.get('sensitive')) || displayMedia === 'show_all' return (displayMedia !== 'hide_all' && !status.get('sensitive')) || displayMedia === 'show_all'
} }
export default
@injectIntl
class Status extends ImmutablePureComponent { class Status extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
descendantsIds: ImmutablePropTypes.list,
ancestorStatus: ImmutablePropTypes.map,
isNotification: PropTypes.bool,
isChild: PropTypes.bool,
isPromoted: PropTypes.bool,
isFeatured: PropTypes.bool,
isMuted: PropTypes.bool,
isHidden: PropTypes.bool,
isIntersecting: PropTypes.bool,
isComment: PropTypes.bool,
onClick: PropTypes.func,
onReply: PropTypes.func,
onRepost: PropTypes.func,
onQuote: PropTypes.func,
onFavorite: PropTypes.func,
onMention: PropTypes.func,
onOpenMedia: PropTypes.func,
onOpenVideo: PropTypes.func,
onHeightChange: PropTypes.func,
onToggleHidden: PropTypes.func,
onShare: PropTypes.func,
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
onFetchComments: PropTypes.func,
onFetchContext: PropTypes.func,
getScrollPosition: PropTypes.func,
updateScrollBottom: PropTypes.func,
cacheMediaWidth: PropTypes.func,
cachedMediaWidth: PropTypes.number,
contextType: PropTypes.string,
commentsLimited: PropTypes.bool,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onCommentSortOpen: PropTypes.func.isRequired,
isComposeModalOpen: PropTypes.bool,
commentSortingType: PropTypes.string,
}
// Avoid checking props that are functions (and whose equality will always // Avoid checking props that are functions (and whose equality will always
// evaluate to false. See react-immutable-pure-component for usage. // evaluate to false. See react-immutable-pure-component for usage.
updateOnProps = [ updateOnProps = [
@ -635,3 +592,46 @@ class Status extends ImmutablePureComponent {
} }
} }
Status.propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
descendantsIds: ImmutablePropTypes.list,
ancestorStatus: ImmutablePropTypes.map,
isNotification: PropTypes.bool,
isChild: PropTypes.bool,
isPromoted: PropTypes.bool,
isFeatured: PropTypes.bool,
isMuted: PropTypes.bool,
isHidden: PropTypes.bool,
isIntersecting: PropTypes.bool,
isComment: PropTypes.bool,
onClick: PropTypes.func,
onReply: PropTypes.func,
onRepost: PropTypes.func,
onQuote: PropTypes.func,
onFavorite: PropTypes.func,
onMention: PropTypes.func,
onOpenMedia: PropTypes.func,
onOpenVideo: PropTypes.func,
onHeightChange: PropTypes.func,
onToggleHidden: PropTypes.func,
onShare: PropTypes.func,
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
onFetchComments: PropTypes.func,
onFetchContext: PropTypes.func,
getScrollPosition: PropTypes.func,
updateScrollBottom: PropTypes.func,
cacheMediaWidth: PropTypes.func,
cachedMediaWidth: PropTypes.number,
contextType: PropTypes.string,
commentsLimited: PropTypes.bool,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
onCommentSortOpen: PropTypes.func.isRequired,
isComposeModalOpen: PropTypes.bool,
commentSortingType: PropTypes.string,
}
export default injectIntl(Status)

View File

@ -9,32 +9,8 @@ import Text from './text'
import StatusActionBarItem from './status_action_bar_item' import StatusActionBarItem from './status_action_bar_item'
import { CX } from '../constants' import { CX } from '../constants'
const messages = defineMessages({
comment: { id: 'status.comment', defaultMessage: 'Comment' },
quote: { id: 'status.quote', defaultMessage: 'Quote' },
repost: { id: 'status.repost', defaultMessage: 'Repost' },
cannot_repost: { id: 'status.cannot_repost', defaultMessage: 'This post cannot be reposted' },
like: { id: 'status.like', defaultMessage: 'Like' },
likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' },
repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' },
commentsLabel: { id: 'comments.label', defaultMessage: '{number, plural, one {# comment} other {# comments}}' },
})
export default
@injectIntl
class StatusActionBar extends ImmutablePureComponent { class StatusActionBar extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
onFavorite: PropTypes.func.isRequired,
onQuote: PropTypes.func.isRequired,
onReply: PropTypes.func.isRequired,
onRepost: PropTypes.func.isRequired,
status: ImmutablePropTypes.map.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
}
updateOnProps = ['status'] updateOnProps = ['status']
handleReplyClick = () => { handleReplyClick = () => {
@ -205,3 +181,27 @@ class StatusActionBar extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
comment: { id: 'status.comment', defaultMessage: 'Comment' },
quote: { id: 'status.quote', defaultMessage: 'Quote' },
repost: { id: 'status.repost', defaultMessage: 'Repost' },
cannot_repost: { id: 'status.cannot_repost', defaultMessage: 'This post cannot be reposted' },
like: { id: 'status.like', defaultMessage: 'Like' },
likesLabel: { id: 'likes.label', defaultMessage: '{number, plural, one {# like} other {# likes}}' },
repostsLabel: { id: 'reposts.label', defaultMessage: '{number, plural, one {# repost} other {# reposts}}' },
commentsLabel: { id: 'comments.label', defaultMessage: '{number, plural, one {# comment} other {# comments}}' },
})
StatusActionBar.propTypes = {
intl: PropTypes.object.isRequired,
onFavorite: PropTypes.func.isRequired,
onQuote: PropTypes.func.isRequired,
onReply: PropTypes.func.isRequired,
onRepost: PropTypes.func.isRequired,
status: ImmutablePropTypes.map.isRequired,
onOpenLikes: PropTypes.func.isRequired,
onOpenReposts: PropTypes.func.isRequired,
}
export default injectIntl(StatusActionBar)

View File

@ -8,20 +8,7 @@ import Responsive from '../features/ui/util/responsive_component'
import Button from './button' import Button from './button'
import Text from './text' import Text from './text'
export default class StatusActionBarItem extends React.PureComponent { class StatusActionBarItem extends React.PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
altTitle: PropTypes.string,
onClick: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
active: PropTypes.bool,
disabled: PropTypes.bool,
buttonRef: PropTypes.oneOf([
PropTypes.func,
PropTypes.node,
]),
}
render() { render() {
const { const {
@ -80,3 +67,18 @@ export default class StatusActionBarItem extends React.PureComponent {
} }
} }
StatusActionBarItem.propTypes = {
title: PropTypes.string.isRequired,
altTitle: PropTypes.string,
onClick: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
active: PropTypes.bool,
disabled: PropTypes.bool,
buttonRef: PropTypes.oneOf([
PropTypes.func,
PropTypes.node,
]),
}
export default StatusActionBarItem

View File

@ -56,15 +56,7 @@ const addAutoPlay = html => {
return html return html
} }
export default class StatusCard extends ImmutablePureComponent { class StatusCard extends ImmutablePureComponent {
static propTypes = {
card: ImmutablePropTypes.map,
onOpenMedia: PropTypes.func.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
isReduced: PropTypes.bool,
}
state = { state = {
width: this.props.defaultWidth || 280, width: this.props.defaultWidth || 280,
@ -263,3 +255,13 @@ export default class StatusCard extends ImmutablePureComponent {
} }
} }
StatusCard.propTypes = {
card: ImmutablePropTypes.map,
onOpenMedia: PropTypes.func.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
isReduced: PropTypes.bool,
}
export default StatusCard

View File

@ -11,28 +11,8 @@ import Bundle from '../features/ui/util/bundle';
import StatusContent from './status_content'; import StatusContent from './status_content';
import Switch from './switch'; import Switch from './switch';
const mapStateToProps = (state, { id }) => ({
status: state.getIn(['statuses', id]),
checked: state.getIn(['reports', 'new', 'status_ids'], ImmutableSet()).includes(id),
});
const mapDispatchToProps = (dispatch, { id }) => ({
onToggle(e) {
dispatch(toggleStatusReport(id, e.target.checked));
},
});
export default
@connect(mapStateToProps, mapDispatchToProps)
class StatusCheckBox extends ImmutablePureComponent { class StatusCheckBox extends ImmutablePureComponent {
static propTypes = {
status: ImmutablePropTypes.map.isRequired,
checked: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
disabled: PropTypes.bool,
};
render () { render () {
const { status, checked, onToggle, disabled } = this.props; const { status, checked, onToggle, disabled } = this.props;
let media = null; let media = null;
@ -87,3 +67,23 @@ class StatusCheckBox extends ImmutablePureComponent {
} }
} }
const mapStateToProps = (state, { id }) => ({
status: state.getIn(['statuses', id]),
checked: state.getIn(['reports', 'new', 'status_ids'], ImmutableSet()).includes(id),
})
const mapDispatchToProps = (dispatch, { id }) => ({
onToggle(e) {
dispatch(toggleStatusReport(id, e.target.checked))
},
})
StatusCheckBox.propTypes = {
status: ImmutablePropTypes.map.isRequired,
checked: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
disabled: PropTypes.bool,
}
export default connect(mapStateToProps, mapDispatchToProps)(StatusCheckBox)

View File

@ -11,38 +11,14 @@ import Text from './text'
const MAX_HEIGHT = 200 const MAX_HEIGHT = 200
const messages = defineMessages({
show: { id: 'status.show_more', defaultMessage: 'Show' },
hide: { id: 'status.show_less', defaultMessage: 'Hide' },
readMore: { id: 'status.read_more', defaultMessage: 'Read more' },
})
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
// .emojione {
// margin: -3px 0 0;
// @include size(20px);
// }
export default
@injectIntl
class StatusContent extends ImmutablePureComponent { class StatusContent extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
} }
static propTypes = {
status: ImmutablePropTypes.map.isRequired,
expanded: PropTypes.bool,
onExpandedToggle: PropTypes.func,
onClick: PropTypes.func,
collapsable: PropTypes.bool,
intl: PropTypes.object.isRequired,
isComment: PropTypes.bool,
}
state = { state = {
hidden: true, hidden: true,
collapsed: null, // `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't). collapsed: null, // `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't).
@ -353,3 +329,21 @@ class StatusContent extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
show: { id: 'status.show_more', defaultMessage: 'Show' },
hide: { id: 'status.show_less', defaultMessage: 'Hide' },
readMore: { id: 'status.read_more', defaultMessage: 'Read more' },
})
StatusContent.propTypes = {
status: ImmutablePropTypes.map.isRequired,
expanded: PropTypes.bool,
onExpandedToggle: PropTypes.func,
onClick: PropTypes.func,
collapsable: PropTypes.bool,
intl: PropTypes.object.isRequired,
isComment: PropTypes.bool,
}
export default injectIntl(StatusContent)

View File

@ -18,47 +18,10 @@ import Icon from './icon'
import Button from './button' import Button from './button'
import Avatar from './avatar' import Avatar from './avatar'
const messages = defineMessages({
edited: { id: 'status.edited', defaultMessage: 'Edited' },
expirationMessage: { id: 'status.expiration_message', defaultMessage: 'This status expires {time}' },
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
public_long: { id: 'privacy.public.long', defaultMessage: 'Visible for anyone on or off Gab' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Do not show in public timelines' },
private_long: { id: 'privacy.private.long', defaultMessage: 'Visible for your followers only' },
})
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
const mapDispatchToProps = (dispatch) => ({
onOpenStatusRevisionsPopover(status) {
dispatch(openModal('STATUS_REVISIONS', {
status,
}))
},
onOpenStatusOptionsPopover(targetRef, status) {
dispatch(openPopover('STATUS_OPTIONS', {
targetRef,
status,
position: 'left-start',
}))
},
})
export default
@injectIntl
@connect(null, mapDispatchToProps)
class StatusHeader extends ImmutablePureComponent { class StatusHeader extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
onOpenStatusRevisionsPopover: PropTypes.func.isRequired,
onOpenStatusOptionsPopover: PropTypes.func.isRequired,
reduced: PropTypes.bool,
}
handleOpenStatusOptionsPopover = () => { handleOpenStatusOptionsPopover = () => {
this.props.onOpenStatusOptionsPopover(this.statusOptionsButton, this.props.status) this.props.onOpenStatusOptionsPopover(this.statusOptionsButton, this.props.status)
} }
@ -230,3 +193,39 @@ class StatusHeader extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
edited: { id: 'status.edited', defaultMessage: 'Edited' },
expirationMessage: { id: 'status.expiration_message', defaultMessage: 'This status expires {time}' },
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
public_long: { id: 'privacy.public.long', defaultMessage: 'Visible for anyone on or off Gab' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Do not show in public timelines' },
private_long: { id: 'privacy.private.long', defaultMessage: 'Visible for your followers only' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenStatusRevisionsPopover(status) {
dispatch(openModal('STATUS_REVISIONS', {
status,
}))
},
onOpenStatusOptionsPopover(targetRef, status) {
dispatch(openPopover('STATUS_OPTIONS', {
targetRef,
status,
position: 'left-start',
}))
},
})
StatusHeader.propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
onOpenStatusRevisionsPopover: PropTypes.func.isRequired,
onOpenStatusOptionsPopover: PropTypes.func.isRequired,
reduced: PropTypes.bool,
}
export default injectIntl(connect(null, mapDispatchToProps)(StatusHeader))

View File

@ -15,97 +15,8 @@ import StatusPlaceholder from './placeholder/status_placeholder'
import ScrollableList from './scrollable_list' import ScrollableList from './scrollable_list'
import TimelineQueueButtonHeader from './timeline_queue_button_header' import TimelineQueueButtonHeader from './timeline_queue_button_header'
const makeGetStatusIds = () => createSelector([
(state, { type, id }) => state.getIn(['settings', type], ImmutableMap()),
(state, { type, id }) => state.getIn(['timelines', id, 'items'], ImmutableList()),
(state) => state.get('statuses'),
], (columnSettings, statusIds, statuses) => {
return statusIds.filter(id => {
if (id === null) return true
const statusForId = statuses.get(id)
let showStatus = true
if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null
}
if (columnSettings.getIn(['shows', 'reply']) === false) {
showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me)
}
return showStatus
})
})
const mapStateToProps = (state, { timelineId }) => {
if (!timelineId) return {}
const getStatusIds = makeGetStatusIds()
const statusIds = getStatusIds(state, {
type: timelineId.substring(0, 5) === 'group' ? 'group' : timelineId,
id: timelineId
})
const promotedStatuses = Array.isArray(promotions) ?
promotions.map((block) => {
const s = {}
s[block.status_id] = state.getIn(['statuses', block.status_id])
return s
}) : []
return {
statusIds,
promotedStatuses,
isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
totalQueuedItemsCount: state.getIn(['timelines', timelineId, 'totalQueuedItemsCount']),
}
}
const mapDispatchToProps = (dispatch, ownProps) => ({
onDequeueTimeline(timelineId) {
dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore))
},
onScrollToTop: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, true))
}, 100),
onScroll: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, false))
}, 100),
onFetchContext(statusId) {
dispatch(fetchContext(statusId, true))
},
onFetchStatus(statusId) {
dispatch(fetchStatus(statusId))
},
})
export default
@connect(mapStateToProps, mapDispatchToProps)
class StatusList extends ImmutablePureComponent { class StatusList extends ImmutablePureComponent {
static propTypes = {
scrollKey: PropTypes.string.isRequired,
statusIds: ImmutablePropTypes.list.isRequired,
featuredStatusIds: ImmutablePropTypes.list,
onLoadMore: PropTypes.func,
isLoading: PropTypes.bool,
isPartial: PropTypes.bool,
hasMore: PropTypes.bool,
emptyMessage: PropTypes.string,
timelineId: PropTypes.string,
queuedItemSize: PropTypes.number,
onDequeueTimeline: PropTypes.func.isRequired,
onScrollToTop: PropTypes.func.isRequired,
onScroll: PropTypes.func.isRequired,
onFetchContext: PropTypes.func.isRequired,
onFetchStatus: PropTypes.func.isRequired,
promotedStatuses: PropTypes.object,
}
state = { state = {
refreshing: false, refreshing: false,
fetchedContext: false, fetchedContext: false,
@ -342,3 +253,92 @@ class StatusList extends ImmutablePureComponent {
} }
} }
const makeGetStatusIds = () => createSelector([
(state, { type, id }) => state.getIn(['settings', type], ImmutableMap()),
(state, { type, id }) => state.getIn(['timelines', id, 'items'], ImmutableList()),
(state) => state.get('statuses'),
], (columnSettings, statusIds, statuses) => {
return statusIds.filter(id => {
if (id === null) return true
const statusForId = statuses.get(id)
let showStatus = true
if (columnSettings.getIn(['shows', 'reblog']) === false) {
showStatus = showStatus && statusForId.get('reblog') === null
}
if (columnSettings.getIn(['shows', 'reply']) === false) {
showStatus = showStatus && (statusForId.get('in_reply_to_id') === null || statusForId.get('in_reply_to_account_id') === me)
}
return showStatus
})
})
const mapStateToProps = (state, { timelineId }) => {
if (!timelineId) return {}
const getStatusIds = makeGetStatusIds()
const statusIds = getStatusIds(state, {
type: timelineId.substring(0, 5) === 'group' ? 'group' : timelineId,
id: timelineId
})
const promotedStatuses = Array.isArray(promotions) ?
promotions.map((block) => {
const s = {}
s[block.status_id] = state.getIn(['statuses', block.status_id])
return s
}) : []
return {
statusIds,
promotedStatuses,
isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
hasMore: state.getIn(['timelines', timelineId, 'hasMore']),
totalQueuedItemsCount: state.getIn(['timelines', timelineId, 'totalQueuedItemsCount']),
}
}
const mapDispatchToProps = (dispatch, ownProps) => ({
onDequeueTimeline(timelineId) {
dispatch(dequeueTimeline(timelineId, ownProps.onLoadMore))
},
onScrollToTop: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, true))
}, 100),
onScroll: debounce(() => {
dispatch(scrollTopTimeline(ownProps.timelineId, false))
}, 100),
onFetchContext(statusId) {
dispatch(fetchContext(statusId, true))
},
onFetchStatus(statusId) {
dispatch(fetchStatus(statusId))
},
})
StatusList.propTypes = {
scrollKey: PropTypes.string.isRequired,
statusIds: ImmutablePropTypes.list.isRequired,
featuredStatusIds: ImmutablePropTypes.list,
onLoadMore: PropTypes.func,
isLoading: PropTypes.bool,
isPartial: PropTypes.bool,
hasMore: PropTypes.bool,
emptyMessage: PropTypes.string,
timelineId: PropTypes.string,
queuedItemSize: PropTypes.number,
onDequeueTimeline: PropTypes.func.isRequired,
onScrollToTop: PropTypes.func.isRequired,
onScroll: PropTypes.func.isRequired,
onFetchContext: PropTypes.func.isRequired,
onFetchStatus: PropTypes.func.isRequired,
promotedStatuses: PropTypes.object,
}
export default connect(mapStateToProps, mapDispatchToProps)(StatusList)

View File

@ -11,22 +11,7 @@ import Poll from './poll'
// to use the progress bar to show download progress // to use the progress bar to show download progress
import Bundle from '../features/ui/util/bundle' import Bundle from '../features/ui/util/bundle'
export default class StatusMedia extends ImmutablePureComponent { class StatusMedia extends ImmutablePureComponent {
static propTypes = {
status: ImmutablePropTypes.map,
isChild: PropTypes.bool,
isComment: PropTypes.bool,
onOpenMedia: PropTypes.func,
onOpenVideo: PropTypes.func,
width: PropTypes.number,
onToggleVisibility: PropTypes.func,
visible: PropTypes.bool,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.number,
isComposeModalOpen: PropTypes.bool,
isStatusCard: PropTypes.bool,
}
// Avoid checking props that are functions (and whose equality will always // Avoid checking props that are functions (and whose equality will always
// evaluate to false. See react-immutable-pure-component for usage. // evaluate to false. See react-immutable-pure-component for usage.
@ -130,3 +115,20 @@ export default class StatusMedia extends ImmutablePureComponent {
} }
} }
StatusMedia.propTypes = {
status: ImmutablePropTypes.map,
isChild: PropTypes.bool,
isComment: PropTypes.bool,
onOpenMedia: PropTypes.func,
onOpenVideo: PropTypes.func,
width: PropTypes.number,
onToggleVisibility: PropTypes.func,
visible: PropTypes.bool,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.number,
isComposeModalOpen: PropTypes.bool,
isStatusCard: PropTypes.bool,
}
export default StatusMedia

View File

@ -7,25 +7,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
import Icon from './icon' import Icon from './icon'
import Text from './text' import Text from './text'
const messages = defineMessages({
filtered: { id: 'status.filtered', defaultMessage: 'Filtered' },
promoted: { id: 'status.promoted', defaultMessage: 'Promoted gab' },
pinned: { id: 'status.pinned', defaultMessage: 'Pinned gab' },
reposted: { id: 'status.reposted_by', defaultMessage: '{name} reposted' },
})
export default
@injectIntl
class StatusPrepend extends ImmutablePureComponent { class StatusPrepend extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
isComment: PropTypes.bool,
isFeatured: PropTypes.bool,
isPromoted: PropTypes.bool,
}
render() { render() {
const { const {
intl, intl,
@ -111,3 +94,20 @@ class StatusPrepend extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
filtered: { id: 'status.filtered', defaultMessage: 'Filtered' },
promoted: { id: 'status.promoted', defaultMessage: 'Promoted gab' },
pinned: { id: 'status.pinned', defaultMessage: 'Pinned gab' },
reposted: { id: 'status.reposted_by', defaultMessage: '{name} reposted' },
})
StatusPrepend.propTypes = {
intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map,
isComment: PropTypes.bool,
isFeatured: PropTypes.bool,
isPromoted: PropTypes.bool,
}
export default injectIntl(StatusPrepend)

View File

@ -9,23 +9,11 @@ import Button from '../../../../components/button';
import DisplayName from '../../../../components/display_name'; import DisplayName from '../../../../components/display_name';
import { isRtl } from '../../../../utils/rtl'; import { isRtl } from '../../../../utils/rtl';
const messages = defineMessages({
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
});
export default
@injectIntl
class ReplyIndicator extends ImmutablePureComponent { class ReplyIndicator extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
}; }
static propTypes = {
status: ImmutablePropTypes.map,
onCancel: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
handleClick = () => { handleClick = () => {
this.props.onCancel(); this.props.onCancel();
@ -64,3 +52,15 @@ class ReplyIndicator extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
})
ReplyIndicator.propTypes = {
status: ImmutablePropTypes.map,
onCancel: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
}
export default injectIntl(ReplyIndicator)

View File

@ -3,18 +3,7 @@ import PropTypes from 'prop-types'
import { CX } from '../constants' import { CX } from '../constants'
import Text from './text' import Text from './text'
export default class Switch extends React.PureComponent { class Switch extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
description: PropTypes.string,
label: PropTypes.string,
checked: PropTypes.bool,
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
disabled: PropTypes.bool,
labelProps: PropTypes.object,
}
render() { render() {
const { const {
@ -69,3 +58,16 @@ export default class Switch extends React.PureComponent {
} }
} }
Switch.propTypes = {
id: PropTypes.string.isRequired,
description: PropTypes.string,
label: PropTypes.string,
checked: PropTypes.bool,
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
disabled: PropTypes.bool,
labelProps: PropTypes.object,
}
export default Switch

View File

@ -8,12 +8,7 @@ import TabBarItem from './tab_bar_item'
* @param {array} [props.tabs] - tab bar data for creating `TabBarItem` * @param {array} [props.tabs] - tab bar data for creating `TabBarItem`
* @param {bool} [props.isLarge] - to style the tab bar larger * @param {bool} [props.isLarge] - to style the tab bar larger
*/ */
export default class TabBar extends React.PureComponent { class TabBar extends React.PureComponent {
static propTypes = {
tabs: PropTypes.array,
isLarge: PropTypes.bool,
}
render() { render() {
const { tabs, isLarge } = this.props const { tabs, isLarge } = this.props
@ -43,3 +38,10 @@ export default class TabBar extends React.PureComponent {
} }
} }
TabBar.propTypes = {
tabs: PropTypes.array,
isLarge: PropTypes.bool,
}
export default TabBar

View File

@ -13,18 +13,8 @@ import Text from './text'
* @param {string} [props.title] - title to use * @param {string} [props.title] - title to use
* @param {string} [props.to] - location to direct to on click * @param {string} [props.to] - location to direct to on click
*/ */
export default
@withRouter
class TabBarItem extends React.PureComponent { class TabBarItem extends React.PureComponent {
static propTypes = {
isLarge: PropTypes.bool,
isActive: PropTypes.bool,
onClick: PropTypes.func,
title: PropTypes.string,
to: PropTypes.string,
}
state = { state = {
isCurrent: false, isCurrent: false,
} }
@ -117,3 +107,13 @@ class TabBarItem extends React.PureComponent {
} }
} }
TabBarItem.propTypes = {
isLarge: PropTypes.bool,
isActive: PropTypes.bool,
onClick: PropTypes.func,
title: PropTypes.string,
to: PropTypes.string,
}
export default withRouter(TabBarItem)

View File

@ -53,28 +53,7 @@ const ALIGNMENTS = {
* @param {string} [props.tagName='span'] tagName of the text element * @param {string} [props.tagName='span'] tagName of the text element
* @param {string} [props.weight='normal'] weight of the text * @param {string} [props.weight='normal'] weight of the text
*/ */
export default class Text extends React.PureComponent { class Text extends React.PureComponent {
static propTypes = {
align: PropTypes.oneOf(Object.keys(ALIGNMENTS)),
isBadge: PropTypes.bool,
children: PropTypes.any,
className: PropTypes.string,
color: PropTypes.oneOf(Object.keys(COLORS)),
hasUnderline: PropTypes.bool,
htmlFor: PropTypes.string,
size: PropTypes.oneOf(Object.keys(SIZES)),
tagName: PropTypes.string,
weight: PropTypes.oneOf(Object.keys(WEIGHTS)),
}
static defaultProps = {
tagName: 'span',
align: ALIGNMENTS.left,
color: COLORS.primary,
size: SIZES.normal,
weight: WEIGHTS.normal,
}
render() { render() {
const { const {
@ -136,3 +115,26 @@ export default class Text extends React.PureComponent {
} }
} }
Text.propTypes = {
align: PropTypes.oneOf(Object.keys(ALIGNMENTS)),
isBadge: PropTypes.bool,
children: PropTypes.any,
className: PropTypes.string,
color: PropTypes.oneOf(Object.keys(COLORS)),
hasUnderline: PropTypes.bool,
htmlFor: PropTypes.string,
size: PropTypes.oneOf(Object.keys(SIZES)),
tagName: PropTypes.string,
weight: PropTypes.oneOf(Object.keys(WEIGHTS)),
}
Text.defaultProps = {
tagName: 'span',
align: ALIGNMENTS.left,
color: COLORS.primary,
size: SIZES.normal,
weight: WEIGHTS.normal,
}
export default Text

View File

@ -5,17 +5,7 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class Textarea extends React.PureComponent { class Textarea extends React.PureComponent {
static propTypes = {
placeholder: PropTypes.string,
prependIcon: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
onKeyUp: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
title: PropTypes.string,
}
handleOnChange = (e) => { handleOnChange = (e) => {
this.props.onChange(e.target.value) this.props.onChange(e.target.value)
@ -76,3 +66,16 @@ export default class Textarea extends React.PureComponent {
) )
} }
} }
Textarea.propTypes = {
placeholder: PropTypes.string,
prependIcon: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
onKeyUp: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
title: PropTypes.string,
}
export default Textarea

View File

@ -12,30 +12,8 @@ import Responsive from '../features/ui/util/responsive_component'
import Avatar from './avatar' import Avatar from './avatar'
import Heading from './heading' import Heading from './heading'
const messages = defineMessages({
createPost: { id: 'column_header.create_post', defaultMessage: 'Create Post' },
})
const mapStateToProps = (state) => ({
account: state.getIn(['accounts', me]),
})
export default
@connect(mapStateToProps)
@injectIntl
class TimelineComposeBlock extends ImmutablePureComponent { class TimelineComposeBlock extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map.isRequired,
size: PropTypes.number,
modal: PropTypes.bool,
}
static defaultProps = {
size: 32,
}
render() { render() {
const { const {
account, account,
@ -78,3 +56,24 @@ class TimelineComposeBlock extends ImmutablePureComponent {
} }
} }
const messages = defineMessages({
createPost: { id: 'column_header.create_post', defaultMessage: 'Create Post' },
})
const mapStateToProps = (state) => ({
account: state.getIn(['accounts', me]),
})
TimelineComposeBlock.propTypes = {
intl: PropTypes.object.isRequired,
account: ImmutablePropTypes.map.isRequired,
size: PropTypes.number,
modal: PropTypes.bool,
}
TimelineComposeBlock.defaultProps = {
size: 32,
}
export default injectIntl(connect(mapStateToProps)(TimelineComposeBlock))

View File

@ -10,19 +10,7 @@ import Text from './text'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
export default class TimelineQueueButtonHeader extends React.PureComponent { class TimelineQueueButtonHeader extends React.PureComponent {
static propTypes = {
onClick: PropTypes.func.isRequired,
count: PropTypes.number,
itemType: PropTypes.string,
floating: PropTypes.bool,
}
static defaultProps = {
count: 0,
itemType: 'item',
}
state = { state = {
onVisibleOffset: 0, onVisibleOffset: 0,
@ -134,3 +122,17 @@ export default class TimelineQueueButtonHeader extends React.PureComponent {
} }
} }
TimelineQueueButtonHeader.propTypes = {
onClick: PropTypes.func.isRequired,
count: PropTypes.number,
itemType: PropTypes.string,
floating: PropTypes.bool,
}
TimelineQueueButtonHeader.defaultProps = {
count: 0,
itemType: 'item',
}
export default TimelineQueueButtonHeader

View File

@ -10,26 +10,7 @@ import DotTextSeperator from './dot_text_seperator'
import RelativeTimestamp from './relative_timestamp' import RelativeTimestamp from './relative_timestamp'
import Text from './text' import Text from './text'
export default class TrendingItem extends React.PureComponent { class TrendingItem extends React.PureComponent {
static propTypes = {
index: PropTypes.number,
isLast: PropTypes.bool,
isHidden: PropTypes.bool,
title: PropTypes.string,
description: PropTypes.string,
author: PropTypes.string,
url: PropTypes.string,
date: PropTypes.string,
}
static defaultProps = {
title: '',
description: '',
author: '',
url: '',
date: '',
}
state = { state = {
hovering: false, hovering: false,
@ -142,3 +123,24 @@ export default class TrendingItem extends React.PureComponent {
} }
} }
TrendingItem.propTypes = {
index: PropTypes.number,
isLast: PropTypes.bool,
isHidden: PropTypes.bool,
title: PropTypes.string,
description: PropTypes.string,
author: PropTypes.string,
url: PropTypes.string,
date: PropTypes.string,
}
TrendingItem.defaultProps = {
title: '',
description: '',
author: '',
url: '',
date: '',
}
export default TrendingItem

View File

@ -9,16 +9,8 @@ const messages = defineMessages({
title: { id: 'upload_area.title', defaultMessage: 'Drag & drop to upload' }, title: { id: 'upload_area.title', defaultMessage: 'Drag & drop to upload' },
}) })
export default
@injectIntl
class UploadArea extends React.PureComponent { class UploadArea extends React.PureComponent {
static propTypes = {
active: PropTypes.bool,
onClose: PropTypes.func,
intl: PropTypes.object.isRequired,
}
handleKeyUp = (e) => { handleKeyUp = (e) => {
if (!this.props.active) return if (!this.props.active) return
@ -82,3 +74,11 @@ class UploadArea extends React.PureComponent {
} }
} }
UploadArea.propTypes = {
active: PropTypes.bool,
onClose: PropTypes.func,
intl: PropTypes.object.isRequired,
}
export default injectIntl(UploadArea)

View File

@ -10,18 +10,7 @@ import Text from './text'
* @param {string} props.to - location to go to on click * @param {string} props.to - location to go to on click
* @param {string} props.value - top value * @param {string} props.value - top value
*/ */
export default class UserStat extends React.PureComponent { class UserStat extends React.PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
to: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.object,
]).isRequired,
isCentered: PropTypes.bool.isRequired,
}
state = { state = {
hovering: false, hovering: false,
@ -73,3 +62,16 @@ export default class UserStat extends React.PureComponent {
} }
} }
UserStat.propTypes = {
title: PropTypes.string.isRequired,
to: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.object,
]).isRequired,
isCentered: PropTypes.bool.isRequired,
}
export default UserStat

View File

@ -28,20 +28,6 @@ import Text from './text'
const checkInterval = 100 const checkInterval = 100
const FIXED_VAR = 6 const FIXED_VAR = 6
const messages = defineMessages({
play: { id: 'video.play', defaultMessage: 'Play' },
pause: { id: 'video.pause', defaultMessage: 'Pause' },
mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
hide: { id: 'video.hide', defaultMessage: 'Hide video' },
fullscreen: { id: 'video.fullscreen', defaultMessage: 'Full screen' },
exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' },
sensitive: { id: 'status.sensitive_warning', defaultMessage: 'Sensitive content' },
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
video_stats: { id: 'video.stats_label', defaultMessage: 'Video meta stats' },
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide media' },
})
const formatTime = (secondsNum) => { const formatTime = (secondsNum) => {
if (isNaN(secondsNum)) secondsNum = 0 if (isNaN(secondsNum)) secondsNum = 0
@ -109,41 +95,8 @@ export const getPointerPosition = (el, event) => {
return position return position
} }
const mapDispatchToProps = (dispatch) => ({
onOpenVideoStatsPopover(targetRef, meta) {
dispatch(openPopover(POPOVER_VIDEO_STATS, {
targetRef,
meta,
position: 'top',
}))
}
})
export default
@injectIntl
@connect(null, mapDispatchToProps)
class Video extends ImmutablePureComponent { class Video extends ImmutablePureComponent {
static propTypes = {
preview: PropTypes.string,
src: PropTypes.string.isRequired,
alt: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
sensitive: PropTypes.bool,
startTime: PropTypes.number,
detailed: PropTypes.bool,
inline: PropTypes.bool,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
intl: PropTypes.object.isRequired,
blurhash: PropTypes.string,
aspectRatio: PropTypes.number,
meta: ImmutablePropTypes.map,
onOpenVideoStatsPopover: PropTypes.func.isRequired,
}
state = { state = {
currentTime: 0, currentTime: 0,
duration: 0, duration: 0,
@ -832,3 +785,50 @@ class Video extends ImmutablePureComponent {
) )
} }
} }
const messages = defineMessages({
play: { id: 'video.play', defaultMessage: 'Play' },
pause: { id: 'video.pause', defaultMessage: 'Pause' },
mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
hide: { id: 'video.hide', defaultMessage: 'Hide video' },
fullscreen: { id: 'video.fullscreen', defaultMessage: 'Full screen' },
exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' },
sensitive: { id: 'status.sensitive_warning', defaultMessage: 'Sensitive content' },
hidden: { id: 'status.media_hidden', defaultMessage: 'Media hidden' },
video_stats: { id: 'video.stats_label', defaultMessage: 'Video meta stats' },
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide media' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenVideoStatsPopover(targetRef, meta) {
dispatch(openPopover(POPOVER_VIDEO_STATS, {
targetRef,
meta,
position: 'top',
}))
}
})
Video.propTypes = {
preview: PropTypes.string,
src: PropTypes.string.isRequired,
alt: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
sensitive: PropTypes.bool,
startTime: PropTypes.number,
detailed: PropTypes.bool,
inline: PropTypes.bool,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
intl: PropTypes.object.isRequired,
blurhash: PropTypes.string,
aspectRatio: PropTypes.number,
meta: ImmutablePropTypes.map,
onOpenVideoStatsPopover: PropTypes.func.isRequired,
}
export default injectIntl(connect(null, mapDispatchToProps)(Video))

View File

@ -17,21 +17,7 @@ const clamp = (min, max, value) => {
return Math.min(max, Math.max(min, value)) return Math.min(max, Math.max(min, value))
} }
export default class ZoomableImage extends React.PureComponent { class ZoomableImage extends React.PureComponent {
static propTypes = {
alt: PropTypes.string,
src: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
}
static defaultProps = {
alt: '',
width: null,
height: null,
}
state = { state = {
scale: MIN_SCALE, scale: MIN_SCALE,
@ -155,3 +141,19 @@ export default class ZoomableImage extends React.PureComponent {
} }
} }
ZoomableImage.propTypes = {
alt: PropTypes.string,
src: PropTypes.string.isRequired,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
}
ZoomableImage.defaultProps = {
alt: '',
width: null,
height: null,
}
export default ZoomableImage

View File

@ -37,10 +37,6 @@ class ListsDirectory extends ImmutablePureComponent {
fetched: false, fetched: false,
} }
updateOnProps = [
'lists',
]
componentDidMount() { componentDidMount() {
this.props.onFetchLists() this.props.onFetchLists()
.then(() => this.setState({ fetched: true })) .then(() => this.setState({ fetched: true }))

View File

@ -52,12 +52,6 @@ class News extends React.PureComponent {
activeDomain: null, activeDomain: null,
} }
updateOnProps = [
'items',
'isLoading',
'isError',
]
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) { if (this.props.location !== prevProps.location) {
this.setActiveDomain(this.props.location) this.setActiveDomain(this.props.location)

Some files were not shown because too many files have changed in this diff Show More