Skip to content

Commit 770047a

Browse files
authored
fix: likers & retweeters cache update - [CU-869bcu3fq] (#257)
1 parent 70cfdd8 commit 770047a

7 files changed

Lines changed: 159 additions & 23 deletions

File tree

src/__tests__/hooks/profile/useFollowMutation.test.tsx

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,22 @@ describe('useFollowMutation', () => {
277277
pages: [
278278
{
279279
data: [
280-
{ username: 'targetUser', displayName: 'Target User', isFollowing: false },
281-
{ username: 'otherUser', displayName: 'Other User', isFollowing: true },
280+
{
281+
username: 'targetUser',
282+
displayName: 'Target User',
283+
bio: null,
284+
avatarUrl: null,
285+
bioEntities: null,
286+
relationship: { ...rel, following: false },
287+
},
288+
{
289+
username: 'otherUser',
290+
displayName: 'Other User',
291+
bio: null,
292+
avatarUrl: null,
293+
bioEntities: null,
294+
relationship: { ...rel, following: true },
295+
},
282296
],
283297
nextCursor: undefined,
284298
},
@@ -299,8 +313,8 @@ describe('useFollowMutation', () => {
299313
'tweetLikers',
300314
'tweet-123',
301315
]) as typeof likersData;
302-
expect(updatedLikers.pages[0].data[0].isFollowing).toBe(true);
303-
expect(updatedLikers.pages[0].data[1].isFollowing).toBe(true); // unchanged
316+
expect(updatedLikers.pages[0].data[0].relationship?.following).toBe(true);
317+
expect(updatedLikers.pages[0].data[1].relationship?.following).toBe(true); // unchanged
304318
});
305319

306320
it('updates tweetRetweeters cache when following a user', async () => {
@@ -322,8 +336,22 @@ describe('useFollowMutation', () => {
322336
pages: [
323337
{
324338
data: [
325-
{ username: 'retweeter', displayName: 'Retweeter', isFollowing: false },
326-
{ username: 'anotherUser', displayName: 'Another', isFollowing: false },
339+
{
340+
username: 'retweeter',
341+
displayName: 'Retweeter',
342+
bio: null,
343+
avatarUrl: null,
344+
bioEntities: null,
345+
relationship: { ...rel, following: false },
346+
},
347+
{
348+
username: 'anotherUser',
349+
displayName: 'Another',
350+
bio: null,
351+
avatarUrl: null,
352+
bioEntities: null,
353+
relationship: { ...rel, following: false },
354+
},
327355
],
328356
nextCursor: undefined,
329357
},
@@ -344,8 +372,8 @@ describe('useFollowMutation', () => {
344372
'tweetRetweeters',
345373
'tweet-456',
346374
]) as typeof retweetersData;
347-
expect(updatedRetweeters.pages[0].data[0].isFollowing).toBe(true);
348-
expect(updatedRetweeters.pages[0].data[1].isFollowing).toBe(false);
375+
expect(updatedRetweeters.pages[0].data[0].relationship?.following).toBe(true);
376+
expect(updatedRetweeters.pages[0].data[1].relationship?.following).toBe(false);
349377
});
350378

351379
it('creates default relationship when target profile has no relationship', async () => {
@@ -446,7 +474,16 @@ describe('useFollowMutation', () => {
446474
const likersData = {
447475
pages: [
448476
{
449-
data: [{ username: 'targetUser', displayName: 'Target', isFollowing: false }],
477+
data: [
478+
{
479+
username: 'targetUser',
480+
displayName: 'Target',
481+
bio: null,
482+
avatarUrl: null,
483+
bioEntities: null,
484+
relationship: { ...rel, following: false },
485+
},
486+
],
450487
nextCursor: undefined,
451488
},
452489
],
@@ -457,7 +494,16 @@ describe('useFollowMutation', () => {
457494
const retweetersData = {
458495
pages: [
459496
{
460-
data: [{ username: 'targetUser', displayName: 'Target', isFollowing: false }],
497+
data: [
498+
{
499+
username: 'targetUser',
500+
displayName: 'Target',
501+
bio: null,
502+
avatarUrl: null,
503+
bioEntities: null,
504+
relationship: { ...rel, following: false },
505+
},
506+
],
461507
nextCursor: undefined,
462508
},
463509
],
@@ -484,8 +530,8 @@ describe('useFollowMutation', () => {
484530
'tweet-789',
485531
]) as typeof retweetersData;
486532

487-
expect(revertedLikers.pages[0].data[0].isFollowing).toBe(false);
488-
expect(revertedRetweeters.pages[0].data[0].isFollowing).toBe(false);
533+
expect(revertedLikers.pages[0].data[0].relationship?.following).toBe(false);
534+
expect(revertedRetweeters.pages[0].data[0].relationship?.following).toBe(false);
489535
});
490536

491537
it('handles mutation without target profile in cache', async () => {

src/__tests__/screens/tweets/TweetDetailScreen.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,9 @@ describe('TweetDetailScreen', () => {
561561
});
562562
});
563563

564-
expect(input.props.value).toBe('');
564+
await waitFor(() => {
565+
expect(input.props.value).toBe('');
566+
});
565567
});
566568

567569
it('should show error if reply fails', async () => {

src/hooks/profile/useBlockMutation.tsx

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { InfiniteData, QueryClient, useMutation, useQueryClient } from '@tanstack/react-query';
22

33
import { ApiException, ApiResponseBase } from '@/libs/api';
4+
import { queryKeys } from '@/libs/queryKeys';
45
import { blockUser, unblockUser } from '@/services/me';
56
import { ListResponse } from '@/services/settings';
7+
import { GetTweetLikesResponse, GetTweetRetweetersResponse } from '@/services/tweets';
68
import { useUserStore } from '@/stores/userStore';
79
import { UserProfile } from '@/types/user';
810
import { updateSearchUsersCache } from '@/utils/updateSearchCache';
@@ -21,11 +23,13 @@ export type BlockMutationContext = {
2123
};
2224

2325
type InfiniteListResponse = InfiniteData<ListResponse, string | undefined>;
26+
type TweetLikersInfiniteResponse = InfiniteData<GetTweetLikesResponse, string | undefined>;
27+
type TweetRetweetersInfiniteResponse = InfiniteData<GetTweetRetweetersResponse, string | undefined>;
2428

2529
function updateLists(queryClient: QueryClient, username: string, isBlocked: boolean) {
26-
const queryKeys: ('blocks' | 'mutes')[] = ['blocks', 'mutes'];
30+
const listKeys: ('blocks' | 'mutes')[] = ['blocks', 'mutes'];
2731

28-
for (const key of queryKeys) {
32+
for (const key of listKeys) {
2933
const queries = queryClient.getQueriesData<InfiniteListResponse>({
3034
queryKey: [key],
3135
});
@@ -55,6 +59,66 @@ function updateLists(queryClient: QueryClient, username: string, isBlocked: bool
5559
}
5660
}
5761

62+
function updateTweetLikersAndRetweetersLists(
63+
queryClient: QueryClient,
64+
username: string,
65+
isBlocked: boolean
66+
) {
67+
const likersQueries = queryClient.getQueriesData<TweetLikersInfiniteResponse>({
68+
predicate: (query) => query.queryKey[0] === queryKeys.tweetLikers('')[0],
69+
});
70+
71+
likersQueries.forEach(([queryKey, data]) => {
72+
if (!data) return;
73+
74+
const pages = data.pages.map((page) => ({
75+
...page,
76+
data: page.data.map((user) =>
77+
user.username === username
78+
? {
79+
...user,
80+
relationship: {
81+
...user.relationship,
82+
blocking: isBlocked,
83+
follower: isBlocked ? false : user.relationship?.follower,
84+
following: isBlocked ? false : user.relationship?.following,
85+
},
86+
}
87+
: user
88+
),
89+
}));
90+
91+
queryClient.setQueryData(queryKey, { ...data, pages });
92+
});
93+
94+
const retweetersQueries = queryClient.getQueriesData<TweetRetweetersInfiniteResponse>({
95+
predicate: (query) => query.queryKey[0] === queryKeys.tweetRetweeters('')[0],
96+
});
97+
98+
retweetersQueries.forEach(([queryKey, data]) => {
99+
if (!data) return;
100+
101+
const pages = data.pages.map((page) => ({
102+
...page,
103+
data: page.data.map((user) =>
104+
user.username === username
105+
? {
106+
...user,
107+
relationship: {
108+
...user.relationship,
109+
blocking: isBlocked,
110+
follower: isBlocked ? false : user.relationship?.follower,
111+
following: isBlocked ? false : user.relationship?.following,
112+
},
113+
}
114+
: user
115+
),
116+
}));
117+
118+
queryClient.setQueryData(queryKey, { ...data, pages });
119+
});
120+
}
121+
58122
export function useBlockMutation() {
59123
const queryClient = useQueryClient();
60124
const updateUser = useUserStore((state) => state.updateUser);
@@ -110,6 +174,7 @@ export function useBlockMutation() {
110174
});
111175

112176
updateLists(queryClient, username, block);
177+
updateTweetLikersAndRetweetersLists(queryClient, username, block);
113178

114179
updateUser({
115180
followersCount: newViewerFollowersCount,

src/hooks/profile/useFollowMutation.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { InfiniteData, QueryClient, useMutation, useQueryClient } from '@tanstack/react-query';
22

33
import { ApiException } from '@/libs/api';
4+
import { queryKeys } from '@/libs/queryKeys';
45
import { followUser, unfollowUser } from '@/services/connections';
56
import { GetTweetLikesResponse, GetTweetRetweetersResponse } from '@/services/tweets';
67
import { useUserStore } from '@/stores/userStore';
@@ -77,30 +78,50 @@ function updateTweetLikersAndRetweetersLists(
7778
isFollowing: boolean
7879
) {
7980
const likersQueries = queryClient.getQueriesData<TweetLikersInfiniteResponse>({
80-
queryKey: ['tweetLikers'],
81+
predicate: (query) => query.queryKey[0] === queryKeys.tweetLikers('')[0],
8182
});
8283

8384
likersQueries.forEach(([queryKey, data]) => {
8485
if (!data) return;
8586

8687
const pages = data.pages.map((page) => ({
8788
...page,
88-
data: page.data.map((user) => (user.username === username ? { ...user, isFollowing } : user)),
89+
data: page.data.map((user) =>
90+
user.username === username
91+
? {
92+
...user,
93+
relationship: {
94+
...user.relationship,
95+
following: isFollowing,
96+
},
97+
}
98+
: user
99+
),
89100
}));
90101

91102
queryClient.setQueryData(queryKey, { ...data, pages });
92103
});
93104

94105
const retweetersQueries = queryClient.getQueriesData<TweetRetweetersInfiniteResponse>({
95-
queryKey: ['tweetRetweeters'],
106+
predicate: (query) => query.queryKey[0] === queryKeys.tweetRetweeters('')[0],
96107
});
97108

98109
retweetersQueries.forEach(([queryKey, data]) => {
99110
if (!data) return;
100111

101112
const pages = data.pages.map((page) => ({
102113
...page,
103-
data: page.data.map((user) => (user.username === username ? { ...user, isFollowing } : user)),
114+
data: page.data.map((user) =>
115+
user.username === username
116+
? {
117+
...user,
118+
relationship: {
119+
...user.relationship,
120+
following: isFollowing,
121+
},
122+
}
123+
: user
124+
),
104125
}));
105126

106127
queryClient.setQueryData(queryKey, { ...data, pages });

src/hooks/tweets/useTweetLikers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useInfiniteQuery } from '@tanstack/react-query';
22

3+
import { queryKeys } from '@/libs/queryKeys';
34
import { getTweetLikes } from '@/services/tweets';
45

56
export const useTweetLikers = (tweetId: string) => {
67
return useInfiniteQuery({
7-
queryKey: ['tweetLikers', tweetId],
8+
queryKey: queryKeys.tweetLikers(tweetId),
89
queryFn: ({ pageParam }) =>
910
getTweetLikes(tweetId, pageParam ? { cursor: pageParam } : undefined),
1011
initialPageParam: undefined as string | undefined,

src/hooks/tweets/useTweetRetweeters.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { useInfiniteQuery } from '@tanstack/react-query';
22

3+
import { queryKeys } from '@/libs/queryKeys';
34
import { getTweetRetweeters } from '@/services/tweets';
45

56
export const useTweetRetweeters = (tweetId: string) => {
67
return useInfiniteQuery({
7-
queryKey: ['tweetRetweeters', tweetId],
8+
queryKey: queryKeys.tweetRetweeters(tweetId),
89
queryFn: ({ pageParam }) =>
910
getTweetRetweeters(tweetId, pageParam ? { cursor: pageParam } : undefined),
1011
initialPageParam: undefined as string | undefined,

src/libs/queryKeys.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ export const queryKeys = {
88
? (['tweet', tweetId, 'replies', cursor] as const)
99
: (['tweet', tweetId, 'replies'] as const),
1010
tweetQuotes: (tweetId: string) => ['tweet', tweetId, 'quotes'] as const,
11-
tweetLikers: (tweetId: string) => ['tweet', tweetId, 'likers'] as const,
12-
tweetRetweeters: (tweetId: string) => ['tweet', tweetId, 'retweeters'] as const,
11+
tweetLikers: (tweetId: string) => ['tweetLikers', tweetId] as const,
12+
tweetRetweeters: (tweetId: string) => ['tweetRetweeters', tweetId] as const,
1313

1414
timeline: {
1515
forYou: (username: string) => ['timeline', 'for-you', username] as const,

0 commit comments

Comments
 (0)