Convert ActionButton to TSX
This commit is contained in:
parent
870f78e413
commit
8dc7cc8794
8 changed files with 174 additions and 198 deletions
|
@ -3,7 +3,7 @@ import { Link, useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
|
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
|
||||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||||
import { useAppSelector, useOnScreen } from 'soapbox/hooks';
|
import { useAppSelector, useOnScreen } from 'soapbox/hooks';
|
||||||
import { getAcct } from 'soapbox/utils/accounts';
|
import { getAcct } from 'soapbox/utils/accounts';
|
||||||
import { displayFqn } from 'soapbox/utils/state';
|
import { displayFqn } from 'soapbox/utils/state';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
updateProfileHoverCard,
|
updateProfileHoverCard,
|
||||||
} from 'soapbox/actions/profile_hover_card';
|
} from 'soapbox/actions/profile_hover_card';
|
||||||
import Badge from 'soapbox/components/badge';
|
import Badge from 'soapbox/components/badge';
|
||||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||||
import { UserPanel } from 'soapbox/features/ui/util/async-components';
|
import { UserPanel } from 'soapbox/features/ui/util/async-components';
|
||||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||||
|
|
|
@ -16,7 +16,7 @@ import Badge from 'soapbox/components/badge';
|
||||||
import StillImage from 'soapbox/components/still_image';
|
import StillImage from 'soapbox/components/still_image';
|
||||||
import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, MenuDivider } from 'soapbox/components/ui';
|
import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, MenuDivider } from 'soapbox/components/ui';
|
||||||
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
||||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||||
import {
|
import {
|
||||||
isLocal,
|
isLocal,
|
||||||
isRemote,
|
isRemote,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import DisplayName from 'soapbox/components/display_name';
|
||||||
import Permalink from 'soapbox/components/permalink';
|
import Permalink from 'soapbox/components/permalink';
|
||||||
import RelativeTimestamp from 'soapbox/components/relative_timestamp';
|
import RelativeTimestamp from 'soapbox/components/relative_timestamp';
|
||||||
import { Text } from 'soapbox/components/ui';
|
import { Text } from 'soapbox/components/ui';
|
||||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||||
import { makeGetAccount } from 'soapbox/selectors';
|
import { makeGetAccount } from 'soapbox/selectors';
|
||||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||||
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
import SoapboxPropTypes from 'soapbox/utils/soapbox_prop_types';
|
||||||
|
@ -82,4 +82,4 @@ class AccountCard extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import Avatar from 'soapbox/components/avatar';
|
import Avatar from 'soapbox/components/avatar';
|
||||||
import DisplayName from 'soapbox/components/display_name';
|
import DisplayName from 'soapbox/components/display_name';
|
||||||
import Permalink from 'soapbox/components/permalink';
|
import Permalink from 'soapbox/components/permalink';
|
||||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||||
import { useAppSelector } from 'soapbox/hooks';
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
import { makeGetAccount } from 'soapbox/selectors';
|
import { makeGetAccount } from 'soapbox/selectors';
|
||||||
|
|
||||||
|
|
168
app/soapbox/features/ui/components/action-button.tsx
Normal file
168
app/soapbox/features/ui/components/action-button.tsx
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import {
|
||||||
|
followAccount,
|
||||||
|
unfollowAccount,
|
||||||
|
blockAccount,
|
||||||
|
unblockAccount,
|
||||||
|
muteAccount,
|
||||||
|
unmuteAccount,
|
||||||
|
} from 'soapbox/actions/accounts';
|
||||||
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
|
import { Button } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||||
|
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||||
|
remote_follow: { id: 'account.remote_follow', defaultMessage: 'Remote follow' },
|
||||||
|
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
||||||
|
requested_small: { id: 'account.requested_small', defaultMessage: 'Awaiting approval' },
|
||||||
|
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||||
|
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||||
|
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||||
|
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IAccount {
|
||||||
|
account: AccountEntity
|
||||||
|
small?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActionButton = ({ account, small }: IAccount) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const features = useFeatures();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const me = useAppSelector((state) => state.me);
|
||||||
|
|
||||||
|
const handleFollow = () => {
|
||||||
|
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||||
|
dispatch(unfollowAccount(account.get('id')));
|
||||||
|
} else {
|
||||||
|
dispatch(followAccount(account.get('id')));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlock = () => {
|
||||||
|
if (account.getIn(['relationship', 'blocking'])) {
|
||||||
|
dispatch(unblockAccount(account.get('id')));
|
||||||
|
} else {
|
||||||
|
dispatch(blockAccount(account.get('id')));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMute = () => {
|
||||||
|
if (account.getIn(['relationship', 'muting'])) {
|
||||||
|
dispatch(unmuteAccount(account.get('id')));
|
||||||
|
} else {
|
||||||
|
dispatch(muteAccount(account.get('id')));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoteFollow = () => {
|
||||||
|
dispatch(openModal('UNAUTHORIZED', {
|
||||||
|
action: 'FOLLOW',
|
||||||
|
account: account.get('id'),
|
||||||
|
ap_id: account.get('url'),
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const empty = <></>;
|
||||||
|
|
||||||
|
if (!me) {
|
||||||
|
// Remote follow
|
||||||
|
if (features.remoteInteractionsAPI) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={handleRemoteFollow}
|
||||||
|
icon={require('@tabler/icons/icons/plus.svg')}
|
||||||
|
text={intl.formatMessage(messages.follow)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form method='POST' action='/main/ostatus'>
|
||||||
|
<input type='hidden' name='nickname' value={account.get('acct')} />
|
||||||
|
<input type='hidden' name='profile' value='' />
|
||||||
|
<Button text={intl.formatMessage(messages.remote_follow)} type='submit' />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me !== account.get('id')) {
|
||||||
|
const isFollowing = account.getIn(['relationship', 'following']);
|
||||||
|
const blockedBy = account.getIn(['relationship', 'blocked_by']) as boolean;
|
||||||
|
|
||||||
|
if (!account.get('relationship')) {
|
||||||
|
// Wait until the relationship is loaded
|
||||||
|
return empty;
|
||||||
|
} else if (account.getIn(['relationship', 'requested'])) {
|
||||||
|
// Awaiting acceptance
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size='sm'
|
||||||
|
theme='secondary'
|
||||||
|
text={small ? intl.formatMessage(messages.requested_small) : intl.formatMessage(messages.requested)}
|
||||||
|
onClick={handleFollow}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (!account.getIn(['relationship', 'blocking']) && !account.getIn(['relationship', 'muting'])) {
|
||||||
|
// Follow & Unfollow
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size='sm'
|
||||||
|
disabled={blockedBy}
|
||||||
|
theme={isFollowing ? 'secondary' : 'primary'}
|
||||||
|
icon={blockedBy ? require('@tabler/icons/icons/ban.svg') : (!isFollowing && require('@tabler/icons/icons/plus.svg'))}
|
||||||
|
onClick={handleFollow}
|
||||||
|
>
|
||||||
|
{isFollowing ? (
|
||||||
|
intl.formatMessage(messages.unfollow)
|
||||||
|
) : (
|
||||||
|
intl.formatMessage(blockedBy ? messages.blocked : messages.follow)
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||||
|
// Unblock
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
theme='danger'
|
||||||
|
size='sm'
|
||||||
|
text={intl.formatMessage(messages.unblock, { name: account.get('username') })}
|
||||||
|
onClick={handleBlock}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (account.getIn(['relationship', 'muting'])) {
|
||||||
|
// Unmute
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
theme='danger'
|
||||||
|
size='sm'
|
||||||
|
text={intl.formatMessage(messages.unmute, { name: account.get('username') })}
|
||||||
|
onClick={handleMute}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Edit profile
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
theme='secondary'
|
||||||
|
size='sm'
|
||||||
|
text={intl.formatMessage(messages.edit_profile)}
|
||||||
|
to='/settings/profile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActionButton;
|
|
@ -1,180 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import {
|
|
||||||
followAccount,
|
|
||||||
unfollowAccount,
|
|
||||||
blockAccount,
|
|
||||||
unblockAccount,
|
|
||||||
muteAccount,
|
|
||||||
unmuteAccount,
|
|
||||||
} from 'soapbox/actions/accounts';
|
|
||||||
import { openModal } from 'soapbox/actions/modals';
|
|
||||||
import Icon from 'soapbox/components/icon';
|
|
||||||
import { Button } from 'soapbox/components/ui';
|
|
||||||
import { getFeatures } from 'soapbox/utils/features';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
|
||||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
|
||||||
remote_follow: { id: 'account.remote_follow', defaultMessage: 'Remote follow' },
|
|
||||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
|
||||||
requested_small: { id: 'account.requested_small', defaultMessage: 'Awaiting approval' },
|
|
||||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
|
||||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
|
||||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
|
||||||
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const me = state.get('me');
|
|
||||||
const instance = state.get('instance');
|
|
||||||
|
|
||||||
return {
|
|
||||||
me,
|
|
||||||
features: getFeatures(instance),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
onFollow(account) {
|
|
||||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
|
||||||
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(muteAccount(account.get('id')));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onOpenUnauthorizedModal(account) {
|
|
||||||
dispatch(openModal('UNAUTHORIZED', {
|
|
||||||
action: 'FOLLOW',
|
|
||||||
account: account.get('id'),
|
|
||||||
ap_id: account.get('url'),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
@injectIntl
|
|
||||||
class ActionButton extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
account: ImmutablePropTypes.record.isRequired,
|
|
||||||
onFollow: PropTypes.func.isRequired,
|
|
||||||
onBlock: PropTypes.func.isRequired,
|
|
||||||
onOpenUnauthorizedModal: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
small: PropTypes.bool,
|
|
||||||
features: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
small: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
window.addEventListener('resize', this.handleResize, { passive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
window.removeEventListener('resize', this.handleResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFollow = () => {
|
|
||||||
this.props.onFollow(this.props.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBlock = () => {
|
|
||||||
this.props.onBlock(this.props.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMute = () => {
|
|
||||||
this.props.onMute(this.props.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRemoteFollow = () => {
|
|
||||||
this.props.onOpenUnauthorizedModal(this.props.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { account, intl, me, small, features } = this.props;
|
|
||||||
const empty = <></>;
|
|
||||||
|
|
||||||
if (!me) {
|
|
||||||
// Remote follow
|
|
||||||
if (features.remoteInteractionsAPI) {
|
|
||||||
return (<Button
|
|
||||||
className='button--follow'
|
|
||||||
onClick={this.handleRemoteFollow}
|
|
||||||
>
|
|
||||||
{intl.formatMessage(messages.follow)}
|
|
||||||
<Icon src={require('@tabler/icons/icons/plus.svg')} />
|
|
||||||
</Button>);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<form method='POST' action='/main/ostatus'>
|
|
||||||
<input type='hidden' name='nickname' value={account.get('acct')} />
|
|
||||||
<input type='hidden' name='profile' value='' />
|
|
||||||
<Button className='logo-button' text={intl.formatMessage(messages.remote_follow)} click='submit' />
|
|
||||||
</form>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (me !== account.get('id')) {
|
|
||||||
const isFollowing = account.getIn(['relationship', 'following']);
|
|
||||||
const blockedBy = account.getIn(['relationship', 'blocked_by']);
|
|
||||||
|
|
||||||
if (!account.get('relationship')) { // Wait until the relationship is loaded
|
|
||||||
return empty;
|
|
||||||
} else if (account.getIn(['relationship', 'requested'])) {
|
|
||||||
// Awaiting acceptance
|
|
||||||
return <Button size='sm' theme='secondary' text={small ? intl.formatMessage(messages.requested_small) : intl.formatMessage(messages.requested)} onClick={this.handleFollow} />;
|
|
||||||
} else if (!account.getIn(['relationship', 'blocking']) && !account.getIn(['relationship', 'muting'])) {
|
|
||||||
// Follow & Unfollow
|
|
||||||
return (<Button
|
|
||||||
size='sm'
|
|
||||||
disabled={blockedBy}
|
|
||||||
theme={isFollowing ? 'secondary' : 'primary'}
|
|
||||||
icon={blockedBy ? require('@tabler/icons/icons/ban.svg') : (!isFollowing && require('@tabler/icons/icons/plus.svg'))}
|
|
||||||
onClick={this.handleFollow}
|
|
||||||
>
|
|
||||||
{isFollowing ? (
|
|
||||||
intl.formatMessage(messages.unfollow)
|
|
||||||
) : (
|
|
||||||
intl.formatMessage(blockedBy ? messages.blocked : messages.follow)
|
|
||||||
)}
|
|
||||||
</Button>);
|
|
||||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
|
||||||
// Unblock
|
|
||||||
return <Button theme='danger' size='sm' text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.handleBlock} />;
|
|
||||||
} else if (account.getIn(['relationship', 'muting'])) {
|
|
||||||
// Unmute
|
|
||||||
return <Button theme='danger' size='sm' text={intl.formatMessage(messages.unmute, { name: account.get('username') })} onClick={this.handleMute} />;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Edit profile
|
|
||||||
return <Button theme='secondary' size='sm' text={intl.formatMessage(messages.edit_profile)} to='/settings/profile' />;
|
|
||||||
}
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -114,18 +114,6 @@ a.button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--follow {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
margin: 0 0 0 6px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--welcome {
|
.button--welcome {
|
||||||
.emojione {
|
.emojione {
|
||||||
margin: -1px 6px 0 -4px;
|
margin: -1px 6px 0 -4px;
|
||||||
|
|
Loading…
Reference in a new issue