@planningcenter/chat-react-native 3.41.0-rc.0 → 3.41.1-qa-799.0
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/page/page_error_boundary.d.ts.map +1 -1
- package/build/components/page/page_error_boundary.js +29 -1
- package/build/components/page/page_error_boundary.js.map +1 -1
- package/build/contexts/api_provider.d.ts.map +1 -1
- package/build/contexts/api_provider.js +12 -2
- package/build/contexts/api_provider.js.map +1 -1
- package/build/contexts/conversations_context.d.ts +3 -1
- package/build/contexts/conversations_context.d.ts.map +1 -1
- package/build/contexts/conversations_context.js +2 -2
- package/build/contexts/conversations_context.js.map +1 -1
- package/build/hooks/services/use_team_members_for_new_conversation.d.ts +14 -14
- package/build/hooks/use_api.d.ts +48 -47
- package/build/hooks/use_api.d.ts.map +1 -1
- package/build/hooks/use_api.js +8 -10
- package/build/hooks/use_api.js.map +1 -1
- package/build/hooks/use_auto_dismiss_keyboard.d.ts +2 -0
- package/build/hooks/use_auto_dismiss_keyboard.d.ts.map +1 -0
- package/build/hooks/use_auto_dismiss_keyboard.js +13 -0
- package/build/hooks/use_auto_dismiss_keyboard.js.map +1 -0
- package/build/hooks/use_chat_permissions.d.ts +14 -14
- package/build/hooks/use_conversation_message.d.ts.map +1 -1
- package/build/hooks/use_conversation_message.js +1 -4
- package/build/hooks/use_conversation_message.js.map +1 -1
- package/build/hooks/use_conversations.d.ts +4 -2
- package/build/hooks/use_conversations.d.ts.map +1 -1
- package/build/hooks/use_conversations.js +2 -2
- package/build/hooks/use_conversations.js.map +1 -1
- package/build/hooks/use_groups.d.ts +26 -26
- package/build/hooks/use_groups_groups.d.ts +26 -26
- package/build/hooks/use_my_gender.d.ts.map +1 -1
- package/build/hooks/use_my_gender.js +1 -2
- package/build/hooks/use_my_gender.js.map +1 -1
- package/build/hooks/use_new_conversation_entry.d.ts +6 -1
- package/build/hooks/use_new_conversation_entry.d.ts.map +1 -1
- package/build/hooks/use_new_conversation_entry.js +19 -5
- package/build/hooks/use_new_conversation_entry.js.map +1 -1
- package/build/hooks/use_new_conversation_from_filter.js +2 -8
- package/build/hooks/use_new_conversation_from_filter.js.map +1 -1
- package/build/hooks/use_people_person.d.ts.map +1 -1
- package/build/hooks/use_people_person.js +1 -2
- package/build/hooks/use_people_person.js.map +1 -1
- package/build/hooks/use_teams.d.ts +26 -26
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +14 -14
- package/build/screens/conversation_filters/hooks/filters.d.ts +40 -40
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +2 -0
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js +4 -0
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +2 -0
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
- package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_type_screen.js +4 -6
- package/build/screens/conversation_select_type_screen.js.map +1 -1
- package/build/screens/conversations/components/chat_group_badge.d.ts.map +1 -1
- package/build/screens/conversations/components/chat_group_badge.js +1 -10
- package/build/screens/conversations/components/chat_group_badge.js.map +1 -1
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/list_header_component.js +6 -0
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.js +1 -1
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/utils/performance_tracking.js +2 -0
- package/build/utils/performance_tracking.js.map +1 -1
- package/build/utils/uri.d.ts +1 -1
- package/package.json +3 -3
- package/src/__tests__/hooks/use_api.test.tsx +11 -0
- package/src/components/page/page_error_boundary.tsx +46 -1
- package/src/contexts/api_provider.tsx +16 -2
- package/src/contexts/conversations_context.tsx +19 -7
- package/src/hooks/use_api.ts +18 -27
- package/src/hooks/use_auto_dismiss_keyboard.ts +11 -0
- package/src/hooks/use_conversation_message.ts +1 -4
- package/src/hooks/use_conversations.ts +8 -4
- package/src/hooks/use_my_gender.ts +12 -10
- package/src/hooks/use_new_conversation_entry.ts +39 -11
- package/src/hooks/use_new_conversation_from_filter.ts +12 -12
- package/src/hooks/use_people_person.ts +12 -10
- package/src/screens/conversation_screen.tsx +3 -0
- package/src/screens/conversation_select_recipients/conversation_new_entry_screen.tsx +6 -0
- package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +3 -0
- package/src/screens/conversation_select_type_screen.tsx +5 -6
- package/src/screens/conversations/components/chat_group_badge.tsx +4 -10
- package/src/screens/conversations/components/list_header_component.tsx +7 -0
- package/src/screens/conversations/conversations_screen.tsx +1 -1
- package/src/utils/performance_tracking.ts +2 -0
|
@@ -12,6 +12,7 @@ import { useAppState } from '../hooks/use_app_state'
|
|
|
12
12
|
import { appGrantsRequestArgs } from '../hooks/use_chat_permissions'
|
|
13
13
|
import { getRequestQueryKey, RequestQueryKey } from '../hooks/use_suspense_api'
|
|
14
14
|
import { emitAuthRefresh } from '../utils/auth_events'
|
|
15
|
+
import { ResponseError } from '../utils/response_error'
|
|
15
16
|
import { ChatContext, ChatContextValue } from './chat_context'
|
|
16
17
|
|
|
17
18
|
let apiClient: ApiClient | undefined
|
|
@@ -26,11 +27,21 @@ const defaultQueryFn = ({ queryKey }: { queryKey: QueryKey }) => {
|
|
|
26
27
|
return apiClient[app].get({ url, data, headers })
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
const configuredRetry = (failureCount: number, error: any) => {
|
|
31
|
+
if (is429Error(error)) return false
|
|
32
|
+
|
|
33
|
+
return failureCount < 3
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const is429Error = (error: any): boolean => {
|
|
37
|
+
return error instanceof ResponseError && error.status === 429
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export const chatQueryClient = new QueryClient({
|
|
30
41
|
defaultOptions: {
|
|
31
42
|
queries: {
|
|
32
43
|
queryFn: defaultQueryFn,
|
|
33
|
-
retry:
|
|
44
|
+
retry: configuredRetry,
|
|
34
45
|
},
|
|
35
46
|
},
|
|
36
47
|
})
|
|
@@ -98,7 +109,10 @@ function useSessionChanged(value: Pick<ChatContextValue, 'token' | 'env'>): bool
|
|
|
98
109
|
const tokenChanged = Boolean(
|
|
99
110
|
prevToken?.access_token && newToken?.access_token !== prevToken?.access_token
|
|
100
111
|
)
|
|
101
|
-
|
|
112
|
+
|
|
113
|
+
const envChanged = Boolean(prevEnv && newEnv !== prevEnv)
|
|
114
|
+
|
|
115
|
+
return tokenChanged || envChanged
|
|
102
116
|
}
|
|
103
117
|
|
|
104
118
|
function usePrevious<T>(value: T): T {
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
InfiniteData,
|
|
5
5
|
} from '@tanstack/react-query'
|
|
6
6
|
import React, { createContext, PropsWithChildren, useContext, useMemo, useState } from 'react'
|
|
7
|
+
import { ApiGetQueryOptions } from '../hooks'
|
|
7
8
|
import { useConversations, UseConversationsValue } from '../hooks/use_conversations'
|
|
8
9
|
import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
|
|
9
10
|
import { ApiCollection, ConversationResource } from '../types'
|
|
11
|
+
import { ResponseError } from '../utils/response_error'
|
|
10
12
|
|
|
11
13
|
interface ConversationsContextValue extends UseConversationsValue {
|
|
12
14
|
activeConversationId?: number
|
|
@@ -37,15 +39,22 @@ const ConversationsContext = createContext<ConversationsContextValue>({
|
|
|
37
39
|
export const ConversationsContextProvider = ({
|
|
38
40
|
children,
|
|
39
41
|
args = {},
|
|
40
|
-
|
|
42
|
+
opts: paginatorOptions,
|
|
43
|
+
}: PropsWithChildren<{
|
|
44
|
+
args: ConversationFiltersParams
|
|
45
|
+
opts?: ApiGetQueryOptions
|
|
46
|
+
}>) => {
|
|
41
47
|
const [activeConversationId, setActiveConversationId] = useState<number | undefined>()
|
|
42
48
|
const { chat_group_graph_id, group_source_app_name, show_direct_messages } = args
|
|
43
49
|
|
|
44
|
-
const query = useConversations(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
const query = useConversations(
|
|
51
|
+
{
|
|
52
|
+
chat_group_graph_id,
|
|
53
|
+
group_source_app_name,
|
|
54
|
+
show_direct_messages,
|
|
55
|
+
},
|
|
56
|
+
paginatorOptions
|
|
57
|
+
)
|
|
49
58
|
|
|
50
59
|
const value = useMemo(
|
|
51
60
|
() => ({
|
|
@@ -63,7 +72,10 @@ export const ConversationsContextProvider = ({
|
|
|
63
72
|
function fetchNextPage(
|
|
64
73
|
_options?: FetchNextPageOptions
|
|
65
74
|
): Promise<
|
|
66
|
-
InfiniteQueryObserverResult<
|
|
75
|
+
InfiniteQueryObserverResult<
|
|
76
|
+
InfiniteData<ApiCollection<ConversationResource>, unknown>,
|
|
77
|
+
ResponseError
|
|
78
|
+
>
|
|
67
79
|
> {
|
|
68
80
|
throw new Error('Function not implemented.')
|
|
69
81
|
}
|
package/src/hooks/use_api.ts
CHANGED
|
@@ -1,66 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnyUseSuspenseInfiniteQueryOptions,
|
|
3
|
-
InfiniteData,
|
|
4
|
-
useInfiniteQuery,
|
|
5
|
-
useQuery,
|
|
6
|
-
} from '@tanstack/react-query'
|
|
1
|
+
import { InfiniteData, useInfiniteQuery, useQuery } from '@tanstack/react-query'
|
|
7
2
|
import { useContext } from 'react'
|
|
8
3
|
import { ChatContext } from '../contexts/chat_context'
|
|
9
|
-
import { ApiCollection, ApiResource,
|
|
4
|
+
import { ApiCollection, ApiResource, ResourceObject } from '../types'
|
|
10
5
|
import { GetRequest, RequestData } from '../utils/client'
|
|
6
|
+
import { ResponseError, throwResponseError } from '../utils/response_error'
|
|
11
7
|
import { getNextPageParamFromMeta } from './paginator_meta'
|
|
12
8
|
import { App, useApiClient } from './use_api_client'
|
|
13
9
|
import { getRequestQueryKey, RequestQueryKey } from './use_suspense_api'
|
|
14
10
|
|
|
15
11
|
interface ApiGetOptions extends GetRequest {
|
|
16
12
|
app?: App
|
|
17
|
-
enabled?: boolean
|
|
18
13
|
}
|
|
19
14
|
|
|
20
|
-
type
|
|
15
|
+
export type ApiGetQueryOptions = {
|
|
21
16
|
staleTime?: number
|
|
22
17
|
gcTime?: number
|
|
18
|
+
enabled?: boolean
|
|
19
|
+
throwOnError?: boolean | ((error: ResponseError) => boolean)
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
export const useApiGet = <T extends ResourceObject | ResourceObject[]>(
|
|
26
23
|
args: ApiGetOptions,
|
|
27
|
-
opts?:
|
|
24
|
+
opts?: ApiGetQueryOptions
|
|
28
25
|
) => {
|
|
29
26
|
type Resource = ApiResource<T>
|
|
30
27
|
const { session } = useContext(ChatContext)
|
|
31
28
|
const apiClient = useApiClient()
|
|
32
29
|
|
|
33
|
-
const enabled = !!session.token?.access_token && (
|
|
30
|
+
const enabled = !!session.token?.access_token && (opts?.enabled ?? true)
|
|
34
31
|
|
|
35
|
-
const { data, ...query } = useQuery<Resource,
|
|
32
|
+
const { data, ...query } = useQuery<Resource, ResponseError>({
|
|
36
33
|
queryKey: getRequestQueryKey(args),
|
|
37
34
|
queryFn: ({ queryKey }) => {
|
|
38
35
|
const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey
|
|
39
36
|
|
|
40
|
-
return apiClient[app].get({ url, data: d, headers }) as Promise<Resource>
|
|
37
|
+
return (apiClient[app].get({ url, data: d, headers }) as Promise<Resource>).catch(
|
|
38
|
+
throwResponseError
|
|
39
|
+
)
|
|
41
40
|
},
|
|
42
|
-
enabled,
|
|
43
41
|
...opts,
|
|
42
|
+
enabled,
|
|
44
43
|
})
|
|
45
44
|
|
|
46
45
|
return { ...data, ...query }
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
export type PaginatorOptions = Omit<
|
|
50
|
-
AnyUseSuspenseInfiniteQueryOptions,
|
|
51
|
-
'getNextPageParam' | 'initialPageParam' | 'queryFn' | 'queryKey'
|
|
52
|
-
>
|
|
53
|
-
|
|
54
48
|
export const useApiPaginator = <T extends ResourceObject>(
|
|
55
49
|
args: ApiGetOptions,
|
|
56
|
-
opts?:
|
|
50
|
+
opts?: ApiGetQueryOptions
|
|
57
51
|
) => {
|
|
58
52
|
const { session } = useContext(ChatContext)
|
|
59
53
|
const apiClient = useApiClient()
|
|
60
|
-
const enabled = !!session.token?.access_token && (
|
|
54
|
+
const enabled = !!session.token?.access_token && (opts?.enabled ?? true)
|
|
61
55
|
const query = useInfiniteQuery<
|
|
62
56
|
ApiCollection<T>,
|
|
63
|
-
|
|
57
|
+
ResponseError,
|
|
64
58
|
InfiniteData<ApiCollection<T>>,
|
|
65
59
|
any,
|
|
66
60
|
Partial<RequestData> | undefined
|
|
@@ -74,15 +68,12 @@ export const useApiPaginator = <T extends ResourceObject>(
|
|
|
74
68
|
const offset = pageParam?.offset || args.data.offset
|
|
75
69
|
const data = { ...args.data, where, offset }
|
|
76
70
|
|
|
77
|
-
return apiClient[app].get<ApiCollection<T>>({
|
|
78
|
-
url: args.url,
|
|
79
|
-
data,
|
|
80
|
-
})
|
|
71
|
+
return apiClient[app].get<ApiCollection<T>>({ url: args.url, data }).catch(throwResponseError)
|
|
81
72
|
},
|
|
82
73
|
initialPageParam: {} as Partial<RequestData>,
|
|
83
74
|
getNextPageParam: lastPage => getNextPageParamFromMeta(lastPage.meta?.next),
|
|
84
|
-
enabled,
|
|
85
75
|
...(opts || {}),
|
|
76
|
+
enabled,
|
|
86
77
|
})
|
|
87
78
|
|
|
88
79
|
const data: T[] = query.data?.pages?.flatMap(page => page.data) || []
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useIsFocused } from '@react-navigation/native'
|
|
2
|
+
import { useEffect } from 'react'
|
|
3
|
+
import { Keyboard, Platform } from 'react-native'
|
|
4
|
+
|
|
5
|
+
export function useAutoDismissKeyboard() {
|
|
6
|
+
const isFocused = useIsFocused()
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (Platform.OS !== 'android') return
|
|
9
|
+
if (!isFocused) Keyboard.dismiss()
|
|
10
|
+
}, [isFocused])
|
|
11
|
+
}
|
|
@@ -15,10 +15,7 @@ export const useConversationMessage = ({
|
|
|
15
15
|
data: message,
|
|
16
16
|
isError,
|
|
17
17
|
isLoading,
|
|
18
|
-
} = useApiGet<MessageResource>({
|
|
19
|
-
...getMessageRequestArgs({ conversation_id, messageId }),
|
|
20
|
-
enabled,
|
|
21
|
-
})
|
|
18
|
+
} = useApiGet<MessageResource>(getMessageRequestArgs({ conversation_id, messageId }), { enabled })
|
|
22
19
|
const queryKey = getMessageQueryKey({ conversation_id, messageId })
|
|
23
20
|
|
|
24
21
|
return { message, isError, isLoading, queryKey }
|
|
@@ -2,11 +2,12 @@ import { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query'
|
|
|
2
2
|
import { useMemo } from 'react'
|
|
3
3
|
import { ApiCollection, ConversationResource } from '../types'
|
|
4
4
|
import { ConversationRequestArgs, getConversationsRequestArgs } from '../utils/request/conversation'
|
|
5
|
-
import {
|
|
5
|
+
import { ResponseError } from '../utils/response_error'
|
|
6
|
+
import { ApiGetQueryOptions, useApiPaginator } from './use_api'
|
|
6
7
|
|
|
7
8
|
export type ConversationPaginationResult = UseInfiniteQueryResult<
|
|
8
9
|
InfiniteData<ApiCollection<ConversationResource>, unknown>,
|
|
9
|
-
|
|
10
|
+
ResponseError
|
|
10
11
|
>
|
|
11
12
|
|
|
12
13
|
export type UseConversationsValue = Pick<
|
|
@@ -24,9 +25,12 @@ export type UseConversationsValue = Pick<
|
|
|
24
25
|
refetch: () => Promise<any>
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
export function useConversations(
|
|
28
|
+
export function useConversations(
|
|
29
|
+
args?: Partial<ConversationRequestArgs>,
|
|
30
|
+
opts?: ApiGetQueryOptions
|
|
31
|
+
): UseConversationsValue {
|
|
28
32
|
const requestArgs = getConversationsRequestArgs(args)
|
|
29
|
-
const { data, ...rest } = useApiPaginator<ConversationResource>(requestArgs)
|
|
33
|
+
const { data, ...rest } = useApiPaginator<ConversationResource>(requestArgs, opts)
|
|
30
34
|
|
|
31
35
|
const conversations = useMemo(() => data.sort(sortByLastMessage), [data])
|
|
32
36
|
|
|
@@ -16,18 +16,20 @@ export function useMyGender() {
|
|
|
16
16
|
const { featureEnabled } = useFeatures()
|
|
17
17
|
const isFeatureEnabled = featureEnabled(availableFeatures.gender_specific_conversations)
|
|
18
18
|
|
|
19
|
-
const { data, isFetching } = useApiGet<PersonWithGender>(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const { data, isFetching } = useApiGet<PersonWithGender>(
|
|
20
|
+
{
|
|
21
|
+
url: '/me',
|
|
22
|
+
data: {
|
|
23
|
+
include: ['gender'],
|
|
24
|
+
fields: {
|
|
25
|
+
Person: ['gender'],
|
|
26
|
+
Gender: ['value'],
|
|
27
|
+
},
|
|
27
28
|
},
|
|
29
|
+
app: 'people',
|
|
28
30
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
{ enabled: isFeatureEnabled }
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
const gender = data?.gender
|
|
33
35
|
const genderValue = gender?.value ?? null
|
|
@@ -1,20 +1,44 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
2
|
import { useAppGrants } from './use_chat_permissions'
|
|
3
3
|
|
|
4
|
-
export type NewConversationEntryMode =
|
|
4
|
+
export type NewConversationEntryMode =
|
|
5
|
+
| 'select_type'
|
|
6
|
+
| 'groups'
|
|
7
|
+
| 'teams'
|
|
8
|
+
| 'direct_message'
|
|
9
|
+
| 'none'
|
|
5
10
|
|
|
6
|
-
export function
|
|
11
|
+
export function useConversationTypeAccess() {
|
|
7
12
|
const appGrants = useAppGrants()
|
|
8
13
|
|
|
14
|
+
return useMemo(
|
|
15
|
+
() => ({
|
|
16
|
+
canCreateGroupsConversations: appGrants.data?.some(
|
|
17
|
+
g => g.createConversations && g.appName === 'Groups'
|
|
18
|
+
),
|
|
19
|
+
canCreateServicesConversations: appGrants.data?.some(
|
|
20
|
+
g => g.createConversations && g.appName === 'Services'
|
|
21
|
+
),
|
|
22
|
+
canCreateDirectMessages: appGrants.data?.some(
|
|
23
|
+
g => g.createConversations && g.appName === 'Chat'
|
|
24
|
+
),
|
|
25
|
+
}),
|
|
26
|
+
[appGrants.data]
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useNewConversationEntry(): NewConversationEntryMode {
|
|
31
|
+
const { canCreateGroupsConversations, canCreateServicesConversations, canCreateDirectMessages } =
|
|
32
|
+
useConversationTypeAccess()
|
|
33
|
+
|
|
9
34
|
return useMemo(() => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (canCreateGroupsConversations && canCreateServicesConversations) {
|
|
35
|
+
const availableCount = [
|
|
36
|
+
canCreateGroupsConversations,
|
|
37
|
+
canCreateServicesConversations,
|
|
38
|
+
canCreateDirectMessages,
|
|
39
|
+
].filter(Boolean).length
|
|
40
|
+
|
|
41
|
+
if (availableCount > 1) {
|
|
18
42
|
return 'select_type'
|
|
19
43
|
}
|
|
20
44
|
|
|
@@ -26,6 +50,10 @@ export function useNewConversationEntry(): NewConversationEntryMode {
|
|
|
26
50
|
return 'teams'
|
|
27
51
|
}
|
|
28
52
|
|
|
53
|
+
if (canCreateDirectMessages) {
|
|
54
|
+
return 'direct_message'
|
|
55
|
+
}
|
|
56
|
+
|
|
29
57
|
return 'none'
|
|
30
|
-
}, [
|
|
58
|
+
}, [canCreateGroupsConversations, canCreateServicesConversations, canCreateDirectMessages])
|
|
31
59
|
}
|
|
@@ -25,19 +25,19 @@ export function useNewConversationFromFilter(
|
|
|
25
25
|
const isGroupsGroup = sourceAppName === 'Groups' && sourceType === 'Group'
|
|
26
26
|
const isServicesTeam = sourceAppName === 'Services' && sourceType === 'Team'
|
|
27
27
|
|
|
28
|
-
const { data: group } = useApiGet<GroupResource>(
|
|
29
|
-
url: `/me/groups/${chatGroupGraphId}`,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
app: 'chat',
|
|
33
|
-
})
|
|
28
|
+
const { data: group } = useApiGet<GroupResource>(
|
|
29
|
+
{ url: `/me/groups/${chatGroupGraphId}`, data: { fields: { Group: ['name'] } }, app: 'chat' },
|
|
30
|
+
{ enabled: !!chatGroupGraphId }
|
|
31
|
+
)
|
|
34
32
|
|
|
35
|
-
const { data: groupsGroup } = useApiGet<GroupsGroupResource>(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const { data: groupsGroup } = useApiGet<GroupsGroupResource>(
|
|
34
|
+
{
|
|
35
|
+
url: `/me/groups/${sourceId}`,
|
|
36
|
+
data: { fields: { Group: ['can_create_conversation'] } },
|
|
37
|
+
app: 'groups',
|
|
38
|
+
},
|
|
39
|
+
{ enabled: isGroupsGroup && !!sourceId }
|
|
40
|
+
)
|
|
41
41
|
|
|
42
42
|
return useMemo(() => {
|
|
43
43
|
if (isGroupsGroup && group?.name && sourceId) {
|
|
@@ -16,18 +16,20 @@ interface PeoplePerson extends ResourceObject {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export const usePeoplePerson = (person?: { id: number }) => {
|
|
19
|
-
const { data: peoplePerson } = useApiGet<PeoplePerson>(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const { data: peoplePerson } = useApiGet<PeoplePerson>(
|
|
20
|
+
{
|
|
21
|
+
url: `/people/${person?.id}`,
|
|
22
|
+
data: {
|
|
23
|
+
include: ['emails'],
|
|
24
|
+
fields: {
|
|
25
|
+
Person: ['id', 'name', 'avatar', 'emails'],
|
|
26
|
+
Email: ['address', 'primary'],
|
|
27
|
+
},
|
|
27
28
|
},
|
|
29
|
+
app: 'people',
|
|
28
30
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
{ enabled: Boolean(person?.id) }
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
return peoplePerson
|
|
33
35
|
}
|
|
@@ -28,6 +28,7 @@ import { KeyboardView } from '../components/display/keyboard_view'
|
|
|
28
28
|
import BlankState from '../components/primitive/blank_state_primitive'
|
|
29
29
|
import { ConversationContextProvider } from '../contexts/conversation_context'
|
|
30
30
|
import { useTheme } from '../hooks'
|
|
31
|
+
import { useAutoDismissKeyboard } from '../hooks/use_auto_dismiss_keyboard'
|
|
31
32
|
import { useConversation } from '../hooks/use_conversation'
|
|
32
33
|
import { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'
|
|
33
34
|
import { useConversationMessages } from '../hooks/use_conversation_messages'
|
|
@@ -130,6 +131,8 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
130
131
|
})
|
|
131
132
|
}, [])
|
|
132
133
|
|
|
134
|
+
useAutoDismissKeyboard()
|
|
135
|
+
|
|
133
136
|
useEffect(() => {
|
|
134
137
|
if (reply_root_id) {
|
|
135
138
|
navigation.setParams({
|
|
@@ -16,6 +16,7 @@ type NewConversationStackParamList = {
|
|
|
16
16
|
ConversationNewEntry: ConversationSelectRecipientsParams | undefined
|
|
17
17
|
ConversationSelectGroupRecipients: ConversationSelectRecipientsParams | undefined
|
|
18
18
|
ConversationSelectTeamsILeadRecipients: ConversationSelectRecipientsParams | undefined
|
|
19
|
+
ConversationSelectDirectMessageRecipients: ConversationSelectRecipientsParams | undefined
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const ConversationNewEntryScreen = ({ route }: ConversationSelectRecipientsScreenProps) => {
|
|
@@ -34,6 +35,11 @@ export const ConversationNewEntryScreen = ({ route }: ConversationSelectRecipien
|
|
|
34
35
|
return
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
if (entryMode === 'direct_message') {
|
|
39
|
+
navigation.replace('ConversationSelectDirectMessageRecipients', route.params)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
if (entryMode === 'none') {
|
|
38
44
|
navigation.goBack()
|
|
39
45
|
return
|
|
@@ -10,6 +10,7 @@ import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_di
|
|
|
10
10
|
import { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates'
|
|
11
11
|
import { useDirectMessageConversationValidate } from '../../hooks/direct_messages/use_direct_message_conversation_validate'
|
|
12
12
|
import { useFindOrCreateDirectMessageConversation } from '../../hooks/direct_messages/use_find_or_create_direct_message_conversation'
|
|
13
|
+
import { useAutoDismissKeyboard } from '../../hooks/use_auto_dismiss_keyboard'
|
|
13
14
|
import { DirectMessageCandidateResource } from '../../types/resources/direct_message_candidate'
|
|
14
15
|
import { ConversationSelectRecipientsScreenProps } from './types/screen_props'
|
|
15
16
|
|
|
@@ -26,6 +27,8 @@ export function ConversationSelectDirectMessageRecipientsScreen(
|
|
|
26
27
|
new Map()
|
|
27
28
|
)
|
|
28
29
|
|
|
30
|
+
useAutoDismissKeyboard()
|
|
31
|
+
|
|
29
32
|
useEffect(() => {
|
|
30
33
|
const timer = setTimeout(() => setDebouncedTerm(searchTerm), 200)
|
|
31
34
|
return () => clearTimeout(timer)
|
|
@@ -3,7 +3,7 @@ import React from 'react'
|
|
|
3
3
|
import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
|
|
4
4
|
import { useCurrentPerson } from '../hooks/use_current_person'
|
|
5
5
|
import { availableFeatures, useFeatures } from '../hooks/use_features'
|
|
6
|
-
import {
|
|
6
|
+
import { useConversationTypeAccess } from '../hooks/use_new_conversation_entry'
|
|
7
7
|
import type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
|
|
8
8
|
import { AppName } from '../types/resources/app_name'
|
|
9
9
|
import { GraphId } from '../types/resources/group_resource'
|
|
@@ -26,15 +26,14 @@ type NewConversationTypeScreen =
|
|
|
26
26
|
|
|
27
27
|
export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {
|
|
28
28
|
const navigation = useNavigation()
|
|
29
|
-
const
|
|
29
|
+
const { canCreateGroupsConversations, canCreateServicesConversations } =
|
|
30
|
+
useConversationTypeAccess()
|
|
30
31
|
const { featureEnabled } = useFeatures()
|
|
31
32
|
const { directMessagesDisabled, under_18 } = useCurrentPerson()
|
|
32
33
|
const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
|
|
33
34
|
route.params || {}
|
|
34
35
|
|
|
35
36
|
const filterParams = { chat_group_graph_id, group_source_app_name }
|
|
36
|
-
const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'
|
|
37
|
-
const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'
|
|
38
37
|
const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)
|
|
39
38
|
|
|
40
39
|
const handleFilterPress = () => {
|
|
@@ -89,14 +88,14 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
|
|
|
89
88
|
accessibilityHint="Creates a conversation pre-scoped to the current filter"
|
|
90
89
|
/>
|
|
91
90
|
)}
|
|
92
|
-
{
|
|
91
|
+
{canCreateGroupsConversations && (
|
|
93
92
|
<FormSheet.Action
|
|
94
93
|
title="Group"
|
|
95
94
|
onPress={handleGroupPress}
|
|
96
95
|
accessibilityHint="Opens group selection screen"
|
|
97
96
|
/>
|
|
98
97
|
)}
|
|
99
|
-
{
|
|
98
|
+
{canCreateServicesConversations && (
|
|
100
99
|
<FormSheet.Action
|
|
101
100
|
title="Team"
|
|
102
101
|
onPress={handleTeamPress}
|
|
@@ -11,16 +11,10 @@ export const ChatGroupBadge = ({ rowPaddingHorizontal }: { rowPaddingHorizontal:
|
|
|
11
11
|
const navigation = useNavigation()
|
|
12
12
|
const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
|
|
13
13
|
const { chat_group_graph_id } = route.params || {}
|
|
14
|
-
const { data: group } = useApiGet<GroupResource>(
|
|
15
|
-
url: `/me/groups/${chat_group_graph_id}`,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Group: [],
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
enabled: !!chat_group_graph_id,
|
|
22
|
-
app: 'chat',
|
|
23
|
-
})
|
|
14
|
+
const { data: group } = useApiGet<GroupResource>(
|
|
15
|
+
{ url: `/me/groups/${chat_group_graph_id}`, data: { fields: { Group: [] } }, app: 'chat' },
|
|
16
|
+
{ enabled: !!chat_group_graph_id }
|
|
17
|
+
)
|
|
24
18
|
|
|
25
19
|
const handleBadgePress = useCallback(() => {
|
|
26
20
|
navigation.setParams({
|
|
@@ -87,6 +87,13 @@ export const ListHeaderComponent = () => {
|
|
|
87
87
|
params: { ...route.params },
|
|
88
88
|
})
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
if (entryMode === 'direct_message') {
|
|
92
|
+
return navigation.navigate('New', {
|
|
93
|
+
screen: 'ConversationSelectDirectMessageRecipients',
|
|
94
|
+
params: { ...route.params },
|
|
95
|
+
})
|
|
96
|
+
}
|
|
90
97
|
}, [navigation, route.params, entryMode, newConversationFromFilter])
|
|
91
98
|
|
|
92
99
|
const handleChatSettings = useCallback(() => {
|
|
@@ -22,7 +22,7 @@ export function ConversationsScreen({ route }: ConversationsScreenProps) {
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<View style={styles.container}>
|
|
25
|
-
<ConversationsContextProvider args={route.params}>
|
|
25
|
+
<ConversationsContextProvider args={route.params} opts={{ throwOnError: true }}>
|
|
26
26
|
<Conversations ListHeaderComponent={ListHeaderComponent} />
|
|
27
27
|
</ConversationsContextProvider>
|
|
28
28
|
</View>
|