pl-fe: migrate scheduled statuses to tanstack query

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk
2025-03-15 12:13:31 +01:00
parent ca667fe891
commit 43167628bd
15 changed files with 106 additions and 248 deletions

View File

@ -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,
};

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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(),
});
}
};

View File

@ -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);
});

View File

@ -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>
);

View File

@ -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(() => {

View 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 };

View File

@ -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 };

View 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 };

View File

@ -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,

View File

@ -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 };

View File

@ -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;
}