@planningcenter/chat-react-native 3.38.0-rc.1 → 3.38.0-rc.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversation/jump_to_bottom_button.d.ts +1 -2
- package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
- package/build/components/conversation/jump_to_bottom_button.js +7 -39
- package/build/components/conversation/jump_to_bottom_button.js.map +1 -1
- package/build/components/conversation/message_list.d.ts +10 -0
- package/build/components/conversation/message_list.d.ts.map +1 -0
- package/build/components/conversation/message_list.js +13 -0
- package/build/components/conversation/message_list.js.map +1 -0
- package/build/components/conversation/reply_shadow_message.d.ts +2 -1
- package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
- package/build/components/conversation/reply_shadow_message.js.map +1 -1
- package/build/components/display/conversation_avatar.d.ts +2 -1
- package/build/components/display/conversation_avatar.d.ts.map +1 -1
- package/build/components/display/conversation_avatar.js +6 -5
- package/build/components/display/conversation_avatar.js.map +1 -1
- package/build/components/display/emoji_avatar.d.ts +3 -1
- package/build/components/display/emoji_avatar.d.ts.map +1 -1
- package/build/components/display/emoji_avatar.js +2 -2
- package/build/components/display/emoji_avatar.js.map +1 -1
- package/build/components/display/icon_avatar.d.ts +3 -1
- package/build/components/display/icon_avatar.d.ts.map +1 -1
- package/build/components/display/icon_avatar.js +2 -2
- package/build/components/display/icon_avatar.js.map +1 -1
- package/build/contexts/conversation_context.d.ts +1 -8
- package/build/contexts/conversation_context.d.ts.map +1 -1
- package/build/contexts/conversation_context.js +3 -21
- package/build/contexts/conversation_context.js.map +1 -1
- package/build/hooks/groups/use_group_chat_conversation_payload.d.ts.map +1 -1
- package/build/hooks/groups/use_group_chat_conversation_payload.js +1 -0
- package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -1
- package/build/hooks/index.d.ts +1 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/use_conversation_messages.d.ts +6 -15
- package/build/hooks/use_conversation_messages.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages.js +9 -62
- package/build/hooks/use_conversation_messages.js.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
- package/build/hooks/use_conversation_messages_jolt_events.js +4 -4
- package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
- package/build/hooks/use_conversations_actions.d.ts +0 -5
- package/build/hooks/use_conversations_actions.d.ts.map +1 -1
- package/build/hooks/use_conversations_actions.js +0 -12
- package/build/hooks/use_conversations_actions.js.map +1 -1
- package/build/hooks/use_features.d.ts +0 -1
- package/build/hooks/use_features.d.ts.map +1 -1
- package/build/hooks/use_features.js +0 -1
- package/build/hooks/use_features.js.map +1 -1
- package/build/hooks/use_mark_latest_message_read.d.ts +1 -1
- package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
- package/build/hooks/use_mark_latest_message_read.js +1 -17
- package/build/hooks/use_mark_latest_message_read.js.map +1 -1
- package/build/hooks/use_preview_avatar_diameter.d.ts +2 -0
- package/build/hooks/use_preview_avatar_diameter.d.ts.map +1 -0
- package/build/hooks/use_preview_avatar_diameter.js +11 -0
- package/build/hooks/use_preview_avatar_diameter.js.map +1 -0
- package/build/hooks/use_suspense_api.d.ts +0 -1
- package/build/hooks/use_suspense_api.d.ts.map +1 -1
- package/build/hooks/use_suspense_api.js +1 -1
- package/build/hooks/use_suspense_api.js.map +1 -1
- package/build/jest.js +1 -1
- package/build/jest.js.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.js +11 -9
- package/build/screens/avatar_picker/avatar_picker_screen.js.map +1 -1
- package/build/screens/avatar_picker/avatar_preview.d.ts.map +1 -1
- package/build/screens/avatar_picker/avatar_preview.js +13 -5
- package/build/screens/avatar_picker/avatar_preview.js.map +1 -1
- package/build/screens/avatar_picker/emoji_tab.d.ts.map +1 -1
- package/build/screens/avatar_picker/emoji_tab.js +3 -7
- package/build/screens/avatar_picker/emoji_tab.js.map +1 -1
- package/build/screens/avatar_picker/upload_tab.d.ts.map +1 -1
- package/build/screens/avatar_picker/upload_tab.js +2 -1
- package/build/screens/avatar_picker/upload_tab.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +5 -2
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.js +3 -2
- package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +47 -18
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +2 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +23 -26
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/types.js.map +1 -1
- package/build/screens/conversation_screen.d.ts +0 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +45 -96
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js +3 -3
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.js +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.js.map +1 -1
- package/build/screens/team_conversation_screen.d.ts.map +1 -1
- package/build/screens/team_conversation_screen.js +24 -1
- package/build/screens/team_conversation_screen.js.map +1 -1
- package/build/utils/cache/messages_cache.d.ts +0 -1
- package/build/utils/cache/messages_cache.d.ts.map +1 -1
- package/build/utils/cache/messages_cache.js +0 -4
- package/build/utils/cache/messages_cache.js.map +1 -1
- package/build/utils/client/client.d.ts +1 -1
- package/build/utils/client/client.d.ts.map +1 -1
- package/build/utils/client/client.js +7 -6
- package/build/utils/client/client.js.map +1 -1
- package/build/utils/client/instrumented_fetch.js +3 -5
- package/build/utils/client/instrumented_fetch.js.map +1 -1
- package/build/utils/group_messages.d.ts +2 -9
- package/build/utils/group_messages.d.ts.map +1 -1
- package/build/utils/group_messages.js +1 -20
- package/build/utils/group_messages.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/hooks/use_group_chat_conversation_payload.test.tsx +50 -0
- package/src/__tests__/jest.ts +1 -1
- package/src/__tests__/utils/client.ts +32 -0
- package/src/components/conversation/__tests__/message_list.test.tsx +14 -0
- package/src/components/conversation/jump_to_bottom_button.tsx +8 -57
- package/src/components/conversation/message_list.tsx +42 -0
- package/src/components/conversation/reply_shadow_message.tsx +1 -1
- package/src/components/display/conversation_avatar.tsx +7 -5
- package/src/components/display/emoji_avatar.tsx +10 -2
- package/src/components/display/icon_avatar.tsx +10 -2
- package/src/contexts/conversation_context.tsx +2 -30
- package/src/hooks/groups/use_group_chat_conversation_payload.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use_conversation_messages.ts +20 -120
- package/src/hooks/use_conversation_messages_jolt_events.ts +3 -4
- package/src/hooks/use_conversations_actions.ts +0 -15
- package/src/hooks/use_features.ts +0 -1
- package/src/hooks/use_mark_latest_message_read.ts +2 -16
- package/src/hooks/use_preview_avatar_diameter.ts +12 -0
- package/src/hooks/use_suspense_api.ts +1 -1
- package/src/jest.ts +1 -1
- package/src/screens/avatar_picker/avatar_picker_screen.tsx +25 -9
- package/src/screens/avatar_picker/avatar_preview.tsx +14 -5
- package/src/screens/avatar_picker/emoji_tab.tsx +3 -6
- package/src/screens/avatar_picker/upload_tab.tsx +2 -0
- package/src/screens/conversation_details_screen.tsx +10 -1
- package/src/screens/conversation_filter_recipients/components/header_row.tsx +3 -2
- package/src/screens/conversation_filter_recipients/hooks/__tests__/use_service_types_with_teams.test.ts +108 -0
- package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +46 -19
- package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +31 -29
- package/src/screens/conversation_filter_recipients/types.tsx +1 -1
- package/src/screens/conversation_screen.tsx +69 -186
- package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +6 -4
- package/src/screens/conversation_select_recipients/components/team_recipient_row.tsx +2 -1
- package/src/screens/team_conversation_screen.tsx +33 -1
- package/src/utils/__tests__/group_messages.test.ts +0 -71
- package/src/utils/cache/messages_cache.ts +0 -5
- package/src/utils/client/__tests__/instrumented_fetch.test.ts +9 -5
- package/src/utils/client/client.ts +9 -7
- package/src/utils/client/instrumented_fetch.ts +3 -6
- package/src/utils/group_messages.ts +2 -42
- package/build/components/conversation/unread_divider.d.ts +0 -6
- package/build/components/conversation/unread_divider.d.ts.map +0 -1
- package/build/components/conversation/unread_divider.js +0 -59
- package/build/components/conversation/unread_divider.js.map +0 -1
- package/build/hooks/use_flat_list_viewability.d.ts +0 -20
- package/build/hooks/use_flat_list_viewability.d.ts.map +0 -1
- package/build/hooks/use_flat_list_viewability.js +0 -30
- package/build/hooks/use_flat_list_viewability.js.map +0 -1
- package/build/hooks/use_jump_to_bottom_action.d.ts +0 -9
- package/build/hooks/use_jump_to_bottom_action.d.ts.map +0 -1
- package/build/hooks/use_jump_to_bottom_action.js +0 -62
- package/build/hooks/use_jump_to_bottom_action.js.map +0 -1
- package/build/hooks/use_jump_to_unread_anchor.d.ts +0 -20
- package/build/hooks/use_jump_to_unread_anchor.d.ts.map +0 -1
- package/build/hooks/use_jump_to_unread_anchor.js +0 -53
- package/build/hooks/use_jump_to_unread_anchor.js.map +0 -1
- package/build/hooks/use_jump_to_unread_gates.d.ts +0 -5
- package/build/hooks/use_jump_to_unread_gates.d.ts.map +0 -1
- package/build/hooks/use_jump_to_unread_gates.js +0 -10
- package/build/hooks/use_jump_to_unread_gates.js.map +0 -1
- package/build/hooks/use_scroll_tracking.d.ts +0 -13
- package/build/hooks/use_scroll_tracking.d.ts.map +0 -1
- package/build/hooks/use_scroll_tracking.js +0 -45
- package/build/hooks/use_scroll_tracking.js.map +0 -1
- package/build/hooks/use_track_highest_seen_message.d.ts +0 -4
- package/build/hooks/use_track_highest_seen_message.d.ts.map +0 -1
- package/build/hooks/use_track_highest_seen_message.js +0 -35
- package/build/hooks/use_track_highest_seen_message.js.map +0 -1
- package/build/utils/conversation_messages.d.ts +0 -10
- package/build/utils/conversation_messages.d.ts.map +0 -1
- package/build/utils/conversation_messages.js +0 -22
- package/build/utils/conversation_messages.js.map +0 -1
- package/build/utils/highest_seen_tracker.d.ts +0 -12
- package/build/utils/highest_seen_tracker.d.ts.map +0 -1
- package/build/utils/highest_seen_tracker.js +0 -37
- package/build/utils/highest_seen_tracker.js.map +0 -1
- package/build/utils/message_viewability.d.ts +0 -24
- package/build/utils/message_viewability.d.ts.map +0 -1
- package/build/utils/message_viewability.js +0 -29
- package/build/utils/message_viewability.js.map +0 -1
- package/build/utils/unread_divider_helpers.d.ts +0 -18
- package/build/utils/unread_divider_helpers.d.ts.map +0 -1
- package/build/utils/unread_divider_helpers.js +0 -13
- package/build/utils/unread_divider_helpers.js.map +0 -1
- package/src/__tests__/hooks/use_conversation_messages.test.tsx +0 -109
- package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +0 -154
- package/src/__tests__/utils/cache/messages_cache.test.ts +0 -54
- package/src/components/conversation/unread_divider.tsx +0 -90
- package/src/hooks/use_flat_list_viewability.ts +0 -50
- package/src/hooks/use_jump_to_bottom_action.ts +0 -75
- package/src/hooks/use_jump_to_unread_anchor.ts +0 -68
- package/src/hooks/use_jump_to_unread_gates.ts +0 -10
- package/src/hooks/use_scroll_tracking.ts +0 -64
- package/src/hooks/use_track_highest_seen_message.ts +0 -43
- package/src/utils/__tests__/conversation_messages.test.ts +0 -105
- package/src/utils/__tests__/highest_seen_tracker.test.ts +0 -82
- package/src/utils/__tests__/message_viewability.test.ts +0 -168
- package/src/utils/__tests__/unread_divider_helpers.test.ts +0 -85
- package/src/utils/conversation_messages.ts +0 -37
- package/src/utils/highest_seen_tracker.ts +0 -42
- package/src/utils/message_viewability.ts +0 -49
- package/src/utils/unread_divider_helpers.ts +0 -25
|
@@ -1,128 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
InfiniteData,
|
|
4
|
-
useQueryClient,
|
|
5
|
-
useSuspenseInfiniteQuery,
|
|
6
|
-
useSuspenseQueries,
|
|
7
|
-
} from '@tanstack/react-query'
|
|
8
|
-
import { useCallback, useMemo } from 'react'
|
|
9
|
-
import { useConversationContext } from '../contexts/conversation_context'
|
|
10
|
-
import { ApiCollection, MessageResource } from '../types'
|
|
11
|
-
import {
|
|
12
|
-
anchoredSeedPageParams,
|
|
13
|
-
MessagesPageParam,
|
|
14
|
-
newerPageParam,
|
|
15
|
-
olderPageParam,
|
|
16
|
-
sortAndFilterMessages,
|
|
17
|
-
} from '../utils/conversation_messages'
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { MessageResource } from '../types'
|
|
18
3
|
import { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'
|
|
19
|
-
import {
|
|
20
|
-
import { throwResponseError } from './use_suspense_api'
|
|
21
|
-
|
|
22
|
-
type Args = { conversation_id: number; reply_root_id?: string | null }
|
|
23
|
-
|
|
24
|
-
export type ConversationMessagesOptions = Omit<
|
|
25
|
-
AnyUseSuspenseInfiniteQueryOptions,
|
|
26
|
-
| 'getNextPageParam'
|
|
27
|
-
| 'getPreviousPageParam'
|
|
28
|
-
| 'initialData'
|
|
29
|
-
| 'initialPageParam'
|
|
30
|
-
| 'queryFn'
|
|
31
|
-
| 'queryKey'
|
|
32
|
-
>
|
|
4
|
+
import { SuspensePaginatorOptions, useSuspensePaginator } from './use_suspense_api'
|
|
33
5
|
|
|
34
6
|
export const useConversationMessages = (
|
|
35
|
-
{ conversation_id, reply_root_id }:
|
|
36
|
-
opts?:
|
|
7
|
+
{ conversation_id, reply_root_id }: { conversation_id: number; reply_root_id?: string | null },
|
|
8
|
+
opts?: SuspensePaginatorOptions
|
|
37
9
|
) => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const requestArgs = useMemo(
|
|
43
|
-
() => getMessagesRequestArgs({ conversation_id, reply_root_id }),
|
|
44
|
-
[conversation_id, reply_root_id]
|
|
10
|
+
const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator<MessageResource>(
|
|
11
|
+
getMessagesRequestArgs({ conversation_id, reply_root_id }),
|
|
12
|
+
opts
|
|
45
13
|
)
|
|
46
|
-
const queryKey =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return apiClient.chat
|
|
58
|
-
.get<ApiCollection<MessageResource>>({ url: requestArgs.url, data })
|
|
59
|
-
.catch(throwResponseError)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const seedPageParams = anchored ? anchoredSeedPageParams(initialMessageId) : []
|
|
63
|
-
const seedQueries = useSuspenseQueries({
|
|
64
|
-
queries: seedPageParams.map((pageParam, index) => ({
|
|
65
|
-
queryKey: [...queryKey, 'seed', index],
|
|
66
|
-
queryFn: () => fetchPage(pageParam),
|
|
67
|
-
staleTime: Infinity,
|
|
68
|
-
gcTime: 0,
|
|
69
|
-
})),
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const initialData: InfiniteData<ApiCollection<MessageResource>, MessagesPageParam> | undefined =
|
|
73
|
-
anchored
|
|
74
|
-
? {
|
|
75
|
-
pages: seedQueries.map(q => q.data),
|
|
76
|
-
pageParams: seedPageParams,
|
|
77
|
-
}
|
|
78
|
-
: undefined
|
|
79
|
-
|
|
80
|
-
const initialPageParam: MessagesPageParam = anchored ? seedPageParams[0] : {}
|
|
81
|
-
|
|
82
|
-
const {
|
|
83
|
-
data,
|
|
84
|
-
refetch,
|
|
85
|
-
isRefetching,
|
|
86
|
-
fetchNextPage,
|
|
87
|
-
hasNextPage,
|
|
88
|
-
fetchPreviousPage,
|
|
89
|
-
hasPreviousPage,
|
|
90
|
-
isFetchingPreviousPage,
|
|
91
|
-
} = useSuspenseInfiniteQuery<
|
|
92
|
-
ApiCollection<MessageResource>,
|
|
93
|
-
Response,
|
|
94
|
-
InfiniteData<ApiCollection<MessageResource>, MessagesPageParam>,
|
|
95
|
-
typeof queryKey,
|
|
96
|
-
MessagesPageParam
|
|
97
|
-
>({
|
|
98
|
-
queryKey,
|
|
99
|
-
queryFn: ({ pageParam }) => fetchPage(pageParam),
|
|
100
|
-
initialPageParam,
|
|
101
|
-
initialData,
|
|
102
|
-
getNextPageParam: olderPageParam,
|
|
103
|
-
getPreviousPageParam: anchored ? newerPageParam : () => undefined,
|
|
104
|
-
...(opts || {}),
|
|
105
|
-
...(anchored ? { staleTime: Infinity, refetchOnMount: false } : {}),
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const messages = useMemo(() => sortAndFilterMessages(data.pages), [data.pages])
|
|
109
|
-
|
|
110
|
-
const queryClient = useQueryClient()
|
|
111
|
-
const cancelFetchNewerMessages = useCallback(
|
|
112
|
-
() => queryClient.cancelQueries({ queryKey }),
|
|
113
|
-
[queryClient, queryKey]
|
|
14
|
+
const queryKey = getMessagesQueryKey({ conversation_id, reply_root_id })
|
|
15
|
+
const messages = useMemo(
|
|
16
|
+
() =>
|
|
17
|
+
data
|
|
18
|
+
.filter(
|
|
19
|
+
message =>
|
|
20
|
+
(!message.deletedAt || message.replyRootId) &&
|
|
21
|
+
(message.attachments?.length || message.text?.length)
|
|
22
|
+
)
|
|
23
|
+
.sort((a, b) => -a.id.localeCompare(b.id)),
|
|
24
|
+
[data]
|
|
114
25
|
)
|
|
115
26
|
|
|
116
|
-
return {
|
|
117
|
-
messages,
|
|
118
|
-
refetch,
|
|
119
|
-
isRefetching,
|
|
120
|
-
fetchOlderMessages: fetchNextPage,
|
|
121
|
-
hasMoreOlderMessages: hasNextPage,
|
|
122
|
-
fetchNewerMessages: fetchPreviousPage,
|
|
123
|
-
hasMoreNewerMessages: hasPreviousPage,
|
|
124
|
-
isFetchingNewerMessages: isFetchingPreviousPage,
|
|
125
|
-
cancelFetchNewerMessages,
|
|
126
|
-
queryKey,
|
|
127
|
-
}
|
|
27
|
+
return { messages, refetch, isRefetching, fetchNextPage, queryKey }
|
|
128
28
|
}
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
updateCacheWithIndividualMessage,
|
|
13
13
|
updateCacheWithReaction,
|
|
14
14
|
getThreadedMessagesQueryKey,
|
|
15
|
-
hasUnloadedNewerPages,
|
|
16
15
|
} from '../utils/cache/messages_cache'
|
|
17
16
|
import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'
|
|
18
17
|
import { completeMessageCreationTracking } from '../utils/performance_tracking'
|
|
@@ -53,10 +52,10 @@ export function useConversationMessagesJoltEvents({ conversationId }: Props) {
|
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
55
|
+
// Update the main conversation cache
|
|
56
|
+
updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event)
|
|
59
57
|
|
|
58
|
+
// If message has a reply_root_id, also update the threaded cache
|
|
60
59
|
if (data.reply_root_id) {
|
|
61
60
|
const threadedMessagesQueryKey = getThreadedMessagesQueryKey(
|
|
62
61
|
conversationId,
|
|
@@ -98,21 +98,6 @@ export const useConversationsMute = ({ conversation }: { conversation: Conversat
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export const useConversationsMarkReadUpTo = ({ conversationId }: { conversationId: number }) => {
|
|
102
|
-
const apiClient = useApiClient()
|
|
103
|
-
|
|
104
|
-
return useMutation({
|
|
105
|
-
mutationKey: ['markReadUpTo', conversationId],
|
|
106
|
-
mutationFn: async ({ sortKey }: { sortKey: string }) =>
|
|
107
|
-
apiClient.chat.post({
|
|
108
|
-
url: `/me/conversations/${conversationId}/mark_read_up_to`,
|
|
109
|
-
data: {
|
|
110
|
-
data: { type: 'Conversation', attributes: { sort_key: sortKey } },
|
|
111
|
-
},
|
|
112
|
-
}),
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
|
|
116
101
|
export const useMarkAllRead = () => {
|
|
117
102
|
const apiClient = useApiClient()
|
|
118
103
|
const { args } = useConversationsContext()
|
|
@@ -40,7 +40,6 @@ export const availableFeatures = {
|
|
|
40
40
|
message_reporting: 'ROLLOUT_MOBILE_message_reporting',
|
|
41
41
|
granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',
|
|
42
42
|
custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',
|
|
43
|
-
jump_to_unread: 'ROLLOUT_jump_to_unread',
|
|
44
43
|
conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
|
|
45
44
|
video_moderation: 'ROLLOUT_MOBILE_video_moderation',
|
|
46
45
|
} as const satisfies Record<string, `ROLLOUT_${string}`>
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { debounce } from 'lodash'
|
|
2
2
|
import { useEffect, useMemo, useRef } from 'react'
|
|
3
|
-
import { useConversationContext } from '../contexts/conversation_context'
|
|
4
3
|
import { ConversationResource, MessageResource } from '../types'
|
|
5
4
|
import { useAppState } from './use_app_state'
|
|
6
5
|
import { useConversationsMarkRead } from './use_conversations_actions'
|
|
7
|
-
import { useJumpToUnreadGates } from './use_jump_to_unread_gates'
|
|
8
6
|
|
|
9
7
|
interface Props {
|
|
10
8
|
conversation: ConversationResource
|
|
11
|
-
messages
|
|
9
|
+
messages: MessageResource[]
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export function useMarkLatestMessageRead({ conversation }: Props) {
|
|
15
|
-
const { jumpToUnreadActive } = useJumpToUnreadGates()
|
|
16
|
-
const { currentPageReplyRootId, atEndOfMessageHistory } = useConversationContext()
|
|
17
13
|
const firedOnce = useRef<boolean>(false)
|
|
18
14
|
const { markRead } = useConversationsMarkRead({ conversation })
|
|
19
15
|
const debouncedMarkRead = useMemo(
|
|
@@ -29,20 +25,10 @@ export function useMarkLatestMessageRead({ conversation }: Props) {
|
|
|
29
25
|
|
|
30
26
|
useEffect(() => {
|
|
31
27
|
if (!isActive || !shouldMarkRead) return
|
|
32
|
-
if (currentPageReplyRootId) return
|
|
33
|
-
if (jumpToUnreadActive && !atEndOfMessageHistory) return
|
|
34
28
|
|
|
35
29
|
firedOnce.current = true
|
|
36
30
|
|
|
37
31
|
debouncedMarkRead(true)
|
|
38
32
|
// keeping unreadReactionCount in the dependency array to watch for changes
|
|
39
|
-
}, [
|
|
40
|
-
debouncedMarkRead,
|
|
41
|
-
isActive,
|
|
42
|
-
shouldMarkRead,
|
|
43
|
-
unreadReactionCount,
|
|
44
|
-
currentPageReplyRootId,
|
|
45
|
-
jumpToUnreadActive,
|
|
46
|
-
atEndOfMessageHistory,
|
|
47
|
-
])
|
|
33
|
+
}, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount])
|
|
48
34
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useWindowDimensions } from 'react-native'
|
|
2
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../utils'
|
|
3
|
+
import { useFontScale } from './use_font_scale'
|
|
4
|
+
|
|
5
|
+
const VIEWPORT_FRACTION = 0.22
|
|
6
|
+
const BASE_DIAMETER = 80
|
|
7
|
+
|
|
8
|
+
export function usePreviewAvatarDiameter() {
|
|
9
|
+
const { width } = useWindowDimensions()
|
|
10
|
+
const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER_LANDMARK })
|
|
11
|
+
return Math.min(BASE_DIAMETER * fontScale, width * VIEWPORT_FRACTION)
|
|
12
|
+
}
|
|
@@ -90,7 +90,7 @@ export const useSuspensePaginator = <T extends ResourceObject>(
|
|
|
90
90
|
return { ...query, data, totalCount }
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
const throwResponseError = (error: unknown) => {
|
|
94
94
|
if (error instanceof Response) {
|
|
95
95
|
throw new ResponseError(error as FailedResponse)
|
|
96
96
|
}
|
package/src/jest.ts
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
type AvatarUpdatePayload,
|
|
14
14
|
} from '../../hooks/use_conversation_avatar_update'
|
|
15
15
|
import { useFontScale } from '../../hooks/use_font_scale'
|
|
16
|
+
import { usePreviewAvatarDiameter } from '../../hooks/use_preview_avatar_diameter'
|
|
17
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
16
18
|
import type { ImagePickerAsset } from '../../utils/native_adapters/image_picker'
|
|
17
19
|
import {
|
|
18
20
|
avatarPickerReducer,
|
|
@@ -71,6 +73,7 @@ function EditModeContent({ conversationId }: { conversationId: number }) {
|
|
|
71
73
|
const navigation = useNavigation()
|
|
72
74
|
const { data: conversation } = useConversation({ conversation_id: conversationId })
|
|
73
75
|
const mutation = useConversationAvatarUpdate({ conversationId })
|
|
76
|
+
const previewDiameter = usePreviewAvatarDiameter()
|
|
74
77
|
|
|
75
78
|
const [state, dispatch] = useReducer(avatarPickerReducer, conversation, initAvatarPickerState)
|
|
76
79
|
|
|
@@ -110,7 +113,14 @@ function EditModeContent({ conversationId }: { conversationId: number }) {
|
|
|
110
113
|
</FormSheet.HeaderTextButton>
|
|
111
114
|
</>
|
|
112
115
|
}
|
|
113
|
-
fallbackPreview={
|
|
116
|
+
fallbackPreview={
|
|
117
|
+
<ConversationAvatar
|
|
118
|
+
conversation={conversation}
|
|
119
|
+
size="2xl"
|
|
120
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
121
|
+
style={{ width: previewDiameter, height: previewDiameter }}
|
|
122
|
+
/>
|
|
123
|
+
}
|
|
114
124
|
/>
|
|
115
125
|
)
|
|
116
126
|
}
|
|
@@ -187,7 +197,10 @@ function AvatarPickerFormSheet({
|
|
|
187
197
|
activeTab={state.activeTab}
|
|
188
198
|
onTabPress={tab => dispatch({ type: 'SELECT_TAB', payload: tab })}
|
|
189
199
|
renderItem={({ item }) => (
|
|
190
|
-
<Text
|
|
200
|
+
<Text
|
|
201
|
+
style={[styles.tabLabel, item === state.activeTab && styles.tabLabelActive]}
|
|
202
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
203
|
+
>
|
|
191
204
|
{TAB_LABELS[item]}
|
|
192
205
|
</Text>
|
|
193
206
|
)}
|
|
@@ -226,7 +239,15 @@ function AvatarPickerFormSheet({
|
|
|
226
239
|
|
|
227
240
|
function EmptyAvatarPlaceholder() {
|
|
228
241
|
const styles = useStyles()
|
|
229
|
-
|
|
242
|
+
const diameter = usePreviewAvatarDiameter()
|
|
243
|
+
return (
|
|
244
|
+
<View
|
|
245
|
+
style={[
|
|
246
|
+
styles.emptyAvatarPlaceholder,
|
|
247
|
+
{ width: diameter, height: diameter, borderRadius: diameter / 2 },
|
|
248
|
+
]}
|
|
249
|
+
/>
|
|
250
|
+
)
|
|
230
251
|
}
|
|
231
252
|
|
|
232
253
|
type ValidAvatarPickerState = AvatarPickerState &
|
|
@@ -264,9 +285,7 @@ function buildPayload(state: AvatarPickerState): AvatarUpdatePayload | null {
|
|
|
264
285
|
|
|
265
286
|
const useStyles = () => {
|
|
266
287
|
const { colors } = useTheme()
|
|
267
|
-
const fontScale = useFontScale({ maxFontSizeMultiplier:
|
|
268
|
-
const uncappedFontScale = useFontScale()
|
|
269
|
-
const emptyAvatarDiameter = 80 * uncappedFontScale
|
|
288
|
+
const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER_LANDMARK })
|
|
270
289
|
|
|
271
290
|
return StyleSheet.create({
|
|
272
291
|
formSheetRoot: {
|
|
@@ -301,9 +320,6 @@ const useStyles = () => {
|
|
|
301
320
|
borderTopColor: colors.borderColorDefaultBase,
|
|
302
321
|
},
|
|
303
322
|
emptyAvatarPlaceholder: {
|
|
304
|
-
width: emptyAvatarDiameter,
|
|
305
|
-
height: emptyAvatarDiameter,
|
|
306
|
-
borderRadius: emptyAvatarDiameter / 2,
|
|
307
323
|
borderWidth: 2,
|
|
308
324
|
borderStyle: 'dashed',
|
|
309
325
|
borderColor: colors.borderColorDefaultBase,
|
|
@@ -3,6 +3,8 @@ import { StyleSheet, View } from 'react-native'
|
|
|
3
3
|
import { EmojiAvatar } from '../../components/display/emoji_avatar'
|
|
4
4
|
import { IconAvatar } from '../../components/display/icon_avatar'
|
|
5
5
|
import AvatarPrimitive from '../../components/primitive/avatar_primitive'
|
|
6
|
+
import { usePreviewAvatarDiameter } from '../../hooks/use_preview_avatar_diameter'
|
|
7
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
6
8
|
import type { AvatarPickerState } from './avatar_picker_state'
|
|
7
9
|
|
|
8
10
|
interface AvatarPreviewProps {
|
|
@@ -10,18 +12,24 @@ interface AvatarPreviewProps {
|
|
|
10
12
|
fallback: React.ReactNode
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
function getPreviewNode(state: AvatarPickerState): React.ReactNode {
|
|
15
|
+
function getPreviewNode(state: AvatarPickerState, diameter: number): React.ReactNode {
|
|
16
|
+
const sizeProps = {
|
|
17
|
+
size: '2xl',
|
|
18
|
+
maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER_LANDMARK,
|
|
19
|
+
style: { width: diameter, height: diameter },
|
|
20
|
+
} as const
|
|
21
|
+
|
|
14
22
|
switch (state.selectedType) {
|
|
15
23
|
case 'icon':
|
|
16
24
|
if (!state.selectedKey) return null
|
|
17
|
-
return <IconAvatar iconKey={state.selectedKey} color={state.selectedColor}
|
|
25
|
+
return <IconAvatar iconKey={state.selectedKey} color={state.selectedColor} {...sizeProps} />
|
|
18
26
|
case 'emoji':
|
|
19
27
|
if (!state.selectedKey) return null
|
|
20
|
-
return <EmojiAvatar emoji={state.selectedKey} color={state.selectedColor}
|
|
28
|
+
return <EmojiAvatar emoji={state.selectedKey} color={state.selectedColor} {...sizeProps} />
|
|
21
29
|
case 'image':
|
|
22
30
|
if (!state.imagePreviewUri) return null
|
|
23
31
|
return (
|
|
24
|
-
<AvatarPrimitive.Root
|
|
32
|
+
<AvatarPrimitive.Root {...sizeProps}>
|
|
25
33
|
<AvatarPrimitive.Mask>
|
|
26
34
|
<AvatarPrimitive.Image sourceUri={state.imagePreviewUri} />
|
|
27
35
|
</AvatarPrimitive.Mask>
|
|
@@ -33,7 +41,8 @@ function getPreviewNode(state: AvatarPickerState): React.ReactNode {
|
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
export function AvatarPreview({ state, fallback }: AvatarPreviewProps) {
|
|
36
|
-
const
|
|
44
|
+
const diameter = usePreviewAvatarDiameter()
|
|
45
|
+
const preview = getPreviewNode(state, diameter)
|
|
37
46
|
return <View style={styles.container}>{preview ?? fallback}</View>
|
|
38
47
|
}
|
|
39
48
|
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
+
import { EmojiKeyboard, emojisByCategory, type EmojiType } from '@planningcenter/emoji-keyboard'
|
|
1
2
|
import React, { useCallback } from 'react'
|
|
2
3
|
import { StyleSheet, View } from 'react-native'
|
|
3
|
-
import { EmojiKeyboard, type EmojiType, type EmojisByCategory } from 'rn-emoji-keyboard'
|
|
4
|
-
// rn-emoji-keyboard exposes no public exclusion API, so we reach into its
|
|
5
|
-
// internal src/ tree for the emoji JSON. Version is pinned in package.json
|
|
6
|
-
// — verify this path still resolves before bumping rn-emoji-keyboard.
|
|
7
|
-
import emojiData from 'rn-emoji-keyboard/src/assets/emojis.json'
|
|
8
4
|
import { useTheme } from '../../hooks'
|
|
9
5
|
|
|
10
6
|
const BLOCKED_EMOJIS = new Set(['🖕'])
|
|
11
7
|
|
|
12
|
-
const filteredEmojis =
|
|
8
|
+
const filteredEmojis = emojisByCategory.map(category => ({
|
|
13
9
|
...category,
|
|
14
10
|
data: category.data.filter(e => !BLOCKED_EMOJIS.has(e.emoji)),
|
|
15
11
|
}))
|
|
@@ -57,6 +53,7 @@ export function EmojiTab({ onEmojiSelect }: EmojiTabProps) {
|
|
|
57
53
|
categoryPosition="top"
|
|
58
54
|
emojisByCategory={filteredEmojis}
|
|
59
55
|
onEmojiSelected={handleEmojiSelected}
|
|
56
|
+
hideHeader
|
|
60
57
|
enableSearchBar
|
|
61
58
|
enableRecentlyUsed
|
|
62
59
|
theme={emojiTheme}
|
|
@@ -2,6 +2,7 @@ import React, { useCallback } from 'react'
|
|
|
2
2
|
import { Alert, StyleSheet, View } from 'react-native'
|
|
3
3
|
import { Button } from '../../components'
|
|
4
4
|
import { useTheme } from '../../hooks'
|
|
5
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
5
6
|
import { ImagePicker } from '../../utils/native_adapters'
|
|
6
7
|
import type { ImagePickerAsset } from '../../utils/native_adapters/image_picker'
|
|
7
8
|
|
|
@@ -43,6 +44,7 @@ export function UploadTab({ imagePreviewUri, onImageSelect }: UploadTabProps) {
|
|
|
43
44
|
variant="outline"
|
|
44
45
|
appearance="interaction"
|
|
45
46
|
size="md"
|
|
47
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
46
48
|
/>
|
|
47
49
|
</View>
|
|
48
50
|
)
|
|
@@ -49,8 +49,10 @@ import {
|
|
|
49
49
|
useConversationUpdate,
|
|
50
50
|
} from '../hooks/use_conversation'
|
|
51
51
|
import { availableFeatures, useFeatures } from '../hooks/use_features'
|
|
52
|
+
import { usePreviewAvatarDiameter } from '../hooks/use_preview_avatar_diameter'
|
|
52
53
|
import { type ConversationResource, MemberResource, isDefined } from '../types'
|
|
53
54
|
import { GroupResource } from '../types/resources/group_resource'
|
|
55
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../utils'
|
|
54
56
|
import { genderDisplayLabel } from '../utils/gender_display_label'
|
|
55
57
|
import { tokens } from '../vendor/tapestry/tokens'
|
|
56
58
|
// =========================================
|
|
@@ -634,10 +636,16 @@ function AvatarCard({
|
|
|
634
636
|
onPress: () => void
|
|
635
637
|
}) {
|
|
636
638
|
const styles = useStyles()
|
|
639
|
+
const diameter = usePreviewAvatarDiameter()
|
|
637
640
|
|
|
638
641
|
return (
|
|
639
642
|
<View style={styles.avatarCard}>
|
|
640
|
-
<ConversationAvatar
|
|
643
|
+
<ConversationAvatar
|
|
644
|
+
conversation={conversation}
|
|
645
|
+
size="2xl"
|
|
646
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
647
|
+
style={{ width: diameter, height: diameter }}
|
|
648
|
+
/>
|
|
641
649
|
<Button
|
|
642
650
|
title="Update avatar"
|
|
643
651
|
iconNameLeft="general.pencil"
|
|
@@ -645,6 +653,7 @@ function AvatarCard({
|
|
|
645
653
|
variant="outline"
|
|
646
654
|
appearance="interaction"
|
|
647
655
|
size="sm"
|
|
656
|
+
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
648
657
|
/>
|
|
649
658
|
</View>
|
|
650
659
|
)
|
|
@@ -24,6 +24,7 @@ export const HeaderRow = ({ data, nativeID, style, setTeamFilters }: HeaderRowPr
|
|
|
24
24
|
const route = useRoute<RouteProp<ConversationFilterRecipientsScreenProps['route']>>()
|
|
25
25
|
|
|
26
26
|
const { serviceTypeName, teamIdsForServiceType } = data
|
|
27
|
+
const displayName = serviceTypeName ?? 'No service type'
|
|
27
28
|
const { team_ids: currentTeamIds = [] } = route.params
|
|
28
29
|
|
|
29
30
|
const newTeamIdsAdded = [...new Set([...currentTeamIds, ...teamIdsForServiceType])]
|
|
@@ -34,7 +35,7 @@ export const HeaderRow = ({ data, nativeID, style, setTeamFilters }: HeaderRowPr
|
|
|
34
35
|
const selectLabel = allTeamsSelected ? 'Deselect' : 'Select'
|
|
35
36
|
|
|
36
37
|
const headingAccessibilityHint = `${pluralize(teamIdsForServiceType.length, 'team')} available to select`
|
|
37
|
-
const selectAllAccessibilityLabel = `${selectLabel} ${pluralize(teamIdsForServiceType.length, 'team')} for ${
|
|
38
|
+
const selectAllAccessibilityLabel = `${selectLabel} ${pluralize(teamIdsForServiceType.length, 'team')} for ${displayName}`
|
|
38
39
|
|
|
39
40
|
const handleSelectAll = () => {
|
|
40
41
|
setTeamFilters({
|
|
@@ -53,7 +54,7 @@ export const HeaderRow = ({ data, nativeID, style, setTeamFilters }: HeaderRowPr
|
|
|
53
54
|
nativeID={nativeID}
|
|
54
55
|
accessibilityHint={headingAccessibilityHint}
|
|
55
56
|
>
|
|
56
|
-
{
|
|
57
|
+
{displayName}
|
|
57
58
|
</Heading>
|
|
58
59
|
</View>
|
|
59
60
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { TeamResponseItem } from '../../../../types'
|
|
2
|
+
import { decorateTeamResponseItems } from '../use_service_types_with_teams'
|
|
3
|
+
|
|
4
|
+
const makeTeam = (
|
|
5
|
+
overrides: Partial<TeamResponseItem> & { teamId: number; teamName: string }
|
|
6
|
+
): TeamResponseItem => ({
|
|
7
|
+
name: overrides.teamName,
|
|
8
|
+
value: {
|
|
9
|
+
teamId: overrides.teamId,
|
|
10
|
+
serviceTypeId: overrides.value?.serviceTypeId ?? 0,
|
|
11
|
+
serviceTypeIds: overrides.value?.serviceTypeIds ?? [],
|
|
12
|
+
},
|
|
13
|
+
serviceTypeName: overrides.serviceTypeName ?? '',
|
|
14
|
+
serviceTypeNames: overrides.serviceTypeNames ?? [],
|
|
15
|
+
serviceTypeAcronyms: overrides.serviceTypeAcronyms ?? [],
|
|
16
|
+
teamName: overrides.teamName,
|
|
17
|
+
order: overrides.order ?? [0, '', overrides.teamName],
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
describe('decorateTeamResponseItems', () => {
|
|
21
|
+
it('groups teams under their service types', () => {
|
|
22
|
+
const items = [
|
|
23
|
+
makeTeam({
|
|
24
|
+
teamId: 1,
|
|
25
|
+
teamName: 'Worship',
|
|
26
|
+
value: { teamId: 1, serviceTypeId: 10, serviceTypeIds: [10] },
|
|
27
|
+
serviceTypeNames: ['Sunday Morning'],
|
|
28
|
+
}),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
const result = decorateTeamResponseItems(items)
|
|
32
|
+
|
|
33
|
+
expect(result).toHaveLength(1)
|
|
34
|
+
expect(result[0]).toMatchObject({ id: 10, name: 'Sunday Morning', teams: [{ id: 1 }] })
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('gives each team without a service type its own bucket', () => {
|
|
38
|
+
const items = [
|
|
39
|
+
makeTeam({
|
|
40
|
+
teamId: 58,
|
|
41
|
+
teamName: 'Services Team 58',
|
|
42
|
+
value: { teamId: 58, serviceTypeId: 0, serviceTypeIds: [] },
|
|
43
|
+
serviceTypeNames: [],
|
|
44
|
+
}),
|
|
45
|
+
makeTeam({
|
|
46
|
+
teamId: 99,
|
|
47
|
+
teamName: 'Another Typeless Team',
|
|
48
|
+
value: { teamId: 99, serviceTypeId: 0, serviceTypeIds: [] },
|
|
49
|
+
serviceTypeNames: [],
|
|
50
|
+
}),
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
const result = decorateTeamResponseItems(items)
|
|
54
|
+
|
|
55
|
+
expect(result).toHaveLength(2)
|
|
56
|
+
expect(result[0]).toMatchObject({ id: -58, name: 'Services Team 58', teams: [{ id: 58 }] })
|
|
57
|
+
expect(result[1]).toMatchObject({
|
|
58
|
+
id: -99,
|
|
59
|
+
name: 'Another Typeless Team',
|
|
60
|
+
teams: [{ id: 99 }],
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('places teams with and without service types in the right buckets', () => {
|
|
65
|
+
const items = [
|
|
66
|
+
makeTeam({
|
|
67
|
+
teamId: 1,
|
|
68
|
+
teamName: 'Worship',
|
|
69
|
+
value: { teamId: 1, serviceTypeId: 10, serviceTypeIds: [10] },
|
|
70
|
+
serviceTypeNames: ['Sunday Morning'],
|
|
71
|
+
}),
|
|
72
|
+
makeTeam({
|
|
73
|
+
teamId: 58,
|
|
74
|
+
teamName: 'Services Team 58',
|
|
75
|
+
value: { teamId: 58, serviceTypeId: 0, serviceTypeIds: [] },
|
|
76
|
+
serviceTypeNames: [],
|
|
77
|
+
}),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
const result = decorateTeamResponseItems(items)
|
|
81
|
+
|
|
82
|
+
expect(result).toHaveLength(2)
|
|
83
|
+
expect(result[0]).toMatchObject({ id: -58, name: 'Services Team 58', teams: [{ id: 58 }] })
|
|
84
|
+
expect(result[1]).toMatchObject({ id: 10, name: 'Sunday Morning' })
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('filters by search query, matching teams without service types by name', () => {
|
|
88
|
+
const items = [
|
|
89
|
+
makeTeam({
|
|
90
|
+
teamId: 58,
|
|
91
|
+
teamName: 'Services Team 58',
|
|
92
|
+
value: { teamId: 58, serviceTypeId: 0, serviceTypeIds: [] },
|
|
93
|
+
serviceTypeNames: [],
|
|
94
|
+
}),
|
|
95
|
+
makeTeam({
|
|
96
|
+
teamId: 99,
|
|
97
|
+
teamName: 'Unrelated Team',
|
|
98
|
+
value: { teamId: 99, serviceTypeId: 0, serviceTypeIds: [] },
|
|
99
|
+
serviceTypeNames: [],
|
|
100
|
+
}),
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
const result = decorateTeamResponseItems(items, 'Services Team')
|
|
104
|
+
|
|
105
|
+
expect(result).toHaveLength(1)
|
|
106
|
+
expect(result[0]).toMatchObject({ id: -58, name: 'Services Team 58', teams: [{ id: 58 }] })
|
|
107
|
+
})
|
|
108
|
+
})
|