pl-fe: migrate scheduled statuses to tanstack query
Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
@ -1,126 +0,0 @@
|
||||
import { getClient } from '../api';
|
||||
|
||||
import type { PaginatedResponse, ScheduledStatus } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const SCHEDULED_STATUSES_FETCH_REQUEST = 'SCHEDULED_STATUSES_FETCH_REQUEST' as const;
|
||||
const SCHEDULED_STATUSES_FETCH_SUCCESS = 'SCHEDULED_STATUSES_FETCH_SUCCESS' as const;
|
||||
const SCHEDULED_STATUSES_FETCH_FAIL = 'SCHEDULED_STATUSES_FETCH_FAIL' as const;
|
||||
|
||||
const SCHEDULED_STATUSES_EXPAND_REQUEST = 'SCHEDULED_STATUSES_EXPAND_REQUEST' as const;
|
||||
const SCHEDULED_STATUSES_EXPAND_SUCCESS = 'SCHEDULED_STATUSES_EXPAND_SUCCESS' as const;
|
||||
const SCHEDULED_STATUSES_EXPAND_FAIL = 'SCHEDULED_STATUSES_EXPAND_FAIL' as const;
|
||||
|
||||
const SCHEDULED_STATUS_CANCEL_REQUEST = 'SCHEDULED_STATUS_CANCEL_REQUEST' as const;
|
||||
const SCHEDULED_STATUS_CANCEL_SUCCESS = 'SCHEDULED_STATUS_CANCEL_SUCCESS' as const;
|
||||
|
||||
const fetchScheduledStatuses = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
|
||||
if (state.status_lists.scheduled_statuses?.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const features = state.auth.client.features;
|
||||
|
||||
if (!features.scheduledStatuses) return;
|
||||
|
||||
dispatch(fetchScheduledStatusesRequest());
|
||||
|
||||
return getClient(getState()).scheduledStatuses.getScheduledStatuses().then(({ next, items }) => {
|
||||
dispatch(fetchScheduledStatusesSuccess(items, next));
|
||||
}).catch(error => {
|
||||
dispatch(fetchScheduledStatusesFail(error));
|
||||
});
|
||||
};
|
||||
|
||||
interface ScheduledStatusCancelRequestAction {
|
||||
type: typeof SCHEDULED_STATUS_CANCEL_REQUEST;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
interface ScheduledStatusCancelSuccessAction {
|
||||
type: typeof SCHEDULED_STATUS_CANCEL_SUCCESS;
|
||||
statusId: string;
|
||||
}
|
||||
|
||||
const cancelScheduledStatus = (statusId: string) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch<ScheduledStatusCancelRequestAction>({ type: SCHEDULED_STATUS_CANCEL_REQUEST, statusId });
|
||||
return getClient(getState()).scheduledStatuses.cancelScheduledStatus(statusId).then(() => {
|
||||
dispatch<ScheduledStatusCancelSuccessAction>({ type: SCHEDULED_STATUS_CANCEL_SUCCESS, statusId });
|
||||
});
|
||||
};
|
||||
|
||||
const fetchScheduledStatusesRequest = () => ({
|
||||
type: SCHEDULED_STATUSES_FETCH_REQUEST,
|
||||
});
|
||||
|
||||
const fetchScheduledStatusesSuccess = (statuses: Array<ScheduledStatus>, next: (() => Promise<PaginatedResponse<ScheduledStatus>>) | null) => ({
|
||||
type: SCHEDULED_STATUSES_FETCH_SUCCESS,
|
||||
statuses,
|
||||
next,
|
||||
});
|
||||
|
||||
const fetchScheduledStatusesFail = (error: unknown) => ({
|
||||
type: SCHEDULED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
const expandScheduledStatuses = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const next = getState().status_lists.scheduled_statuses?.next as any as () => Promise<PaginatedResponse<ScheduledStatus>> || null;
|
||||
|
||||
if (next === null || getState().status_lists.scheduled_statuses?.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandScheduledStatusesRequest());
|
||||
|
||||
next().then(response => {
|
||||
dispatch(expandScheduledStatusesSuccess(response.items, response.next));
|
||||
}).catch(error => {
|
||||
dispatch(expandScheduledStatusesFail(error));
|
||||
});
|
||||
};
|
||||
|
||||
const expandScheduledStatusesRequest = () => ({
|
||||
type: SCHEDULED_STATUSES_EXPAND_REQUEST,
|
||||
});
|
||||
|
||||
const expandScheduledStatusesSuccess = (statuses: Array<ScheduledStatus>, next: (() => Promise<PaginatedResponse<ScheduledStatus>>) | null) => ({
|
||||
type: SCHEDULED_STATUSES_EXPAND_SUCCESS,
|
||||
statuses,
|
||||
next,
|
||||
});
|
||||
|
||||
const expandScheduledStatusesFail = (error: unknown) => ({
|
||||
type: SCHEDULED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
type ScheduledStatusesAction =
|
||||
| ScheduledStatusCancelRequestAction
|
||||
| ScheduledStatusCancelSuccessAction
|
||||
| ReturnType<typeof fetchScheduledStatusesRequest>
|
||||
| ReturnType<typeof fetchScheduledStatusesSuccess>
|
||||
| ReturnType<typeof fetchScheduledStatusesFail>
|
||||
| ReturnType<typeof expandScheduledStatusesRequest>
|
||||
| ReturnType<typeof expandScheduledStatusesSuccess>
|
||||
| ReturnType<typeof expandScheduledStatusesFail>
|
||||
|
||||
export {
|
||||
SCHEDULED_STATUSES_FETCH_REQUEST,
|
||||
SCHEDULED_STATUSES_FETCH_SUCCESS,
|
||||
SCHEDULED_STATUSES_FETCH_FAIL,
|
||||
SCHEDULED_STATUSES_EXPAND_REQUEST,
|
||||
SCHEDULED_STATUSES_EXPAND_SUCCESS,
|
||||
SCHEDULED_STATUSES_EXPAND_FAIL,
|
||||
SCHEDULED_STATUS_CANCEL_REQUEST,
|
||||
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
||||
fetchScheduledStatuses,
|
||||
cancelScheduledStatus,
|
||||
expandScheduledStatuses,
|
||||
type ScheduledStatusesAction,
|
||||
};
|
||||
@ -1,3 +1,5 @@
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { scheduledStatusesQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
import { isLoggedIn } from 'pl-fe/utils/auth';
|
||||
@ -43,7 +45,12 @@ const createStatus = (params: CreateStatusParams, idempotencyKey: string, status
|
||||
// The backend might still be processing the rich media attachment
|
||||
const expectsCard = status.scheduled_at === null && !status.card && shouldHaveCard(status);
|
||||
|
||||
if (status.scheduled_at === null) dispatch(importEntities({ statuses: [{ ...status, expectsCard }] }, { idempotencyKey, withParents: true }));
|
||||
if (status.scheduled_at === null) {
|
||||
dispatch(importEntities({ statuses: [{ ...status, expectsCard }] }, { idempotencyKey, withParents: true }));
|
||||
} else {
|
||||
queryClient.invalidateQueries(scheduledStatusesQueryOptions);
|
||||
}
|
||||
|
||||
dispatch<StatusesAction>({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey, editing: !!statusId });
|
||||
|
||||
// Poll the backend for the updated card
|
||||
|
||||
@ -3,9 +3,13 @@
|
||||
* @module pl-fe/api
|
||||
*/
|
||||
import * as BuildConfig from 'pl-fe/build-config';
|
||||
import { RootState } from 'pl-fe/store';
|
||||
import { buildFullPath } from 'pl-fe/utils/url';
|
||||
|
||||
import type { RootState, Store } from 'pl-fe/store';
|
||||
|
||||
let store: Store;
|
||||
import('pl-fe/store').then((value) => store = value.store).catch(() => {});
|
||||
|
||||
type PlfeResponse<T = any> = Response & { data: string; json: T };
|
||||
|
||||
/**
|
||||
@ -33,7 +37,7 @@ const staticFetch = async (input: URL | RequestInfo, init?: RequestInit | undefi
|
||||
return { headers, ok, redirected, status, statusText, type, url, data, json } as any as PlfeResponse;
|
||||
};
|
||||
|
||||
const getClient = (state: RootState | (() => RootState)) => {
|
||||
const getClient = (state: RootState | (() => RootState) = store?.getState()) => {
|
||||
if (typeof state === 'function') state = state();
|
||||
|
||||
return state.auth.client;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
/* eslint-disable jsx-a11y/interactive-supports-focus */
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
import clsx from 'clsx';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
@ -19,6 +20,7 @@ import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status';
|
||||
import { useFollowRequestsCount } from 'pl-fe/queries/accounts/use-follow-requests';
|
||||
import { scheduledStatusesCountQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
import { useInteractionRequestsCount } from 'pl-fe/queries/statuses/use-interaction-requests';
|
||||
import { makeGetOtherAccounts } from 'pl-fe/selectors';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
@ -98,7 +100,7 @@ const SidebarMenu: React.FC = React.memo((): JSX.Element | null => {
|
||||
const { settings } = useSettingsStore();
|
||||
const followRequestsCount = useFollowRequestsCount().data || 0;
|
||||
const interactionRequestsCount = useInteractionRequestsCount().data || 0;
|
||||
const scheduledStatusCount = useAppSelector((state) => Object.keys(state.scheduled_statuses).length);
|
||||
const scheduledStatusCount = useInfiniteQuery(scheduledStatusesCountQueryOptions).data || 0;
|
||||
const draftCount = useAppSelector((state) => Object.keys(state.draft_statuses).length);
|
||||
// const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
const [sidebarVisible, setSidebarVisible] = useState(isSidebarOpen);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
import React, { useMemo } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
@ -12,6 +13,7 @@ import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status';
|
||||
import { useFollowRequestsCount } from 'pl-fe/queries/accounts/use-follow-requests';
|
||||
import { scheduledStatusesCountQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
import { useInteractionRequestsCount } from 'pl-fe/queries/statuses/use-interaction-requests';
|
||||
|
||||
import Account from './account';
|
||||
@ -47,7 +49,7 @@ const SidebarNavigation = React.memo(() => {
|
||||
const followRequestsCount = useFollowRequestsCount().data || 0;
|
||||
const interactionRequestsCount = useInteractionRequestsCount().data || 0;
|
||||
const dashboardCount = useAppSelector((state) => state.admin.openReports.length + state.admin.awaitingApproval.length);
|
||||
const scheduledStatusCount = useAppSelector((state) => Object.keys(state.scheduled_statuses).length);
|
||||
const scheduledStatusCount = useInfiniteQuery(scheduledStatusesCountQueryOptions).data || 0;
|
||||
const draftCount = useAppSelector((state) => Object.keys(state.draft_statuses).length);
|
||||
|
||||
const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { cancelScheduledStatus } from 'pl-fe/actions/scheduled-statuses';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { cancelScheduledStatusMutationOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
import { useModalsStore } from 'pl-fe/stores/modals';
|
||||
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||
|
||||
@ -24,20 +24,20 @@ interface IScheduledStatusActionBar {
|
||||
const ScheduledStatusActionBar: React.FC<IScheduledStatusActionBar> = ({ status }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { mutate: cancelScheduledStatus } = useMutation(cancelScheduledStatusMutationOptions(status.id));
|
||||
const { openModal } = useModalsStore();
|
||||
const { settings } = useSettingsStore();
|
||||
|
||||
const handleCancelClick = () => {
|
||||
const deleteModal = settings.deleteModal;
|
||||
if (!deleteModal) {
|
||||
dispatch(cancelScheduledStatus(status.id));
|
||||
cancelScheduledStatus();
|
||||
} else {
|
||||
openModal('CONFIRM', {
|
||||
heading: intl.formatMessage(messages.deleteHeading),
|
||||
message: intl.formatMessage(messages.deleteMessage),
|
||||
confirm: intl.formatMessage(messages.deleteConfirm),
|
||||
onConfirm: () => dispatch(cancelScheduledStatus(status.id)),
|
||||
onConfirm: () => cancelScheduledStatus(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -14,14 +14,14 @@ import { buildStatus } from '../builder';
|
||||
|
||||
import ScheduledStatusActionBar from './scheduled-status-action-bar';
|
||||
|
||||
import type { ScheduledStatus as ScheduledStatusEntity } from 'pl-api';
|
||||
|
||||
interface IScheduledStatus {
|
||||
statusId: string;
|
||||
scheduledStatus: ScheduledStatusEntity;
|
||||
}
|
||||
|
||||
const ScheduledStatus: React.FC<IScheduledStatus> = ({ statusId, ...other }) => {
|
||||
const ScheduledStatus: React.FC<IScheduledStatus> = ({ scheduledStatus, ...other }) => {
|
||||
const status = useAppSelector((state) => {
|
||||
const scheduledStatus = state.scheduled_statuses[statusId];
|
||||
if (!scheduledStatus) return null;
|
||||
return buildStatus(state, scheduledStatus);
|
||||
});
|
||||
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { useEffect } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { fetchScheduledStatuses, expandScheduledStatuses } from 'pl-fe/actions/scheduled-statuses';
|
||||
import ScrollableList from 'pl-fe/components/scrollable-list';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { scheduledStatusesQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
|
||||
import ScheduledStatus from './components/scheduled-status';
|
||||
|
||||
@ -14,35 +12,23 @@ const messages = defineMessages({
|
||||
heading: { id: 'column.scheduled_statuses', defaultMessage: 'Scheduled posts' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch) => {
|
||||
dispatch(expandScheduledStatuses());
|
||||
}, 300, { leading: true });
|
||||
|
||||
const ScheduledStatuses = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const statusIds = useAppSelector((state) => state.status_lists.scheduled_statuses!.items);
|
||||
const isLoading = useAppSelector((state) => state.status_lists.scheduled_statuses!.isLoading);
|
||||
const hasMore = useAppSelector((state) => !!state.status_lists.scheduled_statuses!.next);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchScheduledStatuses());
|
||||
}, []);
|
||||
const { data: scheduledStatuses = [], isLoading, hasNextPage, fetchNextPage } = useInfiniteQuery(scheduledStatusesQueryOptions);
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.scheduled_statuses' defaultMessage="You don't have any scheduled statuses yet. When you add one, it will show up here." />;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='scheduledStatuses'
|
||||
hasMore={hasMore}
|
||||
hasMore={hasNextPage}
|
||||
isLoading={typeof isLoading === 'boolean' ? isLoading : true}
|
||||
onLoadMore={() => handleLoadMore(dispatch)}
|
||||
onLoadMore={() => fetchNextPage({ cancelRefetch: false })}
|
||||
emptyMessage={emptyMessage}
|
||||
listClassName='divide-y divide-solid divide-gray-200 dark:divide-gray-800'
|
||||
>
|
||||
{statusIds.map((id: string) => <ScheduledStatus key={id} statusId={id} />)}
|
||||
{scheduledStatuses.map((status) => <ScheduledStatus key={status.id} scheduledStatus={status} />)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
|
||||
@ -8,7 +8,6 @@ import { fetchFilters } from 'pl-fe/actions/filters';
|
||||
import { fetchMarker } from 'pl-fe/actions/markers';
|
||||
import { expandNotifications } from 'pl-fe/actions/notifications';
|
||||
import { register as registerPushNotifications } from 'pl-fe/actions/push-notifications/registerer';
|
||||
import { fetchScheduledStatuses } from 'pl-fe/actions/scheduled-statuses';
|
||||
import { fetchHomeTimeline } from 'pl-fe/actions/timelines';
|
||||
import { useUserStream } from 'pl-fe/api/hooks/streaming/use-user-stream';
|
||||
import SidebarNavigation from 'pl-fe/components/sidebar-navigation';
|
||||
@ -40,7 +39,9 @@ import RemoteInstanceLayout from 'pl-fe/layouts/remote-instance-layout';
|
||||
import SearchLayout from 'pl-fe/layouts/search-layout';
|
||||
import StatusLayout from 'pl-fe/layouts/status-layout';
|
||||
import { prefetchFollowRequests } from 'pl-fe/queries/accounts/use-follow-requests';
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { prefetchCustomEmojis } from 'pl-fe/queries/instance/use-custom-emojis';
|
||||
import { scheduledStatusesQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses';
|
||||
import { useUiStore } from 'pl-fe/stores/ui';
|
||||
import { getVapidKey } from 'pl-fe/utils/auth';
|
||||
import { isStandalone } from 'pl-fe/utils/state';
|
||||
@ -420,7 +421,9 @@ const UI: React.FC<IUI> = React.memo(({ children }) => {
|
||||
setTimeout(() => prefetchFollowRequests(client), 700);
|
||||
}
|
||||
|
||||
setTimeout(() => dispatch(fetchScheduledStatuses()), 900);
|
||||
setTimeout(() => {
|
||||
queryClient.prefetchInfiniteQuery(scheduledStatusesQueryOptions);
|
||||
}, 900);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
30
packages/pl-fe/src/queries/statuses/scheduled-statuses.ts
Normal file
30
packages/pl-fe/src/queries/statuses/scheduled-statuses.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { infiniteQueryOptions } from '@tanstack/react-query';
|
||||
import { create } from 'mutative';
|
||||
|
||||
import { getClient } from 'pl-fe/api';
|
||||
|
||||
import { queryClient } from '../client';
|
||||
import { makePaginatedResponseQueryOptions } from '../utils/make-paginated-response-query-options';
|
||||
import { mutationOptions } from '../utils/mutation-options';
|
||||
|
||||
const scheduledStatusesQueryOptions = makePaginatedResponseQueryOptions(
|
||||
['scheduledStatuses'],
|
||||
(client) => client.scheduledStatuses.getScheduledStatuses(),
|
||||
)();
|
||||
|
||||
const scheduledStatusesCountQueryOptions = infiniteQueryOptions({
|
||||
...scheduledStatusesQueryOptions,
|
||||
select: (data) => data.pages.map(page => page.items).flat().length,
|
||||
});
|
||||
|
||||
const cancelScheduledStatusMutationOptions = (scheduledStatusId: string) => mutationOptions({
|
||||
mutationKey: ['scheduledStatuses', scheduledStatusId],
|
||||
mutationFn: () => getClient().scheduledStatuses.cancelScheduledStatus(scheduledStatusId),
|
||||
onSettled: () => {
|
||||
queryClient.setQueryData(scheduledStatusesQueryOptions.queryKey, (data) => create(data, (draft) => {
|
||||
draft?.pages.forEach(page => page.items = page.items.filter(({ id }) => id !== scheduledStatusId));
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export { scheduledStatusesQueryOptions, scheduledStatusesCountQueryOptions, cancelScheduledStatusMutationOptions };
|
||||
@ -0,0 +1,19 @@
|
||||
import { type InfiniteData, infiniteQueryOptions } from '@tanstack/react-query';
|
||||
|
||||
import { store } from 'pl-fe/store';
|
||||
|
||||
import type { PaginatedResponse, PlApiClient } from 'pl-api';
|
||||
|
||||
const makePaginatedResponseQueryOptions = <T1 extends Array<any>, T2, T3 = Array<T2>>(
|
||||
queryKey: Array<string | undefined> | ((...params: T1) => Array<string | undefined>),
|
||||
queryFn: (client: PlApiClient, params: T1) => Promise<PaginatedResponse<T2>>,
|
||||
select?: (data: InfiniteData<PaginatedResponse<T2>>) => T3,
|
||||
) => (...params: T1) => infiniteQueryOptions({
|
||||
queryKey: typeof queryKey === 'object' ? queryKey : queryKey(...params),
|
||||
queryFn: ({ pageParam }) => pageParam.next?.() || queryFn(store.getState().auth.client, params),
|
||||
initialPageParam: { previous: null, next: null, items: [], partial: false } as Awaited<ReturnType<typeof queryFn>>,
|
||||
getNextPageParam: (page) => page.next ? page : undefined,
|
||||
select: select ?? ((data) => data.pages.map(page => page.items).flat() as T3),
|
||||
});
|
||||
|
||||
export { makePaginatedResponseQueryOptions };
|
||||
12
packages/pl-fe/src/queries/utils/mutation-options.ts
Normal file
12
packages/pl-fe/src/queries/utils/mutation-options.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { DefaultError } from '@tanstack/query-core';
|
||||
import type { UseMutationOptions } from '@tanstack/react-query';
|
||||
|
||||
// From https://github.com/TanStack/query/discussions/6096#discussioncomment-9685102
|
||||
const mutationOptions = <
|
||||
TData = unknown,
|
||||
TError = DefaultError,
|
||||
TVariables = void,
|
||||
TContext = unknown,
|
||||
>(options: UseMutationOptions<TData, TError, TVariables, TContext>): UseMutationOptions<TData, TError, TVariables, TContext> => options;
|
||||
|
||||
export { mutationOptions };
|
||||
@ -27,7 +27,6 @@ import pending_statuses from './pending-statuses';
|
||||
import plfe from './pl-fe';
|
||||
import polls from './polls';
|
||||
import push_notifications from './push-notifications';
|
||||
import scheduled_statuses from './scheduled-statuses';
|
||||
import security from './security';
|
||||
import status_lists from './status-lists';
|
||||
import statuses from './statuses';
|
||||
@ -58,7 +57,6 @@ const reducers = {
|
||||
plfe,
|
||||
polls,
|
||||
push_notifications,
|
||||
scheduled_statuses,
|
||||
security,
|
||||
status_lists,
|
||||
statuses,
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT, type ImporterAction } from 'pl-fe/actions/importer';
|
||||
import {
|
||||
SCHEDULED_STATUSES_FETCH_SUCCESS,
|
||||
SCHEDULED_STATUS_CANCEL_REQUEST,
|
||||
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
||||
type ScheduledStatusesAction,
|
||||
} from 'pl-fe/actions/scheduled-statuses';
|
||||
import { STATUS_CREATE_SUCCESS, type StatusesAction } from 'pl-fe/actions/statuses';
|
||||
|
||||
import type { Status, ScheduledStatus } from 'pl-api';
|
||||
|
||||
type State = Record<string, ScheduledStatus>;
|
||||
|
||||
const initialState: State = {};
|
||||
|
||||
const importStatus = (state: State, status: Status | ScheduledStatus) => {
|
||||
if (!status.scheduled_at) return state;
|
||||
state[status.id] = status;
|
||||
};
|
||||
|
||||
const importStatuses = (state: State, statuses: Array<Status | ScheduledStatus>) => {
|
||||
statuses.forEach(status => importStatus(state, status));
|
||||
};
|
||||
|
||||
const deleteStatus = (state: State, statusId: string) => {
|
||||
delete state[statusId];
|
||||
};
|
||||
|
||||
const scheduled_statuses = (state: State = initialState, action: ImporterAction | ScheduledStatusesAction | StatusesAction) => {
|
||||
switch (action.type) {
|
||||
case STATUS_IMPORT:
|
||||
case STATUS_CREATE_SUCCESS:
|
||||
return create(state, (draft) => importStatus(draft, action.status));
|
||||
case STATUSES_IMPORT:
|
||||
case SCHEDULED_STATUSES_FETCH_SUCCESS:
|
||||
return create(state, (draft) => importStatuses(draft, action.statuses));
|
||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
||||
return create(state, (draft) => deleteStatus(draft, action.statusId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { scheduled_statuses as default };
|
||||
@ -43,20 +43,9 @@ import {
|
||||
type InteractionsAction,
|
||||
} from 'pl-fe/actions/interactions';
|
||||
import { PINNED_STATUSES_FETCH_SUCCESS, type PinStatusesAction } from 'pl-fe/actions/pin-statuses';
|
||||
import {
|
||||
SCHEDULED_STATUSES_FETCH_REQUEST,
|
||||
SCHEDULED_STATUSES_FETCH_SUCCESS,
|
||||
SCHEDULED_STATUSES_FETCH_FAIL,
|
||||
SCHEDULED_STATUSES_EXPAND_REQUEST,
|
||||
SCHEDULED_STATUSES_EXPAND_SUCCESS,
|
||||
SCHEDULED_STATUSES_EXPAND_FAIL,
|
||||
SCHEDULED_STATUS_CANCEL_REQUEST,
|
||||
SCHEDULED_STATUS_CANCEL_SUCCESS,
|
||||
type ScheduledStatusesAction,
|
||||
} from 'pl-fe/actions/scheduled-statuses';
|
||||
import { STATUS_CREATE_SUCCESS, type StatusesAction } from 'pl-fe/actions/statuses';
|
||||
|
||||
import type { PaginatedResponse, ScheduledStatus, Status } from 'pl-api';
|
||||
import type { PaginatedResponse, Status } from 'pl-api';
|
||||
import type { StatusesAction } from 'pl-fe/actions/statuses';
|
||||
|
||||
interface StatusList {
|
||||
next: (() => Promise<PaginatedResponse<Status>>) | null;
|
||||
@ -78,7 +67,6 @@ const initialState: State = {
|
||||
favourites: newStatusList(),
|
||||
bookmarks: newStatusList(),
|
||||
pins: newStatusList(),
|
||||
scheduled_statuses: newStatusList(),
|
||||
recent_events: newStatusList(),
|
||||
joined_events: newStatusList(),
|
||||
};
|
||||
@ -125,11 +113,6 @@ const removeOneFromList = (state: State, listType: string, status: string | Pick
|
||||
list.items = list.items.filter(id => id !== statusId);
|
||||
};
|
||||
|
||||
const maybeAppendScheduledStatus = (state: State, status: Pick<ScheduledStatus | Status, 'id' | 'scheduled_at'>) => {
|
||||
if (!status.scheduled_at) return state;
|
||||
return prependOneToList(state, 'scheduled_statuses', getStatusId(status));
|
||||
};
|
||||
|
||||
const addBookmarkToLists = (state: State, status: Pick<Status, 'id' | 'bookmark_folder'>) => {
|
||||
prependOneToList(state, 'bookmarks', status);
|
||||
const folderId = status.bookmark_folder;
|
||||
@ -146,7 +129,7 @@ const removeBookmarkFromLists = (state: State, status: Pick<Status, 'id' | 'book
|
||||
}
|
||||
};
|
||||
|
||||
const statusLists = (state = initialState, action: BookmarksAction | EventsAction | FavouritesAction | InteractionsAction | PinStatusesAction | ScheduledStatusesAction | StatusesAction): State => {
|
||||
const statusLists = (state = initialState, action: BookmarksAction | EventsAction | FavouritesAction | InteractionsAction | PinStatusesAction | StatusesAction): State => {
|
||||
switch (action.type) {
|
||||
case FAVOURITED_STATUSES_FETCH_REQUEST:
|
||||
case FAVOURITED_STATUSES_EXPAND_REQUEST:
|
||||
@ -192,19 +175,6 @@ const statusLists = (state = initialState, action: BookmarksAction | EventsActio
|
||||
return create(state, draft => prependOneToList(draft, 'pins', action.status));
|
||||
case UNPIN_SUCCESS:
|
||||
return create(state, draft => removeOneFromList(draft, 'pins', action.status));
|
||||
case SCHEDULED_STATUSES_FETCH_REQUEST:
|
||||
case SCHEDULED_STATUSES_EXPAND_REQUEST:
|
||||
return create(state, draft => setLoading(draft, 'scheduled_statuses', true));
|
||||
case SCHEDULED_STATUSES_FETCH_FAIL:
|
||||
case SCHEDULED_STATUSES_EXPAND_FAIL:
|
||||
return create(state, draft => setLoading(draft, 'scheduled_statuses', false));
|
||||
case SCHEDULED_STATUSES_FETCH_SUCCESS:
|
||||
return create(state, draft => normalizeList(draft, 'scheduled_statuses', action.statuses, action.next as any));
|
||||
case SCHEDULED_STATUSES_EXPAND_SUCCESS:
|
||||
return create(state, draft => appendToList(draft, 'scheduled_statuses', action.statuses, action.next as any));
|
||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
||||
return create(state, draft => removeOneFromList(draft, 'scheduled_statuses', action.statusId));
|
||||
case RECENT_EVENTS_FETCH_REQUEST:
|
||||
return create(state, draft => setLoading(draft, 'recent_events', true));
|
||||
case RECENT_EVENTS_FETCH_FAIL:
|
||||
@ -217,8 +187,6 @@ const statusLists = (state = initialState, action: BookmarksAction | EventsActio
|
||||
return create(state, draft => setLoading(draft, 'joined_events', false));
|
||||
case JOINED_EVENTS_FETCH_SUCCESS:
|
||||
return create(state, draft => normalizeList(draft, 'joined_events', action.statuses, action.next));
|
||||
case STATUS_CREATE_SUCCESS:
|
||||
return create(state, draft => maybeAppendScheduledStatus(draft, action.status));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user