pl-fe: Display interaction requests
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
3b0cd07e1d
commit
dba85273b2
6 changed files with 88 additions and 0 deletions
|
@ -0,0 +1,50 @@
|
|||
import { type InfiniteData, useInfiniteQuery } from '@tanstack/react-query';
|
||||
|
||||
import { importEntities } from 'pl-fe/actions/importer';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
|
||||
import type { InteractionRequest, PaginatedResponse } from 'pl-api';
|
||||
import type { AppDispatch } from 'pl-fe/store';
|
||||
|
||||
const minifyInteractionRequest = ({ account, status, reply, ...interactionRequest }: InteractionRequest) => ({
|
||||
account_id: account.id,
|
||||
status: status?.id || null,
|
||||
reply: reply?.id || null,
|
||||
...interactionRequest,
|
||||
});
|
||||
|
||||
type MinifiedInteractionRequest = ReturnType<typeof minifyInteractionRequest>;
|
||||
|
||||
const minifyInteractionRequestsList = (dispatch: AppDispatch, { previous, next, items, ...response }: PaginatedResponse<InteractionRequest>): PaginatedResponse<MinifiedInteractionRequest> => {
|
||||
dispatch(importEntities({
|
||||
statuses: items.map(item => [item.status, item.reply]).flat(),
|
||||
}));
|
||||
|
||||
return {
|
||||
...response,
|
||||
previous: previous ? () => previous().then(response => minifyInteractionRequestsList(dispatch, response)) : null,
|
||||
next: next ? () => next().then(response => minifyInteractionRequestsList(dispatch, response)) : null,
|
||||
items: items.map(minifyInteractionRequest),
|
||||
};
|
||||
};
|
||||
|
||||
const useInteractionRequests = <T>(select?: (data: InfiniteData<PaginatedResponse<MinifiedInteractionRequest>>) => T) => {
|
||||
const client = useClient();
|
||||
const features = useFeatures();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return useInfiniteQuery({
|
||||
queryKey: ['interaction_requests'],
|
||||
queryFn: ({ pageParam }) => pageParam.next?.() || client.interactionRequests.getInteractionRequests().then(response => minifyInteractionRequestsList(dispatch, response)),
|
||||
initialPageParam: { previous: null, next: null, items: [], partial: false } as PaginatedResponse<MinifiedInteractionRequest>,
|
||||
getNextPageParam: (page) => page.next ? page : undefined,
|
||||
enabled: features.interactionRequests,
|
||||
select,
|
||||
});
|
||||
};
|
||||
|
||||
const useInteractionRequestsCount = () => useInteractionRequests(data => data.pages.map(({ items }) => items).flat().length);
|
||||
|
||||
export { useInteractionRequests, useInteractionRequestsCount };
|
|
@ -6,6 +6,7 @@ import { Link, NavLink } from 'react-router-dom';
|
|||
|
||||
import { fetchOwnAccounts, logOut, switchAccount } from 'pl-fe/actions/auth';
|
||||
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
|
||||
import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests';
|
||||
import Account from 'pl-fe/components/account';
|
||||
import Divider from 'pl-fe/components/ui/divider';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
|
@ -42,6 +43,7 @@ const messages = defineMessages({
|
|||
drafts: { id: 'navigation.drafts', defaultMessage: 'Drafts' },
|
||||
addAccount: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },
|
||||
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
interactionRequests: { id: 'navigation.interaction_requests', defaultMessage: 'Interaction requests' },
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
login: { id: 'account.login', defaultMessage: 'Log in' },
|
||||
register: { id: 'account.register', defaultMessage: 'Sign up' },
|
||||
|
@ -96,6 +98,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
const otherAccounts: ImmutableList<AccountEntity> = useAppSelector((state) => getOtherAccounts(state));
|
||||
const { settings } = useSettingsStore();
|
||||
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
|
||||
const interactionRequestsCount = useInteractionRequestsCount().data || 0;
|
||||
const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size);
|
||||
const draftCount = useAppSelector((state) => state.draft_statuses.size);
|
||||
// const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
|
@ -232,6 +235,15 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{(interactionRequestsCount > 0) && (
|
||||
<SidebarLink
|
||||
to='/interaction_requests'
|
||||
icon={require('@tabler/icons/outline/flag-question.svg')}
|
||||
text={intl.formatMessage(messages.interactionRequests)}
|
||||
onClick={closeSidebar}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.conversations && (
|
||||
<SidebarLink
|
||||
to='/conversations'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import { useStatContext } from 'pl-fe/contexts/stat-context';
|
||||
|
@ -31,6 +32,7 @@ const messages = defineMessages({
|
|||
scheduledStatuses: { id: 'column.scheduled_statuses', defaultMessage: 'Scheduled posts' },
|
||||
drafts: { id: 'navigation.drafts', defaultMessage: 'Drafts' },
|
||||
conversations: { id: 'navigation.direct_messages', defaultMessage: 'Direct messages' },
|
||||
interactionRequests: { id: 'navigation.interaction_requests', defaultMessage: 'Interaction requests' },
|
||||
});
|
||||
|
||||
/** Desktop sidebar with links to different views in the app. */
|
||||
|
@ -47,6 +49,7 @@ const SidebarNavigation = () => {
|
|||
|
||||
const notificationCount = useAppSelector((state) => state.notifications.unread);
|
||||
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
|
||||
const interactionRequestsCount = useInteractionRequestsCount().data || 0;
|
||||
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size);
|
||||
const draftCount = useAppSelector((state) => state.draft_statuses.size);
|
||||
|
@ -74,6 +77,15 @@ const SidebarNavigation = () => {
|
|||
});
|
||||
}
|
||||
|
||||
if (interactionRequestsCount > 0) {
|
||||
menu.push({
|
||||
to: '/interaction_requests',
|
||||
text: intl.formatMessage(messages.interactionRequests),
|
||||
icon: require('@tabler/icons/outline/flag-question.svg'),
|
||||
count: interactionRequestsCount,
|
||||
});
|
||||
}
|
||||
|
||||
if (features.bookmarks) {
|
||||
menu.push({
|
||||
to: '/bookmarks',
|
||||
|
|
11
packages/pl-fe/src/features/interaction-requests/index.tsx
Normal file
11
packages/pl-fe/src/features/interaction-requests/index.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
import { useInteractionRequests } from 'pl-fe/api/hooks/statuses/use-interaction-requests';
|
||||
|
||||
const InteractionRequests = () => {
|
||||
const interactionRequestsQuery = useInteractionRequests();
|
||||
|
||||
return <>{JSON.stringify(interactionRequestsQuery.data)}</>;
|
||||
};
|
||||
|
||||
export { InteractionRequests as default };
|
|
@ -138,6 +138,7 @@ import {
|
|||
Circle,
|
||||
BubbleTimeline,
|
||||
InteractionPolicies,
|
||||
InteractionRequests,
|
||||
} from './util/async-components';
|
||||
import GlobalHotkeys from './util/global-hotkeys';
|
||||
import { WrappedRoute } from './util/react-router-helpers';
|
||||
|
@ -255,6 +256,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters/:id' layout={DefaultLayout} component={EditFilter} content={children} />}
|
||||
{(features.filters || features.filtersV2) && <WrappedRoute path='/filters' layout={DefaultLayout} component={Filters} content={children} />}
|
||||
{(features.followedHashtagsList) && <WrappedRoute path='/followed_tags' layout={DefaultLayout} component={FollowedTags} content={children} />}
|
||||
{features.interactionRequests && <WrappedRoute path='/interaction_requests' layout={DefaultLayout} component={InteractionRequests} content={children} />}
|
||||
<WrappedRoute path='/@:username' publicRoute exact layout={ProfileLayout} component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path='/@:username/with_replies' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||
<WrappedRoute path='/@:username/followers' publicRoute={!authenticatedProfile} layout={ProfileLayout} component={Followers} content={children} />
|
||||
|
|
|
@ -56,6 +56,7 @@ export const HomeTimeline = lazy(() => import('pl-fe/features/home-timeline'));
|
|||
export const ImportData = lazy(() => import('pl-fe/features/import-data'));
|
||||
export const IntentionalError = lazy(() => import('pl-fe/features/intentional-error'));
|
||||
export const InteractionPolicies = lazy(() => import('pl-fe/features/interaction-policies'));
|
||||
export const InteractionRequests = lazy(() => import('pl-fe/features/interaction-requests'));
|
||||
export const LandingTimeline = lazy(() => import('pl-fe/features/landing-timeline'));
|
||||
export const Lists = lazy(() => import('pl-fe/features/lists'));
|
||||
export const ListTimeline = lazy(() => import('pl-fe/features/list-timeline'));
|
||||
|
|
Loading…
Reference in a new issue