Add useAccountLookup hook, fix useRelationships
This commit is contained in:
parent
9f53a81fa1
commit
ec8177d578
|
@ -22,9 +22,9 @@ import { createStatus } from './statuses';
|
||||||
|
|
||||||
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
||||||
import type { Emoji } from 'soapbox/features/emoji';
|
import type { Emoji } from 'soapbox/features/emoji';
|
||||||
import type { Group } from 'soapbox/schemas';
|
import type { Account, Group } from 'soapbox/schemas';
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
import type { Account, APIEntity, Status, Tag } from 'soapbox/types/entities';
|
import type { APIEntity, Status, Tag } from 'soapbox/types/entities';
|
||||||
import type { History } from 'soapbox/types/history';
|
import type { History } from 'soapbox/types/history';
|
||||||
|
|
||||||
const { CancelToken, isCancel } = axios;
|
const { CancelToken, isCancel } = axios;
|
||||||
|
|
|
@ -8,8 +8,9 @@ import { importFetchedAccounts } from './importer';
|
||||||
import { openModal } from './modals';
|
import { openModal } from './modals';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { Account as AccountEntity } from 'soapbox/schemas';
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
import type { APIEntity, Account as AccountEntity } from 'soapbox/types/entities';
|
import type { APIEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
||||||
const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
||||||
|
|
|
@ -9,10 +9,11 @@ function useAccount(accountId?: string) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
|
||||||
const { entity: account, ...result } = useEntity<Account>(
|
const { entity: account, ...result } = useEntity<Account>(
|
||||||
[Entities.ACCOUNTS, accountId || ''],
|
[Entities.ACCOUNTS, accountId!],
|
||||||
() => api.get(`/api/v1/accounts/${accountId}`),
|
() => api.get(`/api/v1/accounts/${accountId}`),
|
||||||
{ schema: accountSchema, enabled: !!accountId },
|
{ schema: accountSchema, enabled: !!accountId },
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
relationships,
|
relationships,
|
||||||
isLoading: isRelationshipLoading,
|
isLoading: isRelationshipLoading,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityLookup } from 'soapbox/entity-store/hooks';
|
||||||
|
import { useApi } from 'soapbox/hooks/useApi';
|
||||||
|
import { type Account, accountSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
import { useRelationships } from './useRelationships';
|
||||||
|
|
||||||
|
function useAccountLookup(acct?: string) {
|
||||||
|
const api = useApi();
|
||||||
|
|
||||||
|
const { entity: account, ...result } = useEntityLookup<Account>(
|
||||||
|
Entities.ACCOUNTS,
|
||||||
|
(account) => account.acct === acct,
|
||||||
|
() => api.get(`/api/v1/accounts/lookup?acct=${acct}`),
|
||||||
|
{ schema: accountSchema, enabled: !!acct },
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
relationships,
|
||||||
|
isLoading: isRelationshipLoading,
|
||||||
|
} = useRelationships(account ? [account.id] : []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
isLoading: result.isLoading,
|
||||||
|
isRelationshipLoading,
|
||||||
|
account: account ? { ...account, relationship: relationships[0] || null } : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useAccountLookup };
|
|
@ -7,10 +7,11 @@ import { type Relationship, relationshipSchema } from 'soapbox/schemas';
|
||||||
function useRelationships(ids: string[]) {
|
function useRelationships(ids: string[]) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
const { isLoggedIn } = useLoggedIn();
|
const { isLoggedIn } = useLoggedIn();
|
||||||
|
const q = ids.map(id => `id[]=${id}`).join('&');
|
||||||
|
|
||||||
const { entities: relationships, ...result } = useEntities<Relationship>(
|
const { entities: relationships, ...result } = useEntities<Relationship>(
|
||||||
[Entities.RELATIONSHIPS],
|
[Entities.RELATIONSHIPS, q],
|
||||||
() => api.get(`/api/v1/accounts/relationships?${ids.map(id => `id[]=${id}`).join('&')}`),
|
() => api.get(`/api/v1/accounts/relationships?${q}`),
|
||||||
{ schema: relationshipSchema, enabled: isLoggedIn && ids.filter(Boolean).length > 0 },
|
{ schema: relationshipSchema, enabled: isLoggedIn && ids.filter(Boolean).length > 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
// Accounts
|
// Accounts
|
||||||
export { useAccount } from './accounts/useAccount';
|
export { useAccount } from './accounts/useAccount';
|
||||||
|
export { useAccountLookup } from './accounts/useAccountLookup';
|
||||||
export { useFollow } from './accounts/useFollow';
|
export { useFollow } from './accounts/useFollow';
|
||||||
export { useRelationships } from './accounts/useRelationships';
|
export { useRelationships } from './accounts/useRelationships';
|
||||||
export { usePatronUser } from './accounts/usePatronUser';
|
export { usePatronUser } from './accounts/usePatronUser';
|
||||||
|
|
|
@ -15,10 +15,9 @@ import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui';
|
||||||
|
|
||||||
import type { StatusApprovalStatus } from 'soapbox/normalizers/status';
|
import type { StatusApprovalStatus } from 'soapbox/normalizers/status';
|
||||||
import type { Account as AccountSchema } from 'soapbox/schemas';
|
import type { Account as AccountSchema } from 'soapbox/schemas';
|
||||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
|
||||||
|
|
||||||
interface IInstanceFavicon {
|
interface IInstanceFavicon {
|
||||||
account: AccountEntity | AccountSchema
|
account: AccountSchema
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IAccount {
|
export interface IAccount {
|
||||||
account: AccountEntity | AccountSchema
|
account: AccountSchema
|
||||||
action?: React.ReactElement
|
action?: React.ReactElement
|
||||||
actionAlignment?: 'center' | 'top'
|
actionAlignment?: 'center' | 'top'
|
||||||
actionIcon?: string
|
actionIcon?: string
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Account from 'soapbox/components/account';
|
||||||
import Icon from 'soapbox/components/icon';
|
import Icon from 'soapbox/components/icon';
|
||||||
import { HStack, Text } from 'soapbox/components/ui';
|
import { HStack, Text } from 'soapbox/components/ui';
|
||||||
|
|
||||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
import type { Account as AccountEntity } from 'soapbox/schemas';
|
||||||
|
|
||||||
interface IMovedNote {
|
interface IMovedNote {
|
||||||
from: AccountEntity
|
from: AccountEntity
|
||||||
|
|
|
@ -28,8 +28,8 @@ import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soap
|
||||||
import { normalizeAttachment } from 'soapbox/normalizers';
|
import { normalizeAttachment } from 'soapbox/normalizers';
|
||||||
import { ChatKeys, useChats } from 'soapbox/queries/chats';
|
import { ChatKeys, useChats } from 'soapbox/queries/chats';
|
||||||
import { queryClient } from 'soapbox/queries/client';
|
import { queryClient } from 'soapbox/queries/client';
|
||||||
|
import { Account } from 'soapbox/schemas';
|
||||||
import toast from 'soapbox/toast';
|
import toast from 'soapbox/toast';
|
||||||
import { Account } from 'soapbox/types/entities';
|
|
||||||
import { isDefaultHeader, isLocal, isRemote } from 'soapbox/utils/accounts';
|
import { isDefaultHeader, isLocal, isRemote } from 'soapbox/utils/accounts';
|
||||||
import copy from 'soapbox/utils/copy';
|
import copy from 'soapbox/utils/copy';
|
||||||
import { MASTODON, parseVersion } from 'soapbox/utils/features';
|
import { MASTODON, parseVersion } from 'soapbox/utils/features';
|
||||||
|
@ -576,7 +576,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||||
disabled={createAndNavigateToChat.isLoading}
|
disabled={createAndNavigateToChat.isLoading}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (account.getIn(['pleroma', 'accepts_chat_messages']) === true) {
|
} else if (account.pleroma?.accepts_chat_messages) {
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
src={require('@tabler/icons/messages.svg')}
|
src={require('@tabler/icons/messages.svg')}
|
||||||
|
|
|
@ -9,12 +9,12 @@ import {
|
||||||
expandFollowers,
|
expandFollowers,
|
||||||
fetchAccountByUsername,
|
fetchAccountByUsername,
|
||||||
} from 'soapbox/actions/accounts';
|
} from 'soapbox/actions/accounts';
|
||||||
|
import { useAccountLookup } from 'soapbox/api/hooks';
|
||||||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||||
import ScrollableList from 'soapbox/components/scrollable-list';
|
import ScrollableList from 'soapbox/components/scrollable-list';
|
||||||
import { Column, Spinner } from 'soapbox/components/ui';
|
import { Column, Spinner } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account-container';
|
import AccountContainer from 'soapbox/containers/account-container';
|
||||||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||||
import { findAccountByUsername } from 'soapbox/selectors';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.followers', defaultMessage: 'Followers' },
|
heading: { id: 'column.followers', defaultMessage: 'Followers' },
|
||||||
|
@ -36,7 +36,7 @@ const Followers: React.FC<IFollowers> = (props) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const username = props.params?.username || '';
|
const username = props.params?.username || '';
|
||||||
const account = useAppSelector(state => findAccountByUsername(state, username));
|
const { account } = useAccountLookup(username);
|
||||||
const isOwnAccount = username.toLowerCase() === ownAccount?.username?.toLowerCase();
|
const isOwnAccount = username.toLowerCase() === ownAccount?.username?.toLowerCase();
|
||||||
|
|
||||||
const accountIds = useAppSelector(state => state.user_lists.followers.get(account!?.id)?.items || ImmutableOrderedSet<string>());
|
const accountIds = useAppSelector(state => state.user_lists.followers.get(account!?.id)?.items || ImmutableOrderedSet<string>());
|
||||||
|
|
|
@ -9,12 +9,12 @@ import {
|
||||||
expandFollowing,
|
expandFollowing,
|
||||||
fetchAccountByUsername,
|
fetchAccountByUsername,
|
||||||
} from 'soapbox/actions/accounts';
|
} from 'soapbox/actions/accounts';
|
||||||
|
import { useAccountLookup } from 'soapbox/api/hooks';
|
||||||
import MissingIndicator from 'soapbox/components/missing-indicator';
|
import MissingIndicator from 'soapbox/components/missing-indicator';
|
||||||
import ScrollableList from 'soapbox/components/scrollable-list';
|
import ScrollableList from 'soapbox/components/scrollable-list';
|
||||||
import { Column, Spinner } from 'soapbox/components/ui';
|
import { Column, Spinner } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account-container';
|
import AccountContainer from 'soapbox/containers/account-container';
|
||||||
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||||
import { findAccountByUsername } from 'soapbox/selectors';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.following', defaultMessage: 'Following' },
|
heading: { id: 'column.following', defaultMessage: 'Following' },
|
||||||
|
@ -36,7 +36,7 @@ const Following: React.FC<IFollowing> = (props) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const username = props.params?.username || '';
|
const username = props.params?.username || '';
|
||||||
const account = useAppSelector(state => findAccountByUsername(state, username));
|
const { account } = useAccountLookup(username);
|
||||||
const isOwnAccount = username.toLowerCase() === ownAccount?.username?.toLowerCase();
|
const isOwnAccount = username.toLowerCase() === ownAccount?.username?.toLowerCase();
|
||||||
|
|
||||||
const accountIds = useAppSelector(state => state.user_lists.following.get(account!?.id)?.items || ImmutableOrderedSet<string>());
|
const accountIds = useAppSelector(state => state.user_lists.following.get(account!?.id)?.items || ImmutableOrderedSet<string>());
|
||||||
|
|
|
@ -15,7 +15,6 @@ import { Button, HStack } from 'soapbox/components/ui';
|
||||||
import { useAppDispatch, useFeatures, useLoggedIn } from 'soapbox/hooks';
|
import { useAppDispatch, useFeatures, useLoggedIn } from 'soapbox/hooks';
|
||||||
|
|
||||||
import type { Account } from 'soapbox/schemas';
|
import type { Account } from 'soapbox/schemas';
|
||||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
||||||
|
@ -35,7 +34,7 @@ const messages = defineMessages({
|
||||||
|
|
||||||
interface IActionButton {
|
interface IActionButton {
|
||||||
/** Target account for the action. */
|
/** Target account for the action. */
|
||||||
account: AccountEntity | Account
|
account: Account
|
||||||
/** Type of action to prioritize, eg on Blocks and Mutes pages. */
|
/** Type of action to prioritize, eg on Blocks and Mutes pages. */
|
||||||
actionType?: 'muting' | 'blocking' | 'follow_request'
|
actionType?: 'muting' | 'blocking' | 'follow_request'
|
||||||
/** Displays shorter text on the "Awaiting approval" button. */
|
/** Displays shorter text on the "Awaiting approval" button. */
|
||||||
|
|
|
@ -177,6 +177,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitVerification = () => {
|
const submitVerification = () => {
|
||||||
|
if (!accessToken) return;
|
||||||
// TODO: handle proper validation from Pepe -- expired vs invalid
|
// TODO: handle proper validation from Pepe -- expired vs invalid
|
||||||
dispatch(reConfirmPhoneVerification(verificationCode))
|
dispatch(reConfirmPhoneVerification(verificationCode))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Redirect, useHistory } from 'react-router-dom';
|
import { Redirect, useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useAccountLookup } from 'soapbox/api/hooks';
|
||||||
import { Column, Layout, Tabs } from 'soapbox/components/ui';
|
import { Column, Layout, Tabs } from 'soapbox/components/ui';
|
||||||
import Header from 'soapbox/features/account/components/header';
|
import Header from 'soapbox/features/account/components/header';
|
||||||
import LinkFooter from 'soapbox/features/ui/components/link-footer';
|
import LinkFooter from 'soapbox/features/ui/components/link-footer';
|
||||||
|
@ -16,7 +17,6 @@ import {
|
||||||
PinnedAccountsPanel,
|
PinnedAccountsPanel,
|
||||||
} from 'soapbox/features/ui/util/async-components';
|
} from 'soapbox/features/ui/util/async-components';
|
||||||
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
||||||
import { findAccountByUsername, makeGetAccount } from 'soapbox/selectors';
|
|
||||||
import { getAcct, isLocal } from 'soapbox/utils/accounts';
|
import { getAcct, isLocal } from 'soapbox/utils/accounts';
|
||||||
|
|
||||||
interface IProfilePage {
|
interface IProfilePage {
|
||||||
|
@ -26,21 +26,14 @@ interface IProfilePage {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAccount = makeGetAccount();
|
|
||||||
|
|
||||||
/** Page to display a user's profile. */
|
/** Page to display a user's profile. */
|
||||||
const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const username = params?.username || '';
|
const username = params?.username || '';
|
||||||
|
|
||||||
const account = useAppSelector(state => {
|
const { account } = useAccountLookup(username);
|
||||||
if (username) {
|
|
||||||
const account = findAccountByUsername(state, username);
|
console.log(account?.relationship);
|
||||||
if (account) {
|
|
||||||
return getAccount(state, account.id) || undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const me = useAppSelector(state => state.me);
|
const me = useAppSelector(state => state.me);
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
|
|
|
@ -48,7 +48,7 @@ export function connectStream(
|
||||||
// If the WebSocket fails to be created, don't crash the whole page,
|
// If the WebSocket fails to be created, don't crash the whole page,
|
||||||
// just proceed without a subscription.
|
// just proceed without a subscription.
|
||||||
try {
|
try {
|
||||||
subscription = getStream(streamingAPIBaseURL!, accessToken, path, {
|
subscription = getStream(streamingAPIBaseURL!, accessToken!, path, {
|
||||||
connected() {
|
connected() {
|
||||||
if (pollingRefresh) {
|
if (pollingRefresh) {
|
||||||
clearPolling();
|
clearPolling();
|
||||||
|
|
|
@ -34,8 +34,10 @@ export const isLoggedIn = (getState: () => RootState) => {
|
||||||
export const getAppToken = (state: RootState) => state.auth.app.access_token as string;
|
export const getAppToken = (state: RootState) => state.auth.app.access_token as string;
|
||||||
|
|
||||||
export const getUserToken = (state: RootState, accountId?: string | false | null) => {
|
export const getUserToken = (state: RootState, accountId?: string | false | null) => {
|
||||||
const accountUrl = state.accounts.getIn([accountId, 'url']) as string;
|
if (!accountId) return;
|
||||||
return state.auth.users.get(accountUrl)?.access_token as string;
|
const accountUrl = state.accounts[accountId]?.url;
|
||||||
|
if (!accountUrl) return;
|
||||||
|
return state.auth.users.get(accountUrl)?.access_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAccessToken = (state: RootState) => {
|
export const getAccessToken = (state: RootState) => {
|
||||||
|
|
Loading…
Reference in New Issue