Merge remote-tracking branch 'soapbox/develop' into ts

This commit is contained in:
marcin mikołajczak
2022-06-18 12:11:03 +02:00
51 changed files with 982 additions and 167 deletions

View File

@ -0,0 +1,178 @@
// import { Map as ImmutableMap } from 'immutable';
import React from 'react';
import { render, screen } from '../../../../jest/test-helpers';
import { normalizeAccount, normalizeRelationship } from '../../../../normalizers';
import SubscribeButton from '../subscription-button';
let account = {
id: '1',
acct: 'justin-username',
display_name: 'Justin L',
avatar: 'test.jpg',
};
describe('<SubscribeButton />', () => {
let store;
describe('with "accountNotifies" disabled', () => {
it('renders nothing', () => {
account = normalizeAccount({ ...account, relationship: normalizeRelationship({ following: true }) });
render(<SubscribeButton account={account} />, null, store);
expect(screen.queryAllByTestId('icon-button')).toHaveLength(0);
});
});
// describe('with "accountNotifies" enabled', () => {
// beforeEach(() => {
// store = {
// ...store,
// instance: normalizeInstance({
// version: '3.4.1 (compatible; TruthSocial 1.0.0)',
// software: 'TRUTHSOCIAL',
// pleroma: ImmutableMap({}),
// }),
// };
// });
// describe('when the relationship is requested', () => {
// beforeEach(() => {
// account = normalizeAccount({ ...account, relationship: normalizeRelationship({ requested: true }) });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button')).toBeInTheDocument();
// });
// describe('when the user "isSubscribed"', () => {
// beforeEach(() => {
// account = normalizeAccount({
// ...account,
// relationship: normalizeRelationship({ requested: true, notifying: true }),
// });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the unsubscribe button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button').title).toEqual(`Unsubscribe to notifications from @${account.acct}`);
// });
// });
// describe('when the user is not "isSubscribed"', () => {
// beforeEach(() => {
// account = normalizeAccount({
// ...account,
// relationship: normalizeRelationship({ requested: true, notifying: false }),
// });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the unsubscribe button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button').title).toEqual(`Subscribe to notifications from @${account.acct}`);
// });
// });
// });
// describe('when the user is not following the account', () => {
// beforeEach(() => {
// account = normalizeAccount({ ...account, relationship: normalizeRelationship({ following: false }) });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders nothing', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.queryAllByTestId('icon-button')).toHaveLength(0);
// });
// });
// describe('when the user is following the account', () => {
// beforeEach(() => {
// account = normalizeAccount({ ...account, relationship: normalizeRelationship({ following: true }) });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button')).toBeInTheDocument();
// });
// describe('when the user "isSubscribed"', () => {
// beforeEach(() => {
// account = normalizeAccount({
// ...account,
// relationship: normalizeRelationship({ requested: true, notifying: true }),
// });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the unsubscribe button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button').title).toEqual(`Unsubscribe to notifications from @${account.acct}`);
// });
// });
// describe('when the user is not "isSubscribed"', () => {
// beforeEach(() => {
// account = normalizeAccount({
// ...account,
// relationship: normalizeRelationship({ requested: true, notifying: false }),
// });
// store = {
// ...store,
// accounts: ImmutableMap({
// '1': account,
// }),
// };
// });
// it('renders the unsubscribe button', () => {
// render(<SubscribeButton account={account} />, null, store);
// expect(screen.getByTestId('icon-button').title).toEqual(`Subscribe to notifications from @${account.acct}`);
// });
// });
// });
// });
});

View File

