Signed-off-by: marcin mikołajczak <git@mkljczk.pl>next-virtuoso-proof
parent
267ab4b153
commit
2943b91034
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export default function compareId(id1, id2) {
|
export default function compareId(id1: string, id2: string) {
|
||||||
if (id1 === id2) {
|
if (id1 === id2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,43 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import IconButton from './icon_button';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @injectIntl
|
|
||||||
class Account extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
domain: PropTypes.string,
|
|
||||||
onUnblockDomain: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleDomainUnblock = () => {
|
|
||||||
this.props.onUnblockDomain(this.props.domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { domain, intl } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='domain'>
|
|
||||||
<div className='domain__wrapper'>
|
|
||||||
<span className='domain__domain-name'>
|
|
||||||
<strong>{domain}</strong>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className='domain__buttons'>
|
|
||||||
<IconButton active src={require('@tabler/icons/icons/lock-open.svg')} title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { unblockDomain } from 'soapbox/actions/domain_blocks';
|
||||||
|
|
||||||
|
import IconButton from './icon_button';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||||
|
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||||
|
});
|
||||||
|
|
||||||
|
interface IDomain {
|
||||||
|
domain: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Domain: React.FC<IDomain> = ({ domain }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
// const onBlockDomain = () => {
|
||||||
|
// dispatch(openModal('CONFIRM', {
|
||||||
|
// icon: require('@tabler/icons/icons/ban.svg'),
|
||||||
|
// heading: <FormattedMessage id='confirmations.domain_block.heading' defaultMessage='Block {domain}' values={{ domain }} />,
|
||||||
|
// message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||||
|
// confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||||
|
// onConfirm: () => dispatch(blockDomain(domain)),
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
const handleDomainUnblock = () => {
|
||||||
|
dispatch(unblockDomain(domain));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='domain'>
|
||||||
|
<div className='domain__wrapper'>
|
||||||
|
<span className='domain__domain-name'>
|
||||||
|
<strong>{domain}</strong>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className='domain__buttons'>
|
||||||
|
<IconButton active src={require('@tabler/icons/icons/lock-open.svg')} title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={handleDomainUnblock} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Domain;
|
@ -1,35 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
|
||||||
import { openModal } from '../actions/modals';
|
|
||||||
import Domain from '../components/domain';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
|
||||||
const mapStateToProps = () => ({});
|
|
||||||
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
|
||||||
onBlockDomain(domain) {
|
|
||||||
dispatch(openModal('CONFIRM', {
|
|
||||||
icon: require('@tabler/icons/icons/ban.svg'),
|
|
||||||
heading: <FormattedMessage id='confirmations.domain_block.heading' defaultMessage='Block {domain}' values={{ domain }} />,
|
|
||||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
|
||||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
|
||||||
onConfirm: () => dispatch(blockDomain(domain)),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
onUnblockDomain(domain) {
|
|
||||||
dispatch(unblockDomain(domain));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));
|
|
@ -1,38 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import { NavLink } from 'react-router-dom';
|
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon';
|
|
||||||
|
|
||||||
import AvatarOverlay from '../../../components/avatar_overlay';
|
|
||||||
import DisplayName from '../../../components/display_name';
|
|
||||||
|
|
||||||
export default class MovedNote extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
from: ImmutablePropTypes.map.isRequired,
|
|
||||||
to: ImmutablePropTypes.map.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { from, to } = this.props;
|
|
||||||
const displayNameHtml = { __html: from.get('display_name_html') };
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='account__moved-note'>
|
|
||||||
<div className='account__moved-note__message'>
|
|
||||||
<div className='account__moved-note__icon-wrapper'><Icon src={require('feather-icons/dist/icons/briefcase.svg')} className='account__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={`/@${this.props.to.get('acct')}`} className='detailed-status__display-name'>
|
|
||||||
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
|
|
||||||
<DisplayName account={to} />
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
|
import AvatarOverlay from 'soapbox/components/avatar_overlay';
|
||||||
|
import DisplayName from 'soapbox/components/display_name';
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
|
||||||
|
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
interface IMovedNote {
|
||||||
|
from: AccountEntity,
|
||||||
|
to: AccountEntity,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MovedNote: React.FC<IMovedNote> = ({ from, to }) => {
|
||||||
|
const displayNameHtml = { __html: from.display_name_html };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='account__moved-note'>
|
||||||
|
<div className='account__moved-note__message'>
|
||||||
|
<div className='account__moved-note__icon-wrapper'><Icon src={require('feather-icons/dist/icons/briefcase.svg')} className='account__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={`/@${to.acct}`} className='detailed-status__display-name'>
|
||||||
|
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
|
||||||
|
<DisplayName account={to} />
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MovedNote;
|
@ -1,88 +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 Avatar from 'soapbox/components/avatar';
|
|
||||||
import DisplayName from 'soapbox/components/display_name';
|
|
||||||
import Icon from 'soapbox/components/icon';
|
|
||||||
import Permalink from 'soapbox/components/permalink';
|
|
||||||
import { makeGetAccount } from 'soapbox/selectors';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
birthday: { id: 'account.birthday', defaultMessage: 'Born {date}' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
|
||||||
const getAccount = makeGetAccount();
|
|
||||||
|
|
||||||
const mapStateToProps = (state, { accountId }) => {
|
|
||||||
const account = getAccount(state, accountId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
account,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default @connect(makeMapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class Account extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
accountId: PropTypes.string.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
account: ImmutablePropTypes.record,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
added: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { account, accountId } = this.props;
|
|
||||||
|
|
||||||
if (accountId && !account) {
|
|
||||||
this.props.fetchAccount(accountId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { account, intl } = this.props;
|
|
||||||
|
|
||||||
if (!account) return null;
|
|
||||||
|
|
||||||
const birthday = account.get('birthday');
|
|
||||||
if (!birthday) return null;
|
|
||||||
|
|
||||||
const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'short', year: 'numeric' });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='account'>
|
|
||||||
<div className='account__wrapper'>
|
|
||||||
<Permalink className='account__display-name' title={account.get('acct')} href={`/@${account.get('acct')}`} to={`/@${account.get('acct')}`}>
|
|
||||||
<div className='account__display-name'>
|
|
||||||
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
|
||||||
<DisplayName account={account} />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Permalink>
|
|
||||||
<div
|
|
||||||
className='account__birthday'
|
|
||||||
title={intl.formatMessage(messages.birthday, {
|
|
||||||
date: formattedBirthday,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Icon src={require('@tabler/icons/icons/ballon.svg')} />
|
|
||||||
{formattedBirthday}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,64 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import Avatar from 'soapbox/components/avatar';
|
||||||
|
import DisplayName from 'soapbox/components/display_name';
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
import Permalink from 'soapbox/components/permalink';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
import { makeGetAccount } from 'soapbox/selectors';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
birthday: { id: 'account.birthday', defaultMessage: 'Born {date}' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const getAccount = makeGetAccount();
|
||||||
|
|
||||||
|
interface IAccount {
|
||||||
|
accountId: string,
|
||||||
|
fetchAccount: (id: string) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Account: React.FC<IAccount> = ({ accountId, fetchAccount }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (accountId && !account) {
|
||||||
|
fetchAccount(accountId);
|
||||||
|
}
|
||||||
|
}, [accountId]);
|
||||||
|
|
||||||
|
if (!account) return null;
|
||||||
|
|
||||||
|
const birthday = account.get('birthday');
|
||||||
|
if (!birthday) return null;
|
||||||
|
|
||||||
|
const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'short', year: 'numeric' });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='account'>
|
||||||
|
<div className='account__wrapper'>
|
||||||
|
<Permalink className='account__display-name' title={account.get('acct')} href={`/@${account.get('acct')}`} to={`/@${account.get('acct')}`}>
|
||||||
|
<div className='account__display-name'>
|
||||||
|
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||||
|
<DisplayName account={account} />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Permalink>
|
||||||
|
<div
|
||||||
|
className='account__birthday'
|
||||||
|
title={intl.formatMessage(messages.birthday, {
|
||||||
|
date: formattedBirthday,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Icon src={require('@tabler/icons/icons/ballon.svg')} />
|
||||||
|
{formattedBirthday}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Account;
|
@ -1,74 +0,0 @@
|
|||||||
import { debounce } from 'lodash';
|
|
||||||
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, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { Column, Spinner } from 'soapbox/components/ui';
|
|
||||||
|
|
||||||
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
|
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
|
||||||
import AccountContainer from '../../containers/account_container';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
|
|
||||||
hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class Blocks extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
params: PropTypes.object.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
accountIds: ImmutablePropTypes.orderedSet,
|
|
||||||
hasMore: PropTypes.bool,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.dispatch(fetchBlocks());
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
|
||||||
this.props.dispatch(expandBlocks());
|
|
||||||
}, 300, { leading: true });
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { intl, accountIds, hasMore } = this.props;
|
|
||||||
|
|
||||||
if (!accountIds) {
|
|
||||||
return (
|
|
||||||
<Column>
|
|
||||||
<Spinner />
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column label={intl.formatMessage(messages.heading)}>
|
|
||||||
<ScrollableList
|
|
||||||
scrollKey='blocks'
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
hasMore={hasMore}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
className='space-y-4'
|
|
||||||
>
|
|
||||||
{accountIds.map(id =>
|
|
||||||
<AccountContainer key={id} id={id} />,
|
|
||||||
)}
|
|
||||||
</ScrollableList>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,58 @@
|
|||||||
|
import { debounce } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { fetchBlocks, expandBlocks } from 'soapbox/actions/blocks';
|
||||||
|
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||||
|
import { Column, Spinner } from 'soapbox/components/ui';
|
||||||
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoadMore = debounce((dispatch) => {
|
||||||
|
dispatch(expandBlocks());
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
|
const Blocks: React.FC = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const accountIds = useAppSelector((state) => state.user_lists.getIn(['blocks', 'items']));
|
||||||
|
const hasMore = useAppSelector((state) => !!state.user_lists.getIn(['blocks', 'next']));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchBlocks());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!accountIds) {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<Spinner />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
|
<ScrollableList
|
||||||
|
scrollKey='blocks'
|
||||||
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
|
hasMore={hasMore}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
className='space-y-4'
|
||||||
|
>
|
||||||
|
{accountIds.map((id: string) =>
|
||||||
|
<AccountContainer key={id} id={id} />,
|
||||||
|
)}
|
||||||
|
</ScrollableList>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Blocks;
|
@ -1,83 +0,0 @@
|
|||||||
import { debounce } from 'lodash';
|
|
||||||
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, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import SubNavigation from 'soapbox/components/sub_navigation';
|
|
||||||
import { Column } from 'soapbox/components/ui';
|
|
||||||
|
|
||||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from '../../actions/bookmarks';
|
|
||||||
import StatusList from '../../components/status_list';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
statusIds: state.getIn(['status_lists', 'bookmarks', 'items']),
|
|
||||||
isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true),
|
|
||||||
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class Bookmarks extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
shouldUpdateScroll: PropTypes.func,
|
|
||||||
statusIds: ImmutablePropTypes.orderedSet.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
columnId: PropTypes.string,
|
|
||||||
multiColumn: PropTypes.bool,
|
|
||||||
hasMore: PropTypes.bool,
|
|
||||||
isLoading: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchData = () => {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
return dispatch(fetchBookmarkedStatuses());
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
|
||||||
this.props.dispatch(expandBookmarkedStatuses());
|
|
||||||
}, 300, { leading: true })
|
|
||||||
|
|
||||||
handleRefresh = () => {
|
|
||||||
return this.fetchData();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
|
|
||||||
const pinned = !!columnId;
|
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.bookmarks' defaultMessage="You don't have any bookmarks yet. When you add one, it will show up here." />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column transparent>
|
|
||||||
<SubNavigation message={intl.formatMessage(messages.heading)} />
|
|
||||||
<StatusList
|
|
||||||
trackScroll={!pinned}
|
|
||||||
statusIds={statusIds}
|
|
||||||
scrollKey={`bookmarked_statuses-${columnId}`}
|
|
||||||
hasMore={hasMore}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
onRefresh={this.handleRefresh}
|
|
||||||
shouldUpdateScroll={shouldUpdateScroll}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
bindToDocument={!multiColumn}
|
|
||||||
divideType='space'
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,56 @@
|
|||||||
|
import { debounce } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import SubNavigation from 'soapbox/components/sub_navigation';
|
||||||
|
import { Column } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from '../../actions/bookmarks';
|
||||||
|
import StatusList from '../../components/status_list';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoadMore = debounce((dispatch) => {
|
||||||
|
dispatch(expandBookmarkedStatuses());
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
|
const Bookmarks: React.FC = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const statusIds = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'items']));
|
||||||
|
const isLoading = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'isLoading'], true));
|
||||||
|
const hasMore = useAppSelector((state) => !!state.status_lists.getIn(['bookmarks', 'next']));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchBookmarkedStatuses());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
return dispatch(fetchBookmarkedStatuses());
|
||||||
|
};
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.bookmarks' defaultMessage="You don't have any bookmarks yet. When you add one, it will show up here." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column transparent>
|
||||||
|
<SubNavigation message={intl.formatMessage(messages.heading)} />
|
||||||
|
<StatusList
|
||||||
|
statusIds={statusIds}
|
||||||
|
scrollKey={'bookmarked_statuses'}
|
||||||
|
hasMore={hasMore}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
|
onRefresh={handleRefresh}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
divideType='space'
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Bookmarks;
|
@ -1,75 +0,0 @@
|
|||||||
import { debounce } from 'lodash';
|
|
||||||
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, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { Spinner } from 'soapbox/components/ui';
|
|
||||||
|
|
||||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
|
||||||
import DomainContainer from '../../containers/domain_container';
|
|
||||||
import Column from '../ui/components/column';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
|
||||||
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class Blocks extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
params: PropTypes.object.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
hasMore: PropTypes.bool,
|
|
||||||
domains: ImmutablePropTypes.orderedSet,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.dispatch(fetchDomainBlocks());
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
|
||||||
this.props.dispatch(expandDomainBlocks());
|
|
||||||
}, 300, { leading: true });
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { intl, domains, hasMore } = this.props;
|
|
||||||
|
|
||||||
if (!domains) {
|
|
||||||
return (
|
|
||||||
<Column>
|
|
||||||
<Spinner />
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column icon='minus-circle' label={intl.formatMessage(messages.heading)}>
|
|
||||||
<ScrollableList
|
|
||||||
scrollKey='domain_blocks'
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
hasMore={hasMore}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
>
|
|
||||||
{domains.map(domain =>
|
|
||||||
<DomainContainer key={domain} domain={domain} />,
|
|
||||||
)}
|
|
||||||
</ScrollableList>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,60 @@
|
|||||||
|
import { debounce } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { fetchDomainBlocks, expandDomainBlocks } from 'soapbox/actions/domain_blocks';
|
||||||
|
import Domain from 'soapbox/components/domain';
|
||||||
|
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||||
|
import { Spinner } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||||
|
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoadMore = debounce((dispatch) => {
|
||||||
|
dispatch(expandDomainBlocks());
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
|
const DomainBlocks: React.FC = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const domains = useAppSelector((state) => state.domain_lists.getIn(['blocks', 'items'])) as string[];
|
||||||
|
const hasMore = useAppSelector((state) => !!state.domain_lists.getIn(['blocks', 'next']));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchDomainBlocks());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!domains) {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<Spinner />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column icon='minus-circle' label={intl.formatMessage(messages.heading)}>
|
||||||
|
<ScrollableList
|
||||||
|
scrollKey='domain_blocks'
|
||||||
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
|
hasMore={hasMore}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
>
|
||||||
|
{domains.map((domain) =>
|
||||||
|
<Domain key={domain} domain={domain} />,
|
||||||
|
)}
|
||||||
|
</ScrollableList>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DomainBlocks;
|
@ -1,74 +0,0 @@
|
|||||||
import { debounce } from 'lodash';
|
|
||||||
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, FormattedMessage } from 'react-intl';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { Column, Spinner } from 'soapbox/components/ui';
|
|
||||||
|
|
||||||
import { fetchMutes, expandMutes } from '../../actions/mutes';
|
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
|
||||||
import AccountContainer from '../../containers/account_container';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
|
||||||
hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class Mutes extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
params: PropTypes.object.isRequired,
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
hasMore: PropTypes.bool,
|
|
||||||
accountIds: ImmutablePropTypes.orderedSet,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.dispatch(fetchMutes());
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
|
||||||
this.props.dispatch(expandMutes());
|
|
||||||
}, 300, { leading: true });
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { intl, hasMore, accountIds } = this.props;
|
|
||||||
|
|
||||||
if (!accountIds) {
|
|
||||||
return (
|
|
||||||
<Column>
|
|
||||||
<Spinner />
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column label={intl.formatMessage(messages.heading)}>
|
|
||||||
<ScrollableList
|
|
||||||
scrollKey='mutes'
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
hasMore={hasMore}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
className='space-y-4'
|
|
||||||
>
|
|
||||||
{accountIds.map(id =>
|
|
||||||
<AccountContainer key={id} id={id} />,
|
|
||||||
)}
|
|
||||||
</ScrollableList>
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,58 @@
|
|||||||
|
import { debounce } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { fetchMutes, expandMutes } from 'soapbox/actions/mutes';
|
||||||
|
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||||
|
import { Column, Spinner } from 'soapbox/components/ui';
|
||||||
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLoadMore = debounce((dispatch) => {
|
||||||
|
dispatch(expandMutes());
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
|
const Mutes: React.FC = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const accountIds = useAppSelector((state) => state.user_lists.getIn(['mutes', 'items']));
|
||||||
|
const hasMore = useAppSelector((state) => !!state.user_lists.getIn(['mutes', 'next']));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchMutes());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!accountIds) {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<Spinner />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
|
<ScrollableList
|
||||||
|
scrollKey='mutes'
|
||||||
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
|
hasMore={hasMore}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
className='space-y-4'
|
||||||
|
>
|
||||||
|
{accountIds.map(id =>
|
||||||
|
<AccountContainer key={id} id={id} />,
|
||||||
|
)}
|
||||||
|
</ScrollableList>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Mutes;
|
@ -1,64 +0,0 @@
|
|||||||
import { List as ImmutableList } from 'immutable';
|
|
||||||
|
|
||||||
export const validId = id => typeof id === 'string' && id !== 'null' && id !== 'undefined';
|
|
||||||
|
|
||||||
export const isURL = url => {
|
|
||||||
try {
|
|
||||||
new URL(url);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const parseBaseURL = url => {
|
|
||||||
try {
|
|
||||||
return new URL(url).origin;
|
|
||||||
} catch {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getLoggedInAccount = state => {
|
|
||||||
const me = state.get('me');
|
|
||||||
return state.getIn(['accounts', me]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isLoggedIn = getState => {
|
|
||||||
return validId(getState().get('me'));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAppToken = state => state.getIn(['auth', 'app', 'access_token']);
|
|
||||||
|
|
||||||
export const getUserToken = (state, accountId) => {
|
|
||||||
const accountUrl = state.getIn(['accounts', accountId, 'url']);
|
|
||||||
return state.getIn(['auth', 'users', accountUrl, 'access_token']);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAccessToken = state => {
|
|
||||||
const me = state.get('me');
|
|
||||||
return getUserToken(state, me);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAuthUserId = state => {
|
|
||||||
const me = state.getIn(['auth', 'me']);
|
|
||||||
|
|
||||||
return ImmutableList([
|
|
||||||
state.getIn(['auth', 'users', me, 'id']),
|
|
||||||
me,
|
|
||||||
]).find(validId);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAuthUserUrl = state => {
|
|
||||||
const me = state.getIn(['auth', 'me']);
|
|
||||||
|
|
||||||
return ImmutableList([
|
|
||||||
state.getIn(['auth', 'users', me, 'url']),
|
|
||||||
me,
|
|
||||||
]).find(isURL);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Get the VAPID public key. */
|
|
||||||
export const getVapidKey = state => {
|
|
||||||
return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']);
|
|
||||||
};
|
|
@ -0,0 +1,66 @@
|
|||||||
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
import type { RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
export const validId = (id: any) => typeof id === 'string' && id !== 'null' && id !== 'undefined';
|
||||||
|
|
||||||
|
export const isURL = (url: string) => {
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseBaseURL = (url: any) => {
|
||||||
|
try {
|
||||||
|
return new URL(url).origin;
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLoggedInAccount = (state: RootState) => {
|
||||||
|
const me = state.me;
|
||||||
|
return state.accounts.get(me);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isLoggedIn = (getState: () => RootState) => {
|
||||||
|
return validId(getState().me);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAppToken = (state: RootState) => state.auth.getIn(['app', 'access_token']);
|
||||||
|
|
||||||
|
export const getUserToken = (state: RootState, accountId?: string | false | null) => {
|
||||||
|
const accountUrl = state.accounts.getIn([accountId, 'url']);
|
||||||
|
return state.auth.getIn(['users', accountUrl, 'access_token']);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAccessToken = (state: RootState) => {
|
||||||
|
const me = state.me;
|
||||||
|
return getUserToken(state, me);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAuthUserId = (state: RootState) => {
|
||||||
|
const me = state.auth.get('me');
|
||||||
|
|
||||||
|
return ImmutableList([
|
||||||
|
state.auth.getIn(['users', me, 'id']),
|
||||||
|
me,
|
||||||
|
]).find(validId);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAuthUserUrl = (state: RootState) => {
|
||||||
|
const me = state.auth.get('me');
|
||||||
|
|
||||||
|
return ImmutableList([
|
||||||
|
state.auth.getIn(['users', me, 'url']),
|
||||||
|
me,
|
||||||
|
]).find(isURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get the VAPID public key. */
|
||||||
|
export const getVapidKey = (state: RootState) => {
|
||||||
|
return state.auth.getIn(['app', 'vapid_key']) || state.instance.getIn(['pleroma', 'vapid_public_key']);
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
export const decode = base64 => {
|
export const decode = (base64: string) => {
|
||||||
const rawData = window.atob(base64);
|
const rawData = window.atob(base64);
|
||||||
const outputArray = new Uint8Array(rawData.length);
|
const outputArray = new Uint8Array(rawData.length);
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
export const getHost = instance => {
|
|
||||||
try {
|
|
||||||
return new URL(instance.get('uri')).host;
|
|
||||||
} catch {
|
|
||||||
try {
|
|
||||||
return new URL(`https://${instance.get('uri')}`).host;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,17 +1,17 @@
|
|||||||
export const minimumAspectRatio = 9 / 16; // Portrait phone
|
export const minimumAspectRatio = 9 / 16; // Portrait phone
|
||||||
export const maximumAspectRatio = 10; // Generous min-height
|
export const maximumAspectRatio = 10; // Generous min-height
|
||||||
|
|
||||||
export const isPanoramic = ar => {
|
export const isPanoramic = (ar: number) => {
|
||||||
if (isNaN(ar)) return false;
|
if (isNaN(ar)) return false;
|
||||||
return ar >= maximumAspectRatio;
|
return ar >= maximumAspectRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPortrait = ar => {
|
export const isPortrait = (ar: number) => {
|
||||||
if (isNaN(ar)) return false;
|
if (isNaN(ar)) return false;
|
||||||
return ar <= minimumAspectRatio;
|
return ar <= minimumAspectRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isNonConformingRatio = ar => {
|
export const isNonConformingRatio = (ar: number) => {
|
||||||
if (isNaN(ar)) return false;
|
if (isNaN(ar)) return false;
|
||||||
return !isPanoramic(ar) && !isPortrait(ar);
|
return !isPanoramic(ar) && !isPortrait(ar);
|
||||||
};
|
};
|
@ -1,13 +0,0 @@
|
|||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
export const shouldFilter = (status, columnSettings) => {
|
|
||||||
const shows = ImmutableMap({
|
|
||||||
reblog: status.get('reblog') !== null,
|
|
||||||
reply: status.get('in_reply_to_id') !== null,
|
|
||||||
direct: status.get('visibility') === 'direct',
|
|
||||||
});
|
|
||||||
|
|
||||||
return shows.some((value, key) => {
|
|
||||||
return columnSettings.getIn(['shows', key]) === false && value;
|
|
||||||
});
|
|
||||||
};
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
export const shouldFilter = (status: StatusEntity, columnSettings: any) => {
|
||||||
|
const shows = ImmutableMap({
|
||||||
|
reblog: status.reblog !== null,
|
||||||
|
reply: status.in_reply_to_id !== null,
|
||||||
|
direct: status.visibility === 'direct',
|
||||||
|
});
|
||||||
|
|
||||||
|
return shows.some((value, key) => {
|
||||||
|
return columnSettings.getIn(['shows', key]) === false && value;
|
||||||
|
});
|
||||||
|
};
|
Loading…
Reference in new issue