pl-fe: allow specifying boost visibility
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -2151,6 +2151,8 @@ class PlApiClient {
|
||||
* Boost a status
|
||||
* Reshare a status on your own profile.
|
||||
* @see {@link https://docs.joinmastodon.org/methods/statuses/#reblog}
|
||||
*
|
||||
* Specifying reblog visibility requires features{@link Features['reblogVisibility']}.
|
||||
*/
|
||||
reblogStatus: async (statusId: string, visibility?: string) => {
|
||||
const response = await this.request(`/api/v1/statuses/${statusId}/reblog`, { method: 'POST', body: { visibility } });
|
||||
|
||||
@ -47,13 +47,13 @@ const messages = defineMessages({
|
||||
selectFolder: { id: 'status.bookmark.select_folder', defaultMessage: 'Select folder' },
|
||||
});
|
||||
|
||||
const reblog = (status: Pick<Status, 'id'>) =>
|
||||
const reblog = (status: Pick<Status, 'id'>, visibility?: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return noOp();
|
||||
|
||||
dispatch(reblogRequest(status.id));
|
||||
|
||||
return getClient(getState()).statuses.reblogStatus(status.id).then((response) => {
|
||||
return getClient(getState()).statuses.reblogStatus(status.id, visibility).then((response) => {
|
||||
// The reblog API method returns a new status wrapped around the original. In this case we are only
|
||||
// interested in how the original is modified, hence passing it skipping the wrapper
|
||||
if (response.reblog) dispatch(importEntities({ statuses: [response.reblog] }));
|
||||
@ -73,11 +73,11 @@ const unreblog = (status: Pick<Status, 'id'>) =>
|
||||
});
|
||||
};
|
||||
|
||||
const toggleReblog = (status: Pick<Status, 'id' | 'reblogged'>) => {
|
||||
const toggleReblog = (status: Pick<Status, 'id' | 'reblogged'>, visibility?: string) => {
|
||||
if (status.reblogged) {
|
||||
return unreblog(status);
|
||||
} else {
|
||||
return reblog(status);
|
||||
return reblog(status, visibility);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -94,6 +94,10 @@ const messages = defineMessages({
|
||||
quotePost: { id: 'status.quote', defaultMessage: 'Quote post' },
|
||||
reblog: { id: 'status.reblog', defaultMessage: 'Repost' },
|
||||
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Repost to original audience' },
|
||||
reblog_visibility: { id: 'status.reblog_visibility', defaultMessage: 'Repost to specific audience' },
|
||||
reblog_visibility_public: { id: 'status.reblog_visibility_public', defaultMessage: 'Public repost' },
|
||||
reblog_visibility_unlisted: { id: 'status.reblog_visibility_unlisted', defaultMessage: 'Unlisted repost' },
|
||||
reblog_visibility_private: { id: 'status.reblog_visibility_private', defaultMessage: 'Followers-only repost' },
|
||||
redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' },
|
||||
redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
|
||||
redraftHeading: { id: 'confirmations.redraft.heading', defaultMessage: 'Delete & redraft' },
|
||||
@ -658,12 +662,12 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
dispatch(togglePin(status));
|
||||
};
|
||||
|
||||
const handleReblogClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(status));
|
||||
const handleReblogClick = (e: React.MouseEvent | React.KeyboardEvent, visibility?: string) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(status, visibility));
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: modalReblog });
|
||||
openModal('BOOST', { statusId: status.id, onReblog: modalReblog, visibility });
|
||||
}
|
||||
};
|
||||
|
||||
@ -861,6 +865,30 @@ const MenuButton: React.FC<IMenuButton> = ({
|
||||
|
||||
menu.push(null);
|
||||
|
||||
if (publicStatus && !status.reblogged && features.reblogVisibility) {
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.reblog_visibility),
|
||||
icon: require('@tabler/icons/outline/repeat.svg'),
|
||||
items: [
|
||||
{
|
||||
text: intl.formatMessage(messages.reblog_visibility_public),
|
||||
action: (e) => handleReblogClick(e, 'public'),
|
||||
icon: require('@tabler/icons/outline/world.svg'),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage(messages.reblog_visibility_unlisted),
|
||||
action: (e) => handleReblogClick(e, 'unlisted'),
|
||||
icon: require('@tabler/icons/outline/lock-open.svg'),
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage(messages.reblog_visibility_private),
|
||||
action: (e) => handleReblogClick(e, 'private'),
|
||||
icon: require('@tabler/icons/outline/lock.svg'),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (ownAccount) {
|
||||
if (publicStatus) {
|
||||
menu.push({
|
||||
|
||||
@ -245,19 +245,29 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
);
|
||||
}
|
||||
|
||||
const values = {
|
||||
name: <FormattedList type='conjunction' value={renderedAccounts} />,
|
||||
count: accounts.length,
|
||||
};
|
||||
|
||||
return (
|
||||
<StatusInfo
|
||||
avatarSize={avatarSize}
|
||||
icon={<Icon src={require('@tabler/icons/outline/repeat.svg')} className='size-4 text-green-600' />}
|
||||
text={
|
||||
<FormattedMessage
|
||||
id='status.reblogged_by'
|
||||
defaultMessage='{name} reposted'
|
||||
values={{
|
||||
name: <FormattedList type='conjunction' value={renderedAccounts} />,
|
||||
count: accounts.length,
|
||||
}}
|
||||
/>
|
||||
status.visibility === 'private' ? (
|
||||
<FormattedMessage
|
||||
id='status.reblogged_by_private'
|
||||
defaultMessage='{name} reposted to followers'
|
||||
values={values}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='status.reblogged_by'
|
||||
defaultMessage='{name} reposted'
|
||||
values={values}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -270,7 +270,7 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
} else {
|
||||
openModal('BOOST', {
|
||||
statusId: status.id,
|
||||
onReblog: (status) => {
|
||||
onReblog: () => {
|
||||
dispatch(reblog(status));
|
||||
},
|
||||
});
|
||||
|
||||
@ -150,7 +150,7 @@ const Thread: React.FC<IThread> = ({
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
handleModalReblog(status);
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: handleModalReblog });
|
||||
openModal('BOOST', { statusId: status.id, onReblog: () => handleModalReblog(status) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -10,7 +10,6 @@ import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { makeGetStatus } from 'pl-fe/selectors';
|
||||
|
||||
import type { BaseModalProps } from '../modal-root';
|
||||
import type { Status as StatusEntity } from 'pl-fe/normalizers/status';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Un-repost' },
|
||||
@ -19,17 +18,18 @@ const messages = defineMessages({
|
||||
|
||||
interface BoostModalProps {
|
||||
statusId: string;
|
||||
onReblog: (status: Pick<StatusEntity, 'id' | 'reblogged'>) => void;
|
||||
onReblog: () => void;
|
||||
visibility?: string;
|
||||
}
|
||||
|
||||
const BoostModal: React.FC<BaseModalProps & BoostModalProps> = ({ statusId, onReblog, onClose }) => {
|
||||
const BoostModal: React.FC<BaseModalProps & BoostModalProps> = ({ statusId, onReblog, visibility, onClose }) => {
|
||||
const getStatus = useCallback(makeGetStatus(), []);
|
||||
|
||||
const intl = useIntl();
|
||||
const status = useAppSelector(state => getStatus(state, { id: statusId }))!;
|
||||
|
||||
const handleReblog = () => {
|
||||
onReblog(status);
|
||||
onReblog();
|
||||
onClose('BOOST');
|
||||
};
|
||||
|
||||
@ -37,7 +37,11 @@ const BoostModal: React.FC<BaseModalProps & BoostModalProps> = ({ statusId, onRe
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={<FormattedMessage id='boost_modal.title' defaultMessage='Repost?' />}
|
||||
title={visibility === 'unlisted'
|
||||
? <FormattedMessage id='boost_modal.title.unlisted' defaultMessage='Repost unlisted?' />
|
||||
: visibility === 'private'
|
||||
? <FormattedMessage id='boost_modal.title.private' defaultMessage='Repost privately?' />
|
||||
: <FormattedMessage id='boost_modal.title' defaultMessage='Repost?' />}
|
||||
confirmationAction={handleReblog}
|
||||
confirmationText={intl.formatMessage(buttonText)}
|
||||
>
|
||||
|
||||
@ -256,6 +256,8 @@
|
||||
"bookmarks.edit_folder": "Edit folder",
|
||||
"boost_modal.combo": "You can press {combo} to skip this next time",
|
||||
"boost_modal.title": "Repost?",
|
||||
"boost_modal.title.private": "Repost privately?",
|
||||
"boost_modal.title.unlisted": "Repost unlisted?",
|
||||
"bundle_column_error.body": "Something went wrong while loading this page.",
|
||||
"bundle_column_error.retry": "Try again",
|
||||
"bundle_column_error.title": "Network error",
|
||||
@ -1539,7 +1541,12 @@
|
||||
"status.read_more": "Read more",
|
||||
"status.reblog": "Repost",
|
||||
"status.reblog_private": "Repost to original audience",
|
||||
"status.reblog_visibility": "Repost to specific audience",
|
||||
"status.reblog_visibility_private": "Followers-only repost",
|
||||
"status.reblog_visibility_public": "Public repost",
|
||||
"status.reblog_visibility_unlisted": "Unlisted repost",
|
||||
"status.reblogged_by": "{name} reposted",
|
||||
"status.reblogged_by_private": "{name} reposted to followers",
|
||||
"status.reblogged_by_with_group": "{name} reposted from {group}",
|
||||
"status.reblogs.empty": "No one has reposted this post yet. When someone does, they will show up here.",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
|
||||
Reference in New Issue
Block a user