Merge branch 'ts' into 'develop'
Reducers: TypeScript See merge request soapbox-pub/soapbox-fe!1498
This commit is contained in:
commit
bdb958a613
|
@ -142,7 +142,7 @@ export function expandDomainBlocks() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
if (!isLoggedIn(getState)) return;
|
if (!isLoggedIn(getState)) return;
|
||||||
|
|
||||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
const url = getState().domain_lists.blocks.next;
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -249,7 +249,7 @@ export interface IDropdown extends RouteComponentProps {
|
||||||
) => void,
|
) => void,
|
||||||
onClose?: (id: number) => void,
|
onClose?: (id: number) => void,
|
||||||
dropdownPlacement?: string,
|
dropdownPlacement?: string,
|
||||||
openDropdownId?: number,
|
openDropdownId?: number | null,
|
||||||
openedViaKeyboard?: boolean,
|
openedViaKeyboard?: boolean,
|
||||||
text?: string,
|
text?: string,
|
||||||
onShiftClick?: React.EventHandler<React.MouseEvent | React.KeyboardEvent>,
|
onShiftClick?: React.EventHandler<React.MouseEvent | React.KeyboardEvent>,
|
||||||
|
|
|
@ -92,7 +92,7 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
|
||||||
|
|
||||||
if (!account) return null;
|
if (!account) return null;
|
||||||
const accountBio = { __html: account.note_emojified };
|
const accountBio = { __html: account.note_emojified };
|
||||||
const followedBy = me !== account.id && account.relationship.get('followed_by') === true;
|
const followedBy = me !== account.id && account.relationship?.followed_by === true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -581,7 +581,7 @@ class StatusActionBar extends ImmutablePureComponent<IStatusActionBar, IStatusAc
|
||||||
const favouriteCount = status.favourites_count;
|
const favouriteCount = status.favourites_count;
|
||||||
|
|
||||||
const emojiReactCount = reduceEmoji(
|
const emojiReactCount = reduceEmoji(
|
||||||
(status.getIn(['pleroma', 'emoji_reactions']) || ImmutableList()) as ImmutableList<any>,
|
(status.pleroma.get('emoji_reactions') || ImmutableList()) as ImmutableList<any>,
|
||||||
favouriteCount,
|
favouriteCount,
|
||||||
status.favourited,
|
status.favourited,
|
||||||
allowedEmoji,
|
allowedEmoji,
|
||||||
|
|
|
@ -35,7 +35,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
onFollow(account) {
|
onFollow(account) {
|
||||||
dispatch((_, getState) => {
|
dispatch((_, getState) => {
|
||||||
const unfollowModal = getSettings(getState()).get('unfollowModal');
|
const unfollowModal = getSettings(getState()).get('unfollowModal');
|
||||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
if (account.relationship?.following || account.relationship?.requested) {
|
||||||
if (unfollowModal) {
|
if (unfollowModal) {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/icons/minus.svg'),
|
icon: require('@tabler/icons/icons/minus.svg'),
|
||||||
|
@ -54,7 +54,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlock(account) {
|
onBlock(account) {
|
||||||
if (account.getIn(['relationship', 'blocking'])) {
|
if (account.relationship?.blocking) {
|
||||||
dispatch(unblockAccount(account.get('id')));
|
dispatch(unblockAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(blockAccount(account.get('id')));
|
dispatch(blockAccount(account.get('id')));
|
||||||
|
@ -62,7 +62,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onMute(account) {
|
onMute(account) {
|
||||||
if (account.getIn(['relationship', 'muting'])) {
|
if (account.relationship?.muting) {
|
||||||
dispatch(unmuteAccount(account.get('id')));
|
dispatch(unmuteAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(initMuteModal(account));
|
dispatch(initMuteModal(account));
|
||||||
|
|
|
@ -11,9 +11,9 @@ import type { RootState } from 'soapbox/store';
|
||||||
|
|
||||||
const mapStateToProps = (state: RootState) => ({
|
const mapStateToProps = (state: RootState) => ({
|
||||||
isModalOpen: Boolean(state.modals.size && state.modals.last().modalType === 'ACTIONS'),
|
isModalOpen: Boolean(state.modals.size && state.modals.last().modalType === 'ACTIONS'),
|
||||||
dropdownPlacement: state.dropdown_menu.get('placement'),
|
dropdownPlacement: state.dropdown_menu.placement,
|
||||||
openDropdownId: state.dropdown_menu.get('openId'),
|
openDropdownId: state.dropdown_menu.openId,
|
||||||
openedViaKeyboard: state.dropdown_menu.get('keyboard'),
|
openedViaKeyboard: state.dropdown_menu.keyboard,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch, { status, items }: Partial<IDropdown>) => ({
|
const mapDispatchToProps = (dispatch: Dispatch, { status, items }: Partial<IDropdown>) => ({
|
||||||
|
|
|
@ -235,8 +235,8 @@ class Header extends ImmutablePureComponent {
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (account.getIn(['relationship', 'following'])) {
|
if (account.relationship?.following) {
|
||||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
if (account.relationship?.showing_reblogs) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }),
|
text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }),
|
||||||
action: this.props.onReblogToggle,
|
action: this.props.onReblogToggle,
|
||||||
|
@ -251,7 +251,7 @@ class Header extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features.accountSubscriptions) {
|
if (features.accountSubscriptions) {
|
||||||
if (account.getIn(['relationship', 'subscribing'])) {
|
if (account.relationship?.subscribing) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.unsubscribe, { name: account.get('username') }),
|
text: intl.formatMessage(messages.unsubscribe, { name: account.get('username') }),
|
||||||
action: this.props.onSubscriptionToggle,
|
action: this.props.onSubscriptionToggle,
|
||||||
|
@ -274,7 +274,7 @@ class Header extends ImmutablePureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
// menu.push({ text: intl.formatMessage(account.relationship?.endorsed ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
} else if (features.lists && features.unrestrictedLists) {
|
} else if (features.lists && features.unrestrictedLists) {
|
||||||
menu.push({
|
menu.push({
|
||||||
|
@ -284,7 +284,7 @@ class Header extends ImmutablePureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features.removeFromFollowers && account.getIn(['relationship', 'followed_by'])) {
|
if (features.removeFromFollowers && account.relationship?.followed_by) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.removeFromFollowers),
|
text: intl.formatMessage(messages.removeFromFollowers),
|
||||||
action: this.props.onRemoveFromFollowers,
|
action: this.props.onRemoveFromFollowers,
|
||||||
|
@ -292,7 +292,7 @@ class Header extends ImmutablePureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.getIn(['relationship', 'muting'])) {
|
if (account.relationship?.muting) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.unmute, { name: account.get('username') }),
|
text: intl.formatMessage(messages.unmute, { name: account.get('username') }),
|
||||||
action: this.props.onMute,
|
action: this.props.onMute,
|
||||||
|
@ -306,7 +306,7 @@ class Header extends ImmutablePureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.getIn(['relationship', 'blocking'])) {
|
if (account.relationship?.blocking) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.unblock, { name: account.get('username') }),
|
text: intl.formatMessage(messages.unblock, { name: account.get('username') }),
|
||||||
action: this.props.onBlock,
|
action: this.props.onBlock,
|
||||||
|
@ -332,7 +332,7 @@ class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
|
|
||||||
if (account.getIn(['relationship', 'domain_blocking'])) {
|
if (account.relationship?.domain_blocking) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.unblockDomain, { domain }),
|
text: intl.formatMessage(messages.unblockDomain, { domain }),
|
||||||
action: this.props.onUnblockDomain,
|
action: this.props.onUnblockDomain,
|
||||||
|
@ -463,7 +463,7 @@ class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
if (!account || !me) return info;
|
if (!account || !me) return info;
|
||||||
|
|
||||||
if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
|
if (me !== account.get('id') && account.relationship?.followed_by) {
|
||||||
info.push(
|
info.push(
|
||||||
<Badge
|
<Badge
|
||||||
key='followed_by'
|
key='followed_by'
|
||||||
|
@ -471,7 +471,7 @@ class Header extends ImmutablePureComponent {
|
||||||
title={<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />}
|
title={<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
|
} else if (me !== account.get('id') && account.relationship?.blocking) {
|
||||||
info.push(
|
info.push(
|
||||||
<Badge
|
<Badge
|
||||||
key='blocked'
|
key='blocked'
|
||||||
|
@ -481,7 +481,7 @@ class Header extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
|
if (me !== account.get('id') && account.relationship?.muting) {
|
||||||
info.push(
|
info.push(
|
||||||
<Badge
|
<Badge
|
||||||
key='muted'
|
key='muted'
|
||||||
|
@ -489,7 +489,7 @@ class Header extends ImmutablePureComponent {
|
||||||
title={<FormattedMessage id='account.muted' defaultMessage='Muted' />}
|
title={<FormattedMessage id='account.muted' defaultMessage='Muted' />}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
|
} else if (me !== account.get('id') && account.relationship?.domain_blocking) {
|
||||||
info.push(
|
info.push(
|
||||||
<Badge
|
<Badge
|
||||||
key='domain_blocked'
|
key='domain_blocked'
|
||||||
|
|
|
@ -75,7 +75,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
onFollow(account) {
|
onFollow(account) {
|
||||||
dispatch((_, getState) => {
|
dispatch((_, getState) => {
|
||||||
const unfollowModal = getSettings(getState()).get('unfollowModal');
|
const unfollowModal = getSettings(getState()).get('unfollowModal');
|
||||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
if (account.relationship?.following || account.relationship?.requested) {
|
||||||
if (unfollowModal) {
|
if (unfollowModal) {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||||
|
@ -92,7 +92,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlock(account) {
|
onBlock(account) {
|
||||||
if (account.getIn(['relationship', 'blocking'])) {
|
if (account.relationship?.blocking) {
|
||||||
dispatch(unblockAccount(account.get('id')));
|
dispatch(unblockAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
|
@ -119,7 +119,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onReblogToggle(account) {
|
onReblogToggle(account) {
|
||||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
if (account.relationship?.showing_reblogs) {
|
||||||
dispatch(followAccount(account.get('id'), { reblogs: false }));
|
dispatch(followAccount(account.get('id'), { reblogs: false }));
|
||||||
} else {
|
} else {
|
||||||
dispatch(followAccount(account.get('id'), { reblogs: true }));
|
dispatch(followAccount(account.get('id'), { reblogs: true }));
|
||||||
|
@ -127,7 +127,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubscriptionToggle(account) {
|
onSubscriptionToggle(account) {
|
||||||
if (account.getIn(['relationship', 'subscribing'])) {
|
if (account.relationship?.subscribing) {
|
||||||
dispatch(unsubscribeAccount(account.get('id')));
|
dispatch(unsubscribeAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(subscribeAccount(account.get('id')));
|
dispatch(subscribeAccount(account.get('id')));
|
||||||
|
@ -135,7 +135,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onNotifyToggle(account) {
|
onNotifyToggle(account) {
|
||||||
if (account.getIn(['relationship', 'notifying'])) {
|
if (account.relationship?.notifying) {
|
||||||
dispatch(followAccount(account.get('id'), { notify: false }));
|
dispatch(followAccount(account.get('id'), { notify: false }));
|
||||||
} else {
|
} else {
|
||||||
dispatch(followAccount(account.get('id'), { notify: true }));
|
dispatch(followAccount(account.get('id'), { notify: true }));
|
||||||
|
@ -143,7 +143,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onEndorseToggle(account) {
|
onEndorseToggle(account) {
|
||||||
if (account.getIn(['relationship', 'endorsed'])) {
|
if (account.relationship?.endorsed) {
|
||||||
dispatch(unpinAccount(account.get('id')));
|
dispatch(unpinAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(pinAccount(account.get('id')));
|
dispatch(pinAccount(account.get('id')));
|
||||||
|
@ -155,7 +155,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onMute(account) {
|
onMute(account) {
|
||||||
if (account.getIn(['relationship', 'muting'])) {
|
if (account.relationship?.muting) {
|
||||||
dispatch(unmuteAccount(account.get('id')));
|
dispatch(unmuteAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(initMuteModal(account));
|
dispatch(initMuteModal(account));
|
||||||
|
|
|
@ -39,7 +39,7 @@ const ReportStatus: React.FC<IReportStatus> = ({ status }) => {
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
text: intl.formatMessage(messages.viewStatus, { acct: `@${acct}` }),
|
text: intl.formatMessage(messages.viewStatus, { acct: `@${acct}` }),
|
||||||
to: `/@${acct}/posts/${status.get('id')}`,
|
to: `/@${acct}/posts/${status.id}`,
|
||||||
icon: require('@tabler/icons/icons/pencil.svg'),
|
icon: require('@tabler/icons/icons/pencil.svg'),
|
||||||
}, {
|
}, {
|
||||||
text: intl.formatMessage(messages.deleteStatus, { acct: `@${acct}` }),
|
text: intl.formatMessage(messages.deleteStatus, { acct: `@${acct}` }),
|
||||||
|
|
|
@ -7,8 +7,6 @@ import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
import type { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.admin.moderation_log', defaultMessage: 'Moderation Log' },
|
heading: { id: 'column.admin.moderation_log', defaultMessage: 'Moderation Log' },
|
||||||
emptyMessage: { id: 'admin.moderation_log.empty_message', defaultMessage: 'You have not performed any moderation actions yet. When you do, a history will be shown here.' },
|
emptyMessage: { id: 'admin.moderation_log.empty_message', defaultMessage: 'You have not performed any moderation actions yet. When you do, a history will be shown here.' },
|
||||||
|
@ -18,8 +16,10 @@ const ModerationLog = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const items = useAppSelector((state) => state.admin_log.get('index').map((i: number) => state.admin_log.getIn(['items', String(i)]))) as ImmutableMap<string, any>;
|
const items = useAppSelector((state) => {
|
||||||
const hasMore = useAppSelector((state) => state.admin_log.get('total', 0) - state.admin_log.get('index').count() > 0);
|
return state.admin_log.index.map((i) => state.admin_log.items.get(String(i)));
|
||||||
|
});
|
||||||
|
const hasMore = useAppSelector((state) => state.admin_log.total - state.admin_log.index.count() > 0);
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [lastPage, setLastPage] = useState(0);
|
const [lastPage, setLastPage] = useState(0);
|
||||||
|
@ -56,12 +56,12 @@ const ModerationLog = () => {
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
onLoadMore={handleLoadMore}
|
onLoadMore={handleLoadMore}
|
||||||
>
|
>
|
||||||
{items.map((item, i) => (
|
{items.map((item) => item && (
|
||||||
<div className='logentry' key={i}>
|
<div className='logentry' key={item.id}>
|
||||||
<div className='logentry__message'>{item.get('message')}</div>
|
<div className='logentry__message'>{item.message}</div>
|
||||||
<div className='logentry__timestamp'>
|
<div className='logentry__timestamp'>
|
||||||
<FormattedDate
|
<FormattedDate
|
||||||
value={new Date(item.get('time') * 1000)}
|
value={new Date(item.time * 1000)}
|
||||||
hour12={false}
|
hour12={false}
|
||||||
year='numeric'
|
year='numeric'
|
||||||
month='short'
|
month='short'
|
||||||
|
|
|
@ -17,7 +17,7 @@ const Search: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const value = useAppSelector(state => state.aliases.getIn(['suggestions', 'value'])) as string;
|
const value = useAppSelector(state => state.aliases.suggestions.value);
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
dispatch(changeAliasesSuggestions(e.target.value));
|
dispatch(changeAliasesSuggestions(e.target.value));
|
||||||
|
|
|
@ -35,11 +35,11 @@ const Aliases = () => {
|
||||||
const instance = state.instance;
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
if (features.accountMoving) return state.aliases.getIn(['aliases', 'items'], ImmutableList());
|
if (features.accountMoving) return state.aliases.aliases.items;
|
||||||
return account!.pleroma.get('also_known_as');
|
return account!.pleroma.get('also_known_as');
|
||||||
}) as ImmutableList<string>;
|
}) as ImmutableList<string>;
|
||||||
const searchAccountIds = useAppSelector((state) => state.aliases.getIn(['suggestions', 'items'])) as ImmutableList<string>;
|
const searchAccountIds = useAppSelector((state) => state.aliases.suggestions.items);
|
||||||
const loaded = useAppSelector((state) => state.aliases.getIn(['suggestions', 'loaded']));
|
const loaded = useAppSelector((state) => state.aliases.suggestions.loaded);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchAliases);
|
dispatch(fetchAliases);
|
||||||
|
|
|
@ -20,9 +20,9 @@ const Bookmarks: React.FC = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const statusIds = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'items']));
|
const statusIds = useAppSelector((state) => state.status_lists.get('bookmarks')!.items);
|
||||||
const isLoading = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'isLoading'], true));
|
const isLoading = useAppSelector((state) => state.status_lists.get('bookmarks')!.isLoading);
|
||||||
const hasMore = useAppSelector((state) => !!state.status_lists.getIn(['bookmarks', 'next']));
|
const hasMore = useAppSelector((state) => !!state.status_lists.get('bookmarks')!.next);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchBookmarkedStatuses());
|
dispatch(fetchBookmarkedStatuses());
|
||||||
|
@ -43,7 +43,7 @@ const Bookmarks: React.FC = () => {
|
||||||
statusIds={statusIds}
|
statusIds={statusIds}
|
||||||
scrollKey='bookmarked_statuses'
|
scrollKey='bookmarked_statuses'
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
isLoading={isLoading}
|
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||||
onLoadMore={() => handleLoadMore(dispatch)}
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const AccountCard: React.FC<IAccountCard> = ({ id }) => {
|
||||||
|
|
||||||
if (!account) return null;
|
if (!account) return null;
|
||||||
|
|
||||||
const followedBy = me !== account.id && account.relationship.get('followed_by');
|
const followedBy = me !== account.id && account.relationship?.followed_by;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='directory__card'>
|
<div className='directory__card'>
|
||||||
|
|
|
@ -24,8 +24,8 @@ const DomainBlocks: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const domains = useAppSelector((state) => state.domain_lists.getIn(['blocks', 'items'])) as string[];
|
const domains = useAppSelector((state) => state.domain_lists.blocks.items);
|
||||||
const hasMore = useAppSelector((state) => !!state.domain_lists.getIn(['blocks', 'next']));
|
const hasMore = useAppSelector((state) => !!state.domain_lists.blocks.next);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchDomainBlocks());
|
dispatch(fetchDomainBlocks());
|
||||||
|
|
|
@ -32,9 +32,9 @@ const mapStateToProps = (state, { params }) => {
|
||||||
if (isMyAccount) {
|
if (isMyAccount) {
|
||||||
return {
|
return {
|
||||||
isMyAccount,
|
isMyAccount,
|
||||||
statusIds: state.getIn(['status_lists', 'favourites', 'items']),
|
statusIds: state.status_lists.get('favourites').items,
|
||||||
isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true),
|
isLoading: state.status_lists.get('favourites').isLoading,
|
||||||
hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
|
hasMore: !!state.status_lists.get('favourites').next,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,9 @@ const mapStateToProps = (state, { params }) => {
|
||||||
unavailable,
|
unavailable,
|
||||||
username,
|
username,
|
||||||
isAccount: !!state.getIn(['accounts', accountId]),
|
isAccount: !!state.getIn(['accounts', accountId]),
|
||||||
statusIds: state.getIn(['status_lists', `favourites:${accountId}`, 'items'], []),
|
statusIds: state.status_lists.get(`favourites:${accountId}`)?.items || [],
|
||||||
isLoading: state.getIn(['status_lists', `favourites:${accountId}`, 'isLoading'], true),
|
isLoading: state.status_lists.get(`favourites:${accountId}`)?.isLoading,
|
||||||
hasMore: !!state.getIn(['status_lists', `favourites:${accountId}`, 'next']),
|
hasMore: !!state.status_lists.get(`favourites:${accountId}`)?.next,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ class Favourites extends ImmutablePureComponent {
|
||||||
statusIds={statusIds}
|
statusIds={statusIds}
|
||||||
scrollKey='favourited_statuses'
|
scrollKey='favourited_statuses'
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
isLoading={isLoading}
|
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,8 +11,8 @@ import Account from './account';
|
||||||
const FollowRecommendationsList: React.FC = () => {
|
const FollowRecommendationsList: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const suggestions = useAppSelector((state) => state.suggestions.get('items'));
|
const suggestions = useAppSelector((state) => state.suggestions.items);
|
||||||
const isLoading = useAppSelector((state) => state.suggestions.get('isLoading'));
|
const isLoading = useAppSelector((state) => state.suggestions.isLoading);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (suggestions.size === 0) {
|
if (suggestions.size === 0) {
|
||||||
|
@ -30,8 +30,8 @@ const FollowRecommendationsList: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='column-list'>
|
<div className='column-list'>
|
||||||
{suggestions.size > 0 ? suggestions.map((suggestion: { account: string }, idx: number) => (
|
{suggestions.size > 0 ? suggestions.map((suggestion) => (
|
||||||
<Account key={idx} id={suggestion.account} />
|
<Account key={suggestion.account} id={suggestion.account} />
|
||||||
)) : (
|
)) : (
|
||||||
<div className='column-list__empty-message'>
|
<div className='column-list__empty-message'>
|
||||||
<FormattedMessage id='empty_column.follow_recommendations' defaultMessage='Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.' />
|
<FormattedMessage id='empty_column.follow_recommendations' defaultMessage='Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.' />
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
@ -13,9 +12,9 @@ import { useAppSelector } from 'soapbox/hooks';
|
||||||
const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => {
|
const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const suggestions = useAppSelector((state) => state.suggestions.get('items'));
|
const suggestions = useAppSelector((state) => state.suggestions.items);
|
||||||
const hasMore = useAppSelector((state) => !!state.suggestions.get('next'));
|
const hasMore = useAppSelector((state) => !!state.suggestions.next);
|
||||||
const isLoading = useAppSelector((state) => state.suggestions.get('isLoading'));
|
const isLoading = useAppSelector((state) => state.suggestions.isLoading);
|
||||||
|
|
||||||
const handleLoadMore = debounce(() => {
|
const handleLoadMore = debounce(() => {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
@ -40,11 +39,11 @@ const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => {
|
||||||
useWindowScroll={false}
|
useWindowScroll={false}
|
||||||
style={{ height: 320 }}
|
style={{ height: 320 }}
|
||||||
>
|
>
|
||||||
{suggestions.map((suggestion: ImmutableMap<string, any>) => (
|
{suggestions.map((suggestion) => (
|
||||||
<div key={suggestion.get('account')} className='py-2'>
|
<div key={suggestion.account} className='py-2'>
|
||||||
<AccountContainer
|
<AccountContainer
|
||||||
// @ts-ignore: TS thinks `id` is passed to <Account>, but it isn't
|
// @ts-ignore: TS thinks `id` is passed to <Account>, but it isn't
|
||||||
id={suggestion.get('account')}
|
id={suggestion.account}
|
||||||
showProfileHoverCard={false}
|
showProfileHoverCard={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,8 +21,8 @@ const mapStateToProps = (state, { params }) => {
|
||||||
const meUsername = state.getIn(['accounts', me, 'username'], '');
|
const meUsername = state.getIn(['accounts', me, 'username'], '');
|
||||||
return {
|
return {
|
||||||
isMyAccount: (username.toLowerCase() === meUsername.toLowerCase()),
|
isMyAccount: (username.toLowerCase() === meUsername.toLowerCase()),
|
||||||
statusIds: state.getIn(['status_lists', 'pins', 'items']),
|
statusIds: state.status_lists.get('pins').items,
|
||||||
hasMore: !!state.getIn(['status_lists', 'pins', 'next']),
|
hasMore: !!state.status_lists.get('pins').next,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,9 @@ const ScheduledStatuses = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const statusIds = useAppSelector((state) => state.status_lists.getIn(['scheduled_statuses', 'items']));
|
const statusIds = useAppSelector((state) => state.status_lists.get('scheduled_statuses')!.items);
|
||||||
const isLoading = useAppSelector((state) => state.status_lists.getIn(['scheduled_statuses', 'isLoading']));
|
const isLoading = useAppSelector((state) => state.status_lists.get('scheduled_statuses')!.isLoading);
|
||||||
const hasMore = useAppSelector((state) => !!state.status_lists.getIn(['scheduled_statuses', 'next']));
|
const hasMore = useAppSelector((state) => !!state.status_lists.get('scheduled_statuses')!.next);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchScheduledStatuses());
|
dispatch(fetchScheduledStatuses());
|
||||||
|
@ -37,7 +37,7 @@ const ScheduledStatuses = () => {
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='scheduled_statuses'
|
scrollKey='scheduled_statuses'
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
isLoading={isLoading}
|
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||||
onLoadMore={() => handleLoadMore(dispatch)}
|
onLoadMore={() => handleLoadMore(dispatch)}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
|
|
|
@ -387,9 +387,9 @@ class ActionBar extends React.PureComponent<IActionBar, IActionBarState> {
|
||||||
if (me) {
|
if (me) {
|
||||||
if (features.bookmarks) {
|
if (features.bookmarks) {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(status.get('bookmarked') ? messages.unbookmark : messages.bookmark),
|
text: intl.formatMessage(status.bookmarked ? messages.unbookmark : messages.bookmark),
|
||||||
action: this.handleBookmarkClick,
|
action: this.handleBookmarkClick,
|
||||||
icon: require(status.get('bookmarked') ? '@tabler/icons/icons/bookmark-off.svg' : '@tabler/icons/icons/bookmark.svg'),
|
icon: require(status.bookmarked ? '@tabler/icons/icons/bookmark-off.svg' : '@tabler/icons/icons/bookmark.svg'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ class ActionBar extends React.PureComponent<IActionBar, IActionBarState> {
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
} else if (status.visibility === 'private') {
|
} else if (status.visibility === 'private') {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private),
|
text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog_private),
|
||||||
action: this.handleReblogClick,
|
action: this.handleReblogClick,
|
||||||
icon: require('@tabler/icons/icons/repeat.svg'),
|
icon: require('@tabler/icons/icons/repeat.svg'),
|
||||||
});
|
});
|
||||||
|
@ -496,7 +496,7 @@ class ActionBar extends React.PureComponent<IActionBar, IActionBarState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(status.get('sensitive') === false ? messages.markStatusSensitive : messages.markStatusNotSensitive),
|
text: intl.formatMessage(status.sensitive === false ? messages.markStatusSensitive : messages.markStatusNotSensitive),
|
||||||
action: this.handleToggleStatusSensitivity,
|
action: this.handleToggleStatusSensitivity,
|
||||||
icon: require('@tabler/icons/icons/alert-triangle.svg'),
|
icon: require('@tabler/icons/icons/alert-triangle.svg'),
|
||||||
});
|
});
|
||||||
|
@ -523,18 +523,18 @@ class ActionBar extends React.PureComponent<IActionBar, IActionBarState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const canShare = ('share' in navigator) && status.get('visibility') === 'public';
|
const canShare = ('share' in navigator) && status.visibility === 'public';
|
||||||
|
|
||||||
|
|
||||||
let reblogIcon = require('@tabler/icons/icons/repeat.svg');
|
let reblogIcon = require('@tabler/icons/icons/repeat.svg');
|
||||||
|
|
||||||
if (status.get('visibility') === 'direct') {
|
if (status.visibility === 'direct') {
|
||||||
reblogIcon = require('@tabler/icons/icons/mail.svg');
|
reblogIcon = require('@tabler/icons/icons/mail.svg');
|
||||||
} else if (status.get('visibility') === 'private') {
|
} else if (status.visibility === 'private') {
|
||||||
reblogIcon = require('@tabler/icons/icons/lock.svg');
|
reblogIcon = require('@tabler/icons/icons/lock.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
const reblog_disabled = (status.get('visibility') === 'direct' || status.get('visibility') === 'private');
|
const reblog_disabled = (status.visibility === 'direct' || status.visibility === 'private');
|
||||||
|
|
||||||
const reblogMenu: Menu = [{
|
const reblogMenu: Menu = [{
|
||||||
text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog),
|
text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog),
|
||||||
|
|
|
@ -53,7 +53,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
|
||||||
|
|
||||||
const getNormalizedReacts = () => {
|
const getNormalizedReacts = () => {
|
||||||
return reduceEmoji(
|
return reduceEmoji(
|
||||||
ImmutableList(status.getIn(['pleroma', 'emoji_reactions']) as any),
|
ImmutableList(status.pleroma.get('emoji_reactions') as any),
|
||||||
status.favourites_count,
|
status.favourites_count,
|
||||||
status.favourited,
|
status.favourited,
|
||||||
allowedEmoji,
|
allowedEmoji,
|
||||||
|
|
|
@ -332,7 +332,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
handleEditClick = (status: StatusEntity) => {
|
handleEditClick = (status: StatusEntity) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
dispatch(editStatus(status.get('id')));
|
dispatch(editStatus(status.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDirectClick = (account: AccountEntity, router: History) => {
|
handleDirectClick = (account: AccountEntity, router: History) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { render, screen } from '../../../../jest/test-helpers';
|
import { render, screen } from '../../../../jest/test-helpers';
|
||||||
|
@ -16,12 +16,12 @@ describe('<WhoToFollow />', () => {
|
||||||
avatar: 'test.jpg',
|
avatar: 'test.jpg',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
suggestions: ImmutableMap({
|
suggestions: {
|
||||||
items: fromJS([{
|
items: ImmutableOrderedSet([{
|
||||||
source: 'staff',
|
source: 'staff',
|
||||||
account: '1',
|
account: '1',
|
||||||
}]),
|
}]),
|
||||||
}),
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<WhoToFollowPanel limit={1} />, null, store);
|
render(<WhoToFollowPanel limit={1} />, null, store);
|
||||||
|
@ -44,8 +44,8 @@ describe('<WhoToFollow />', () => {
|
||||||
avatar: 'test.jpg',
|
avatar: 'test.jpg',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
suggestions: ImmutableMap({
|
suggestions: {
|
||||||
items: fromJS([
|
items: ImmutableOrderedSet([
|
||||||
{
|
{
|
||||||
source: 'staff',
|
source: 'staff',
|
||||||
account: '1',
|
account: '1',
|
||||||
|
@ -55,7 +55,7 @@ describe('<WhoToFollow />', () => {
|
||||||
account: '2',
|
account: '2',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
}),
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<WhoToFollowPanel limit={3} />, null, store);
|
render(<WhoToFollowPanel limit={3} />, null, store);
|
||||||
|
@ -78,8 +78,8 @@ describe('<WhoToFollow />', () => {
|
||||||
avatar: 'test.jpg',
|
avatar: 'test.jpg',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
suggestions: ImmutableMap({
|
suggestions: {
|
||||||
items: fromJS([
|
items: ImmutableOrderedSet([
|
||||||
{
|
{
|
||||||
source: 'staff',
|
source: 'staff',
|
||||||
account: '1',
|
account: '1',
|
||||||
|
@ -89,7 +89,7 @@ describe('<WhoToFollow />', () => {
|
||||||
account: '2',
|
account: '2',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
}),
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<WhoToFollowPanel limit={1} />, null, store);
|
render(<WhoToFollowPanel limit={1} />, null, store);
|
||||||
|
@ -112,9 +112,9 @@ describe('<WhoToFollow />', () => {
|
||||||
avatar: 'test.jpg',
|
avatar: 'test.jpg',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
suggestions: ImmutableMap({
|
suggestions: {
|
||||||
items: fromJS([]),
|
items: ImmutableOrderedSet([]),
|
||||||
}),
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<WhoToFollowPanel limit={1} />, null, store);
|
render(<WhoToFollowPanel limit={1} />, null, store);
|
||||||
|
|
|
@ -52,7 +52,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
const me = useAppSelector((state) => state.me);
|
const me = useAppSelector((state) => state.me);
|
||||||
|
|
||||||
const handleFollow = () => {
|
const handleFollow = () => {
|
||||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
if (account.relationship?.following || account.relationship?.requested) {
|
||||||
dispatch(unfollowAccount(account.id));
|
dispatch(unfollowAccount(account.id));
|
||||||
} else {
|
} else {
|
||||||
dispatch(followAccount(account.id));
|
dispatch(followAccount(account.id));
|
||||||
|
@ -60,7 +60,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlock = () => {
|
const handleBlock = () => {
|
||||||
if (account.getIn(['relationship', 'blocking'])) {
|
if (account.relationship?.blocking) {
|
||||||
dispatch(unblockAccount(account.id));
|
dispatch(unblockAccount(account.id));
|
||||||
} else {
|
} else {
|
||||||
dispatch(blockAccount(account.id));
|
dispatch(blockAccount(account.id));
|
||||||
|
@ -68,7 +68,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMute = () => {
|
const handleMute = () => {
|
||||||
if (account.getIn(['relationship', 'muting'])) {
|
if (account.relationship?.muting) {
|
||||||
dispatch(unmuteAccount(account.id));
|
dispatch(unmuteAccount(account.id));
|
||||||
} else {
|
} else {
|
||||||
dispatch(muteAccount(account.id));
|
dispatch(muteAccount(account.id));
|
||||||
|
@ -85,7 +85,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
|
|
||||||
/** Handles actionType='muting' */
|
/** Handles actionType='muting' */
|
||||||
const mutingAction = () => {
|
const mutingAction = () => {
|
||||||
const isMuted = account.getIn(['relationship', 'muting']);
|
const isMuted = account.relationship?.muting;
|
||||||
const messageKey = isMuted ? messages.unmute : messages.mute;
|
const messageKey = isMuted ? messages.unmute : messages.mute;
|
||||||
const text = intl.formatMessage(messageKey, { name: account.username });
|
const text = intl.formatMessage(messageKey, { name: account.username });
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
|
|
||||||
/** Handles actionType='blocking' */
|
/** Handles actionType='blocking' */
|
||||||
const blockingAction = () => {
|
const blockingAction = () => {
|
||||||
const isBlocked = account.getIn(['relationship', 'blocking']);
|
const isBlocked = account.relationship?.blocking;
|
||||||
const messageKey = isBlocked ? messages.unblock : messages.block;
|
const messageKey = isBlocked ? messages.unblock : messages.block;
|
||||||
const text = intl.formatMessage(messageKey, { name: account.username });
|
const text = intl.formatMessage(messageKey, { name: account.username });
|
||||||
|
|
||||||
|
@ -154,8 +154,8 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me !== account.id) {
|
if (me !== account.id) {
|
||||||
const isFollowing = account.getIn(['relationship', 'following']);
|
const isFollowing = account.relationship?.following;
|
||||||
const blockedBy = account.getIn(['relationship', 'blocked_by']) as boolean;
|
const blockedBy = account.relationship?.blocked_by as boolean;
|
||||||
|
|
||||||
if (actionType) {
|
if (actionType) {
|
||||||
if (actionType === 'muting') {
|
if (actionType === 'muting') {
|
||||||
|
@ -165,10 +165,10 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.relationship.isEmpty()) {
|
if (!account.relationship) {
|
||||||
// Wait until the relationship is loaded
|
// Wait until the relationship is loaded
|
||||||
return null;
|
return null;
|
||||||
} else if (account.getIn(['relationship', 'requested'])) {
|
} else if (account.relationship?.requested) {
|
||||||
// Awaiting acceptance
|
// Awaiting acceptance
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -178,7 +178,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
onClick={handleFollow}
|
onClick={handleFollow}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (!account.getIn(['relationship', 'blocking']) && !account.getIn(['relationship', 'muting'])) {
|
} else if (!account.relationship?.blocking && !account.relationship?.muting) {
|
||||||
// Follow & Unfollow
|
// Follow & Unfollow
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -195,7 +195,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
} else if (account.relationship?.blocking) {
|
||||||
// Unblock
|
// Unblock
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -47,9 +47,9 @@ const SelectedStatus = ({ statusId }: { statusId: string }) => {
|
||||||
return (
|
return (
|
||||||
<Stack space={2} className='p-4 rounded-lg bg-gray-100 dark:bg-slate-700'>
|
<Stack space={2} className='p-4 rounded-lg bg-gray-100 dark:bg-slate-700'>
|
||||||
<AccountContainer
|
<AccountContainer
|
||||||
id={status.get('account') as any}
|
id={status.account as any}
|
||||||
showProfileHoverCard={false}
|
showProfileHoverCard={false}
|
||||||
timestamp={status.get('created_at')}
|
timestamp={status.created_at}
|
||||||
hideActions
|
hideActions
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -59,10 +59,10 @@ const SelectedStatus = ({ statusId }: { statusId: string }) => {
|
||||||
collapsable
|
collapsable
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{status.get('media_attachments').size > 0 && (
|
{status.media_attachments.size > 0 && (
|
||||||
<AttachmentThumbs
|
<AttachmentThumbs
|
||||||
media={status.get('media_attachments')}
|
media={status.media_attachments}
|
||||||
sensitive={status.get('sensitive')}
|
sensitive={status.sensitive}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
@ -29,14 +29,14 @@ const mapStateToProps = state => {
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
onSubscriptionToggle(account) {
|
onSubscriptionToggle(account) {
|
||||||
if (account.getIn(['relationship', 'subscribing'])) {
|
if (account.relationship?.subscribing) {
|
||||||
dispatch(unsubscribeAccount(account.get('id')));
|
dispatch(unsubscribeAccount(account.get('id')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(subscribeAccount(account.get('id')));
|
dispatch(subscribeAccount(account.get('id')));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onNotifyToggle(account) {
|
onNotifyToggle(account) {
|
||||||
if (account.getIn(['relationship', 'notifying'])) {
|
if (account.relationship?.notifying) {
|
||||||
dispatch(followAccount(account.get('id'), { notify: false }));
|
dispatch(followAccount(account.get('id'), { notify: false }));
|
||||||
} else {
|
} else {
|
||||||
dispatch(followAccount(account.get('id'), { notify: true }));
|
dispatch(followAccount(account.get('id'), { notify: true }));
|
||||||
|
@ -60,9 +60,9 @@ class SubscriptionButton extends ImmutablePureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { account, intl, features } = this.props;
|
const { account, intl, features } = this.props;
|
||||||
const subscribing = features.accountNotifies ? account.getIn(['relationship', 'notifying']) : account.getIn(['relationship', 'subscribing']);
|
const subscribing = features.accountNotifies ? account.relationship?.notifying : account.relationship?.subscribing;
|
||||||
const following = account.getIn(['relationship', 'following']);
|
const following = account.relationship?.following;
|
||||||
const requested = account.getIn(['relationship', 'requested']);
|
const requested = account.relationship?.requested;
|
||||||
|
|
||||||
if (requested || following) {
|
if (requested || following) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { fetchSuggestions, dismissSuggestion } from 'soapbox/actions/suggestions';
|
import { fetchSuggestions, dismissSuggestion } from 'soapbox/actions/suggestions';
|
||||||
|
@ -8,6 +7,8 @@ import { Widget } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
import { useAppSelector } from 'soapbox/hooks';
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
||||||
});
|
});
|
||||||
|
@ -20,11 +21,11 @@ const WhoToFollowPanel = ({ limit }: IWhoToFollowPanel) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const suggestions = useAppSelector((state) => state.suggestions.get('items'));
|
const suggestions = useAppSelector((state) => state.suggestions.items);
|
||||||
const suggestionsToRender = suggestions.slice(0, limit);
|
const suggestionsToRender = suggestions.slice(0, limit);
|
||||||
|
|
||||||
const handleDismiss = (account: ImmutableMap<string, any>) => {
|
const handleDismiss = (account: AccountEntity) => {
|
||||||
dispatch(dismissSuggestion(account.get('id')));
|
dispatch(dismissSuggestion(account.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -45,11 +46,11 @@ const WhoToFollowPanel = ({ limit }: IWhoToFollowPanel) => {
|
||||||
title={<FormattedMessage id='who_to_follow.title' defaultMessage='People To Follow' />}
|
title={<FormattedMessage id='who_to_follow.title' defaultMessage='People To Follow' />}
|
||||||
// onAction={handleAction}
|
// onAction={handleAction}
|
||||||
>
|
>
|
||||||
{suggestionsToRender.map((suggestion: ImmutableMap<string, any>) => (
|
{suggestionsToRender.map((suggestion) => (
|
||||||
<AccountContainer
|
<AccountContainer
|
||||||
key={suggestion.get('account')}
|
key={suggestion.account}
|
||||||
// @ts-ignore: TS thinks `id` is passed to <Account>, but it isn't
|
// @ts-ignore: TS thinks `id` is passed to <Account>, but it isn't
|
||||||
id={suggestion.get('account')}
|
id={suggestion.account}
|
||||||
actionIcon={require('@tabler/icons/icons/x.svg')}
|
actionIcon={require('@tabler/icons/icons/x.svg')}
|
||||||
actionTitle={intl.formatMessage(messages.dismissSuggestion)}
|
actionTitle={intl.formatMessage(messages.dismissSuggestion)}
|
||||||
onActionClick={handleDismiss}
|
onActionClick={handleDismiss}
|
||||||
|
|
|
@ -343,7 +343,7 @@ const UI: React.FC = ({ children }) => {
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const vapidKey = useAppSelector(state => getVapidKey(state));
|
const vapidKey = useAppSelector(state => getVapidKey(state));
|
||||||
|
|
||||||
const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.get('openId') !== null);
|
const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.openId !== null);
|
||||||
const accessToken = useAppSelector(state => getAccessToken(state));
|
const accessToken = useAppSelector(state => getAccessToken(state));
|
||||||
const streamingUrl = useAppSelector(state => state.instance.urls.get('streaming_api'));
|
const streamingUrl = useAppSelector(state => state.instance.urls.get('streaming_api'));
|
||||||
const standalone = useAppSelector(isStandalone);
|
const standalone = useAppSelector(isStandalone);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { unescapeHTML } from 'soapbox/utils/html';
|
||||||
import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers';
|
import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers';
|
||||||
|
|
||||||
import type { PatronAccount } from 'soapbox/reducers/patron';
|
import type { PatronAccount } from 'soapbox/reducers/patron';
|
||||||
import type { Emoji, Field, EmbeddedEntity } from 'soapbox/types/entities';
|
import type { Emoji, Field, EmbeddedEntity, Relationship } from 'soapbox/types/entities';
|
||||||
|
|
||||||
// https://docs.joinmastodon.org/entities/account/
|
// https://docs.joinmastodon.org/entities/account/
|
||||||
export const AccountRecord = ImmutableRecord({
|
export const AccountRecord = ImmutableRecord({
|
||||||
|
@ -61,7 +61,7 @@ export const AccountRecord = ImmutableRecord({
|
||||||
note_emojified: '',
|
note_emojified: '',
|
||||||
note_plain: '',
|
note_plain: '',
|
||||||
patron: null as PatronAccount | null,
|
patron: null as PatronAccount | null,
|
||||||
relationship: ImmutableMap<string, any>(),
|
relationship: null as Relationship | null,
|
||||||
should_refetch: false,
|
should_refetch: false,
|
||||||
staff: false,
|
staff: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ export { ListRecord, normalizeList } from './list';
|
||||||
export { MentionRecord, normalizeMention } from './mention';
|
export { MentionRecord, normalizeMention } from './mention';
|
||||||
export { NotificationRecord, normalizeNotification } from './notification';
|
export { NotificationRecord, normalizeNotification } from './notification';
|
||||||
export { PollRecord, PollOptionRecord, normalizePoll } from './poll';
|
export { PollRecord, PollOptionRecord, normalizePoll } from './poll';
|
||||||
|
export { RelationshipRecord, normalizeRelationship } from './relationship';
|
||||||
export { StatusRecord, normalizeStatus } from './status';
|
export { StatusRecord, normalizeStatus } from './status';
|
||||||
export { StatusEditRecord, normalizeStatusEdit } from './status_edit';
|
export { StatusEditRecord, normalizeStatusEdit } from './status_edit';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* Relationship normalizer:
|
||||||
|
* Converts API relationships into our internal format.
|
||||||
|
* @see {@link https://docs.joinmastodon.org/entities/relationship/}
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
Map as ImmutableMap,
|
||||||
|
Record as ImmutableRecord,
|
||||||
|
fromJS,
|
||||||
|
} from 'immutable';
|
||||||
|
|
||||||
|
// https://docs.joinmastodon.org/entities/relationship/
|
||||||
|
// https://api.pleroma.social/#operation/AccountController.relationships
|
||||||
|
export const RelationshipRecord = ImmutableRecord({
|
||||||
|
blocked_by: false,
|
||||||
|
blocking: false,
|
||||||
|
domain_blocking: false,
|
||||||
|
endorsed: false,
|
||||||
|
followed_by: false,
|
||||||
|
following: false,
|
||||||
|
id: '',
|
||||||
|
muting: false,
|
||||||
|
muting_notifications: false,
|
||||||
|
note: '',
|
||||||
|
notifying: false,
|
||||||
|
requested: false,
|
||||||
|
showing_reblogs: false,
|
||||||
|
subscribing: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const normalizeRelationship = (relationship: Record<string, any>) => {
|
||||||
|
return RelationshipRecord(
|
||||||
|
ImmutableMap(fromJS(relationship)),
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,13 +0,0 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
|
|
||||||
import reducer from '../domain_lists';
|
|
||||||
|
|
||||||
describe('domain_lists reducer', () => {
|
|
||||||
it('should return the initial state', () => {
|
|
||||||
expect(reducer(undefined, {})).toEqual(ImmutableMap({
|
|
||||||
blocks: ImmutableMap({
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import reducer from '../domain_lists';
|
||||||
|
|
||||||
|
describe('domain_lists reducer', () => {
|
||||||
|
it('should return the initial state', () => {
|
||||||
|
expect(reducer(undefined, {} as any).toJS()).toEqual({
|
||||||
|
blocks: {
|
||||||
|
items: [],
|
||||||
|
next: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,13 +1,11 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
import reducer from '../dropdown_menu';
|
import reducer from '../dropdown_menu';
|
||||||
|
|
||||||
describe('dropdown_menu reducer', () => {
|
describe('dropdown_menu reducer', () => {
|
||||||
it('should return the initial state', () => {
|
it('should return the initial state', () => {
|
||||||
expect(reducer(undefined, {})).toEqual(ImmutableMap({
|
expect(reducer(undefined, {} as any).toJS()).toEqual({
|
||||||
openId: null,
|
openId: null,
|
||||||
placement: null,
|
placement: null,
|
||||||
keyboard: false,
|
keyboard: false,
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
import lain from 'soapbox/__fixtures__/lain.json';
|
import lain from 'soapbox/__fixtures__/lain.json';
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import reducer from '../relationships';
|
||||||
|
|
||||||
describe('relationships reducer', () => {
|
describe('relationships reducer', () => {
|
||||||
it('should return the initial state', () => {
|
it('should return the initial state', () => {
|
||||||
expect(reducer(undefined, {})).toEqual(ImmutableMap());
|
expect(reducer(undefined, {} as any)).toEqual(ImmutableMap());
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ACCOUNT_IMPORT', () => {
|
describe('ACCOUNT_IMPORT', () => {
|
||||||
|
@ -18,8 +18,8 @@ describe('relationships reducer', () => {
|
||||||
type: ACCOUNT_IMPORT,
|
type: ACCOUNT_IMPORT,
|
||||||
account: lain,
|
account: lain,
|
||||||
};
|
};
|
||||||
const state = ImmutableMap();
|
const state = ImmutableMap<string, any>();
|
||||||
expect(reducer(state, action)).toEqual(fromJS({
|
expect(reducer(state, action).toJS()).toEqual({
|
||||||
'9v5bqYwY2jfmvPNhTM': {
|
'9v5bqYwY2jfmvPNhTM': {
|
||||||
blocked_by: false,
|
blocked_by: false,
|
||||||
blocking: false,
|
blocking: false,
|
||||||
|
@ -30,11 +30,13 @@ describe('relationships reducer', () => {
|
||||||
id: '9v5bqYwY2jfmvPNhTM',
|
id: '9v5bqYwY2jfmvPNhTM',
|
||||||
muting: false,
|
muting: false,
|
||||||
muting_notifications: false,
|
muting_notifications: false,
|
||||||
|
note: '',
|
||||||
|
notifying: false,
|
||||||
requested: false,
|
requested: false,
|
||||||
showing_reblogs: true,
|
showing_reblogs: true,
|
||||||
subscribing: false,
|
subscribing: false,
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,30 +0,0 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
|
|
||||||
import reducer from '../status_lists';
|
|
||||||
|
|
||||||
describe('status_lists reducer', () => {
|
|
||||||
it('should return the initial state', () => {
|
|
||||||
expect(reducer(undefined, {})).toEqual(ImmutableMap({
|
|
||||||
favourites: ImmutableMap({
|
|
||||||
next: null,
|
|
||||||
loaded: false,
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
bookmarks: ImmutableMap({
|
|
||||||
next: null,
|
|
||||||
loaded: false,
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
pins: ImmutableMap({
|
|
||||||
next: null,
|
|
||||||
loaded: false,
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
scheduled_statuses: ImmutableMap({
|
|
||||||
next: null,
|
|
||||||
loaded: false,
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import reducer from '../status_lists';
|
||||||
|
|
||||||
|
describe('status_lists reducer', () => {
|
||||||
|
it('should return the initial state', () => {
|
||||||
|
expect(reducer(undefined, {} as any).toJS()).toEqual({
|
||||||
|
favourites: {
|
||||||
|
next: null,
|
||||||
|
loaded: false,
|
||||||
|
isLoading: null,
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
bookmarks: {
|
||||||
|
next: null,
|
||||||
|
loaded: false,
|
||||||
|
isLoading: null,
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
pins: {
|
||||||
|
next: null,
|
||||||
|
loaded: false,
|
||||||
|
isLoading: null,
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
scheduled_statuses: {
|
||||||
|
next: null,
|
||||||
|
loaded: false,
|
||||||
|
isLoading: null,
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,40 +0,0 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
|
|
||||||
|
|
||||||
import { SUGGESTIONS_DISMISS } from 'soapbox/actions/suggestions';
|
|
||||||
|
|
||||||
import reducer from '../suggestions';
|
|
||||||
|
|
||||||
describe('suggestions reducer', () => {
|
|
||||||
it('should return the initial state', () => {
|
|
||||||
expect(reducer(undefined, {})).toEqual(ImmutableMap({
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
next: null,
|
|
||||||
isLoading: false,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('SUGGESTIONS_DISMISS', () => {
|
|
||||||
it('should remove the account', () => {
|
|
||||||
const action = { type: SUGGESTIONS_DISMISS, id: '123' };
|
|
||||||
|
|
||||||
const state = fromJS({
|
|
||||||
items: [
|
|
||||||
{ account: '123', source: 'past_interactions' },
|
|
||||||
{ account: '456', source: 'past_interactions' },
|
|
||||||
{ account: '789', source: 'past_interactions' },
|
|
||||||
],
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expected = fromJS({
|
|
||||||
items: [
|
|
||||||
{ account: '456', source: 'past_interactions' },
|
|
||||||
{ account: '789', source: 'past_interactions' },
|
|
||||||
],
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { SUGGESTIONS_FETCH_SUCCESS, SUGGESTIONS_DISMISS } from 'soapbox/actions/suggestions';
|
||||||
|
|
||||||
|
import reducer from '../suggestions';
|
||||||
|
|
||||||
|
describe('suggestions reducer', () => {
|
||||||
|
it('should return the initial state', () => {
|
||||||
|
expect(reducer(undefined, {} as any).toJS()).toEqual({
|
||||||
|
items: [],
|
||||||
|
next: null,
|
||||||
|
isLoading: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('SUGGESTIONS_DISMISS', () => {
|
||||||
|
it('should remove the account', () => {
|
||||||
|
let state = reducer(undefined, {} as any);
|
||||||
|
|
||||||
|
state = reducer(state, {
|
||||||
|
type: SUGGESTIONS_FETCH_SUCCESS,
|
||||||
|
accounts: [
|
||||||
|
{ id: '123' },
|
||||||
|
{ id: '456' },
|
||||||
|
{ id: '789' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const action = { type: SUGGESTIONS_DISMISS, id: '123' };
|
||||||
|
|
||||||
|
const expected = {
|
||||||
|
items: [
|
||||||
|
{ account: '456', source: 'past_interactions' },
|
||||||
|
{ account: '789', source: 'past_interactions' },
|
||||||
|
],
|
||||||
|
isLoading: false,
|
||||||
|
next: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(reducer(state, action).toJS()).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -27,9 +27,9 @@ describe('timelines reducer', () => {
|
||||||
|
|
||||||
describe('TIMELINE_EXPAND_FAIL', () => {
|
describe('TIMELINE_EXPAND_FAIL', () => {
|
||||||
it('sets loading to false', () => {
|
it('sets loading to false', () => {
|
||||||
const state = fromJS({
|
const state = ImmutableMap(fromJS({
|
||||||
home: { isLoading: true },
|
home: { isLoading: true },
|
||||||
});
|
}));
|
||||||
|
|
||||||
const action = {
|
const action = {
|
||||||
type: TIMELINE_EXPAND_FAIL,
|
type: TIMELINE_EXPAND_FAIL,
|
||||||
|
@ -43,9 +43,9 @@ describe('timelines reducer', () => {
|
||||||
|
|
||||||
describe('TIMELINE_EXPAND_SUCCESS', () => {
|
describe('TIMELINE_EXPAND_SUCCESS', () => {
|
||||||
it('sets loading to false', () => {
|
it('sets loading to false', () => {
|
||||||
const state = fromJS({
|
const state = ImmutableMap(fromJS({
|
||||||
home: { isLoading: true },
|
home: { isLoading: true },
|
||||||
});
|
}));
|
||||||
|
|
||||||
const action = {
|
const action = {
|
||||||
type: TIMELINE_EXPAND_SUCCESS,
|
type: TIMELINE_EXPAND_SUCCESS,
|
||||||
|
@ -70,9 +70,9 @@ describe('timelines reducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('merges new status IDs', () => {
|
it('merges new status IDs', () => {
|
||||||
const state = fromJS({
|
const state = ImmutableMap(fromJS({
|
||||||
home: { items: ImmutableOrderedSet(['5', '2', '1']) },
|
home: { items: ImmutableOrderedSet(['5', '2', '1']) },
|
||||||
});
|
}));
|
||||||
|
|
||||||
const expected = ImmutableOrderedSet(['6', '5', '4', '2', '1']);
|
const expected = ImmutableOrderedSet(['6', '5', '4', '2', '1']);
|
||||||
|
|
||||||
|
@ -87,9 +87,9 @@ describe('timelines reducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('merges old status IDs', () => {
|
it('merges old status IDs', () => {
|
||||||
const state = fromJS({
|
const state = ImmutableMap(fromJS({
|
||||||
home: { items: ImmutableOrderedSet(['6', '4', '3']) },
|
home: { items: ImmutableOrderedSet(['6', '4', '3']) },
|
||||||
});
|
}));
|
||||||
|
|
||||||
const expected = ImmutableOrderedSet(['6', '4', '3', '5', '2', '1']);
|
const expected = ImmutableOrderedSet(['6', '4', '3', '5', '2', '1']);
|
||||||
|
|
||||||
|
@ -104,9 +104,9 @@ describe('timelines reducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('overrides pinned post IDs', () => {
|
it('overrides pinned post IDs', () => {
|
||||||
const state = fromJS({
|
const state = ImmutableMap(fromJS({
|
||||||
'account:1:pinned': { items: ImmutableOrderedSet(['5', '2', '1']) },
|
'account:1:pinned': { items: ImmutableOrderedSet(['5', '2', '1']) },
|
||||||
});
|
}));
|
||||||
|
|
||||||
const expected = ImmutableOrderedSet(['9', '8', '7']);
|
const expected = ImmutableOrderedSet(['9', '8', '7']);
|
||||||
|
|
|
@ -30,15 +30,14 @@ import {
|
||||||
ADMIN_USERS_UNSUGGEST_FAIL,
|
ADMIN_USERS_UNSUGGEST_FAIL,
|
||||||
} from 'soapbox/actions/admin';
|
} from 'soapbox/actions/admin';
|
||||||
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
|
||||||
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
|
||||||
import { normalizeAccount } from 'soapbox/normalizers/account';
|
|
||||||
import { normalizeId } from 'soapbox/utils/normalizers';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ACCOUNT_IMPORT,
|
ACCOUNT_IMPORT,
|
||||||
ACCOUNTS_IMPORT,
|
ACCOUNTS_IMPORT,
|
||||||
ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP,
|
ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP,
|
||||||
} from '../actions/importer';
|
} from 'soapbox/actions/importer';
|
||||||
|
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
|
||||||
|
import { normalizeAccount } from 'soapbox/normalizers/account';
|
||||||
|
import { normalizeId } from 'soapbox/utils/normalizers';
|
||||||
|
|
||||||
type AccountRecord = ReturnType<typeof normalizeAccount>;
|
type AccountRecord = ReturnType<typeof normalizeAccount>;
|
||||||
type AccountMap = ImmutableMap<string, any>;
|
type AccountMap = ImmutableMap<string, any>;
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
|
||||||
|
|
||||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
|
||||||
|
|
||||||
import {
|
|
||||||
ACCOUNT_FOLLOW_SUCCESS,
|
|
||||||
ACCOUNT_UNFOLLOW_SUCCESS,
|
|
||||||
} from '../actions/accounts';
|
|
||||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer';
|
|
||||||
|
|
||||||
const normalizeAccount = (state, account) => state.set(account.id, fromJS({
|
|
||||||
followers_count: account.followers_count,
|
|
||||||
following_count: account.following_count,
|
|
||||||
statuses_count: account.statuses_count,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const normalizeAccounts = (state, accounts) => {
|
|
||||||
accounts.forEach(account => {
|
|
||||||
state = normalizeAccount(state, account);
|
|
||||||
});
|
|
||||||
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateFollowCounters = (state, counterUpdates) => {
|
|
||||||
return state.withMutations(state => {
|
|
||||||
counterUpdates.forEach(counterUpdate => {
|
|
||||||
state.update(counterUpdate.id, ImmutableMap(), counters => counters.merge({
|
|
||||||
followers_count: counterUpdate.follower_count,
|
|
||||||
following_count: counterUpdate.following_count,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialState = ImmutableMap();
|
|
||||||
|
|
||||||
export default function accountsCounters(state = initialState, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case ACCOUNT_IMPORT:
|
|
||||||
return normalizeAccount(state, action.account);
|
|
||||||
case ACCOUNTS_IMPORT:
|
|
||||||
return normalizeAccounts(state, action.accounts);
|
|
||||||
case ACCOUNT_FOLLOW_SUCCESS:
|
|
||||||
return action.alreadyFollowing ? state :
|
|
||||||
state.updateIn([action.relationship.id, 'followers_count'], num => num + 1);
|
|
||||||
case ACCOUNT_UNFOLLOW_SUCCESS:
|
|
||||||
return state.updateIn([action.relationship.id, 'followers_count'], num => Math.max(0, num - 1));
|
|
||||||
case STREAMING_FOLLOW_RELATIONSHIPS_UPDATE:
|
|
||||||
return updateFollowCounters(state, [action.follower, action.following]);
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { List as ImmutableList, Map as ImmutableMap, Record as ImmutableRecord } from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ACCOUNT_FOLLOW_SUCCESS,
|
||||||
|
ACCOUNT_UNFOLLOW_SUCCESS,
|
||||||
|
} from 'soapbox/actions/accounts';
|
||||||
|
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from 'soapbox/actions/importer';
|
||||||
|
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
const CounterRecord = ImmutableRecord({
|
||||||
|
followers_count: 0,
|
||||||
|
following_count: 0,
|
||||||
|
statuses_count: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
type Counter = ReturnType<typeof CounterRecord>;
|
||||||
|
type State = ImmutableMap<string, Counter>;
|
||||||
|
type APIEntity = Record<string, any>;
|
||||||
|
type APIEntities = Array<APIEntity>;
|
||||||
|
|
||||||
|
const normalizeAccount = (state: State, account: APIEntity) => state.set(account.id, CounterRecord({
|
||||||
|
followers_count: account.followers_count,
|
||||||
|
following_count: account.following_count,
|
||||||
|
statuses_count: account.statuses_count,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const normalizeAccounts = (state: State, accounts: ImmutableList<APIEntities>) => {
|
||||||
|
accounts.forEach(account => {
|
||||||
|
state = normalizeAccount(state, account);
|
||||||
|
});
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateFollowCounters = (state: State, counterUpdates: APIEntities) => {
|
||||||
|
return state.withMutations(state => {
|
||||||
|
counterUpdates.forEach((counterUpdate) => {
|
||||||
|
state.update(counterUpdate.id, CounterRecord(), counters => counters.merge({
|
||||||
|
followers_count: counterUpdate.follower_count,
|
||||||
|
following_count: counterUpdate.following_count,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function accountsCounters(state: State = ImmutableMap<string, Counter>(), action: AnyAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case ACCOUNT_IMPORT:
|
||||||
|
return normalizeAccount(state, action.account);
|
||||||
|
case ACCOUNTS_IMPORT:
|
||||||
|
return normalizeAccounts(state, action.accounts);
|
||||||
|
case ACCOUNT_FOLLOW_SUCCESS:
|
||||||
|
return action.alreadyFollowing ? state :
|
||||||
|
state.updateIn([action.relationship.id, 'followers_count'], 0, (count) => typeof count === 'number' ? count + 1 : 0);
|
||||||
|
case ACCOUNT_UNFOLLOW_SUCCESS:
|
||||||
|
return state.updateIn([action.relationship.id, 'followers_count'], 0, (count) => typeof count === 'number' ? Math.max(0, count - 1) : 0);
|
||||||
|
case STREAMING_FOLLOW_RELATIONSHIPS_UPDATE:
|
||||||
|
return updateFollowCounters(state, [action.follower, action.following]);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
/**
|
|
||||||
* Accounts Meta: private user data only the owner should see.
|
|
||||||
* @module soapbox/reducers/accounts_meta
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
|
||||||
|
|
||||||
import { VERIFY_CREDENTIALS_SUCCESS, AUTH_ACCOUNT_REMEMBER_SUCCESS } from 'soapbox/actions/auth';
|
|
||||||
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS } from 'soapbox/actions/me';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap();
|
|
||||||
|
|
||||||
const importAccount = (state, account) => {
|
|
||||||
const accountId = account.get('id');
|
|
||||||
|
|
||||||
return state.set(accountId, ImmutableMap({
|
|
||||||
pleroma: account.get('pleroma', ImmutableMap()).delete('settings_store'),
|
|
||||||
source: account.get('source', ImmutableMap()),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function accounts_meta(state = initialState, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case ME_FETCH_SUCCESS:
|
|
||||||
case ME_PATCH_SUCCESS:
|
|
||||||
return importAccount(state, fromJS(action.me));
|
|
||||||
case VERIFY_CREDENTIALS_SUCCESS:
|
|
||||||
case AUTH_ACCOUNT_REMEMBER_SUCCESS:
|
|
||||||
return importAccount(state, fromJS(action.account));
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* Accounts Meta: private user data only the owner should see.
|
||||||
|
* @module soapbox/reducers/accounts_meta
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Map as ImmutableMap, Record as ImmutableRecord, fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { VERIFY_CREDENTIALS_SUCCESS, AUTH_ACCOUNT_REMEMBER_SUCCESS } from 'soapbox/actions/auth';
|
||||||
|
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS } from 'soapbox/actions/me';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
const MetaRecord = ImmutableRecord({
|
||||||
|
pleroma: ImmutableMap<string, any>(),
|
||||||
|
source: ImmutableMap<string, any>(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type Meta = ReturnType<typeof MetaRecord>;
|
||||||
|
type State = ImmutableMap<string, Meta>;
|
||||||
|
|
||||||
|
const importAccount = (state: State, account: ImmutableMap<string, any>) => {
|
||||||
|
const accountId = account.get('id');
|
||||||
|
|
||||||
|
return state.set(accountId, MetaRecord({
|
||||||
|
pleroma: account.get('pleroma', ImmutableMap()).delete('settings_store'),
|
||||||
|
source: account.get('source', ImmutableMap()),
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function accounts_meta(state: State = ImmutableMap<string, Meta>(), action: AnyAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case ME_FETCH_SUCCESS:
|
||||||
|
case ME_PATCH_SUCCESS:
|
||||||
|
return importAccount(state, ImmutableMap(fromJS(action.me)));
|
||||||
|
case VERIFY_CREDENTIALS_SUCCESS:
|
||||||
|
case AUTH_ACCOUNT_REMEMBER_SUCCESS:
|
||||||
|
return importAccount(state, ImmutableMap(fromJS(action.account)));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,40 +2,53 @@ import {
|
||||||
Map as ImmutableMap,
|
Map as ImmutableMap,
|
||||||
Record as ImmutableRecord,
|
Record as ImmutableRecord,
|
||||||
OrderedSet as ImmutableOrderedSet,
|
OrderedSet as ImmutableOrderedSet,
|
||||||
fromJS,
|
|
||||||
} from 'immutable';
|
} from 'immutable';
|
||||||
|
|
||||||
import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin';
|
import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
const LogEntryRecord = ImmutableRecord({
|
||||||
|
data: ImmutableMap<string, any>(),
|
||||||
|
id: 0,
|
||||||
|
message: '',
|
||||||
|
time: 0,
|
||||||
|
});
|
||||||
|
|
||||||
const ReducerRecord = ImmutableRecord({
|
const ReducerRecord = ImmutableRecord({
|
||||||
items: ImmutableMap(),
|
items: ImmutableMap<string, LogEntry>(),
|
||||||
index: ImmutableOrderedSet(),
|
index: ImmutableOrderedSet<number>(),
|
||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const parseItems = items => {
|
type LogEntry = ReturnType<typeof LogEntryRecord>;
|
||||||
const ids = [];
|
type State = ReturnType<typeof ReducerRecord>;
|
||||||
const map = {};
|
type APIEntity = Record<string, any>;
|
||||||
|
type APIEntities = Array<APIEntity>;
|
||||||
|
|
||||||
|
const parseItems = (items: APIEntities) => {
|
||||||
|
const ids: Array<number> = [];
|
||||||
|
const map: Record<string, LogEntry> = {};
|
||||||
|
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
ids.push(item.id);
|
ids.push(item.id);
|
||||||
map[item.id] = item;
|
map[item.id] = LogEntryRecord(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ids: ids, map: map };
|
return { ids: ids, map: map };
|
||||||
};
|
};
|
||||||
|
|
||||||
const importItems = (state, items, total) => {
|
const importItems = (state: State, items: APIEntities, total: number) => {
|
||||||
const { ids, map } = parseItems(items);
|
const { ids, map } = parseItems(items);
|
||||||
|
|
||||||
return state.withMutations(state => {
|
return state.withMutations(state => {
|
||||||
state.update('index', v => v.union(ids));
|
state.update('index', v => v.union(ids));
|
||||||
state.update('items', v => v.merge(fromJS(map)));
|
state.update('items', v => v.merge(map));
|
||||||
state.set('total', total);
|
state.set('total', total);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function admin_log(state = ReducerRecord(), action) {
|
export default function admin_log(state = ReducerRecord(), action: AnyAction) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ADMIN_LOG_FETCH_SUCCESS:
|
case ADMIN_LOG_FETCH_SUCCESS:
|
||||||
return importItems(state, action.items, action.total);
|
return importItems(state, action.items, action.total);
|
|
@ -1,4 +1,4 @@
|
||||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
import { List as ImmutableList, Record as ImmutableRecord } from 'immutable';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ALIASES_SUGGESTIONS_READY,
|
ALIASES_SUGGESTIONS_READY,
|
||||||
|
@ -7,19 +7,23 @@ import {
|
||||||
ALIASES_FETCH_SUCCESS,
|
ALIASES_FETCH_SUCCESS,
|
||||||
} from '../actions/aliases';
|
} from '../actions/aliases';
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
import type { AnyAction } from 'redux';
|
||||||
aliases: ImmutableMap({
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
|
||||||
|
const ReducerRecord = ImmutableRecord({
|
||||||
|
aliases: ImmutableRecord({
|
||||||
|
items: ImmutableList<string>(),
|
||||||
loaded: false,
|
loaded: false,
|
||||||
items: ImmutableList(),
|
})(),
|
||||||
}),
|
suggestions: ImmutableRecord({
|
||||||
suggestions: ImmutableMap({
|
items: ImmutableList<string>(),
|
||||||
value: '',
|
value: '',
|
||||||
loaded: false,
|
loaded: false,
|
||||||
items: ImmutableList(),
|
})(),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function aliasesReducer(state = initialState, action) {
|
export default function aliasesReducer(state = ReducerRecord(), action: AnyAction) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ALIASES_FETCH_SUCCESS:
|
case ALIASES_FETCH_SUCCESS:
|
||||||
return state
|
return state
|
||||||
|
@ -30,7 +34,7 @@ export default function aliasesReducer(state = initialState, action) {
|
||||||
.setIn(['suggestions', 'loaded'], false);
|
.setIn(['suggestions', 'loaded'], false);
|
||||||
case ALIASES_SUGGESTIONS_READY:
|
case ALIASES_SUGGESTIONS_READY:
|
||||||
return state
|
return state
|
||||||
.setIn(['suggestions', 'items'], ImmutableList(action.accounts.map(item => item.id)))
|
.setIn(['suggestions', 'items'], ImmutableList(action.accounts.map((item: APIEntity) => item.id)))
|
||||||
.setIn(['suggestions', 'loaded'], true);
|
.setIn(['suggestions', 'loaded'], true);
|
||||||
case ALIASES_SUGGESTIONS_CLEAR:
|
case ALIASES_SUGGESTIONS_CLEAR:
|
||||||
return state.update('suggestions', suggestions => suggestions.withMutations(map => {
|
return state.update('suggestions', suggestions => suggestions.withMutations(map => {
|
|
@ -1,26 +0,0 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
|
|
||||||
import {
|
|
||||||
DOMAIN_BLOCKS_FETCH_SUCCESS,
|
|
||||||
DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
|
||||||
DOMAIN_UNBLOCK_SUCCESS,
|
|
||||||
} from '../actions/domain_blocks';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
|
||||||
blocks: ImmutableMap({
|
|
||||||
items: ImmutableOrderedSet(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function domainLists(state = initialState, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case DOMAIN_BLOCKS_FETCH_SUCCESS:
|
|
||||||
return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next);
|
|
||||||
case DOMAIN_BLOCKS_EXPAND_SUCCESS:
|
|
||||||
return state.updateIn(['blocks', 'items'], set => set.union(action.domains)).setIn(['blocks', 'next'], action.next);
|
|
||||||
case DOMAIN_UNBLOCK_SUCCESS:
|
|
||||||
return state.updateIn(['blocks', 'items'], set => set.delete(action.domain));
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { OrderedSet as ImmutableOrderedSet, Record as ImmutableRecord } from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DOMAIN_BLOCKS_FETCH_SUCCESS,
|
||||||
|
DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||||
|
DOMAIN_UNBLOCK_SUCCESS,
|
||||||
|
} from '../actions/domain_blocks';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
|
const BlocksRecord = ImmutableRecord({
|
||||||
|
items: ImmutableOrderedSet<string>(),
|
||||||
|
next: null as string | null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ReducerRecord = ImmutableRecord({
|
||||||
|
blocks: BlocksRecord(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type State = ReturnType<typeof ReducerRecord>;
|
||||||
|
|
||||||
|
export default function domainLists(state: State = ReducerRecord(), action: AnyAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case DOMAIN_BLOCKS_FETCH_SUCCESS:
|
||||||
|
return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next);
|
||||||
|
case DOMAIN_BLOCKS_EXPAND_SUCCESS:
|
||||||
|
return state.updateIn(['blocks', 'items'], set => (set as ImmutableOrderedSet<string>).union(action.domains)).setIn(['blocks', 'next'], action.next);
|
||||||
|
case DOMAIN_UNBLOCK_SUCCESS:
|
||||||
|
return state.updateIn(['blocks', 'items'], set => (set as ImmutableOrderedSet<string>).delete(action.domain));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
import {
|
|
||||||
DROPDOWN_MENU_OPEN,
|
|
||||||
DROPDOWN_MENU_CLOSE,
|
|
||||||
} from '../actions/dropdown_menu';
|
|
||||||
|
|
||||||
const initialState = ImmutableMap({ openId: null, placement: null, keyboard: false });
|
|
||||||
|
|
||||||
export default function dropdownMenu(state = initialState, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case DROPDOWN_MENU_OPEN:
|
|
||||||
return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard });
|
|
||||||
case DROPDOWN_MENU_CLOSE:
|
|
||||||
return state.get('openId') === action.id ? state.set('openId', null) : state;
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Record as ImmutableRecord } from 'immutable';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DROPDOWN_MENU_OPEN,
|
||||||
|
DROPDOWN_MENU_CLOSE,
|
||||||
|
} from '../actions/dropdown_menu';
|
||||||
|
|
||||||
|
import type { AnyAction } from 'redux';
|
||||||
|
import type { DropdownPlacement } from 'soapbox/components/dropdown_menu';
|
||||||
|
|
||||||
|
const ReducerRecord = ImmutableRecord({
|
||||||
|
openId: null as number | null,
|
||||||
|
placement: null as any as DropdownPlacement,
|
||||||
|
keyboard: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
type State = ReturnType<typeof ReducerRecord>;
|
||||||
|
|
||||||
|
export default function dropdownMenu(state: State = ReducerRecord(), action: AnyAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case DROPDOWN_MENU_OPEN:
|
||||||
|
return state.merge({ openId: action.id, placement: action.placement, keyboard: action.keyboard });
|
||||||
|
case DROPDOWN_MENU_CLOSE:
|
||||||
|
return state.openId === action.id ? state.set('openId', null) : state;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
|
||||||
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
import { STREAMING_FOLLOW_RELATIONSHIPS_UPDATE } from 'soapbox/actions/streaming';
|
||||||
|
import { normalizeRelationship } from 'soapbox/normalizers/relationship';
|
||||||
|
|
||||||
import { ACCOUNT_NOTE_SUBMIT_SUCCESS } from '../actions/account-notes';
|
import { ACCOUNT_NOTE_SUBMIT_SUCCESS } from '../actions/account-notes';
|
||||||
import {
|
import {
|
||||||
|
@ -31,17 +32,22 @@ import {
|
||||||
ACCOUNTS_IMPORT,
|
ACCOUNTS_IMPORT,
|
||||||
} from '../actions/importer';
|
} from '../actions/importer';
|
||||||
|
|
||||||
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));
|
import type { AnyAction } from 'redux';
|
||||||
|
|
||||||
const normalizeRelationships = (state, relationships) => {
|
type Relationship = ReturnType<typeof normalizeRelationship>;
|
||||||
|
type State = ImmutableMap<string, Relationship>;
|
||||||
|
type APIEntity = Record<string, any>;
|
||||||
|
type APIEntities = Array<APIEntity>;
|
||||||
|
|
||||||
|
const normalizeRelationships = (state: State, relationships: APIEntities) => {
|
||||||
relationships.forEach(relationship => {
|
relationships.forEach(relationship => {
|
||||||
state = normalizeRelationship(state, relationship);
|
state = state.set(relationship.id, normalizeRelationship(relationship));
|
||||||
});
|
});
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setDomainBlocking = (state, accounts, blocking) => {
|
const setDomainBlocking = (state: State, accounts: ImmutableList<string>, blocking: boolean) => {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
accounts.forEach(id => {
|
accounts.forEach(id => {
|
||||||
map.setIn([id, 'domain_blocking'], blocking);
|
map.setIn([id, 'domain_blocking'], blocking);
|
||||||
|
@ -49,14 +55,14 @@ const setDomainBlocking = (state, accounts, blocking) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const importPleromaAccount = (state, account) => {
|
const importPleromaAccount = (state: State, account: APIEntity) => {
|
||||||
const relationship = get(account, ['pleroma', 'relationship'], {});
|
const relationship = get(account, ['pleroma', 'relationship'], {});
|
||||||
if (relationship.id && relationship !== {})
|
if (relationship.id && relationship !== {})
|
||||||
return normalizeRelationship(state, relationship);
|
return normalizeRelationships(state, [relationship]);
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const importPleromaAccounts = (state, accounts) => {
|
const importPleromaAccounts = (state: State, accounts: APIEntities) => {
|
||||||
accounts.forEach(account => {
|
accounts.forEach(account => {
|
||||||
state = importPleromaAccount(state, account);
|
state = importPleromaAccount(state, account);
|
||||||
});
|
});
|
||||||
|
@ -64,7 +70,7 @@ const importPleromaAccounts = (state, accounts) => {
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const followStateToRelationship = followState => {
|
const followStateToRelationship = (followState: string) => {
|
||||||
switch (followState) {
|
switch (followState) {
|
||||||
case 'follow_pending':
|
case 'follow_pending':
|
||||||
return { following: false, requested: true };
|
return { following: false, requested: true };
|
||||||
|
@ -77,14 +83,12 @@ const followStateToRelationship = followState => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateFollowRelationship = (state, id, followState) => {
|
const updateFollowRelationship = (state: State, id: string, followState: string) => {
|
||||||
const map = followStateToRelationship(followState);
|
const map = followStateToRelationship(followState);
|
||||||
return state.update(id, ImmutableMap(), relationship => relationship.merge(map));
|
return state.update(id, normalizeRelationship({}), relationship => relationship.merge(map));
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState = ImmutableMap();
|
export default function relationships(state: State = ImmutableMap<string, Relationship>(), action: AnyAction) {
|
||||||
|
|
||||||
export default function relationships(state = initialState, action) {
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ACCOUNT_IMPORT:
|
case ACCOUNT_IMPORT:
|
||||||
return importPleromaAccount(state, action.account);
|
return importPleromaAccount(state, action.account);
|
||||||
|
@ -110,7 +114,7 @@ export default function relationships(state = initialState, action) {
|
||||||
case ACCOUNT_UNPIN_SUCCESS:
|
case ACCOUNT_UNPIN_SUCCESS:
|
||||||
case ACCOUNT_NOTE_SUBMIT_SUCCESS:
|
case ACCOUNT_NOTE_SUBMIT_SUCCESS:
|
||||||
case ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS:
|
case ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS:
|
||||||
return normalizeRelationship(state, action.relationship);
|
return normalizeRelationships(state, [action.relationship]);
|
||||||
case RELATIONSHIPS_FETCH_SUCCESS:
|
case RELATIONSHIPS_FETCH_SUCCESS:
|
||||||
return normalizeRelationships(state, action.relationships);
|
return normalizeRelationships(state, action.relationships);
|
||||||
case DOMAIN_BLOCK_SUCCESS:
|
case DOMAIN_BLOCK_SUCCESS:
|
|
@ -1,4 +1,8 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
import {
|
||||||
|
Map as ImmutableMap,
|
||||||
|
OrderedSet as ImmutableOrderedSet,
|
||||||
|
Record as ImmutableRecord,
|
||||||
|
} from 'immutable';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||||
|
@ -44,29 +48,38 @@ import {
|
||||||
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
||||||
} from '../actions/scheduled_statuses';
|
} from '../actions/scheduled_statuses';
|
||||||
|
|
||||||
const initialMap = ImmutableMap({
|
import type { AnyAction } from 'redux';
|
||||||
next: null,
|
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const StatusListRecord = ImmutableRecord({
|
||||||
|
next: null as string | null,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
items: ImmutableOrderedSet(),
|
isLoading: null as boolean | null,
|
||||||
|
items: ImmutableOrderedSet<string>(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
type State = ImmutableMap<string, StatusList>;
|
||||||
favourites: initialMap,
|
type StatusList = ReturnType<typeof StatusListRecord>;
|
||||||
bookmarks: initialMap,
|
type Status = string | StatusEntity;
|
||||||
pins: initialMap,
|
type Statuses = Array<string | StatusEntity>;
|
||||||
scheduled_statuses: initialMap,
|
|
||||||
|
const initialState: State = ImmutableMap({
|
||||||
|
favourites: StatusListRecord(),
|
||||||
|
bookmarks: StatusListRecord(),
|
||||||
|
pins: StatusListRecord(),
|
||||||
|
scheduled_statuses: StatusListRecord(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const getStatusId = status => typeof status === 'string' ? status : status.get('id');
|
const getStatusId = (status: string | StatusEntity) => typeof status === 'string' ? status : status.id;
|
||||||
|
|
||||||
const getStatusIds = (statuses = []) => (
|
const getStatusIds = (statuses: Statuses = []) => (
|
||||||
ImmutableOrderedSet(statuses.map(status => status.id))
|
ImmutableOrderedSet(statuses.map(getStatusId))
|
||||||
);
|
);
|
||||||
|
|
||||||
const setLoading = (state, listType, loading) => state.setIn([listType, 'isLoading'], loading);
|
const setLoading = (state: State, listType: string, loading: boolean) => state.setIn([listType, 'isLoading'], loading);
|
||||||
|
|
||||||
const normalizeList = (state, listType, statuses, next) => {
|
const normalizeList = (state: State, listType: string, statuses: Statuses, next: string | null) => {
|
||||||
return state.update(listType, initialMap, listMap => listMap.withMutations(map => {
|
return state.update(listType, StatusListRecord(), listMap => listMap.withMutations(map => {
|
||||||
map.set('next', next);
|
map.set('next', next);
|
||||||
map.set('loaded', true);
|
map.set('loaded', true);
|
||||||
map.set('isLoading', false);
|
map.set('isLoading', false);
|
||||||
|
@ -74,29 +87,29 @@ const normalizeList = (state, listType, statuses, next) => {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const appendToList = (state, listType, statuses, next) => {
|
const appendToList = (state: State, listType: string, statuses: Statuses, next: string | null) => {
|
||||||
const newIds = getStatusIds(statuses);
|
const newIds = getStatusIds(statuses);
|
||||||
|
|
||||||
return state.update(listType, initialMap, listMap => listMap.withMutations(map => {
|
return state.update(listType, StatusListRecord(), listMap => listMap.withMutations(map => {
|
||||||
map.set('next', next);
|
map.set('next', next);
|
||||||
map.set('isLoading', false);
|
map.set('isLoading', false);
|
||||||
map.update('items', ImmutableOrderedSet(), items => items.union(newIds));
|
map.update('items', items => items.union(newIds));
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const prependOneToList = (state, listType, status) => {
|
const prependOneToList = (state: State, listType: string, status: Status) => {
|
||||||
const statusId = getStatusId(status);
|
const statusId = getStatusId(status);
|
||||||
return state.updateIn([listType, 'items'], ImmutableOrderedSet(), items => {
|
return state.updateIn([listType, 'items'], ImmutableOrderedSet(), items => {
|
||||||
return ImmutableOrderedSet([statusId]).union(items);
|
return ImmutableOrderedSet([statusId]).union(items as ImmutableOrderedSet<string>);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeOneFromList = (state, listType, status) => {
|
const removeOneFromList = (state: State, listType: string, status: Status) => {
|
||||||
const statusId = getStatusId(status);
|
const statusId = getStatusId(status);
|
||||||
return state.updateIn([listType, 'items'], ImmutableOrderedSet(), items => items.delete(statusId));
|
return state.updateIn([listType, 'items'], ImmutableOrderedSet(), items => (items as ImmutableOrderedSet<string>).delete(statusId));
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function statusLists(state = initialState, action) {
|
export default function statusLists(state = initialState, action: AnyAction) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case FAVOURITED_STATUSES_FETCH_REQUEST:
|
case FAVOURITED_STATUSES_FETCH_REQUEST:
|
||||||
case FAVOURITED_STATUSES_EXPAND_REQUEST:
|
case FAVOURITED_STATUSES_EXPAND_REQUEST:
|
||||||
|
@ -154,7 +167,7 @@ export default function statusLists(state = initialState, action) {
|
||||||
return appendToList(state, 'scheduled_statuses', action.statuses, action.next);
|
return appendToList(state, 'scheduled_statuses', action.statuses, action.next);
|
||||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||||
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
||||||
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.get('id'));
|
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.id);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
|
@ -116,7 +116,7 @@ export const calculateStatus = (
|
||||||
|
|
||||||
// Check whether a status is a quote by secondary characteristics
|
// Check whether a status is a quote by secondary characteristics
|
||||||
const isQuote = (status: StatusRecord) => {
|
const isQuote = (status: StatusRecord) => {
|
||||||
return Boolean(status.getIn(['pleroma', 'quote_url']));
|
return Boolean(status.pleroma.get('quote_url'));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Preserve quote if an existing status already has it
|
// Preserve quote if an existing status already has it
|
||||||
|
@ -124,7 +124,7 @@ const fixQuote = (status: StatusRecord, oldStatus?: StatusRecord): StatusRecord
|
||||||
if (oldStatus && !status.quote && isQuote(status)) {
|
if (oldStatus && !status.quote && isQuote(status)) {
|
||||||
return status
|
return status
|
||||||
.set('quote', oldStatus.quote)
|
.set('quote', oldStatus.quote)
|
||||||
.updateIn(['pleroma', 'quote_visible'], visible => visible || oldStatus.getIn(['pleroma', 'quote_visible']));
|
.updateIn(['pleroma', 'quote_visible'], visible => visible || oldStatus.pleroma.get('quote_visible'));
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
|
import { OrderedSet as ImmutableOrderedSet, Record as ImmutableRecord } from 'immutable';
|
||||||
|
|
||||||
|
|
||||||
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'soapbox/actions/accounts';
|
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'soapbox/actions/accounts';
|
||||||
import { DOMAIN_BLOCK_SUCCESS } from 'soapbox/actions/domain_blocks';
|
import { DOMAIN_BLOCK_SUCCESS } from 'soapbox/actions/domain_blocks';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SUGGESTIONS_FETCH_REQUEST,
|
SUGGESTIONS_FETCH_REQUEST,
|
||||||
SUGGESTIONS_FETCH_SUCCESS,
|
SUGGESTIONS_FETCH_SUCCESS,
|
||||||
|
@ -11,46 +11,58 @@ import {
|
||||||
SUGGESTIONS_V2_FETCH_REQUEST,
|
SUGGESTIONS_V2_FETCH_REQUEST,
|
||||||
SUGGESTIONS_V2_FETCH_SUCCESS,
|
SUGGESTIONS_V2_FETCH_SUCCESS,
|
||||||
SUGGESTIONS_V2_FETCH_FAIL,
|
SUGGESTIONS_V2_FETCH_FAIL,
|
||||||
} from '../actions/suggestions';
|
} from 'soapbox/actions/suggestions';
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
import type { AnyAction } from 'redux';
|
||||||
items: ImmutableOrderedSet(),
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
next: null,
|
|
||||||
|
const SuggestionRecord = ImmutableRecord({
|
||||||
|
source: '',
|
||||||
|
account: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ReducerRecord = ImmutableRecord({
|
||||||
|
items: ImmutableOrderedSet<Suggestion>(),
|
||||||
|
next: null as string | null,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type State = ReturnType<typeof ReducerRecord>;
|
||||||
|
type Suggestion = ReturnType<typeof SuggestionRecord>;
|
||||||
|
type APIEntities = Array<APIEntity>;
|
||||||
|
|
||||||
// Convert a v1 account into a v2 suggestion
|
// Convert a v1 account into a v2 suggestion
|
||||||
const accountToSuggestion = account => {
|
const accountToSuggestion = (account: APIEntity) => {
|
||||||
return {
|
return {
|
||||||
source: 'past_interactions',
|
source: 'past_interactions',
|
||||||
account: account.id,
|
account: account.id,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const importAccounts = (state, accounts) => {
|
const importAccounts = (state: State, accounts: APIEntities) => {
|
||||||
return state.withMutations(state => {
|
return state.withMutations(state => {
|
||||||
state.set('items', fromJS(accounts.map(accountToSuggestion)));
|
state.set('items', ImmutableOrderedSet(accounts.map(accountToSuggestion).map(suggestion => SuggestionRecord(suggestion))));
|
||||||
state.set('isLoading', false);
|
state.set('isLoading', false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const importSuggestions = (state, suggestions, next) => {
|
const importSuggestions = (state: State, suggestions: APIEntities, next: string | null) => {
|
||||||
return state.withMutations(state => {
|
return state.withMutations(state => {
|
||||||
state.update('items', items => items.concat(fromJS(suggestions.map(x => ({ ...x, account: x.account.id })))));
|
state.update('items', items => items.concat(suggestions.map(x => ({ ...x, account: x.account.id })).map(suggestion => SuggestionRecord(suggestion))));
|
||||||
state.set('isLoading', false);
|
state.set('isLoading', false);
|
||||||
state.set('next', next);
|
state.set('next', next);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const dismissAccount = (state, accountId) => {
|
const dismissAccount = (state: State, accountId: string) => {
|
||||||
return state.update('items', items => items.filterNot(item => item.get('account') === accountId));
|
return state.update('items', items => items.filterNot(item => item.account === accountId));
|
||||||
};
|
};
|
||||||
|
|
||||||
const dismissAccounts = (state, accountIds) => {
|
const dismissAccounts = (state: State, accountIds: Array<string>) => {
|
||||||
return state.update('items', items => items.filterNot(item => accountIds.includes(item.get('account'))));
|
return state.update('items', items => items.filterNot(item => accountIds.includes(item.account)));
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function suggestionsReducer(state = initialState, action) {
|
export default function suggestionsReducer(state: State = ReducerRecord(), action: AnyAction) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SUGGESTIONS_FETCH_REQUEST:
|
case SUGGESTIONS_FETCH_REQUEST:
|
||||||
case SUGGESTIONS_V2_FETCH_REQUEST:
|
case SUGGESTIONS_V2_FETCH_REQUEST:
|
|
@ -22,7 +22,7 @@ const getAccountBase = (state: RootState, id: string) => state.accounts.
|
||||||
const getAccountCounters = (state: RootState, id: string) => state.accounts_counters.get(id);
|
const getAccountCounters = (state: RootState, id: string) => state.accounts_counters.get(id);
|
||||||
const getAccountRelationship = (state: RootState, id: string) => state.relationships.get(id);
|
const getAccountRelationship = (state: RootState, id: string) => state.relationships.get(id);
|
||||||
const getAccountMoved = (state: RootState, id: string) => state.accounts.get(state.accounts.get(id)?.moved || '');
|
const getAccountMoved = (state: RootState, id: string) => state.accounts.get(state.accounts.get(id)?.moved || '');
|
||||||
const getAccountMeta = (state: RootState, id: string) => state.accounts_meta.get(id, ImmutableMap());
|
const getAccountMeta = (state: RootState, id: string) => state.accounts_meta.get(id);
|
||||||
const getAccountAdminData = (state: RootState, id: string) => state.admin.users.get(id);
|
const getAccountAdminData = (state: RootState, id: string) => state.admin.users.get(id);
|
||||||
const getAccountPatron = (state: RootState, id: string) => {
|
const getAccountPatron = (state: RootState, id: string) => {
|
||||||
const url = state.accounts.get(id)?.url;
|
const url = state.accounts.get(id)?.url;
|
||||||
|
@ -42,10 +42,12 @@ export const makeGetAccount = () => {
|
||||||
if (!base) return null;
|
if (!base) return null;
|
||||||
|
|
||||||
return base.withMutations(map => {
|
return base.withMutations(map => {
|
||||||
map.merge(counters);
|
if (counters) map.merge(counters);
|
||||||
map.merge(meta);
|
if (meta) {
|
||||||
map.set('pleroma', meta.get('pleroma', ImmutableMap()).merge(base.get('pleroma', ImmutableMap()))); // Lol, thanks Pleroma
|
map.merge(meta);
|
||||||
map.set('relationship', relationship);
|
map.set('pleroma', meta.pleroma.merge(base.get('pleroma', ImmutableMap()))); // Lol, thanks Pleroma
|
||||||
|
}
|
||||||
|
if (relationship) map.set('relationship', relationship);
|
||||||
map.set('moved', moved || null);
|
map.set('moved', moved || null);
|
||||||
map.set('patron', patron || null);
|
map.set('patron', patron || null);
|
||||||
map.setIn(['pleroma', 'admin'], admin);
|
map.setIn(['pleroma', 'admin'], admin);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
NotificationRecord,
|
NotificationRecord,
|
||||||
PollRecord,
|
PollRecord,
|
||||||
PollOptionRecord,
|
PollOptionRecord,
|
||||||
|
RelationshipRecord,
|
||||||
StatusEditRecord,
|
StatusEditRecord,
|
||||||
StatusRecord,
|
StatusRecord,
|
||||||
} from 'soapbox/normalizers';
|
} from 'soapbox/normalizers';
|
||||||
|
@ -34,6 +35,7 @@ type Mention = ReturnType<typeof MentionRecord>;
|
||||||
type Notification = ReturnType<typeof NotificationRecord>;
|
type Notification = ReturnType<typeof NotificationRecord>;
|
||||||
type Poll = ReturnType<typeof PollRecord>;
|
type Poll = ReturnType<typeof PollRecord>;
|
||||||
type PollOption = ReturnType<typeof PollOptionRecord>;
|
type PollOption = ReturnType<typeof PollOptionRecord>;
|
||||||
|
type Relationship = ReturnType<typeof RelationshipRecord>;
|
||||||
type StatusEdit = ReturnType<typeof StatusEditRecord>;
|
type StatusEdit = ReturnType<typeof StatusEditRecord>;
|
||||||
|
|
||||||
interface Account extends ReturnType<typeof AccountRecord> {
|
interface Account extends ReturnType<typeof AccountRecord> {
|
||||||
|
@ -68,6 +70,7 @@ export {
|
||||||
Notification,
|
Notification,
|
||||||
Poll,
|
Poll,
|
||||||
PollOption,
|
PollOption,
|
||||||
|
Relationship,
|
||||||
Status,
|
Status,
|
||||||
StatusEdit,
|
StatusEdit,
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { fromJS } from 'immutable';
|
import { List as ImmutableList, Map as ImmutableMap, fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { normalizeStatus } from 'soapbox/normalizers';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
sortEmoji,
|
sortEmoji,
|
||||||
|
@ -11,7 +13,7 @@ import {
|
||||||
simulateUnEmojiReact,
|
simulateUnEmojiReact,
|
||||||
} from '../emoji_reacts';
|
} from '../emoji_reacts';
|
||||||
|
|
||||||
const ALLOWED_EMOJI = fromJS([
|
const ALLOWED_EMOJI = ImmutableList([
|
||||||
'👍',
|
'👍',
|
||||||
'❤',
|
'❤',
|
||||||
'😂',
|
'😂',
|
||||||
|
@ -30,7 +32,7 @@ describe('filterEmoji', () => {
|
||||||
{ 'count': 1, 'me': true, 'name': '😡' },
|
{ 'count': 1, 'me': true, 'name': '😡' },
|
||||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||||
{ 'count': 1, 'me': true, 'name': '😠' },
|
{ 'count': 1, 'me': true, 'name': '😠' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
it('filters only allowed emoji', () => {
|
it('filters only allowed emoji', () => {
|
||||||
expect(filterEmoji(emojiReacts, ALLOWED_EMOJI)).toEqual(fromJS([
|
expect(filterEmoji(emojiReacts, ALLOWED_EMOJI)).toEqual(fromJS([
|
||||||
{ 'count': 1, 'me': true, 'name': '😂' },
|
{ 'count': 1, 'me': true, 'name': '😂' },
|
||||||
|
@ -49,7 +51,7 @@ describe('sortEmoji', () => {
|
||||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||||
{ 'count': 7, 'me': true, 'name': '😂' },
|
{ 'count': 7, 'me': true, 'name': '😂' },
|
||||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
it('sorts the emoji by count', () => {
|
it('sorts the emoji by count', () => {
|
||||||
expect(sortEmoji(emojiReacts)).toEqual(fromJS([
|
expect(sortEmoji(emojiReacts)).toEqual(fromJS([
|
||||||
{ 'count': 20, 'me': true, 'name': '👍' },
|
{ 'count': 20, 'me': true, 'name': '👍' },
|
||||||
|
@ -72,7 +74,7 @@ describe('mergeEmojiFavourites', () => {
|
||||||
{ 'count': 20, 'me': false, 'name': '👍' },
|
{ 'count': 20, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
it('combines 👍 reacts with favourites', () => {
|
it('combines 👍 reacts with favourites', () => {
|
||||||
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
||||||
{ 'count': 32, 'me': true, 'name': '👍' },
|
{ 'count': 32, 'me': true, 'name': '👍' },
|
||||||
|
@ -86,7 +88,7 @@ describe('mergeEmojiFavourites', () => {
|
||||||
const emojiReacts = fromJS([
|
const emojiReacts = fromJS([
|
||||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||||
{ 'count': 7, 'me': false, 'name': '😯' },
|
{ 'count': 7, 'me': false, 'name': '😯' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
it('adds 👍 reacts to the map equaling favourite count', () => {
|
it('adds 👍 reacts to the map equaling favourite count', () => {
|
||||||
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
expect(mergeEmojiFavourites(emojiReacts, favouritesCount, favourited)).toEqual(fromJS([
|
||||||
{ 'count': 15, 'me': false, 'name': '❤' },
|
{ 'count': 15, 'me': false, 'name': '❤' },
|
||||||
|
@ -116,7 +118,7 @@ describe('reduceEmoji', () => {
|
||||||
{ 'count': 15, 'me': true, 'name': '❤' },
|
{ 'count': 15, 'me': true, 'name': '❤' },
|
||||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
it('sorts, filters, and combines emoji and favourites', () => {
|
it('sorts, filters, and combines emoji and favourites', () => {
|
||||||
expect(reduceEmoji(emojiReacts, 7, true, ALLOWED_EMOJI)).toEqual(fromJS([
|
expect(reduceEmoji(emojiReacts, 7, true, ALLOWED_EMOJI)).toEqual(fromJS([
|
||||||
{ 'count': 27, 'me': true, 'name': '👍' },
|
{ 'count': 27, 'me': true, 'name': '👍' },
|
||||||
|
@ -138,7 +140,7 @@ describe('oneEmojiPerAccount', () => {
|
||||||
{ 'count': 2, 'me': true, 'name': '❤', accounts: [{ id: '1' }, { id: '2' }] },
|
{ 'count': 2, 'me': true, 'name': '❤', accounts: [{ id: '1' }, { id: '2' }] },
|
||||||
{ 'count': 1, 'me': true, 'name': '😯', accounts: [{ id: '1' }] },
|
{ 'count': 1, 'me': true, 'name': '😯', accounts: [{ id: '1' }] },
|
||||||
{ 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] },
|
{ 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
expect(oneEmojiPerAccount(emojiReacts, '1')).toEqual(fromJS([
|
expect(oneEmojiPerAccount(emojiReacts, '1')).toEqual(fromJS([
|
||||||
{ 'count': 2, 'me': true, 'name': '👍', accounts: [{ id: '1' }, { id: '2' }] },
|
{ 'count': 2, 'me': true, 'name': '👍', accounts: [{ id: '1' }, { id: '2' }] },
|
||||||
{ 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] },
|
{ 'count': 1, 'me': false, 'name': '😂', accounts: [{ id: '3' }] },
|
||||||
|
@ -148,7 +150,7 @@ describe('oneEmojiPerAccount', () => {
|
||||||
|
|
||||||
describe('getReactForStatus', () => {
|
describe('getReactForStatus', () => {
|
||||||
it('returns a single owned react (including favourite) for the status', () => {
|
it('returns a single owned react (including favourite) for the status', () => {
|
||||||
const status = fromJS({
|
const status = normalizeStatus(fromJS({
|
||||||
favourited: false,
|
favourited: false,
|
||||||
pleroma: {
|
pleroma: {
|
||||||
emoji_reactions: [
|
emoji_reactions: [
|
||||||
|
@ -158,27 +160,27 @@ describe('getReactForStatus', () => {
|
||||||
{ 'count': 7, 'me': false, 'name': '😂' },
|
{ 'count': 7, 'me': false, 'name': '😂' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
expect(getReactForStatus(status, ALLOWED_EMOJI)).toEqual('❤');
|
expect(getReactForStatus(status, ALLOWED_EMOJI)).toEqual('❤');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a thumbs-up for a favourite', () => {
|
it('returns a thumbs-up for a favourite', () => {
|
||||||
const status = fromJS({ favourites_count: 1, favourited: true });
|
const status = normalizeStatus(fromJS({ favourites_count: 1, favourited: true }));
|
||||||
expect(getReactForStatus(status)).toEqual('👍');
|
expect(getReactForStatus(status)).toEqual('👍');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns undefined when a status has no reacts (or favourites)', () => {
|
it('returns undefined when a status has no reacts (or favourites)', () => {
|
||||||
const status = fromJS({});
|
const status = normalizeStatus(fromJS({}));
|
||||||
expect(getReactForStatus(status)).toEqual(undefined);
|
expect(getReactForStatus(status)).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns undefined when a status has no valid reacts (or favourites)', () => {
|
it('returns undefined when a status has no valid reacts (or favourites)', () => {
|
||||||
const status = fromJS([
|
const status = normalizeStatus(fromJS([
|
||||||
{ 'count': 1, 'me': true, 'name': '🔪' },
|
{ 'count': 1, 'me': true, 'name': '🔪' },
|
||||||
{ 'count': 1, 'me': true, 'name': '🌵' },
|
{ 'count': 1, 'me': true, 'name': '🌵' },
|
||||||
{ 'count': 1, 'me': false, 'name': '👀' },
|
{ 'count': 1, 'me': false, 'name': '👀' },
|
||||||
{ 'count': 1, 'me': false, 'name': '🍩' },
|
{ 'count': 1, 'me': false, 'name': '🍩' },
|
||||||
]);
|
]));
|
||||||
expect(getReactForStatus(status)).toEqual(undefined);
|
expect(getReactForStatus(status)).toEqual(undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -188,7 +190,7 @@ describe('simulateEmojiReact', () => {
|
||||||
const emojiReacts = fromJS([
|
const emojiReacts = fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
expect(simulateEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
expect(simulateEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 3, 'me': true, 'name': '❤' },
|
{ 'count': 3, 'me': true, 'name': '❤' },
|
||||||
|
@ -199,7 +201,7 @@ describe('simulateEmojiReact', () => {
|
||||||
const emojiReacts = fromJS([
|
const emojiReacts = fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
expect(simulateEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
expect(simulateEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||||
|
@ -213,7 +215,7 @@ describe('simulateUnEmojiReact', () => {
|
||||||
const emojiReacts = fromJS([
|
const emojiReacts = fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 3, 'me': true, 'name': '❤' },
|
{ 'count': 3, 'me': true, 'name': '❤' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
expect(simulateUnEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
expect(simulateUnEmojiReact(emojiReacts, '❤')).toEqual(fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||||
|
@ -225,7 +227,7 @@ describe('simulateUnEmojiReact', () => {
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
||||||
{ 'count': 1, 'me': true, 'name': '😯' },
|
{ 'count': 1, 'me': true, 'name': '😯' },
|
||||||
]);
|
]) as ImmutableList<ImmutableMap<string, any>>;
|
||||||
expect(simulateUnEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
expect(simulateUnEmojiReact(emojiReacts, '😯')).toEqual(fromJS([
|
||||||
{ 'count': 2, 'me': false, 'name': '👍' },
|
{ 'count': 2, 'me': false, 'name': '👍' },
|
||||||
{ 'count': 2, 'me': false, 'name': '❤' },
|
{ 'count': 2, 'me': false, 'name': '❤' },
|
|
@ -1,71 +1,73 @@
|
||||||
import { fromJS } from 'immutable';
|
import { fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { normalizeStatus } from 'soapbox/normalizers/status';
|
||||||
|
|
||||||
import { shouldFilter } from '../timelines';
|
import { shouldFilter } from '../timelines';
|
||||||
|
|
||||||
describe('shouldFilter', () => {
|
describe('shouldFilter', () => {
|
||||||
it('returns false under normal circumstances', () => {
|
it('returns false under normal circumstances', () => {
|
||||||
const columnSettings = fromJS({});
|
const columnSettings = fromJS({});
|
||||||
const status = fromJS({});
|
const status = normalizeStatus(fromJS({}));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reblog: returns true when `shows.reblog == false`', () => {
|
it('reblog: returns true when `shows.reblog == false`', () => {
|
||||||
const columnSettings = fromJS({ shows: { reblog: false } });
|
const columnSettings = fromJS({ shows: { reblog: false } });
|
||||||
const status = fromJS({ reblog: {} });
|
const status = normalizeStatus(fromJS({ reblog: {} }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(true);
|
expect(shouldFilter(status, columnSettings)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reblog: returns false when `shows.reblog == true`', () => {
|
it('reblog: returns false when `shows.reblog == true`', () => {
|
||||||
const columnSettings = fromJS({ shows: { reblog: true } });
|
const columnSettings = fromJS({ shows: { reblog: true } });
|
||||||
const status = fromJS({ reblog: {} });
|
const status = normalizeStatus(fromJS({ reblog: {} }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reply: returns true when `shows.reply == false`', () => {
|
it('reply: returns true when `shows.reply == false`', () => {
|
||||||
const columnSettings = fromJS({ shows: { reply: false } });
|
const columnSettings = fromJS({ shows: { reply: false } });
|
||||||
const status = fromJS({ in_reply_to_id: '1234' });
|
const status = normalizeStatus(fromJS({ in_reply_to_id: '1234' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(true);
|
expect(shouldFilter(status, columnSettings)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reply: returns false when `shows.reply == true`', () => {
|
it('reply: returns false when `shows.reply == true`', () => {
|
||||||
const columnSettings = fromJS({ shows: { reply: true } });
|
const columnSettings = fromJS({ shows: { reply: true } });
|
||||||
const status = fromJS({ in_reply_to_id: '1234' });
|
const status = normalizeStatus(fromJS({ in_reply_to_id: '1234' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('direct: returns true when `shows.direct == false`', () => {
|
it('direct: returns true when `shows.direct == false`', () => {
|
||||||
const columnSettings = fromJS({ shows: { direct: false } });
|
const columnSettings = fromJS({ shows: { direct: false } });
|
||||||
const status = fromJS({ visibility: 'direct' });
|
const status = normalizeStatus(fromJS({ visibility: 'direct' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(true);
|
expect(shouldFilter(status, columnSettings)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('direct: returns false when `shows.direct == true`', () => {
|
it('direct: returns false when `shows.direct == true`', () => {
|
||||||
const columnSettings = fromJS({ shows: { direct: true } });
|
const columnSettings = fromJS({ shows: { direct: true } });
|
||||||
const status = fromJS({ visibility: 'direct' });
|
const status = normalizeStatus(fromJS({ visibility: 'direct' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('direct: returns false for a public post when `shows.direct == false`', () => {
|
it('direct: returns false for a public post when `shows.direct == false`', () => {
|
||||||
const columnSettings = fromJS({ shows: { direct: false } });
|
const columnSettings = fromJS({ shows: { direct: false } });
|
||||||
const status = fromJS({ visibility: 'public' });
|
const status = normalizeStatus(fromJS({ visibility: 'public' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple settings', () => {
|
it('multiple settings', () => {
|
||||||
const columnSettings = fromJS({ shows: { reblog: false, reply: false, direct: false } });
|
const columnSettings = fromJS({ shows: { reblog: false, reply: false, direct: false } });
|
||||||
const status = fromJS({ reblog: null, in_reply_to_id: null, visibility: 'direct' });
|
const status = normalizeStatus(fromJS({ reblog: null, in_reply_to_id: null, visibility: 'direct' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(true);
|
expect(shouldFilter(status, columnSettings)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple settings', () => {
|
it('multiple settings', () => {
|
||||||
const columnSettings = fromJS({ shows: { reblog: false, reply: true, direct: false } });
|
const columnSettings = fromJS({ shows: { reblog: false, reply: true, direct: false } });
|
||||||
const status = fromJS({ reblog: null, in_reply_to_id: '1234', visibility: 'public' });
|
const status = normalizeStatus(fromJS({ reblog: null, in_reply_to_id: '1234', visibility: 'public' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(false);
|
expect(shouldFilter(status, columnSettings)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple settings', () => {
|
it('multiple settings', () => {
|
||||||
const columnSettings = fromJS({ shows: { reblog: true, reply: false, direct: true } });
|
const columnSettings = fromJS({ shows: { reblog: true, reply: false, direct: true } });
|
||||||
const status = fromJS({ reblog: {}, in_reply_to_id: '1234', visibility: 'direct' });
|
const status = normalizeStatus(fromJS({ reblog: {}, in_reply_to_id: '1234', visibility: 'direct' }));
|
||||||
expect(shouldFilter(status, columnSettings)).toBe(true);
|
expect(shouldFilter(status, columnSettings)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -82,9 +82,9 @@ export const reduceEmoji = (emojiReacts: ImmutableList<EmojiReact>, favouritesCo
|
||||||
|
|
||||||
export const getReactForStatus = (status: any, allowedEmoji = ALLOWED_EMOJI): string | undefined => {
|
export const getReactForStatus = (status: any, allowedEmoji = ALLOWED_EMOJI): string | undefined => {
|
||||||
const result = reduceEmoji(
|
const result = reduceEmoji(
|
||||||
status.getIn(['pleroma', 'emoji_reactions'], ImmutableList()),
|
status.pleroma.get('emoji_reactions', ImmutableList()),
|
||||||
status.get('favourites_count', 0),
|
status.favourites_count || 0,
|
||||||
status.get('favourited'),
|
status.favourited,
|
||||||
allowedEmoji,
|
allowedEmoji,
|
||||||
).filter(e => e.get('me') === true)
|
).filter(e => e.get('me') === true)
|
||||||
.getIn([0, 'name']);
|
.getIn([0, 'name']);
|
||||||
|
|
|
@ -4,9 +4,9 @@ import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
export const shouldFilter = (status: StatusEntity, columnSettings: any) => {
|
export const shouldFilter = (status: StatusEntity, columnSettings: any) => {
|
||||||
const shows = ImmutableMap({
|
const shows = ImmutableMap({
|
||||||
reblog: status.get('reblog') !== null,
|
reblog: status.reblog !== null,
|
||||||
reply: status.get('in_reply_to_id') !== null,
|
reply: status.in_reply_to_id !== null,
|
||||||
direct: status.get('visibility') === 'direct',
|
direct: status.visibility === 'direct',
|
||||||
});
|
});
|
||||||
|
|
||||||
return shows.some((value, key) => {
|
return shows.some((value, key) => {
|
||||||
|
|
Loading…
Reference in New Issue