Merge remote-tracking branch 'mkljczk/develop' into develop
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -2,6 +2,7 @@ import { GOTOSOCIAL, MASTODON } from 'pl-api';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { changeSetting } from '@/actions/settings';
|
||||
import DropdownMenu, { type Menu } from '@/components/dropdown-menu';
|
||||
import IconButton from '@/components/ui/icon-button';
|
||||
import { useClient } from '@/hooks/use-client';
|
||||
@@ -86,6 +87,10 @@ const messages = defineMessages({
|
||||
id: 'account.load_activities.fail',
|
||||
defaultMessage: 'Failed to fetch latest posts',
|
||||
},
|
||||
nickname: { id: 'account.nickname.modal_header', defaultMessage: 'Set nickname for @{name}' },
|
||||
nicknamePlaceholder: { id: 'account.nickname.placeholder', defaultMessage: 'Enter a nickname' },
|
||||
nicknameSave: { id: 'account.nickname.save', defaultMessage: 'Save nickname' },
|
||||
nicknameSaved: { id: 'account.nickname.success', defaultMessage: 'Nickname saved' },
|
||||
note: { id: 'account_note.modal_header', defaultMessage: 'Edit note for @{name}' },
|
||||
notePlaceholder: { id: 'account_note.placeholder', defaultMessage: 'Add a note' },
|
||||
noteSaved: { id: 'account_note.success', defaultMessage: 'Note saved' },
|
||||
@@ -206,6 +211,28 @@ const AccountMenu: React.FC<IAccountMenu> = ({ account }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const onEditNickname = () => {
|
||||
const currentNickname = settings.accountNicknames[account.id] ?? '';
|
||||
openModal('TEXT_FIELD', {
|
||||
heading: (
|
||||
<FormattedMessage
|
||||
id='account.nickname.modal_header'
|
||||
defaultMessage='Set nickname for @{name}'
|
||||
values={{ name: account.acct }}
|
||||
/>
|
||||
),
|
||||
placeholder: intl.formatMessage(messages.nicknamePlaceholder),
|
||||
confirm: <FormattedMessage id='account.nickname.save' defaultMessage='Save nickname' />,
|
||||
onConfirm: (value) => {
|
||||
const trimmed = value.trim();
|
||||
changeSetting(['accountNicknames', account.id], trimmed || undefined);
|
||||
toast.success(messages.nicknameSaved);
|
||||
},
|
||||
text: currentNickname,
|
||||
singleLine: true,
|
||||
});
|
||||
};
|
||||
|
||||
const onReport = () => {
|
||||
openModal('REPORT', { accountId: account.id });
|
||||
};
|
||||
@@ -455,6 +482,12 @@ const AccountMenu: React.FC<IAccountMenu> = ({ account }) => {
|
||||
});
|
||||
}
|
||||
|
||||
menu.push({
|
||||
text: intl.formatMessage(messages.nickname, { name: account.acct }),
|
||||
action: onEditNickname,
|
||||
icon: require('@phosphor-icons/core/regular/tag.svg'),
|
||||
});
|
||||
|
||||
menu.push(null);
|
||||
|
||||
if (features.removeFromFollowers && account.relationship?.followed_by) {
|
||||
|
||||
@@ -33,10 +33,14 @@ const messages = defineMessages({
|
||||
deactivated: { id: 'account.deactivated', defaultMessage: 'Deactivated' },
|
||||
bot: { id: 'account.badges.bot', defaultMessage: 'Bot' },
|
||||
pronouns: { id: 'account.pronouns.with_label', defaultMessage: 'Pronouns: {pronouns}' },
|
||||
originalDisplayName: {
|
||||
id: 'account.original_display_name',
|
||||
defaultMessage: 'You have assigned a nickname to this user.',
|
||||
},
|
||||
});
|
||||
|
||||
interface IProfileInfoPanel {
|
||||
account?: Account;
|
||||
account?: Account & { original_display_name?: string };
|
||||
/** Username from URL params, in case the account isn't found. */
|
||||
username: string;
|
||||
}
|
||||
@@ -177,6 +181,19 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
{account.original_display_name &&
|
||||
account.original_display_name !== account.display_name && (
|
||||
<Text
|
||||
theme='muted'
|
||||
truncate
|
||||
title={intl.formatMessage(messages.originalDisplayName)}
|
||||
>
|
||||
{'('}
|
||||
<Emojify text={account.original_display_name} emojis={account.emojis} />
|
||||
{')'}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{account.bot && <Badge slug='bot' title={intl.formatMessage(messages.bot)} />}
|
||||
|
||||
{badges.length > 0 && <div className='flex items-center gap-1'>{badges}</div>}
|
||||
|
||||
@@ -20,6 +20,10 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'This account privacy status is set to locked. The owner manually reviews who can follow them.',
|
||||
},
|
||||
originalDisplayName: {
|
||||
id: 'account.original_display_name',
|
||||
defaultMessage: 'You have assigned a nickname to this user.',
|
||||
},
|
||||
});
|
||||
|
||||
interface IUserPanel {
|
||||
@@ -83,6 +87,19 @@ const UserPanel: React.FC<IUserPanel> = ({ accountId, action, badges, domain })
|
||||
<Emojify text={account.display_name} emojis={account.emojis} />
|
||||
</Text>
|
||||
|
||||
{account.original_display_name &&
|
||||
account.original_display_name !== account.display_name && (
|
||||
<Text
|
||||
theme='muted'
|
||||
truncate
|
||||
title={intl.formatMessage(messages.originalDisplayName)}
|
||||
>
|
||||
{'('}
|
||||
<Emojify text={account.original_display_name} emojis={account.emojis} />
|
||||
{')'}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{verified && <VerificationBadge />}
|
||||
|
||||
{badges && badges.length > 0 && (
|
||||
|
||||
@@ -146,6 +146,9 @@ const layouts = {
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/@{$username}',
|
||||
component: ProfileLayout,
|
||||
validateSearch: v.object({
|
||||
with_replies: v.optional(v.boolean()),
|
||||
}),
|
||||
}),
|
||||
remoteInstance: createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
|
||||
@@ -26,6 +26,7 @@ import { LOCAL_STORAGE_REDIRECT_KEY } from '@/utils/redirect';
|
||||
/** Layout to display a user's profile. */
|
||||
const ProfileLayout: React.FC = () => {
|
||||
const { username } = layouts.profile.useParams();
|
||||
const { with_replies: withReplies } = layouts.profile.useSearch();
|
||||
const location = useLocation();
|
||||
|
||||
const { data: account, isUnauthorized } = useAccountLookup(username, true);
|
||||
@@ -80,7 +81,7 @@ const ProfileLayout: React.FC = () => {
|
||||
|
||||
let activeItem;
|
||||
const pathname = location.pathname.replace(`@${username}/`, '');
|
||||
if (pathname.endsWith('/with_replies')) {
|
||||
if (withReplies) {
|
||||
activeItem = 'replies';
|
||||
} else if (pathname.endsWith('/media')) {
|
||||
activeItem = 'media';
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
"account.mute": "Mute @{name}",
|
||||
"account.muted": "Muted",
|
||||
"account.never_active": "Never",
|
||||
"account.nickname.modal_header": "Set nickname for @{name}",
|
||||
"account.nickname.placeholder": "Enter a nickname",
|
||||
"account.nickname.save": "Save nickname",
|
||||
"account.nickname.success": "Nickname saved",
|
||||
"account.original_display_name": "You have assigned a nickname to this user.",
|
||||
"account.posts": "Posts",
|
||||
"account.posts_with_replies": "Posts & replies",
|
||||
"account.profile": "Profile",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useLoggedIn } from '@/hooks/use-logged-in';
|
||||
import { useCredentialAccount } from '@/queries/accounts/use-account-credentials';
|
||||
import { useRelationshipQuery } from '@/queries/accounts/use-relationship';
|
||||
import { queryKeys } from '@/queries/keys';
|
||||
import { useSettings } from '@/stores/settings';
|
||||
|
||||
import type { NicoliumResponse } from '@/api';
|
||||
|
||||
@@ -30,6 +31,9 @@ const useAccount = (accountId?: string, withRelationship = false) => {
|
||||
const features = useFeatures();
|
||||
const { me } = useLoggedIn();
|
||||
const queryClient = useQueryClient();
|
||||
const { accountNicknames } = useSettings();
|
||||
|
||||
const nickname = accountNicknames[accountId ?? ''];
|
||||
|
||||
const accountQuery = useQuery({
|
||||
queryKey: queryKeys.accounts.show(accountId!),
|
||||
@@ -63,19 +67,14 @@ const useAccount = (accountId?: string, withRelationship = false) => {
|
||||
const mergedRelationship = relationship ?? accountQuery.data.relationship;
|
||||
const mergedIsAdmin = credentialIsAdmin ?? accountQuery.data.is_admin;
|
||||
|
||||
if (
|
||||
mergedRelationship === accountQuery.data.relationship &&
|
||||
mergedIsAdmin === accountQuery.data.is_admin
|
||||
) {
|
||||
return accountQuery.data;
|
||||
}
|
||||
|
||||
return {
|
||||
...accountQuery.data,
|
||||
display_name: nickname ?? accountQuery.data.display_name,
|
||||
original_display_name: accountQuery.data.display_name,
|
||||
relationship: mergedRelationship,
|
||||
is_admin: mergedIsAdmin,
|
||||
};
|
||||
}, [accountQuery.data, relationship, credentialIsAdmin]);
|
||||
}, [accountQuery.data, relationship, credentialIsAdmin, nickname]);
|
||||
|
||||
return {
|
||||
...accountQuery,
|
||||
|
||||
@@ -55,6 +55,7 @@ const settingsSchema = v.object({
|
||||
storeSettingsInNotes: v.fallback(v.boolean(), false),
|
||||
composeInTimelines: v.fallback(v.boolean(), true),
|
||||
rememberTimelinePosition: v.fallback(v.boolean(), true),
|
||||
accountNicknames: v.fallback(v.record(v.string(), v.string()), {}),
|
||||
|
||||
theme: v.optional(
|
||||
coerceObject({
|
||||
|
||||
Reference in New Issue
Block a user