pl-fe: migrate account actions to tanstack query

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2025-10-23 18:25:50 +02:00
parent ce379e8621
commit 08d7c8dfba
16 changed files with 328 additions and 322 deletions

View File

@@ -1,9 +1,32 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS, type AccountsAction } from 'pl-fe/actions/accounts';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useClient } from 'pl-fe/hooks/use-client';
import { useLoggedIn } from 'pl-fe/hooks/use-logged-in';
import type { FollowAccountParams, Relationship } from 'pl-api';
import type { MinifiedSuggestion } from '../trends/use-suggested-accounts';
import type { FollowAccountParams, MuteAccountParams, Relationship } from 'pl-api';
const updateRelationship = (accountId: string, changes: Partial<Relationship> | ((relationship: Relationship) => Relationship), queryClient: ReturnType<typeof useQueryClient>) => {
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId]);
if (!previousRelationship) return;
const newRelationship = typeof changes === 'function' ? changes(previousRelationship) : { ...previousRelationship, ...changes };
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
return { previousRelationship };
};
const restorePreviousRelationship = (
accountId: string,
context: { previousRelationship?: Relationship } | undefined,
queryClient: ReturnType<typeof useQueryClient>,
) => {
if (context?.previousRelationship) {
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
}
};
const useRelationshipQuery = (accountId?: string) => {
const client = useClient();
@@ -16,7 +39,7 @@ const useRelationshipQuery = (accountId?: string) => {
});
};
const useFollowMutation = (accountId: string) => {
const useFollowAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
@@ -24,64 +47,204 @@ const useFollowMutation = (accountId: string) => {
mutationKey: ['accountRelationships', accountId],
mutationFn: (params?: FollowAccountParams) => client.accounts.followAccount(accountId, params),
onMutate: (params) => {
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId])!;
if (!previousRelationship) return;
const newRelationship: Relationship = {
...previousRelationship,
requested: !previousRelationship.following,
notifying: params?.notify ?? previousRelationship.notifying,
showing_reblogs: params?.reblogs ?? previousRelationship.showing_reblogs,
};
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
return { previousRelationship };
},
onError: (_err, _variables, context) => {
if (context?.previousRelationship) {
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
}
return updateRelationship(accountId, (relationship) => ({
...relationship,
requested: !relationship.following,
notifying: params?.notify ?? relationship.notifying,
showing_reblogs: params?.reblogs ?? relationship.showing_reblogs,
}), queryClient);
},
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
},
});
};
const useUnfollowMutation = (accountId: string) => {
const useUnfollowAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.accounts.unfollowAccount(accountId),
onMutate: () => {
const previousRelationship = queryClient.getQueryData<Relationship>(['accountRelationships', accountId])!;
if (!previousRelationship) return;
const newRelationship: Relationship = {
...previousRelationship,
following: false,
requested: false,
notifying: false,
showing_reblogs: false,
};
queryClient.setQueryData(['accountRelationships', accountId], newRelationship);
return { previousRelationship };
},
onError: (_err, _variables, context) => {
if (context?.previousRelationship) {
queryClient.setQueryData(['accountRelationships', accountId], context.previousRelationship);
}
},
onMutate: () => updateRelationship(accountId, {
following: false,
requested: false,
notifying: false,
showing_reblogs: false,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
},
});
};
export { useRelationshipQuery, useFollowMutation, useUnfollowMutation };
const useBlockAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const dispatch = useAppDispatch();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.filtering.blockAccount(accountId),
onMutate: () => updateRelationship(accountId, {
blocking: true,
followed_by: false,
following: false,
notifying: false,
requested: false,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
: undefined);
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
return dispatch<AccountsAction>((dispatch, getState) => dispatch({
type: ACCOUNT_BLOCK_SUCCESS,
relationship: data,
statuses: getState().statuses,
}));
},
});
};
const useUnblockAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.filtering.unblockAccount(accountId),
onMutate: () => updateRelationship(accountId, {
blocking: true,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
},
});
};
const useMuteAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const dispatch = useAppDispatch();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: (params?: MuteAccountParams) => client.filtering.muteAccount(accountId, params),
onMutate: () => updateRelationship(accountId, {
muting: true,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
queryClient.setQueryData<Array<MinifiedSuggestion>>(['suggestions'], suggestions => suggestions
? suggestions.filter((suggestion) => suggestion.account_id !== accountId)
: undefined);
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
return dispatch<AccountsAction>((dispatch, getState) => dispatch({
type: ACCOUNT_MUTE_SUCCESS,
relationship: data,
statuses: getState().statuses,
}));
},
});
};
const useUnmuteAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.filtering.unmuteAccount(accountId),
onMutate: () => updateRelationship(accountId, {
muting: false,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
},
});
};
const usePinAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const { me } = useLoggedIn();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.accounts.pinAccount(accountId),
onMutate: () => updateRelationship(accountId, {
endorsed: true,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
queryClient.invalidateQueries({
queryKey: ['accountsLists', 'endorsedAccounts', me],
});
},
});
};
const useUnpinAccountMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
const { me } = useLoggedIn();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.accounts.unpinAccount(accountId),
onMutate: () => updateRelationship(accountId, {
endorsed: false,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
queryClient.invalidateQueries({
queryKey: ['accountsLists', 'endorsedAccounts', me],
});
},
});
};
const useRemoveAccountFromFollowersMutation = (accountId: string) => {
const client = useClient();
const queryClient = useQueryClient();
return useMutation({
mutationKey: ['accountRelationships', accountId],
mutationFn: () => client.accounts.removeAccountFromFollowers(accountId),
onMutate: () => updateRelationship(accountId, {
followed_by: false,
}, queryClient),
onError: (_err, _variables, context) => restorePreviousRelationship(accountId, context, queryClient),
onSuccess: (data) => {
queryClient.setQueryData(['accountRelationships', accountId], data);
},
});
};
export {
useRelationshipQuery,
useFollowAccountMutation,
useUnfollowAccountMutation,
useBlockAccountMutation,
useUnblockAccountMutation,
useMuteAccountMutation,
useUnmuteAccountMutation,
usePinAccountMutation,
useUnpinAccountMutation,
useRemoveAccountFromFollowersMutation,
};