Skip to content

Commit

Permalink
Merge pull request #516 from lifeomic/filter-conversation-notificatio…
Browse files Browse the repository at this point in the history
…n-badge

fix: Filter Conversation Notification Badge
  • Loading branch information
sternetj committed Jan 15, 2024
2 parents f6130bb + 04925f1 commit 47e9ba1
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/components/MessagesTile/MessagesTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface Props extends Pick<HomeStackScreenProps<'Home'>, 'navigation'> {
}

export function MessagesTile({ navigation, title, id, Icon }: Props) {
const hasUnread = useHasUnread();
const hasUnread = useHasUnread(id);

return (
<Tile
Expand Down
136 changes: 136 additions & 0 deletions src/hooks/useConversations.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React from 'react';
import { renderHook, waitFor } from '@testing-library/react-native';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { mockGraphQLResponse } from '../common/testHelpers/mockGraphQLResponse';
import { useHasUnread } from './useConversations';
import { useProfilesForTile } from './useMessagingProfiles';
import { useUser } from './useUser';
import { GraphQLClientContextProvider } from './useGraphQLClient';

const baseURL = 'http://localhost:8080/unit-test';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});

jest.mock('./useActiveAccount', () => ({
useActiveAccount: jest.fn().mockReturnValue({ account: 'account' }),
}));
jest.mock('./useMessagingProfiles', () => ({
useProfilesForTile: jest.fn(),
}));
jest.mock('./useUser', () => ({
useUser: jest.fn(),
}));

const useProfilesForTileMock = useProfilesForTile as jest.Mock;
const useUserMock = useUser as jest.Mock;

const renderHookInContext = <T extends any>(useHook: () => T) => {
return renderHook(() => useHook(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>
<GraphQLClientContextProvider baseURL={baseURL}>
{children}
</GraphQLClientContextProvider>
</QueryClientProvider>
),
});
};

beforeEach(() => {
useProfilesForTileMock.mockReturnValue({
data: [{ id: 'profile1' }],
});
useUserMock.mockReturnValue({ data: { id: 'userId' } });
});

describe('useHasUnread', () => {
test('returns true if there are matching conversations', async () => {
const scope = mockGraphQLResponse(
`${baseURL}/v1/graphql`,
{},
{
conversations: {
edges: [
{
node: {
conversationId: 'conversation1',
userIds: ['userId', 'profile1'],
hasUnread: true,
},
},
],
pageInfo: { hasNextPage: false },
},
},
);

const { result } = renderHookInContext(() => useHasUnread(''));

await waitFor(() => scope.done());

expect(result.current).toBe(true);
});

test('returns false if there are conversations with no matching profiles', async () => {
const scope = mockGraphQLResponse(
`${baseURL}/v1/graphql`,
{},
{
conversations: {
edges: [
{
node: {
conversationId: 'conversation2',
userIds: ['userId', 'profile2'],
hasUnread: true,
},
},
],
pageInfo: { hasNextPage: false },
},
},
);

const { result } = renderHookInContext(() => useHasUnread(''));

await waitFor(() => scope.done());

expect(result.current).toBe(false);
});

test('handles missing user and profile data', async () => {
// Simulate data not loaded
useProfilesForTileMock.mockReturnValue({ data: undefined });
useUserMock.mockReturnValue({ data: undefined });

const scope = mockGraphQLResponse(
`${baseURL}/v1/graphql`,
{},
{
conversations: {
edges: [
{
node: {
conversationId: 'conversation2',
userIds: ['userId', 'profile1'],
hasUnread: true,
},
},
],
pageInfo: { hasNextPage: false },
},
},
);

const { result } = renderHookInContext(() => useHasUnread(''));

await waitFor(() => scope.done());

expect(result.current).toBe(false);
});
});
25 changes: 20 additions & 5 deletions src/hooks/useConversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
import { gql } from 'graphql-request';
import { useGraphQLClient } from './useGraphQLClient';
import cloneDeep from 'lodash/cloneDeep';
import { useProfilesForTile } from './useMessagingProfiles';
import { useUser } from './useUser';

const conversationsQueryDocument = gql`
query Conversations($after: String, $first: Int) {
Expand Down Expand Up @@ -77,12 +79,25 @@ export type PageInfoData = {
};
};

export function useHasUnread() {
export function useHasUnread(tileId: string) {
const { data: userData } = useUser();
const { data } = useInfiniteConversations();
return data?.pages
.flat()
.flatMap((pageData) => pageData.conversations.edges)
.some(({ node }) => node.hasUnread === true);
const { data: profiles } = useProfilesForTile(tileId);

return (
data?.pages
?.flatMap((page) =>
page.conversations.edges
.flatMap((edge) => edge.node)
// Conversations that contain users not part of this message tile should be hidden
.filter((node) =>
node.userIds.every(
(id) => id === userData?.id || profiles?.find((p) => p.id === id),
),
),
)
?.some((node) => node.hasUnread === true) ?? false
);
}

export function useInfiniteConversations() {
Expand Down

0 comments on commit 47e9ba1

Please sign in to comment.