@ -0,0 +1,105 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import {
followAccount,
subscribeAccount,
unsubscribeAccount,
} from 'soapbox/actions/accounts';
import snackbar from 'soapbox/actions/snackbar';
import { IconButton } from 'soapbox/components/ui';
import { useAppDispatch, useFeatures } from 'soapbox/hooks';
import type { Account as AccountEntity } from 'soapbox/types/entities';
const messages = defineMessages({
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe to notifications from @{name}' },
unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe to notifications from @{name}' },
subscribeSuccess: { id: 'account.subscribe.success', defaultMessage: 'You have subscribed to this account.' },
unsubscribeSuccess: { id: 'account.unsubscribe.success', defaultMessage: 'You have unsubscribed from this account.' },
subscribeFailure: { id: 'account.subscribe.failure', defaultMessage: 'An error occurred trying to subscribed to this account.' },
unsubscribeFailure: { id: 'account.unsubscribe.failure', defaultMessage: 'An error occurred trying to unsubscribed to this account.' },
});
interface ISubscriptionButton {
account: AccountEntity
}
const SubscriptionButton = ({ account }: ISubscriptionButton) => {
const dispatch = useAppDispatch();
const features = useFeatures();
const intl = useIntl();
const isFollowing = account.relationship?.following;
const isRequested = account.relationship?.requested;
const isSubscribed = features.accountNotifies ?
account.relationship?.notifying :
account.relationship?.subscribing;
const title = isSubscribed ?
intl.formatMessage(messages.unsubscribe, { name: account.get('username') }) :
intl.formatMessage(messages.subscribe, { name: account.get('username') });
const onSubscribeSuccess = () =>
dispatch(snackbar.success(intl.formatMessage(messages.subscribeSuccess)));
const onSubscribeFailure = () =>
dispatch(snackbar.error(intl.formatMessage(messages.subscribeFailure)));
const onUnsubscribeSuccess = () =>
dispatch(snackbar.success(intl.formatMessage(messages.unsubscribeSuccess)));
const onUnsubscribeFailure = () =>
dispatch(snackbar.error(intl.formatMessage(messages.unsubscribeFailure)));
const onNotifyToggle = () => {
if (account.relationship?.notifying) {
dispatch(followAccount(account.get('id'), { notify: false } as any))
?.then(() => onUnsubscribeSuccess())
.catch(() => onUnsubscribeFailure());
} else {
dispatch(followAccount(account.get('id'), { notify: true } as any))
?.then(() => onSubscribeSuccess())
.catch(() => onSubscribeFailure());
}
};
const onSubscriptionToggle = () => {
if (account.relationship?.subscribing) {
dispatch(unsubscribeAccount(account.get('id')))
?.then(() => onUnsubscribeSuccess())
.catch(() => onUnsubscribeFailure());
} else {
dispatch(subscribeAccount(account.get('id')))
?.then(() => onSubscribeSuccess())
.catch(() => onSubscribeFailure());
}
};
const handleToggle = () => {
if (features.accountNotifies) {
onNotifyToggle();
} else {
onSubscriptionToggle();
}
};
if (!features.accountSubscriptions && !features.accountNotifies) {
return null;
}
if (isRequested || isFollowing) {
return (
<IconButton
src={isSubscribed ? require('@tabler/icons/icons/bell-ringing.svg') : require('@tabler/icons/icons/bell.svg')}
onClick={handleToggle}
title={title}
className='text-primary-700 bg-primary-100 dark:!bg-slate-700 dark:!text-white hover:bg-primary-200 p-2'
iconClassName='w-5 h-5'
/>
);
}
return null;
};
export default SubscriptionButton;

View File

@ -1,83 +0,0 @@
import classNames from 'classnames';
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,
subscribeAccount,
unsubscribeAccount,
} from 'soapbox/actions/accounts';
import Icon from 'soapbox/components/icon';
import { Button } from 'soapbox/components/ui';
const messages = defineMessages({
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe to notifications from @{name}' },
unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe to notifications from @{name}' },
subscribed: { id: 'account.subscribed', defaultMessage: 'Subscribed' },
});
const mapStateToProps = state => {
const me = state.get('me');
return {
me,
};
};
const mapDispatchToProps = (dispatch) => ({
onSubscriptionToggle(account) {
if (account.relationship?.subscribing) {
dispatch(unsubscribeAccount(account.get('id')));
} else {
dispatch(subscribeAccount(account.get('id')));
}
},
onNotifyToggle(account) {
if (account.relationship?.notifying) {
dispatch(followAccount(account.get('id'), { notify: false }));
} else {
dispatch(followAccount(account.get('id'), { notify: true }));
}
},
});
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class SubscriptionButton extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.record,
features: PropTypes.object.isRequired,
};
handleSubscriptionToggle = () => {
if (this.props.features.accountNotifies) this.props.onNotifyToggle(this.props.account);
else this.props.onSubscriptionToggle(this.props.account);
}
render() {
const { account, intl, features } = this.props;
const subscribing = features.accountNotifies ? account.relationship?.notifying : account.relationship?.subscribing;
const following = account.relationship?.following;
const requested = account.relationship?.requested;
if (requested || following) {
return (
<Button
className={classNames('subscription-button', subscribing && 'button-active')}
title={intl.formatMessage(subscribing ? messages.unsubscribe : messages.subscribe, { name: account.get('username') })}
onClick={this.handleSubscriptionToggle}
>
<Icon src={subscribing ? require('@tabler/icons/icons/bell-ringing.svg') : require('@tabler/icons/icons/bell.svg')} />
{subscribing && intl.formatMessage(messages.subscribed)}
</Button>
);
}
return null;
}
}

View File

@ -1,5 +1,5 @@
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
import { debounce } from 'lodash';
import debounce from 'lodash/debounce';
import React, { useCallback } from 'react';
import { defineMessages } from 'react-intl';