mirror of
https://github.com/mastodon/mastodon.git
synced 2025-10-05 00:22:42 +00:00
Update confirmation dialogs for follow button actions "unfollow", "unblock", and "withdraw request" (#36289)
This commit is contained in:
parent
c12b8f51c1
commit
473bd84c24
|
@ -8,7 +8,6 @@ import { useIdentity } from '@/mastodon/identity_context';
|
|||
import {
|
||||
fetchRelationships,
|
||||
followAccount,
|
||||
unblockAccount,
|
||||
unmuteAccount,
|
||||
} from 'mastodon/actions/accounts';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
|
@ -59,7 +58,8 @@ export const FollowButton: React.FC<{
|
|||
accountId?: string;
|
||||
compact?: boolean;
|
||||
labelLength?: 'auto' | 'short' | 'long';
|
||||
}> = ({ accountId, compact, labelLength = 'auto' }) => {
|
||||
className?: string;
|
||||
}> = ({ accountId, compact, labelLength = 'auto', className }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const { signedIn } = useIdentity();
|
||||
|
@ -96,12 +96,24 @@ export const FollowButton: React.FC<{
|
|||
return;
|
||||
} else if (relationship.muting) {
|
||||
dispatch(unmuteAccount(accountId));
|
||||
} else if (account && (relationship.following || relationship.requested)) {
|
||||
} else if (account && relationship.following) {
|
||||
dispatch(
|
||||
openModal({ modalType: 'CONFIRM_UNFOLLOW', modalProps: { account } }),
|
||||
);
|
||||
} else if (account && relationship.requested) {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM_WITHDRAW_REQUEST',
|
||||
modalProps: { account },
|
||||
}),
|
||||
);
|
||||
} else if (relationship.blocking) {
|
||||
dispatch(unblockAccount(accountId));
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM_UNBLOCK',
|
||||
modalProps: { account },
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
dispatch(followAccount(accountId));
|
||||
}
|
||||
|
@ -144,7 +156,7 @@ export const FollowButton: React.FC<{
|
|||
href='/settings/profile'
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
className={classNames('button button-secondary', {
|
||||
className={classNames(className, 'button button-secondary', {
|
||||
'button--compact': compact,
|
||||
})}
|
||||
>
|
||||
|
@ -158,13 +170,12 @@ export const FollowButton: React.FC<{
|
|||
onClick={handleClick}
|
||||
disabled={
|
||||
relationship?.blocked_by ||
|
||||
relationship?.blocking ||
|
||||
(!(relationship?.following || relationship?.requested) &&
|
||||
(account?.suspended || !!account?.moved))
|
||||
}
|
||||
secondary={following}
|
||||
compact={compact}
|
||||
className={following ? 'button--destructive' : undefined}
|
||||
className={classNames(className, { 'button--destructive': following })}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
|
|
|
@ -34,7 +34,6 @@ import { initMuteModal } from 'mastodon/actions/mutes';
|
|||
import { initReport } from 'mastodon/actions/reports';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { CopyIconButton } from 'mastodon/components/copy_icon_button';
|
||||
import {
|
||||
FollowersCounter,
|
||||
|
@ -384,7 +383,7 @@ export const AccountHeader: React.FC<{
|
|||
const isRemote = account?.acct !== account?.username;
|
||||
const remoteDomain = isRemote ? account?.acct.split('@')[1] : null;
|
||||
|
||||
const menu = useMemo(() => {
|
||||
const menuItems = useMemo(() => {
|
||||
const arr: MenuItem[] = [];
|
||||
|
||||
if (!account) {
|
||||
|
@ -606,6 +605,15 @@ export const AccountHeader: React.FC<{
|
|||
handleUnblockDomain,
|
||||
]);
|
||||
|
||||
const menu = accountId !== me && (
|
||||
<Dropdown
|
||||
disabled={menuItems.length === 0}
|
||||
items={menuItems}
|
||||
icon='ellipsis-v'
|
||||
iconComponent={MoreHorizIcon}
|
||||
/>
|
||||
);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
@ -719,21 +727,16 @@ export const AccountHeader: React.FC<{
|
|||
);
|
||||
}
|
||||
|
||||
if (relationship?.blocking) {
|
||||
const isMovedAndUnfollowedAccount = account.moved && !relationship?.following;
|
||||
|
||||
if (!isMovedAndUnfollowedAccount) {
|
||||
actionBtn = (
|
||||
<Button
|
||||
text={intl.formatMessage(messages.unblock, {
|
||||
name: account.username,
|
||||
})}
|
||||
onClick={handleBlock}
|
||||
<FollowButton
|
||||
accountId={accountId}
|
||||
className='account__header__follow-button'
|
||||
labelLength='long'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
actionBtn = <FollowButton accountId={accountId} />;
|
||||
}
|
||||
|
||||
if (account.moved && !relationship?.following) {
|
||||
actionBtn = '';
|
||||
}
|
||||
|
||||
if (account.locked) {
|
||||
|
@ -815,18 +818,11 @@ export const AccountHeader: React.FC<{
|
|||
/>
|
||||
</a>
|
||||
|
||||
<div className='account__header__tabs__buttons'>
|
||||
<div className='account__header__buttons account__header__buttons--desktop'>
|
||||
{!hidden && actionBtn}
|
||||
{!hidden && bellBtn}
|
||||
{!hidden && shareBtn}
|
||||
{accountId !== me && (
|
||||
<Dropdown
|
||||
disabled={menu.length === 0}
|
||||
items={menu}
|
||||
icon='ellipsis-v'
|
||||
iconComponent={MoreHorizIcon}
|
||||
/>
|
||||
)}
|
||||
{!hidden && actionBtn}
|
||||
{menu}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -856,6 +852,12 @@ export const AccountHeader: React.FC<{
|
|||
<FamiliarFollowers accountId={accountId} />
|
||||
)}
|
||||
|
||||
<div className='account__header__buttons account__header__buttons--mobile'>
|
||||
{!hidden && actionBtn}
|
||||
{!hidden && bellBtn}
|
||||
{menu}
|
||||
</div>
|
||||
|
||||
{!(suspended || hidden) && (
|
||||
<div className='account__header__extra'>
|
||||
<div
|
||||
|
|
|
@ -11,7 +11,7 @@ export interface BaseConfirmationModalProps {
|
|||
export const ConfirmationModal: React.FC<
|
||||
{
|
||||
title: React.ReactNode;
|
||||
message: React.ReactNode;
|
||||
message?: React.ReactNode;
|
||||
confirm: React.ReactNode;
|
||||
cancel?: React.ReactNode;
|
||||
secondary?: React.ReactNode;
|
||||
|
@ -48,7 +48,7 @@ export const ConfirmationModal: React.FC<
|
|||
<div className='safety-action-modal__top'>
|
||||
<div className='safety-action-modal__confirmation'>
|
||||
<h1>{title}</h1>
|
||||
<p>{message}</p>
|
||||
{message && <p>{message}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ export {
|
|||
ConfirmReplyModal,
|
||||
ConfirmEditStatusModal,
|
||||
} from './discard_draft_confirmation';
|
||||
export { ConfirmWithdrawRequestModal } from './withdraw_follow_request';
|
||||
export { ConfirmUnfollowModal } from './unfollow';
|
||||
export { ConfirmUnblockModal } from './unblock';
|
||||
export { ConfirmClearNotificationsModal } from './clear_notifications';
|
||||
export { ConfirmLogOutModal } from './log_out';
|
||||
export { ConfirmFollowToListModal } from './follow_to_list';
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { unblockAccount } from 'mastodon/actions/accounts';
|
||||
import type { Account } from 'mastodon/models/account';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
unblockConfirm: {
|
||||
id: 'confirmations.unblock.confirm',
|
||||
defaultMessage: 'Unblock',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmUnblockModal: React.FC<
|
||||
{
|
||||
account: Account;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ account, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(unblockAccount(account.id));
|
||||
}, [dispatch, account.id]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='confirmations.unblock.title'
|
||||
defaultMessage='Unblock {name}?'
|
||||
values={{ name: `@${account.acct}` }}
|
||||
/>
|
||||
}
|
||||
confirm={intl.formatMessage(messages.unblockConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -10,10 +10,6 @@ import type { BaseConfirmationModalProps } from './confirmation_modal';
|
|||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollowTitle: {
|
||||
id: 'confirmations.unfollow.title',
|
||||
defaultMessage: 'Unfollow user?',
|
||||
},
|
||||
unfollowConfirm: {
|
||||
id: 'confirmations.unfollow.confirm',
|
||||
defaultMessage: 'Unfollow',
|
||||
|
@ -34,12 +30,11 @@ export const ConfirmUnfollowModal: React.FC<
|
|||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.unfollowTitle)}
|
||||
message={
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='confirmations.unfollow.message'
|
||||
defaultMessage='Are you sure you want to unfollow {name}?'
|
||||
values={{ name: <strong>@{account.acct}</strong> }}
|
||||
id='confirmations.unfollow.title'
|
||||
defaultMessage='Unfollow {name}?'
|
||||
values={{ name: `@${account.acct}` }}
|
||||
/>
|
||||
}
|
||||
confirm={intl.formatMessage(messages.unfollowConfirm)}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { unfollowAccount } from 'mastodon/actions/accounts';
|
||||
import type { Account } from 'mastodon/models/account';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
withdrawConfirm: {
|
||||
id: 'confirmations.withdraw_request.confirm',
|
||||
defaultMessage: 'Withdraw request',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmWithdrawRequestModal: React.FC<
|
||||
{
|
||||
account: Account;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ account, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(unfollowAccount(account.id));
|
||||
}, [dispatch, account.id]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='confirmations.withdraw_request.title'
|
||||
defaultMessage='Withdraw request to follow {name}?'
|
||||
values={{ name: `@${account.acct}` }}
|
||||
/>
|
||||
}
|
||||
confirm={intl.formatMessage(messages.withdrawConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -32,7 +32,9 @@ import {
|
|||
ConfirmDeleteListModal,
|
||||
ConfirmReplyModal,
|
||||
ConfirmEditStatusModal,
|
||||
ConfirmUnblockModal,
|
||||
ConfirmUnfollowModal,
|
||||
ConfirmWithdrawRequestModal,
|
||||
ConfirmClearNotificationsModal,
|
||||
ConfirmLogOutModal,
|
||||
ConfirmFollowToListModal,
|
||||
|
@ -57,7 +59,9 @@ export const MODAL_COMPONENTS = {
|
|||
'CONFIRM_DELETE_LIST': () => Promise.resolve({ default: ConfirmDeleteListModal }),
|
||||
'CONFIRM_REPLY': () => Promise.resolve({ default: ConfirmReplyModal }),
|
||||
'CONFIRM_EDIT_STATUS': () => Promise.resolve({ default: ConfirmEditStatusModal }),
|
||||
'CONFIRM_UNBLOCK': () => Promise.resolve({ default: ConfirmUnblockModal }),
|
||||
'CONFIRM_UNFOLLOW': () => Promise.resolve({ default: ConfirmUnfollowModal }),
|
||||
'CONFIRM_WITHDRAW_REQUEST': () => Promise.resolve({ default: ConfirmWithdrawRequestModal }),
|
||||
'CONFIRM_CLEAR_NOTIFICATIONS': () => Promise.resolve({ default: ConfirmClearNotificationsModal }),
|
||||
'CONFIRM_LOG_OUT': () => Promise.resolve({ default: ConfirmLogOutModal }),
|
||||
'CONFIRM_FOLLOW_TO_LIST': () => Promise.resolve({ default: ConfirmFollowToListModal }),
|
||||
|
|
|
@ -257,9 +257,12 @@
|
|||
"confirmations.revoke_quote.confirm": "Remove post",
|
||||
"confirmations.revoke_quote.message": "This action cannot be undone.",
|
||||
"confirmations.revoke_quote.title": "Remove post?",
|
||||
"confirmations.unblock.confirm": "Unblock",
|
||||
"confirmations.unblock.title": "Unblock {name}?",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"confirmations.unfollow.title": "Unfollow user?",
|
||||
"confirmations.unfollow.title": "Unfollow {name}?",
|
||||
"confirmations.withdraw_request.confirm": "Withdraw request",
|
||||
"confirmations.withdraw_request.title": "Withdraw request to follow {name}?",
|
||||
"content_warning.hide": "Hide post",
|
||||
"content_warning.show": "Show anyway",
|
||||
"content_warning.show_more": "Show more",
|
||||
|
|
|
@ -6402,7 +6402,10 @@ a.status-card {
|
|||
line-height: 24px;
|
||||
color: $primary-text-color;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:not(:only-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
|
@ -8407,47 +8410,6 @@ noscript {
|
|||
overflow: hidden;
|
||||
margin-inline-start: -2px; // aligns the pfp with content below
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-top: 55px;
|
||||
overflow: hidden;
|
||||
|
||||
.button {
|
||||
flex-shrink: 1;
|
||||
white-space: nowrap;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
border: 1px solid var(--background-border-color);
|
||||
border-radius: 4px;
|
||||
box-sizing: content-box;
|
||||
padding: 5px;
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.copied {
|
||||
border-color: $valid-value-color;
|
||||
}
|
||||
}
|
||||
|
||||
.optional {
|
||||
@container account-header (max-width: 372px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Fallback for older browsers with no container queries support
|
||||
@media screen and (max-width: (372px + 55px)) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
@ -8496,6 +8458,69 @@ noscript {
|
|||
}
|
||||
}
|
||||
|
||||
&__follow-button {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
$button-breakpoint: 420px;
|
||||
$button-fallback-breakpoint: #{$button-breakpoint} + 55px;
|
||||
|
||||
&--desktop {
|
||||
margin-top: 55px;
|
||||
|
||||
@container (width < #{$button-breakpoint}) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@supports (not (container-type: inline-size)) {
|
||||
@media (max-width: #{$button-fallback-breakpoint}) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--mobile {
|
||||
margin-block: 16px;
|
||||
|
||||
@container (width >= #{$button-breakpoint}) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@supports (not (container-type: inline-size)) {
|
||||
@media (min-width: (#{$button-fallback-breakpoint} + 1px)) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
flex-shrink: 1;
|
||||
white-space: nowrap;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
border: 1px solid var(--background-border-color);
|
||||
border-radius: 4px;
|
||||
box-sizing: content-box;
|
||||
padding: 5px;
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&.copied {
|
||||
border-color: $valid-value-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__bio {
|
||||
.account__header__content {
|
||||
color: $primary-text-color;
|
||||
|
|
Loading…
Reference in New Issue
Block a user