Merge branch 'accounts-hook' into 'develop'
Switch to useAccount hook in every place it's convenient See merge request soapbox-pub/soapbox!2566
This commit is contained in:
commit
cff5f96df4
|
@ -10,8 +10,8 @@ import { importFetchedAccounts } from './importer';
|
|||
import { patchMeSuccess } from './me';
|
||||
|
||||
import type { AxiosError } from 'axios';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||
import type { APIEntity, Account } from 'soapbox/types/entities';
|
||||
|
||||
const ALIASES_FETCH_REQUEST = 'ALIASES_FETCH_REQUEST';
|
||||
const ALIASES_FETCH_SUCCESS = 'ALIASES_FETCH_SUCCESS';
|
||||
|
@ -56,7 +56,7 @@ const fetchAliasesRequest = () => ({
|
|||
type: ALIASES_FETCH_REQUEST,
|
||||
});
|
||||
|
||||
const fetchAliasesSuccess = (aliases: APIEntity[]) => ({
|
||||
const fetchAliasesSuccess = (aliases: unknown[]) => ({
|
||||
type: ALIASES_FETCH_SUCCESS,
|
||||
value: aliases,
|
||||
});
|
||||
|
@ -82,7 +82,7 @@ const fetchAliasesSuggestions = (q: string) =>
|
|||
}).catch(error => toast.showAlertForError(error));
|
||||
};
|
||||
|
||||
const fetchAliasesSuggestionsReady = (query: string, accounts: APIEntity[]) => ({
|
||||
const fetchAliasesSuggestionsReady = (query: string, accounts: unknown[]) => ({
|
||||
type: ALIASES_SUGGESTIONS_READY,
|
||||
query,
|
||||
accounts,
|
||||
|
|
|
@ -3,22 +3,25 @@ import { useEntity } from 'soapbox/entity-store/hooks';
|
|||
import { useApi } from 'soapbox/hooks/useApi';
|
||||
import { type Account, accountSchema } from 'soapbox/schemas';
|
||||
|
||||
|
||||
import { useRelationships } from './useRelationships';
|
||||
|
||||
function useAccount(id: string) {
|
||||
function useAccount(accountId?: string) {
|
||||
const api = useApi();
|
||||
|
||||
const { entity: account, ...result } = useEntity<Account>(
|
||||
[Entities.ACCOUNTS, id],
|
||||
() => api.get(`/api/v1/accounts/${id}`),
|
||||
{ schema: accountSchema },
|
||||
[Entities.ACCOUNTS, accountId || ''],
|
||||
() => api.get(`/api/v1/accounts/${accountId}`),
|
||||
{ schema: accountSchema, enabled: !!accountId },
|
||||
);
|
||||
const { relationships, isLoading } = useRelationships([account?.id as string]);
|
||||
const {
|
||||
relationships,
|
||||
isLoading: isRelationshipLoading,
|
||||
} = useRelationships(accountId ? [accountId] : []);
|
||||
|
||||
return {
|
||||
...result,
|
||||
isLoading: result.isLoading || isLoading,
|
||||
isLoading: result.isLoading,
|
||||
isRelationshipLoading,
|
||||
account: account ? { ...account, relationship: relationships[0] || null } : undefined,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { useEntity } from 'soapbox/entity-store/hooks';
|
||||
import { useApi } from 'soapbox/hooks/useApi';
|
||||
import { type PatronUser, patronUserSchema } from 'soapbox/schemas';
|
||||
|
||||
function usePatronUser(url?: string) {
|
||||
const api = useApi();
|
||||
|
||||
const { entity: patronUser, ...result } = useEntity<PatronUser>(
|
||||
[Entities.PATRON_USERS, url || ''],
|
||||
() => api.get(`/api/patron/v1/accounts/${encodeURIComponent(url!)}`),
|
||||
{ schema: patronUserSchema, enabled: !!url },
|
||||
);
|
||||
|
||||
return { patronUser, ...result };
|
||||
}
|
||||
|
||||
export { usePatronUser };
|
|
@ -3,6 +3,7 @@
|
|||
* Accounts
|
||||
*/
|
||||
export { useAccount } from './accounts/useAccount';
|
||||
export { usePatronUser } from './accounts/usePatronUser';
|
||||
|
||||
/**
|
||||
* Groups
|
||||
|
|
|
@ -9,32 +9,30 @@ import {
|
|||
closeProfileHoverCard,
|
||||
updateProfileHoverCard,
|
||||
} from 'soapbox/actions/profile-hover-card';
|
||||
import { useAccount, usePatronUser } from 'soapbox/api/hooks';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
|
||||
import { UserPanel } from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
|
||||
import { showProfileHoverCard } from './hover-ref-wrapper';
|
||||
import { Card, CardBody, HStack, Icon, Stack, Text } from './ui';
|
||||
|
||||
import type { Account, PatronUser } from 'soapbox/schemas';
|
||||
import type { AppDispatch } from 'soapbox/store';
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const getBadges = (account: Account): JSX.Element[] => {
|
||||
const getBadges = (account?: Account, patronUser?: PatronUser): JSX.Element[] => {
|
||||
const badges = [];
|
||||
|
||||
if (account.admin) {
|
||||
if (account?.admin) {
|
||||
badges.push(<Badge key='admin' slug='admin' title='Admin' />);
|
||||
} else if (account.moderator) {
|
||||
} else if (account?.moderator) {
|
||||
badges.push(<Badge key='moderator' slug='moderator' title='Moderator' />);
|
||||
}
|
||||
|
||||
if (account.getIn(['patron', 'is_patron'])) {
|
||||
if (patronUser?.is_patron) {
|
||||
badges.push(<Badge key='patron' slug='patron' title='Patron' />);
|
||||
}
|
||||
|
||||
|
@ -67,9 +65,10 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
|
|||
|
||||
const me = useAppSelector(state => state.me);
|
||||
const accountId: string | undefined = useAppSelector(state => state.profile_hover_card.accountId || undefined);
|
||||
const account = useAppSelector(state => accountId && getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
const { patronUser } = usePatronUser(account?.url);
|
||||
const targetRef = useAppSelector(state => state.profile_hover_card.ref?.current);
|
||||
const badges = account ? getBadges(account) : [];
|
||||
const badges = getBadges(account, patronUser);
|
||||
|
||||
useEffect(() => {
|
||||
if (accountId) dispatch(fetchRelationships([accountId]));
|
||||
|
@ -112,7 +111,7 @@ export const ProfileHoverCard: React.FC<IProfileHoverCard> = ({ visible = true }
|
|||
<BundleContainer fetchComponent={UserPanel}>
|
||||
{Component => (
|
||||
<Component
|
||||
accountId={account.get('id')}
|
||||
accountId={account.id}
|
||||
action={<ActionButton account={account} small />}
|
||||
badges={badges}
|
||||
/>
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
/* eslint-disable jsx-a11y/interactive-supports-focus */
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
|
||||
import { fetchOwnAccounts, logOut, switchAccount } from 'soapbox/actions/auth';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { closeSidebar } from 'soapbox/actions/sidebar';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import { Stack } from 'soapbox/components/ui';
|
||||
import ProfileStats from 'soapbox/features/ui/components/profile-stats';
|
||||
import { useAppDispatch, useAppSelector, useGroupsPath, useFeatures } from 'soapbox/hooks';
|
||||
import { makeGetAccount, makeGetOtherAccounts } from 'soapbox/selectors';
|
||||
import { makeGetOtherAccounts } from 'soapbox/selectors';
|
||||
|
||||
import { Divider, HStack, Icon, IconButton, Text } from './ui';
|
||||
|
||||
|
@ -76,16 +77,14 @@ const SidebarLink: React.FC<ISidebarLink> = ({ href, to, icon, text, onClick })
|
|||
);
|
||||
};
|
||||
|
||||
const getOtherAccounts = makeGetOtherAccounts();
|
||||
|
||||
const SidebarMenu: React.FC = (): JSX.Element | null => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const getOtherAccounts = useCallback(makeGetOtherAccounts(), []);
|
||||
const features = useFeatures();
|
||||
const getAccount = makeGetAccount();
|
||||
const me = useAppSelector((state) => state.me);
|
||||
const account = useAppSelector((state) => me ? getAccount(state, me) : null);
|
||||
const { account } = useAccount(me || undefined);
|
||||
const otherAccounts: ImmutableList<AccountEntity> = useAppSelector((state) => getOtherAccounts(state));
|
||||
const sidebarOpen = useAppSelector((state) => state.sidebar.sidebarOpen);
|
||||
const settings = useAppSelector((state) => getSettings(state));
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import Account, { IAccount } from '../components/account';
|
||||
import { makeGetAccount } from '../selectors';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account, { IAccount } from 'soapbox/components/account';
|
||||
|
||||
interface IAccountContainer extends Omit<IAccount, 'account'> {
|
||||
id: string
|
||||
}
|
||||
|
||||
const AccountContainer: React.FC<IAccountContainer> = ({ id, ...props }) => {
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
const account = useAppSelector(state => getAccount(state, id));
|
||||
const { account } = useAccount(id);
|
||||
|
||||
return (
|
||||
<Account account={account!} {...props} />
|
||||
|
|
|
@ -4,6 +4,7 @@ export enum Entities {
|
|||
GROUP_MEMBERSHIPS = 'GroupMemberships',
|
||||
GROUP_RELATIONSHIPS = 'GroupRelationships',
|
||||
GROUP_TAGS = 'GroupTags',
|
||||
PATRON_USERS = 'PatronUsers',
|
||||
RELATIONSHIPS = 'Relationships',
|
||||
STATUSES = 'Statuses'
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { approveUsers, deleteUsers } from 'soapbox/actions/admin';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import { AuthorizeRejectButtons } from 'soapbox/components/authorize-reject-buttons';
|
||||
import { Stack, HStack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
interface IUnapprovedAccount {
|
||||
accountId: string
|
||||
|
@ -13,9 +13,8 @@ interface IUnapprovedAccount {
|
|||
/** Displays an unapproved account for moderation purposes. */
|
||||
const UnapprovedAccount: React.FC<IUnapprovedAccount> = ({ accountId }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
|
||||
const account = useAppSelector(state => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
const adminAccount = useAppSelector(state => state.admin.users.get(accountId));
|
||||
|
||||
if (!account) return null;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { addToAliases } from 'soapbox/actions/aliases';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import AccountComponent from 'soapbox/components/account';
|
||||
import IconButton from 'soapbox/components/icon-button';
|
||||
import { HStack } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
add: { id: 'aliases.account.add', defaultMessage: 'Create alias' },
|
||||
|
@ -22,18 +22,12 @@ const Account: React.FC<IAccount> = ({ accountId, aliases }) => {
|
|||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
const me = useAppSelector((state) => state.me);
|
||||
const { account } = useAccount(accountId);
|
||||
|
||||
const added = useAppSelector((state) => {
|
||||
const account = getAccount(state, accountId);
|
||||
const apId = account?.pleroma?.ap_id;
|
||||
const name = features.accountMoving ? account?.acct : apId;
|
||||
if (!name) return false;
|
||||
|
||||
return aliases.includes(name);
|
||||
});
|
||||
const apId = account?.pleroma?.ap_id;
|
||||
const name = features.accountMoving ? account?.acct : apId;
|
||||
const added = name ? aliases.includes(name) : false;
|
||||
|
||||
const handleOnAdd = () => dispatch(addToAliases(account!));
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import AccountComponent from 'soapbox/components/account';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { HStack } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
birthday: { id: 'account.birthday', defaultMessage: 'Born {date}' },
|
||||
|
@ -17,9 +16,7 @@ interface IAccount {
|
|||
|
||||
const Account: React.FC<IAccount> = ({ accountId }) => {
|
||||
const intl = useIntl();
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
interface IAutosuggestAccount {
|
||||
id: string
|
||||
}
|
||||
|
||||
const AutosuggestAccount: React.FC<IAutosuggestAccount> = ({ id }) => {
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
const account = useAppSelector((state) => getAccount(state, id));
|
||||
|
||||
const { account } = useAccount(id);
|
||||
if (!account) return null;
|
||||
|
||||
return <Account account={account} hideActions showProfileHoverCard={false} />;
|
||||
|
|
|
@ -3,24 +3,22 @@ import React from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import RelativeTimestamp from 'soapbox/components/relative-timestamp';
|
||||
import { Stack, Text } from 'soapbox/components/ui';
|
||||
import ActionButton from 'soapbox/features/ui/components/action-button';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
interface IAccountCard {
|
||||
id: string
|
||||
}
|
||||
|
||||
const AccountCard: React.FC<IAccountCard> = ({ id }) => {
|
||||
const me = useAppSelector((state) => state.me);
|
||||
const account = useAppSelector((state) => getAccount(state, id));
|
||||
const { account } = useAccount(id);
|
||||
const autoPlayGif = useAppSelector((state) => getSettings(state).get('autoPlayGif'));
|
||||
|
||||
if (!account) return null;
|
||||
|
|
|
@ -2,21 +2,25 @@ import React from 'react';
|
|||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import VerificationBadge from 'soapbox/components/verification-badge';
|
||||
import { useAccount, useAppSelector } from 'soapbox/hooks';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import { Card, CardBody, CardTitle, HStack, Stack, Text } from '../../components/ui';
|
||||
import ActionButton from '../ui/components/action-button';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'feed_suggestions.heading', defaultMessage: 'Suggested Profiles' },
|
||||
viewAll: { id: 'feed_suggestions.view_all', defaultMessage: 'View all' },
|
||||
});
|
||||
|
||||
const SuggestionItem = ({ accountId }: { accountId: string }) => {
|
||||
const account = useAccount(accountId) as Account;
|
||||
interface ISuggestionItem {
|
||||
accountId: string
|
||||
}
|
||||
|
||||
const SuggestionItem: React.FC<ISuggestionItem> = ({ accountId }) => {
|
||||
const { account } = useAccount(accountId);
|
||||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Stack space={3} className='w-52 shrink-0 rounded-md border border-solid border-gray-300 p-4 dark:border-gray-800 md:w-full md:shrink md:border-transparent md:p-0 dark:md:border-transparent'>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { authorizeFollowRequest, rejectFollowRequest } from 'soapbox/actions/accounts';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import { AuthorizeRejectButtons } from 'soapbox/components/authorize-reject-buttons';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
|
||||
interface IAccountAuthorize {
|
||||
id: string
|
||||
|
@ -12,9 +12,7 @@ interface IAccountAuthorize {
|
|||
|
||||
const AccountAuthorize: React.FC<IAccountAuthorize> = ({ id }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
const account = useAppSelector((state) => getAccount(state, id));
|
||||
const { account } = useAccount(id);
|
||||
|
||||
const onAuthorize = () => dispatch(authorizeFollowRequest(id));
|
||||
const onReject = () => dispatch(rejectFollowRequest(id));
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { fetchGroupBlocks, groupUnblock } from 'soapbox/actions/groups';
|
||||
import { useGroup } from 'soapbox/api/hooks';
|
||||
import { useAccount, useGroup } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import ScrollableList from 'soapbox/components/scrollable-list';
|
||||
import { Button, Column, HStack, Spinner } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
import ColumnForbidden from '../ui/components/column-forbidden';
|
||||
|
@ -28,10 +27,7 @@ interface IBlockedMember {
|
|||
const BlockedMember: React.FC<IBlockedMember> = ({ accountId, groupId }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { fetchAccount } from 'soapbox/actions/accounts';
|
||||
import { addToMentions, removeFromMentions } from 'soapbox/actions/compose';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import AccountComponent from 'soapbox/components/account';
|
||||
import IconButton from 'soapbox/components/icon-button';
|
||||
import { HStack } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useCompose } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { useAppDispatch, useCompose } from 'soapbox/hooks';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'reply_mentions.account.remove', defaultMessage: 'Remove from mentions' },
|
||||
|
@ -23,11 +23,9 @@ interface IAccount {
|
|||
const Account: React.FC<IAccount> = ({ composeId, accountId, author }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const getAccount = useCallback(makeGetAccount(), []);
|
||||
|
||||
const compose = useCompose(composeId);
|
||||
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
const added = !!account && compose.to?.includes(account.acct);
|
||||
|
||||
const onRemove = () => dispatch(removeFromMentions(composeId, accountId));
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { normalizeStatus } from 'soapbox/normalizers/status';
|
||||
import { calculateStatus } from 'soapbox/reducers/statuses';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
import type { ScheduledStatus } from 'soapbox/reducers/scheduled-statuses';
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
export const buildStatus = (state: RootState, scheduledStatus: ScheduledStatus) => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const me = state.me as string;
|
||||
|
||||
const account = getAccount(state, me);
|
||||
const account = state.entities[Entities.ACCOUNTS]?.store[me];
|
||||
|
||||
const status = ImmutableMap({
|
||||
account,
|
||||
|
|
|
@ -9,13 +9,13 @@ import {
|
|||
setBadges as saveBadges,
|
||||
} from 'soapbox/actions/admin';
|
||||
import { deactivateUserModal, deleteUserModal } from 'soapbox/actions/moderation';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import Account from 'soapbox/components/account';
|
||||
import List, { ListItem } from 'soapbox/components/list';
|
||||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||
import OutlineBox from 'soapbox/components/outline-box';
|
||||
import { Button, Text, HStack, Modal, Stack, Toggle } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { useAppDispatch, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
import { getBadges } from 'soapbox/utils/badges';
|
||||
|
@ -23,8 +23,6 @@ import { getBadges } from 'soapbox/utils/badges';
|
|||
import BadgeInput from './badge-input';
|
||||
import StaffRolePicker from './staff-role-picker';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const messages = defineMessages({
|
||||
userVerified: { id: 'admin.users.user_verified_message', defaultMessage: '@{acct} was verified' },
|
||||
userUnverified: { id: 'admin.users.user_unverified_message', defaultMessage: '@{acct} was unverified' },
|
||||
|
@ -49,7 +47,7 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
|||
|
||||
const ownAccount = useOwnAccount();
|
||||
const features = useFeatures();
|
||||
const account = useAppSelector(state => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
|
||||
const accountBadges = account ? getBadges(account) : [];
|
||||
const [badges, setBadges] = useState<string[]>(accountBadges);
|
||||
|
@ -138,7 +136,7 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
|||
{features.suggestionsV2 && (
|
||||
<ListItem label={<FormattedMessage id='account_moderation_modal.fields.suggested' defaultMessage='Suggested in people to follow' />}>
|
||||
<Toggle
|
||||
checked={account.getIn(['pleroma', 'is_suggested']) === true}
|
||||
checked={account.pleroma?.is_suggested === true}
|
||||
onChange={handleSuggestedChange}
|
||||
/>
|
||||
</ListItem>
|
||||
|
|
|
@ -6,13 +6,13 @@ import { SelectDropdown } from 'soapbox/features/forms';
|
|||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||
import type { Account as AccountEntity } from 'soapbox/schemas';
|
||||
|
||||
/** Staff role. */
|
||||
type AccountRole = 'user' | 'moderator' | 'admin';
|
||||
|
||||
/** Get the highest staff role associated with the account. */
|
||||
const getRole = (account: AccountEntity): AccountRole => {
|
||||
const getRole = (account: Pick<AccountEntity, 'admin' | 'moderator'>): AccountRole => {
|
||||
if (account.admin) {
|
||||
return 'admin';
|
||||
} else if (account.moderator) {
|
||||
|
@ -34,7 +34,7 @@ const messages = defineMessages({
|
|||
|
||||
interface IStaffRolePicker {
|
||||
/** Account whose role to change. */
|
||||
account: AccountEntity
|
||||
account: Pick<AccountEntity, 'id' | 'acct' | 'admin' | 'moderator'>
|
||||
}
|
||||
|
||||
/** Picker for setting the staff role of an account. */
|
||||
|
|
|
@ -3,23 +3,22 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|||
|
||||
import { changeAccountNoteComment, submitAccountNote } from 'soapbox/actions/account-notes';
|
||||
import { closeModal } from 'soapbox/actions/modals';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import { Modal, Text } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'account_note.placeholder', defaultMessage: 'No comment provided' },
|
||||
save: { id: 'account_note.save', defaultMessage: 'Save' },
|
||||
});
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const AccountNoteModal = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const isSubmitting = useAppSelector((state) => state.account_notes.edit.isSubmitting);
|
||||
const account = useAppSelector((state) => getAccount(state, state.account_notes.edit.account!));
|
||||
const accountId = useAppSelector((state) => state.account_notes.edit.account);
|
||||
const { account } = useAccount(accountId || undefined);
|
||||
const comment = useAppSelector((state) => state.account_notes.edit.comment);
|
||||
|
||||
const onClose = () => {
|
||||
|
|
|
@ -4,17 +4,16 @@ import { FormattedMessage } from 'react-intl';
|
|||
import { muteAccount } from 'soapbox/actions/accounts';
|
||||
import { closeModal } from 'soapbox/actions/modals';
|
||||
import { toggleHideNotifications, changeMuteDuration } from 'soapbox/actions/mutes';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import { Modal, HStack, Stack, Text, Toggle } from 'soapbox/components/ui';
|
||||
import DurationSelector from 'soapbox/features/compose/components/polls/duration-selector';
|
||||
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const MuteModal = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const account = useAppSelector((state) => getAccount(state, state.mutes.new.accountId!));
|
||||
const accountId = useAppSelector((state) => state.mutes.new.accountId);
|
||||
const { account } = useAccount(accountId || undefined);
|
||||
const notifications = useAppSelector((state) => state.mutes.new.notifications);
|
||||
const duration = useAppSelector((state) => state.mutes.new.duration);
|
||||
const mutesDuration = useFeatures().mutesDuration;
|
||||
|
|
|
@ -4,13 +4,14 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|||
import { blockAccount } from 'soapbox/actions/accounts';
|
||||
import { submitReport, submitReportSuccess, submitReportFail, ReportableEntities } from 'soapbox/actions/reports';
|
||||
import { expandAccountTimeline } from 'soapbox/actions/timelines';
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment-thumbs';
|
||||
import GroupCard from 'soapbox/components/group-card';
|
||||
import List, { ListItem } from 'soapbox/components/list';
|
||||
import StatusContent from 'soapbox/components/status-content';
|
||||
import { Avatar, HStack, Icon, Modal, ProgressBar, Stack, Text } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account-container';
|
||||
import { useAccount, useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import ConfirmationStep from './steps/confirmation-step';
|
||||
import OtherActionsStep from './steps/other-actions-step';
|
||||
|
@ -100,7 +101,7 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
|||
const intl = useIntl();
|
||||
|
||||
const accountId = useAppSelector((state) => state.reports.new.account_id);
|
||||
const account = useAccount(accountId as string);
|
||||
const { account } = useAccount(accountId || undefined);
|
||||
|
||||
const entityType = useAppSelector((state) => state.reports.new.entityType);
|
||||
const isBlocked = useAppSelector((state) => state.reports.new.block);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { usePatronUser } from 'soapbox/api/hooks';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import Markup from 'soapbox/components/markup';
|
||||
import { Icon, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
|
@ -35,7 +36,7 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
interface IProfileInfoPanel {
|
||||
account: Account
|
||||
account?: Account
|
||||
/** Username from URL params, in case the account isn't found. */
|
||||
username: string
|
||||
}
|
||||
|
@ -44,6 +45,7 @@ interface IProfileInfoPanel {
|
|||
const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) => {
|
||||
const intl = useIntl();
|
||||
const { displayFqn } = useSoapboxConfig();
|
||||
const { patronUser } = usePatronUser(account?.url);
|
||||
|
||||
const getStaffBadge = (): React.ReactNode => {
|
||||
if (account?.admin) {
|
||||
|
@ -56,7 +58,7 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
|||
};
|
||||
|
||||
const getCustomBadges = (): React.ReactNode[] => {
|
||||
const badges = getAccountBadges(account);
|
||||
const badges = account ? getAccountBadges(account) : [];
|
||||
|
||||
return badges.map(badge => (
|
||||
<Badge
|
||||
|
@ -70,7 +72,7 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
|||
const getBadges = (): React.ReactNode[] => {
|
||||
const custom = getCustomBadges();
|
||||
const staffBadge = getStaffBadge();
|
||||
const isPatron = account.getIn(['patron', 'is_patron']) === true;
|
||||
const isPatron = patronUser?.is_patron === true;
|
||||
|
||||
const badges = [];
|
||||
|
||||
|
@ -86,7 +88,7 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
|
|||
};
|
||||
|
||||
const renderBirthday = (): React.ReactNode => {
|
||||
const birthday = account.pleroma?.birthday;
|
||||
const birthday = account?.pleroma?.birthday;
|
||||
if (!birthday) return null;
|
||||
|
||||
const formattedBirthday = intl.formatDate(birthday, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' });
|
||||
|
|
|
@ -5,7 +5,7 @@ import { NavLink } from 'react-router-dom';
|
|||
import { HStack, Text } from 'soapbox/components/ui';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
import type { Account } from 'soapbox/schemas';
|
||||
|
||||
const messages = defineMessages({
|
||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||
|
@ -13,7 +13,7 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
interface IProfileStats {
|
||||
account: Account | undefined
|
||||
account: Pick<Account, 'acct' | 'followers_count' | 'following_count'> | undefined
|
||||
onClickHandler?: React.MouseEventHandler
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,15 @@ import React from 'react';
|
|||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useAccount } from 'soapbox/api/hooks';
|
||||
import StillImage from 'soapbox/components/still-image';
|
||||
import { Avatar, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
import VerificationBadge from 'soapbox/components/verification-badge';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
interface IUserPanel {
|
||||
accountId: string
|
||||
action?: JSX.Element
|
||||
|
@ -22,7 +20,7 @@ interface IUserPanel {
|
|||
|
||||
const UserPanel: React.FC<IUserPanel> = ({ accountId, action, badges, domain }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
const { account } = useAccount(accountId);
|
||||
const fqn = useAppSelector((state) => displayFqn(state));
|
||||
|
||||
if (!account) return null;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
export { useAccount } from './useAccount';
|
||||
export { useApi } from './useApi';
|
||||
export { useAppDispatch } from './useAppDispatch';
|
||||
export { useAppSelector } from './useAppSelector';
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
export const useAccount = (id: string) => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
return useAppSelector((state) => getAccount(state, id));
|
||||
};
|
|
@ -10,7 +10,7 @@ import type { AnyAction } from 'redux';
|
|||
|
||||
const NewMuteRecord = ImmutableRecord({
|
||||
isSubmitting: false,
|
||||
accountId: null,
|
||||
accountId: null as string | null,
|
||||
notifications: true,
|
||||
duration: 0,
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ export { groupRelationshipSchema, type GroupRelationship } from './group-relatio
|
|||
export { groupTagSchema, type GroupTag } from './group-tag';
|
||||
export { mentionSchema, type Mention } from './mention';
|
||||
export { notificationSchema, type Notification } from './notification';
|
||||
export { patronUserSchema, type PatronUser } from './patron';
|
||||
export { pollSchema, type Poll, type PollOption } from './poll';
|
||||
export { relationshipSchema, type Relationship } from './relationship';
|
||||
export { statusSchema, type Status } from './status';
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const patronUserSchema = z.object({
|
||||
is_patron: z.boolean().catch(false),
|
||||
url: z.string().url(),
|
||||
}).transform((patron) => {
|
||||
return {
|
||||
id: patron.url,
|
||||
...patron,
|
||||
};
|
||||
});
|
||||
|
||||
type PatronUser = z.infer<typeof patronUserSchema>;
|
||||
|
||||
export { patronUserSchema, type PatronUser };
|
Loading…
Reference in New Issue