diff --git a/packages/pl-fe/src/actions/pin-statuses.ts b/packages/pl-fe/src/actions/pin-statuses.ts deleted file mode 100644 index 4103689e0..000000000 --- a/packages/pl-fe/src/actions/pin-statuses.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { isLoggedIn } from 'pl-fe/utils/auth'; - -import { getClient } from '../api'; - -import { importEntities } from './importer'; - -import type { PaginatedResponse, Status } from 'pl-api'; -import type { AppDispatch, RootState } from 'pl-fe/store'; - -const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS' as const; - -const fetchPinnedStatuses = () => - (dispatch: AppDispatch, getState: () => RootState) => { - if (!isLoggedIn(getState)) return; - const me = getState().me; - - return getClient(getState()).accounts.getAccountStatuses(me as string, { pinned: true }).then(response => { - dispatch(importEntities({ statuses: response.items })); - dispatch(fetchPinnedStatusesSuccess(response.items, response.next)); - }); - }; - -const fetchPinnedStatusesSuccess = (statuses: Array, next: (() => Promise>) | null) => ({ - type: PINNED_STATUSES_FETCH_SUCCESS, - statuses, - next, -}); - -type PinStatusesAction = ReturnType; - -export { - PINNED_STATUSES_FETCH_SUCCESS, - fetchPinnedStatuses, - type PinStatusesAction, -}; diff --git a/packages/pl-fe/src/pages/status-lists/pinned-statuses.tsx b/packages/pl-fe/src/pages/status-lists/pinned-statuses.tsx index b0534bfa6..6d6120ebb 100644 --- a/packages/pl-fe/src/pages/status-lists/pinned-statuses.tsx +++ b/packages/pl-fe/src/pages/status-lists/pinned-statuses.tsx @@ -1,14 +1,12 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useParams } from 'react-router-dom'; -import { fetchPinnedStatuses } from 'pl-fe/actions/pin-statuses'; import MissingIndicator from 'pl-fe/components/missing-indicator'; import StatusList from 'pl-fe/components/status-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 { selectOwnAccount } from 'pl-fe/selectors'; +import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; +import { usePinnedStatuses } from 'pl-fe/queries/status-lists/use-pinned-statuses'; const messages = defineMessages({ heading: { id: 'column.pins', defaultMessage: 'Pinned posts' }, @@ -16,19 +14,11 @@ const messages = defineMessages({ const PinnedStatusesPage = () => { const intl = useIntl(); - const dispatch = useAppDispatch(); const { username } = useParams<{ username: string }>(); - const meUsername = useAppSelector((state) => selectOwnAccount(state)?.username || ''); - const statusIds = useAppSelector((state) => state.status_lists.pins!.items); - const isLoading = useAppSelector((state) => !!state.status_lists.pins!.isLoading); - const hasMore = useAppSelector((state) => !!state.status_lists.pins!.next); - - const isMyAccount = username.toLowerCase() === meUsername.toLowerCase(); - - useEffect(() => { - dispatch(fetchPinnedStatuses()); - }, []); + const { account } = useOwnAccount(); + const { data: statusIds = [], isFetching: isLoading, hasNextPage: hasMore } = usePinnedStatuses(account?.id || ''); + const isMyAccount = username.toLowerCase() === account?.username.toLowerCase(); if (!isMyAccount) { return ( diff --git a/packages/pl-fe/src/queries/status-lists/use-pinned-statuses.ts b/packages/pl-fe/src/queries/status-lists/use-pinned-statuses.ts new file mode 100644 index 000000000..bf00c9937 --- /dev/null +++ b/packages/pl-fe/src/queries/status-lists/use-pinned-statuses.ts @@ -0,0 +1,11 @@ +import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query'; +import { minifyStatusList } from 'pl-fe/queries/utils/minify-list'; + +const usePinnedStatuses = makePaginatedResponseQuery( + (accountId: string) => ['statusLists', 'pins', accountId], + (client, [accountId]) => client.accounts.getAccountStatuses(accountId as string, { pinned: true }).then(minifyStatusList), + undefined, + (accountId: string) => !!accountId, +); + +export { usePinnedStatuses }; diff --git a/packages/pl-fe/src/queries/statuses/use-status-interactions.ts b/packages/pl-fe/src/queries/statuses/use-status-interactions.ts index ad3363da5..1a11f7299 100644 --- a/packages/pl-fe/src/queries/statuses/use-status-interactions.ts +++ b/packages/pl-fe/src/queries/statuses/use-status-interactions.ts @@ -6,6 +6,7 @@ import { PIN_SUCCESS, UNPIN_SUCCESS, type InteractionsAction } from 'pl-fe/actio 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 { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query'; import { minifyAccountList } from 'pl-fe/queries/utils/minify-list'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -237,12 +238,15 @@ const useUnbookmarkStatus = (statusId: string) => { const usePinStatus = (statusId: string) => { const client = useClient(); const dispatch = useAppDispatch(); + const queryClient = useQueryClient(); + const { me } = useLoggedIn(); return useMutation({ mutationKey: ['statuses', 'pin', statusId], mutationFn: () => client.statuses.pinStatus(statusId), onSuccess: (status) => { dispatch(importEntities({ statuses: [status] })); + queryClient.invalidateQueries({ queryKey: ['statusLists', 'pins', me] }); dispatch({ type: PIN_SUCCESS, statusId: status.id, accountId: status.account.id }); }, }); @@ -251,12 +255,15 @@ const usePinStatus = (statusId: string) => { const useUnpinStatus = (statusId: string) => { const client = useClient(); const dispatch = useAppDispatch(); + const queryClient = useQueryClient(); + const { me } = useLoggedIn(); return useMutation({ mutationKey: ['statuses', 'unpin', statusId], mutationFn: () => client.statuses.unpinStatus(statusId), onSuccess: (status) => { dispatch(importEntities({ statuses: [status] })); + queryClient.setQueryData(['statusLists', 'pins', me], filterById(statusId)); dispatch({ type: UNPIN_SUCCESS, statusId: status.id, accountId: status.account.id }); }, }); diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index 94f22fe7d..04b9f9676 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -21,7 +21,6 @@ import plfe from './pl-fe'; import polls from './polls'; import push_notifications from './push-notifications'; import shoutbox from './shoutbox'; -import status_lists from './status-lists'; import statuses from './statuses'; import timelines from './timelines'; @@ -44,7 +43,6 @@ const reducers = { polls, push_notifications, shoutbox, - status_lists, statuses, timelines, }; diff --git a/packages/pl-fe/src/reducers/status-lists.test.ts b/packages/pl-fe/src/reducers/status-lists.test.ts deleted file mode 100644 index d3b6aa2af..000000000 --- a/packages/pl-fe/src/reducers/status-lists.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import reducer from './status-lists'; - -describe('status_lists reducer', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {} as any).toJS()).toEqual({ - pins: { - next: null, - loaded: false, - isLoading: null, - items: [], - }, - }); - }); -}); diff --git a/packages/pl-fe/src/reducers/status-lists.ts b/packages/pl-fe/src/reducers/status-lists.ts deleted file mode 100644 index e7ef542f5..000000000 --- a/packages/pl-fe/src/reducers/status-lists.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { create } from 'mutative'; - -import { - PIN_SUCCESS, - UNPIN_SUCCESS, - type InteractionsAction, -} from 'pl-fe/actions/interactions'; -import { PINNED_STATUSES_FETCH_SUCCESS, type PinStatusesAction } from 'pl-fe/actions/pin-statuses'; - -import type { PaginatedResponse, Status } from 'pl-api'; - -interface StatusList { - next: (() => Promise>) | null; - loaded: boolean; - isLoading: boolean | null; - items: Array; -} - -const newStatusList = (): StatusList => ({ - next: null, - loaded: false, - isLoading: null, - items: [], -}); - -type State = Record; - -const initialState: State = { - favourites: newStatusList(), - pins: newStatusList(), -}; - -const getStatusId = (status: string | Pick) => typeof status === 'string' ? status : status.id; - -const getStatusIds = (statuses: Array> = []) => statuses.map(getStatusId); - -const normalizeList = (state: State, listType: string, statuses: Array>, next: (() => Promise>) | null) => { - const list = state[listType] = state[listType] || newStatusList(); - - list.next = next; - list.loaded = true; - list.isLoading = false; - list.items = getStatusIds(statuses); -}; - -const prependOneToList = (state: State, listType: string, status: string | Pick) => { - const statusId = getStatusId(status); - const list = state[listType] = state[listType] || newStatusList(); - - list.items = [...new Set([statusId, ...list.items])]; -}; - -const removeOneFromList = (state: State, listType: string, status: string | Pick) => { - const statusId = getStatusId(status); - const list = state[listType] = state[listType] || newStatusList(); - - list.items = list.items.filter(id => id !== statusId); -}; - -const statusLists = (state = initialState, action: InteractionsAction | PinStatusesAction): State => { - switch (action.type) { - case PINNED_STATUSES_FETCH_SUCCESS: - return create(state, draft => normalizeList(draft, 'pins', action.statuses, action.next)); - case PIN_SUCCESS: - return create(state, draft => prependOneToList(draft, 'pins', action.statusId)); - case UNPIN_SUCCESS: - return create(state, draft => removeOneFromList(draft, 'pins', action.statusId)); - default: - return state; - } -}; - -export { - statusLists as default, -};