pl-fe: Support GoToSocial interaction policies
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
bff924891c
commit
0c84346c3a
5 changed files with 121 additions and 7 deletions
|
@ -106,10 +106,9 @@ const GroupPopover = (props: IGroupPopoverContainer) => {
|
|||
</Stack>
|
||||
}
|
||||
isFlush
|
||||
children={
|
||||
<div className='inline-block'>{children}</div>
|
||||
}
|
||||
/>
|
||||
>
|
||||
<div className='inline-block'>{children}</div>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import EmojiPickerDropdown from 'pl-fe/features/emoji/containers/emoji-picker-dr
|
|||
import { languages } from 'pl-fe/features/preferences';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useCanInteract } from 'pl-fe/hooks/use-can-interact';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
|
@ -38,6 +39,9 @@ import toast from 'pl-fe/toast';
|
|||
import copy from 'pl-fe/utils/copy';
|
||||
|
||||
import GroupPopover from './groups/popover/group-popover';
|
||||
import Popover from './ui/popover';
|
||||
import Stack from './ui/stack';
|
||||
import Text from './ui/text';
|
||||
|
||||
import type { Menu } from 'pl-fe/components/dropdown-menu';
|
||||
import type { Emoji as EmojiType } from 'pl-fe/features/emoji';
|
||||
|
@ -111,8 +115,76 @@ const messages = defineMessages({
|
|||
addKnownLanguage: { id: 'status.add_known_language', defaultMessage: 'Do not auto-translate posts in {language}.' },
|
||||
translate: { id: 'status.translate', defaultMessage: 'Translate' },
|
||||
hideTranslation: { id: 'status.hide_translation', defaultMessage: 'Hide translation' },
|
||||
|
||||
favouriteInteractionPolicyHeader: { id: 'status.interaction_policy.favourite.header', defaultMessage: 'The author limits who can like this post.' },
|
||||
reblogInteractionPolicyHeader: { id: 'status.interaction_policy.reblog.header', defaultMessage: 'The author limits who can repost this post.' },
|
||||
replyInteractionPolicyHeader: { id: 'status.interaction_policy.reply.header', defaultMessage: 'The author limits who can reply to this post.' },
|
||||
|
||||
favouriteInteractionPolicyFollowers: { id: 'status.interaction_policy.favourite.followers_only', defaultMessage: 'Only users following the author can like.' },
|
||||
favouriteInteractionPolicyFollowing: { id: 'status.interaction_policy.favourite.following_only', defaultMessage: 'Only users followed by the author can like.' },
|
||||
favouriteInteractionPolicyMutuals: { id: 'status.interaction_policy.favourite.mutuals_only', defaultMessage: 'Only users mutually following the author can like.' },
|
||||
favouriteInteractionPolicyMentioned: { id: 'status.interaction_policy.favourite.mentioned_only', defaultMessage: 'Only users mentioned by the author can like.' },
|
||||
|
||||
reblogInteractionPolicyFollowers: { id: 'status.interaction_policy.reblog.followers_only', defaultMessage: 'Only users following the author can repost.' },
|
||||
reblogInteractionPolicyFollowing: { id: 'status.interaction_policy.reblog.following_only', defaultMessage: 'Only users followed by the author can repost.' },
|
||||
reblogInteractionPolicyMutuals: { id: 'status.interaction_policy.reblog.mutuals_only', defaultMessage: 'Only users mutually following the author can repost.' },
|
||||
reblogInteractionPolicyMentioned: { id: 'status.interaction_policy.reblog.mentioned_only', defaultMessage: 'Only users mentioned by the author can repost.' },
|
||||
|
||||
replyInteractionPolicyFollowers: { id: 'status.interaction_policy.reply.followers_only', defaultMessage: 'Only users following the author can reply.' },
|
||||
replyInteractionPolicyFollowing: { id: 'status.interaction_policy.reply.following_only', defaultMessage: 'Only users followed by the author can reply.' },
|
||||
replyInteractionPolicyMutuals: { id: 'status.interaction_policy.reply.mutuals_only', defaultMessage: 'Only users mutually following the author can reply.' },
|
||||
replyInteractionPolicyMentioned: { id: 'status.interaction_policy.reply.mentioned_only', defaultMessage: 'Only users mentioned by the author can reply.' },
|
||||
});
|
||||
|
||||
interface IInteractionPopover {
|
||||
type: 'favourite' | 'reblog' | 'reply';
|
||||
allowed: ReturnType<typeof useCanInteract>['allowed'];
|
||||
}
|
||||
|
||||
const INTERACTION_POLICY_HEADERS = {
|
||||
favourite: messages.favouriteInteractionPolicyHeader,
|
||||
reblog: messages.reblogInteractionPolicyHeader,
|
||||
reply: messages.replyInteractionPolicyHeader,
|
||||
};
|
||||
|
||||
const INTERACTION_POLICY_DESCRIPTIONS = {
|
||||
favourite: {
|
||||
followers: messages.favouriteInteractionPolicyFollowers,
|
||||
following: messages.favouriteInteractionPolicyFollowing,
|
||||
mutuals: messages.favouriteInteractionPolicyMutuals,
|
||||
mentioned: messages.favouriteInteractionPolicyMentioned,
|
||||
},
|
||||
reblog: {
|
||||
followers: messages.reblogInteractionPolicyFollowers,
|
||||
following: messages.reblogInteractionPolicyFollowing,
|
||||
mutuals: messages.reblogInteractionPolicyMutuals,
|
||||
mentioned: messages.reblogInteractionPolicyMentioned,
|
||||
},
|
||||
reply: {
|
||||
followers: messages.replyInteractionPolicyFollowers,
|
||||
following: messages.replyInteractionPolicyFollowing,
|
||||
mutuals: messages.replyInteractionPolicyMutuals,
|
||||
mentioned: messages.replyInteractionPolicyMentioned,
|
||||
},
|
||||
};
|
||||
|
||||
const InteractionPopover: React.FC<IInteractionPopover> = ({ type, allowed }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const allowedType = allowed?.includes('followers') ? 'followers' : allowed?.includes('following') ? 'following' : allowed?.includes('mutuals') ? 'mutuals' : 'mentioned';
|
||||
|
||||
return (
|
||||
<Stack space={1} className='max-w-96'>
|
||||
<Text weight='semibold' align='center'>
|
||||
{intl.formatMessage(INTERACTION_POLICY_HEADERS[type])}
|
||||
</Text>
|
||||
<Text theme='muted' align='center'>
|
||||
{intl.formatMessage(INTERACTION_POLICY_DESCRIPTIONS[type][allowedType])}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
interface IActionButton extends Pick<IStatusActionBar, 'status' | 'statusActionButtonTheme' | 'withLabels'> {
|
||||
me: Me;
|
||||
onOpenUnauthorizedModal: (action?: UnauthorizedModalAction) => void;
|
||||
|
@ -133,6 +205,7 @@ const ReplyButton: React.FC<IReplyButton> = ({
|
|||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const canReply = useCanInteract(status, 'can_reply');
|
||||
const { groupRelationship } = useGroupRelationship(status.group_id || undefined);
|
||||
|
||||
let replyTitle;
|
||||
|
@ -170,6 +243,15 @@ const ReplyButton: React.FC<IReplyButton> = ({
|
|||
/>
|
||||
);
|
||||
|
||||
if (me && !canReply.canInteract) return (
|
||||
<Popover
|
||||
interaction='click'
|
||||
content={<InteractionPopover allowed={canReply.allowed} type='reply' />}
|
||||
>
|
||||
{replyButton}
|
||||
</Popover>
|
||||
);
|
||||
|
||||
return status.group ? (
|
||||
<GroupPopover
|
||||
group={status.group}
|
||||
|
@ -198,6 +280,7 @@ const ReblogButton: React.FC<IReblogButton> = ({
|
|||
|
||||
const { boostModal } = useSettings();
|
||||
const { openModal } = useModalsStore();
|
||||
const canReblog = useCanInteract(status, 'can_reblog');
|
||||
|
||||
let reblogIcon = require('@tabler/icons/outline/repeat.svg');
|
||||
|
||||
|
@ -239,6 +322,15 @@ const ReblogButton: React.FC<IReblogButton> = ({
|
|||
/>
|
||||
);
|
||||
|
||||
if (me && !canReblog.canInteract) return (
|
||||
<Popover
|
||||
interaction='click'
|
||||
content={<InteractionPopover allowed={canReblog.allowed} type='reblog' />}
|
||||
>
|
||||
{reblogButton}
|
||||
</Popover>
|
||||
);
|
||||
|
||||
if (!features.quotePosts || !me) return reblogButton;
|
||||
|
||||
const handleQuoteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
|
@ -282,6 +374,7 @@ const FavouriteButton: React.FC<IActionButton> = ({
|
|||
const intl = useIntl();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
const canFavourite = useCanInteract(status, 'can_favourite');
|
||||
|
||||
const handleFavouriteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
|
@ -295,7 +388,7 @@ const FavouriteButton: React.FC<IActionButton> = ({
|
|||
openModal('FAVOURITES', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
const favouriteButton = (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.favourite)}
|
||||
icon={features.statusDislikes ? require('@tabler/icons/outline/thumb-up.svg') : require('@tabler/icons/outline/heart.svg')}
|
||||
|
@ -309,6 +402,15 @@ const FavouriteButton: React.FC<IActionButton> = ({
|
|||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
|
||||
if (me && !canFavourite.canInteract) return (
|
||||
<Popover
|
||||
interaction='click'
|
||||
content={<InteractionPopover allowed={canFavourite.allowed} type='favourite' />}
|
||||
>
|
||||
{favouriteButton}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
const DislikeButton: React.FC<IActionButton> = ({
|
||||
|
|
|
@ -683,7 +683,6 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
theme='outlined'
|
||||
className='px-2'
|
||||
iconClassName='h-4 w-4'
|
||||
children={null}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
|
|
|
@ -389,7 +389,6 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
theme='outlined'
|
||||
className='h-[30px] px-2'
|
||||
iconClassName='h-4 w-4'
|
||||
children={null}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
|
||||
|
|
|
@ -1459,6 +1459,21 @@
|
|||
"status.group": "Posted in {group}",
|
||||
"status.group_mod_delete": "Delete post from group",
|
||||
"status.hide_translation": "Hide translation",
|
||||
"status.interaction_policy.favourite.followers_only": "Only users following the author can like.",
|
||||
"status.interaction_policy.favourite.following_only": "Only users followed by the author can like.",
|
||||
"status.interaction_policy.favourite.header": "The author limits who can like this post.",
|
||||
"status.interaction_policy.favourite.mentioned_only": "Only users mentioned by the author can like.",
|
||||
"status.interaction_policy.favourite.mutuals_only": "Only users mutually following the author can like.",
|
||||
"status.interaction_policy.reblog.followers_only": "Only users following the author can repost.",
|
||||
"status.interaction_policy.reblog.following_only": "Only users followed by the author can repost.",
|
||||
"status.interaction_policy.reblog.header": "The author limits who can repost this post.",
|
||||
"status.interaction_policy.reblog.mentioned_only": "Only users mentioned by the author can repost.",
|
||||
"status.interaction_policy.reblog.mutuals_only": "Only users mutually following the author can repost.",
|
||||
"status.interaction_policy.reply.followers_only": "Only users following the author can reply.",
|
||||
"status.interaction_policy.reply.following_only": "Only users followed by the author can reply.",
|
||||
"status.interaction_policy.reply.header": "The author limits who can reply to this post.",
|
||||
"status.interaction_policy.reply.mentioned_only": "Only users mentioned by the author can reply.",
|
||||
"status.interaction_policy.reply.mutuals_only": "Only users mutually following the author can reply.",
|
||||
"status.interactions.dislikes": "{count, plural, one {Dislike} other {Dislikes}}",
|
||||
"status.interactions.favourites": "{count, plural, one {Like} other {Likes}}",
|
||||
"status.interactions.quotes": "{count, plural, one {Quote} other {Quotes}}",
|
||||
|
|
Loading…
Reference in a new issue