Nicolium: subscribers page
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -80,18 +80,24 @@ const ProfileStats: React.FC<IProfileStats> = ({ account, onClickHandler }) => {
|
||||
</Link>
|
||||
|
||||
{account.subscribers_count > 0 && (
|
||||
// <Link to='/@{$username}/subscribers' params={{ username: account.acct }} onClick={onClickHandler} title={intl.formatNumber(account.subscribers_count)} className='hover:underline'>
|
||||
<HStack alignItems='center' space={1}>
|
||||
{!demetricator && (
|
||||
<Text theme='primary' weight='bold' size='sm'>
|
||||
{shortNumberFormat(account.subscribers_count)}
|
||||
<Link
|
||||
to='/@{$username}/subscribers'
|
||||
params={{ username: account.acct }}
|
||||
onClick={onClickHandler}
|
||||
title={intl.formatNumber(account.subscribers_count)}
|
||||
className='hover:underline'
|
||||
>
|
||||
<HStack alignItems='center' space={1}>
|
||||
{!demetricator && (
|
||||
<Text theme='primary' weight='bold' size='sm'>
|
||||
{shortNumberFormat(account.subscribers_count)}
|
||||
</Text>
|
||||
)}
|
||||
<Text weight='bold' size='sm'>
|
||||
<FormattedMessage id='account.subscribers' defaultMessage='Subscribers' />
|
||||
</Text>
|
||||
)}
|
||||
<Text weight='bold' size='sm'>
|
||||
<FormattedMessage id='account.subscribers' defaultMessage='Subscribers' />
|
||||
</Text>
|
||||
</HStack>
|
||||
// </Link>
|
||||
</HStack>
|
||||
</Link>
|
||||
)}
|
||||
</HStack>
|
||||
);
|
||||
|
||||
@@ -142,6 +142,7 @@ import {
|
||||
SettingsStore,
|
||||
Share,
|
||||
Status,
|
||||
Subscribers,
|
||||
TestTimeline,
|
||||
ThemeEditor,
|
||||
Privacy,
|
||||
@@ -729,6 +730,15 @@ export const profileFollowingRoute = createRoute({
|
||||
component: Following,
|
||||
});
|
||||
|
||||
export const profileSubscribersRoute = createRoute({
|
||||
getParentRoute: () => layouts.profile,
|
||||
path: '/subscribers',
|
||||
component: Subscribers,
|
||||
validateSearch: v.object({
|
||||
include_expired: v.optional(v.boolean(), false),
|
||||
}),
|
||||
});
|
||||
|
||||
export const profileMediaRoute = createRoute({
|
||||
getParentRoute: () => layouts.profile,
|
||||
path: '/media',
|
||||
@@ -1538,6 +1548,7 @@ const routeTree = rootRoute.addChildren([
|
||||
profileRoute,
|
||||
profileFollowersRoute,
|
||||
profileFollowingRoute,
|
||||
profileSubscribersRoute,
|
||||
profileMediaRoute,
|
||||
profileTaggedRoute,
|
||||
profileFavoritesRoute,
|
||||
|
||||
@@ -106,6 +106,7 @@ export const Settings = lazy(() => import('@/pages/settings/settings'));
|
||||
export const SettingsStore = lazy(() => import('@/pages/developers/settings-store'));
|
||||
export const Share = lazy(() => import('@/pages/utils/share'));
|
||||
export const Status = lazy(() => import('@/pages/statuses/status'));
|
||||
export const Subscribers = lazy(() => import('@/pages/account-lists/subscribers'));
|
||||
export const TestTimeline = lazy(() => import('@/pages/timelines/test-timeline'));
|
||||
export const ThemeEditor = lazy(() => import('@/pages/dashboard/theme-editor'));
|
||||
export const Privacy = lazy(() => import('@/pages/settings/privacy'));
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
"account.subscribe.failure": "An error occurred trying to subscribe to this account.",
|
||||
"account.subscribe.success": "You have subscribed to this account.",
|
||||
"account.subscribers": "Subscribers",
|
||||
"account.subscribers.empty": "No one subscribes to this user yet.",
|
||||
"account.subscribers.include_expired": "Include expired subscriptions",
|
||||
"account.timezone": "Timezone: {timezone}",
|
||||
"account.timezone.equal": "(same as you)",
|
||||
"account.unblock": "Unblock @{name}",
|
||||
@@ -508,6 +510,7 @@
|
||||
"column.scheduled_statuses": "Scheduled posts",
|
||||
"column.search": "Search",
|
||||
"column.settings_store": "Settings store",
|
||||
"column.subscribers": "Subscribers",
|
||||
"column.test": "Test timeline",
|
||||
"column.tokens": "Active sessions",
|
||||
"column.wrenched": "Recent wrenches timeline",
|
||||
|
||||
97
packages/pl-fe/src/pages/account-lists/subscribers.tsx
Normal file
97
packages/pl-fe/src/pages/account-lists/subscribers.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { useAccountLookup } from '@/api/hooks/accounts/use-account-lookup';
|
||||
import List, { ListItem } from '@/components/list';
|
||||
import MissingIndicator from '@/components/missing-indicator';
|
||||
import ScrollableList from '@/components/scrollable-list';
|
||||
import Column from '@/components/ui/column';
|
||||
import Spinner from '@/components/ui/spinner';
|
||||
import Toggle from '@/components/ui/toggle';
|
||||
import AccountContainer from '@/containers/account-container';
|
||||
import { profileSubscribersRoute } from '@/features/ui/router';
|
||||
import { useSubscribers } from '@/queries/account-lists/use-follows';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.subscribers', defaultMessage: 'Subscribers' },
|
||||
});
|
||||
|
||||
/** Displays a list of accounts subscribing the given account. */
|
||||
const SubscribersPage: React.FC = () => {
|
||||
const navigate = useNavigate({ from: profileSubscribersRoute.fullPath });
|
||||
const { username } = profileSubscribersRoute.useParams();
|
||||
const { include_expired: includeExpired } = profileSubscribersRoute.useSearch();
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const { account, isUnavailable } = useAccountLookup(username);
|
||||
|
||||
const {
|
||||
data = [],
|
||||
hasNextPage,
|
||||
fetchNextPage,
|
||||
isFetching,
|
||||
isLoading,
|
||||
} = useSubscribers(account?.id, includeExpired);
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner />;
|
||||
}
|
||||
|
||||
if (!account) {
|
||||
return <MissingIndicator />;
|
||||
}
|
||||
|
||||
if (isUnavailable) {
|
||||
return (
|
||||
<div className='empty-column-indicator'>
|
||||
<FormattedMessage
|
||||
id='empty_column.account_unavailable'
|
||||
defaultMessage='Profile unavailable'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)} transparent>
|
||||
<List>
|
||||
<ListItem
|
||||
className='mb-3 black:mx-4 black:mb-0'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='account.subscribers.include_expired'
|
||||
defaultMessage='Include expired subscriptions'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Toggle
|
||||
checked={includeExpired}
|
||||
onChange={() => navigate({ search: { include_expired: !includeExpired } })}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='subscribers'
|
||||
hasMore={hasNextPage}
|
||||
onLoadMore={fetchNextPage}
|
||||
emptyMessageText={
|
||||
<FormattedMessage
|
||||
id='account.subscribers.empty'
|
||||
defaultMessage='No one subscribes to this user yet.'
|
||||
/>
|
||||
}
|
||||
itemClassName='pb-4'
|
||||
isLoading={isFetching}
|
||||
>
|
||||
{data.map((accountId) => (
|
||||
<AccountContainer key={accountId} id={accountId} />
|
||||
))}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export { SubscribersPage as default };
|
||||
@@ -22,10 +22,18 @@ const useFollowing = makePaginatedResponseQuery(
|
||||
);
|
||||
|
||||
const useSubscribers = makePaginatedResponseQuery(
|
||||
(accountId?: string) => ['accountsLists', 'subscribers', accountId],
|
||||
(client, [accountId]) =>
|
||||
(accountId?: string, includeExpired?: boolean) => [
|
||||
'accountsLists',
|
||||
'subscribers',
|
||||
accountId,
|
||||
includeExpired || false,
|
||||
],
|
||||
(client, [accountId, includeExpired]) =>
|
||||
client.accounts
|
||||
.getAccountSubscribers(accountId!, { with_relationships: true })
|
||||
.getAccountSubscribers(accountId!, {
|
||||
include_expired: includeExpired,
|
||||
with_relationships: true,
|
||||
})
|
||||
.then(minifyAccountList),
|
||||
undefined,
|
||||
(accountId) => !!accountId,
|
||||
|
||||
Reference in New Issue
Block a user