From ae77b678b47f49dee68d45fbbe8f1f71f924ef0a Mon Sep 17 00:00:00 2001 From: mkljczk Date: Sat, 30 Nov 2024 20:27:23 +0100 Subject: [PATCH] pl-fe: move profile directory to tanstack query Signed-off-by: mkljczk --- packages/pl-fe/src/actions/directory.ts | 87 ------------------- .../api/hooks/account-lists/use-directory.ts | 27 ++++++ .../pl-fe/src/features/directory/index.tsx | 31 +++---- packages/pl-fe/src/reducers/user-lists.ts | 28 +----- 4 files changed, 40 insertions(+), 133 deletions(-) delete mode 100644 packages/pl-fe/src/actions/directory.ts create mode 100644 packages/pl-fe/src/api/hooks/account-lists/use-directory.ts diff --git a/packages/pl-fe/src/actions/directory.ts b/packages/pl-fe/src/actions/directory.ts deleted file mode 100644 index 874b4590a..000000000 --- a/packages/pl-fe/src/actions/directory.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { getClient } from '../api'; - -import { fetchRelationships } from './accounts'; -import { importEntities } from './importer'; - -import type { Account, ProfileDirectoryParams } from 'pl-api'; -import type { AppDispatch, RootState } from 'pl-fe/store'; - -const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST' as const; -const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS' as const; -const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL' as const; - -const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST' as const; -const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS' as const; -const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL' as const; - -const fetchDirectory = (params: ProfileDirectoryParams) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(fetchDirectoryRequest()); - - return getClient(getState()).instance.profileDirectory({ ...params, limit: 20 }).then((data) => { - dispatch(importEntities({ accounts: data })); - dispatch(fetchDirectorySuccess(data)); - dispatch(fetchRelationships(data.map((x) => x.id))); - }).catch(error => dispatch(fetchDirectoryFail(error))); - }; - -const fetchDirectoryRequest = () => ({ - type: DIRECTORY_FETCH_REQUEST, -}); - -const fetchDirectorySuccess = (accounts: Array) => ({ - type: DIRECTORY_FETCH_SUCCESS, - accounts, -}); - -const fetchDirectoryFail = (error: unknown) => ({ - type: DIRECTORY_FETCH_FAIL, - error, -}); - -const expandDirectory = (params: Record) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(expandDirectoryRequest()); - - const loadedItems = getState().user_lists.directory.items.length; - - return getClient(getState()).instance.profileDirectory({ ...params, offset: loadedItems, limit: 20 }).then((data) => { - dispatch(importEntities({ accounts: data })); - dispatch(expandDirectorySuccess(data)); - dispatch(fetchRelationships(data.map((x) => x.id))); - }).catch(error => dispatch(expandDirectoryFail(error))); - }; - -const expandDirectoryRequest = () => ({ - type: DIRECTORY_EXPAND_REQUEST, -}); - -const expandDirectorySuccess = (accounts: Array) => ({ - type: DIRECTORY_EXPAND_SUCCESS, - accounts, -}); - -const expandDirectoryFail = (error: unknown) => ({ - type: DIRECTORY_EXPAND_FAIL, - error, -}); - -type DirectoryAction = - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType; - -export { - DIRECTORY_FETCH_REQUEST, - DIRECTORY_FETCH_SUCCESS, - DIRECTORY_FETCH_FAIL, - DIRECTORY_EXPAND_REQUEST, - DIRECTORY_EXPAND_SUCCESS, - DIRECTORY_EXPAND_FAIL, - fetchDirectory, - expandDirectory, - type DirectoryAction, -}; diff --git a/packages/pl-fe/src/api/hooks/account-lists/use-directory.ts b/packages/pl-fe/src/api/hooks/account-lists/use-directory.ts new file mode 100644 index 000000000..5dec97374 --- /dev/null +++ b/packages/pl-fe/src/api/hooks/account-lists/use-directory.ts @@ -0,0 +1,27 @@ +import { 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'; + +const useDirectory = (order: 'active' | 'new', local: boolean = false) => { + const client = useClient(); + const dispatch = useAppDispatch(); + + return useInfiniteQuery({ + queryKey: ['accountsLists', 'directory', order, local], + queryFn: ({ pageParam: offset }) => client.instance.profileDirectory({ + order, + local, + offset, + }).then((accounts) => { + dispatch(importEntities({ accounts })); + return accounts.map(({ id }) => id); + }), + initialPageParam: 0, + getNextPageParam: (_, allPages) => allPages.at(-1)?.length === 0 ? undefined : allPages.flat().length, + select: (data) => data?.pages.flat(), + }); +}; + +export { useDirectory }; diff --git a/packages/pl-fe/src/features/directory/index.tsx b/packages/pl-fe/src/features/directory/index.tsx index c2ce419eb..3c6e5fc2b 100644 --- a/packages/pl-fe/src/features/directory/index.tsx +++ b/packages/pl-fe/src/features/directory/index.tsx @@ -1,16 +1,14 @@ import clsx from 'clsx'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { useLocation } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom-v5-compat'; -import { fetchDirectory, expandDirectory } from 'pl-fe/actions/directory'; +import { useDirectory } from 'pl-fe/api/hooks/account-lists/use-directory'; import LoadMore from 'pl-fe/components/load-more'; import { RadioGroup, RadioItem } from 'pl-fe/components/radio'; import { CardTitle } from 'pl-fe/components/ui/card'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; -import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; import { useInstance } from 'pl-fe/hooks/use-instance'; @@ -26,32 +24,25 @@ const messages = defineMessages({ const Directory = () => { const intl = useIntl(); - const dispatch = useAppDispatch(); - const { search } = useLocation(); - const params = new URLSearchParams(search); + const [params, setParams] = useSearchParams(); const instance = useInstance(); const features = useFeatures(); - const accountIds = useAppSelector((state) => state.user_lists.directory.items); - const isLoading = useAppSelector((state) => state.user_lists.directory.isLoading); + const order = (params.get('order') || 'active') as 'active' | 'new'; + const local = !!params.get('local'); - const [order, setOrder] = useState(params.get('order') || 'active'); - const [local, setLocal] = useState(!!params.get('local')); - - useEffect(() => { - dispatch(fetchDirectory({ order: order || 'active', local: local || false })); - }, [order, local]); + const { data: accountIds = [], isLoading, hasNextPage, fetchNextPage } = useDirectory(order, local); const handleChangeOrder: React.ChangeEventHandler = e => { - setOrder(e.target.value); + setParams({ local: local ? 'true' : '', order: e.target.value }); }; const handleChangeLocal: React.ChangeEventHandler = e => { - setLocal(e.target.value === '1'); + setParams({ local: e.target.value === '1' ? 'true' : '', order }); }; const handleLoadMore = () => { - dispatch(expandDirectory({ order: order || 'active', local: local || false })); + fetchNextPage({ cancelRefetch: false }); }; return ( @@ -108,7 +99,7 @@ const Directory = () => { )} - + {hasNextPage && } ); diff --git a/packages/pl-fe/src/reducers/user-lists.ts b/packages/pl-fe/src/reducers/user-lists.ts index 0d3ddcce5..d443593d8 100644 --- a/packages/pl-fe/src/reducers/user-lists.ts +++ b/packages/pl-fe/src/reducers/user-lists.ts @@ -9,15 +9,6 @@ import { BIRTHDAY_REMINDERS_FETCH_SUCCESS, type AccountsAction, } from 'pl-fe/actions/accounts'; -import { - DIRECTORY_FETCH_REQUEST, - DIRECTORY_FETCH_SUCCESS, - DIRECTORY_FETCH_FAIL, - DIRECTORY_EXPAND_REQUEST, - DIRECTORY_EXPAND_SUCCESS, - DIRECTORY_EXPAND_FAIL, - type DirectoryAction, -} from 'pl-fe/actions/directory'; import { EVENT_PARTICIPATIONS_EXPAND_SUCCESS, EVENT_PARTICIPATIONS_FETCH_SUCCESS, @@ -78,7 +69,7 @@ interface ParticipationRequestList { isLoading: boolean; } -type ListKey = 'follow_requests' | 'directory'; +type ListKey = 'follow_requests'; type NestedListKey = 'reblogged_by' | 'favourited_by' | 'disliked_by' | 'pinned' | 'birthday_reminders' | 'familiar_followers' | 'event_participations' | 'membership_requests' | 'group_blocks'; type State = Record & Record> & { @@ -92,7 +83,6 @@ const initialState: State = { disliked_by: {}, reactions: {}, follow_requests: { next: null, items: [], isLoading: false }, - directory: { next: null, items: [], isLoading: true }, pinned: {}, birthday_reminders: {}, familiar_followers: {}, @@ -157,7 +147,7 @@ const normalizeFollowRequest = (state: State, notification: NotificationGroup) = draft.follow_requests.items = [...new Set([...notification.sample_account_ids, ...draft.follow_requests.items])]; }); -const userLists = (state = initialState, action: AccountsAction | DirectoryAction | EventsAction | FamiliarFollowersAction | GroupsAction | InteractionsAction | NotificationsAction): State => { +const userLists = (state = initialState, action: AccountsAction | EventsAction | FamiliarFollowersAction | GroupsAction | InteractionsAction | NotificationsAction): State => { switch (action.type) { case REBLOGS_FETCH_SUCCESS: return normalizeList(state, ['reblogged_by', action.statusId], action.accounts, action.next); @@ -186,20 +176,6 @@ const userLists = (state = initialState, action: AccountsAction | DirectoryActio case FOLLOW_REQUEST_AUTHORIZE_SUCCESS: case FOLLOW_REQUEST_REJECT_SUCCESS: return removeFromList(state, ['follow_requests'], action.accountId); - case DIRECTORY_FETCH_SUCCESS: - return normalizeList(state, ['directory'], action.accounts); - case DIRECTORY_EXPAND_SUCCESS: - return appendToList(state, ['directory'], action.accounts, null); - case DIRECTORY_FETCH_REQUEST: - case DIRECTORY_EXPAND_REQUEST: - return create(state, (draft) => { - draft.directory.isLoading = true; - }); - case DIRECTORY_FETCH_FAIL: - case DIRECTORY_EXPAND_FAIL: - return create(state, (draft) => { - draft.directory.isLoading = false; - }); case PINNED_ACCOUNTS_FETCH_SUCCESS: return normalizeList(state, ['pinned', action.accountId], action.accounts, action.next); case BIRTHDAY_REMINDERS_FETCH_SUCCESS: