Mention repost author when replying to a reposted status
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
775d272254
commit
9c5e3a98e0
6 changed files with 29 additions and 18 deletions
|
@ -152,9 +152,10 @@ interface ComposeReplyAction {
|
|||
account: Account;
|
||||
explicitAddressing: boolean;
|
||||
preserveSpoilers: boolean;
|
||||
rebloggedBy?: Account;
|
||||
}
|
||||
|
||||
const replyCompose = (status: Status) =>
|
||||
const replyCompose = (status: Status, rebloggedBy?: Account) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
const instance = state.instance;
|
||||
|
@ -171,6 +172,7 @@ const replyCompose = (status: Status) =>
|
|||
account,
|
||||
explicitAddressing,
|
||||
preserveSpoilers,
|
||||
rebloggedBy: rebloggedBy,
|
||||
};
|
||||
|
||||
dispatch(action);
|
||||
|
|
|
@ -28,7 +28,7 @@ import { getReactForStatus, reduceEmoji } from 'soapbox/utils/emoji-reacts';
|
|||
import GroupPopover from './groups/popover/group-popover';
|
||||
|
||||
import type { Menu } from 'soapbox/components/dropdown-menu';
|
||||
import type { Group, Status } from 'soapbox/types/entities';
|
||||
import type { Account, Group, Status } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' },
|
||||
|
@ -99,6 +99,7 @@ const messages = defineMessages({
|
|||
|
||||
interface IStatusActionBar {
|
||||
status: Status;
|
||||
rebloggedBy?: Account;
|
||||
withLabels?: boolean;
|
||||
expandable?: boolean;
|
||||
space?: 'sm' | 'md' | 'lg';
|
||||
|
@ -113,6 +114,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
space = 'sm',
|
||||
statusActionButtonTheme = 'default',
|
||||
fromBookmarks = false,
|
||||
rebloggedBy,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
|
@ -148,7 +150,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
|
||||
const handleReplyClick: React.MouseEventHandler = (e) => {
|
||||
if (me) {
|
||||
dispatch(replyCompose(status));
|
||||
dispatch(replyCompose(status, rebloggedBy));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REPLY');
|
||||
}
|
||||
|
@ -211,7 +213,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
};
|
||||
|
||||
const doDeleteStatus = (withRedraft = false) => {
|
||||
dispatch((_, getState) => {
|
||||
dispatch((_) => {
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.id, withRedraft));
|
||||
} else {
|
||||
|
|
|
@ -138,7 +138,7 @@ const Status: React.FC<IStatus> = (props) => {
|
|||
|
||||
const handleHotkeyReply = (e?: KeyboardEvent): void => {
|
||||
e?.preventDefault();
|
||||
dispatch(replyCompose(actualStatus));
|
||||
dispatch(replyCompose(actualStatus, status.reblog && typeof status.reblog === 'object' ? status.account : undefined));
|
||||
};
|
||||
|
||||
const handleHotkeyFavourite = (): void => {
|
||||
|
@ -458,7 +458,7 @@ const Status: React.FC<IStatus> = (props) => {
|
|||
|
||||
{!hideActionBar && (
|
||||
<div className='pt-4'>
|
||||
<StatusActionBar status={actualStatus} fromBookmarks={fromBookmarks} />
|
||||
<StatusActionBar status={actualStatus} rebloggedBy={isReblog ? status.account : undefined} fromBookmarks={fromBookmarks} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -2,8 +2,7 @@ import React, { useCallback } from 'react';
|
|||
import { FormattedList, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { useAppDispatch, useAppSelector, useCompose, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
import { statusToMentionsAccountIdsArray } from 'soapbox/reducers/compose';
|
||||
import { useAppDispatch, useAppSelector, useCompose, useFeatures } from 'soapbox/hooks';
|
||||
import { makeGetStatus } from 'soapbox/selectors';
|
||||
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
@ -20,14 +19,11 @@ const ReplyMentions: React.FC<IReplyMentions> = ({ composeId }) => {
|
|||
const getStatus = useCallback(makeGetStatus(), []);
|
||||
const status = useAppSelector<StatusEntity | null>(state => getStatus(state, { id: compose.in_reply_to! }));
|
||||
const to = compose.to;
|
||||
const { account } = useOwnAccount();
|
||||
|
||||
if (!features.explicitAddressing || !status || !to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parentTo = status && statusToMentionsAccountIdsArray(status, account!);
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -36,7 +32,7 @@ const ReplyMentions: React.FC<IReplyMentions> = ({ composeId }) => {
|
|||
}));
|
||||
};
|
||||
|
||||
if (!parentTo || (parentTo.size === 0)) {
|
||||
if (!compose.parent_reblogged_by && to.size === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ const ReplyMentionsModal: React.FC<IReplyMentionsModal> = ({ composeId, onClose
|
|||
const status = useAppSelector<StatusEntity | null>(state => getStatus(state, { id: compose.in_reply_to! }));
|
||||
const { account } = useOwnAccount();
|
||||
|
||||
const mentions = statusToMentionsAccountIdsArray(status!, account!);
|
||||
const mentions = statusToMentionsAccountIdsArray(status!, account!, compose.parent_reblogged_by);
|
||||
const author = (status?.account as AccountEntity).id;
|
||||
|
||||
const onClickClose = () => {
|
||||
|
|
|
@ -108,6 +108,7 @@ export const ReducerCompose = ImmutableRecord({
|
|||
tagHistory: ImmutableList<string>(),
|
||||
text: '',
|
||||
to: ImmutableOrderedSet<string>(),
|
||||
parent_reblogged_by: null as string | null,
|
||||
});
|
||||
|
||||
type State = ImmutableMap<string, Compose>;
|
||||
|
@ -125,19 +126,21 @@ const statusToTextMentions = (status: Status, account: Account) => {
|
|||
.join('');
|
||||
};
|
||||
|
||||
export const statusToMentionsArray = (status: Status, account: Account) => {
|
||||
export const statusToMentionsArray = (status: Status, account: Account, rebloggedBy?: Account) => {
|
||||
const author = status.getIn(['account', 'acct']) as string;
|
||||
const mentions = status.get('mentions')?.map((m) => m.acct) || [];
|
||||
|
||||
return ImmutableOrderedSet<string>([author])
|
||||
.concat(rebloggedBy ? [rebloggedBy.acct] : [])
|
||||
.concat(mentions)
|
||||
.delete(account.acct) as ImmutableOrderedSet<string>;
|
||||
};
|
||||
|
||||
export const statusToMentionsAccountIdsArray = (status: StatusEntity, account: Account) => {
|
||||
export const statusToMentionsAccountIdsArray = (status: StatusEntity, account: Account, parentRebloggedBy?: string | null) => {
|
||||
const mentions = status.mentions.map((m) => m.id);
|
||||
|
||||
return ImmutableOrderedSet<string>([account.id])
|
||||
return ImmutableOrderedSet<string>([status.account.id])
|
||||
.concat(parentRebloggedBy ? [parentRebloggedBy] : [])
|
||||
.concat(mentions)
|
||||
.delete(account.id);
|
||||
};
|
||||
|
@ -306,9 +309,14 @@ export default function compose(state = initialState, action: ComposeAction | Ev
|
|||
return updateCompose(state, action.id, compose => compose.withMutations(map => {
|
||||
const defaultCompose = state.get('default')!;
|
||||
|
||||
const to = action.explicitAddressing
|
||||
? statusToMentionsArray(action.status, action.account, action.rebloggedBy)
|
||||
: ImmutableOrderedSet<string>();
|
||||
|
||||
map.set('group_id', action.status.getIn(['group', 'id']) as string);
|
||||
map.set('in_reply_to', action.status.get('id'));
|
||||
map.set('to', action.explicitAddressing ? statusToMentionsArray(action.status, action.account) : ImmutableOrderedSet<string>());
|
||||
map.set('to', to);
|
||||
map.set('parent_reblogged_by', action.rebloggedBy?.id || null);
|
||||
map.set('text', !action.explicitAddressing ? statusToTextMentions(action.status, action.account) : '');
|
||||
map.set('privacy', privacyPreference(action.status.visibility, defaultCompose.privacy));
|
||||
map.set('focusDate', new Date());
|
||||
|
@ -334,6 +342,7 @@ export default function compose(state = initialState, action: ComposeAction | Ev
|
|||
|
||||
map.set('quote', action.status.get('id'));
|
||||
map.set('to', ImmutableOrderedSet<string>([author]));
|
||||
map.set('parent_reblogged_by', null);
|
||||
map.set('text', '');
|
||||
map.set('privacy', privacyPreference(action.status.visibility, defaultCompose.privacy));
|
||||
map.set('focusDate', new Date());
|
||||
|
@ -435,11 +444,13 @@ export default function compose(state = initialState, action: ComposeAction | Ev
|
|||
})));
|
||||
case COMPOSE_SET_STATUS:
|
||||
return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => {
|
||||
const to = action.explicitAddressing ? getExplicitMentions(action.status.account.id, action.status) : ImmutableOrderedSet<string>();
|
||||
if (!action.withRedraft && !action.draftId) {
|
||||
map.set('id', action.status.id);
|
||||
}
|
||||
map.set('text', action.rawText || unescapeHTML(expandMentions(action.status)));
|
||||
map.set('to', action.explicitAddressing ? getExplicitMentions(action.status.account.id, action.status) : ImmutableOrderedSet<string>());
|
||||
map.set('to', to);
|
||||
map.set('parent_reblogged_by', null);
|
||||
map.set('in_reply_to', action.status.get('in_reply_to_id'));
|
||||
map.set('privacy', action.status.get('visibility'));
|
||||
map.set('focusDate', new Date());
|
||||
|
|
Loading…
Reference in a new issue