@planningcenter/chat-react-native 4.0.1-qa-staging.2 → 4.0.1-qa-staging.4
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/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +2 -1
- package/build/components/conversation/message.js.map +1 -1
- package/build/contexts/api_provider.d.ts.map +1 -1
- package/build/contexts/api_provider.js +12 -1
- package/build/contexts/api_provider.js.map +1 -1
- package/build/hooks/use_features.d.ts +16 -0
- package/build/hooks/use_features.d.ts.map +1 -1
- package/build/hooks/use_features.js +43 -47
- package/build/hooks/use_features.js.map +1 -1
- package/build/screens/conversation_new/components/groups_form.js +80 -71
- package/build/screens/conversation_new/components/groups_form.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 -0
- 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 +157 -150
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/components/search_list_header_component.d.ts +2 -0
- package/build/screens/conversations/components/search_list_header_component.d.ts.map +1 -0
- package/build/screens/conversations/components/search_list_header_component.js +496 -0
- package/build/screens/conversations/components/search_list_header_component.js.map +1 -0
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +28 -16
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/utils/time.d.ts +1 -0
- package/build/utils/time.d.ts.map +1 -1
- package/build/utils/time.js +1 -0
- package/build/utils/time.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/hooks/use_features.test.ts +61 -0
- package/src/components/conversation/message.tsx +6 -1
- package/src/contexts/api_provider.tsx +4 -0
- package/src/hooks/use_features.ts +26 -14
- package/src/screens/conversation_new/components/groups_form.tsx +7 -2
- package/src/screens/conversations/components/__tests__/chat_group_badge.test.tsx +32 -0
- package/src/screens/conversations/components/__tests__/list_header_component.test.tsx +66 -0
- package/src/screens/conversations/components/chat_group_badge.tsx +1 -0
- package/src/screens/conversations/components/list_header_component.tsx +18 -28
- package/src/screens/conversations/components/search_list_header_component.tsx +291 -0
- package/src/screens/conversations/conversations_screen.tsx +6 -1
- package/src/utils/time.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAE/C,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAS1D;AAED,eAAO,MAAM,YAAY,QAAqB,CAAA;AAC9C,eAAO,MAAM,YAAY,QAAqB,CAAA;AAC9C,eAAO,MAAM,cAAc,QAAsB,CAAA;AACjD,eAAO,MAAM,QAAQ,QAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAE/C,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAS1D;AAED,eAAO,MAAM,YAAY,QAAqB,CAAA;AAC9C,eAAO,MAAM,UAAU,QAAqB,CAAA;AAC5C,eAAO,MAAM,YAAY,QAAqB,CAAA;AAC9C,eAAO,MAAM,cAAc,QAAsB,CAAA;AACjD,eAAO,MAAM,QAAQ,QAAmB,CAAA"}
|
package/build/utils/time.js
CHANGED
|
@@ -9,6 +9,7 @@ export function toMs(value, unit) {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
export const FIVE_SECONDS = toMs(5, 'seconds');
|
|
12
|
+
export const ONE_MINUTE = toMs(1, 'minutes');
|
|
12
13
|
export const FIVE_MINUTES = toMs(5, 'minutes');
|
|
13
14
|
export const THIRTY_MINUTES = toMs(30, 'minutes');
|
|
14
15
|
export const ONE_HOUR = toMs(1, 'hours');
|
package/build/utils/time.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","names":["toMs","value","unit","FIVE_SECONDS","FIVE_MINUTES","THIRTY_MINUTES","ONE_HOUR"],"sources":["../../src/utils/time.ts"],"sourcesContent":["type TimeUnit = 'hours' | 'minutes' | 'seconds'\n\nexport function toMs(value: number, unit: TimeUnit): number {\n switch (unit) {\n case 'hours':\n return value * 60 * 60 * 1000\n case 'minutes':\n return value * 60 * 1000\n case 'seconds':\n return value * 1000\n }\n}\n\nexport const FIVE_SECONDS = toMs(5, 'seconds')\nexport const FIVE_MINUTES = toMs(5, 'minutes')\nexport const THIRTY_MINUTES = toMs(30, 'minutes')\nexport const ONE_HOUR = toMs(1, 'hours')\n"],"mappings":"AAEA,OAAO,SAASA,IAAIA,CAACC,KAAa,EAAEC,IAAc,EAAU;EAC1D,QAAQA,IAAI;IACV,KAAK,OAAO;MACV,OAAOD,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IAC/B,KAAK,SAAS;MACZ,OAAOA,KAAK,GAAG,EAAE,GAAG,IAAI;IAC1B,KAAK,SAAS;MACZ,OAAOA,KAAK,GAAG,IAAI;EACvB;AACF;AAEA,OAAO,MAAME,YAAY,GAAGH,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;AAC9C,OAAO,MAAMI,
|
|
1
|
+
{"version":3,"file":"time.js","names":["toMs","value","unit","FIVE_SECONDS","ONE_MINUTE","FIVE_MINUTES","THIRTY_MINUTES","ONE_HOUR"],"sources":["../../src/utils/time.ts"],"sourcesContent":["type TimeUnit = 'hours' | 'minutes' | 'seconds'\n\nexport function toMs(value: number, unit: TimeUnit): number {\n switch (unit) {\n case 'hours':\n return value * 60 * 60 * 1000\n case 'minutes':\n return value * 60 * 1000\n case 'seconds':\n return value * 1000\n }\n}\n\nexport const FIVE_SECONDS = toMs(5, 'seconds')\nexport const ONE_MINUTE = toMs(1, 'minutes')\nexport const FIVE_MINUTES = toMs(5, 'minutes')\nexport const THIRTY_MINUTES = toMs(30, 'minutes')\nexport const ONE_HOUR = toMs(1, 'hours')\n"],"mappings":"AAEA,OAAO,SAASA,IAAIA,CAACC,KAAa,EAAEC,IAAc,EAAU;EAC1D,QAAQA,IAAI;IACV,KAAK,OAAO;MACV,OAAOD,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;IAC/B,KAAK,SAAS;MACZ,OAAOA,KAAK,GAAG,EAAE,GAAG,IAAI;IAC1B,KAAK,SAAS;MACZ,OAAOA,KAAK,GAAG,IAAI;EACvB;AACF;AAEA,OAAO,MAAME,YAAY,GAAGH,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;AAC9C,OAAO,MAAMI,UAAU,GAAGJ,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;AAC5C,OAAO,MAAMK,YAAY,GAAGL,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;AAC9C,OAAO,MAAMM,cAAc,GAAGN,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC;AACjD,OAAO,MAAMO,QAAQ,GAAGP,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "4.0.1-qa-staging.
|
|
3
|
+
"version": "4.0.1-qa-staging.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
35
35
|
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
|
36
|
-
"@planningcenter/emoji-keyboard": "4.0.1-qa-staging.
|
|
36
|
+
"@planningcenter/emoji-keyboard": "4.0.1-qa-staging.4",
|
|
37
37
|
"lodash-inflection": "^1.5.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sf-symbols-typescript": "^2.2.0",
|
|
85
85
|
"typescript": "~6.0.3"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "a7faa8fb4d6db21faac3abab923e22e66ffbbb70"
|
|
88
88
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { buildTestQueryClient } from '../../__utils__/query_client'
|
|
2
|
+
import type { ApiClient } from '../../hooks/use_api_client'
|
|
3
|
+
import { featuresQueryOptions } from '../../hooks/use_features'
|
|
4
|
+
|
|
5
|
+
const features = {
|
|
6
|
+
data: [{ type: 'Feature', id: '1', name: 'ROLLOUT_search', enabled: true }],
|
|
7
|
+
links: {},
|
|
8
|
+
meta: { count: 1, totalCount: 1 },
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const buildClient = (get: jest.Mock) => ({ chat: { get } }) as unknown as ApiClient
|
|
12
|
+
|
|
13
|
+
const fetchTwice = async (get: jest.Mock, secondsBetween: number) => {
|
|
14
|
+
const queryClient = buildTestQueryClient()
|
|
15
|
+
const options = featuresQueryOptions(buildClient(get))
|
|
16
|
+
|
|
17
|
+
await queryClient.fetchQuery(options)
|
|
18
|
+
jest.advanceTimersByTime(secondsBetween * 1000)
|
|
19
|
+
await queryClient.fetchQuery(options)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('featuresQueryOptions', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.useFakeTimers()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.useRealTimers()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('keeps successful flags fresh for five minutes', async () => {
|
|
32
|
+
const get = jest.fn().mockResolvedValue(features)
|
|
33
|
+
|
|
34
|
+
await fetchTwice(get, 4 * 60)
|
|
35
|
+
|
|
36
|
+
expect(get).toHaveBeenCalledTimes(1)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('refetches right away after a failed fetch', async () => {
|
|
40
|
+
const get = jest.fn().mockRejectedValue({ status: 503 })
|
|
41
|
+
|
|
42
|
+
await fetchTwice(get, 1)
|
|
43
|
+
|
|
44
|
+
expect(get).toHaveBeenCalledTimes(2)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('backs off for a minute after a 429', async () => {
|
|
48
|
+
const get = jest.fn().mockRejectedValue({ status: 429 })
|
|
49
|
+
const queryClient = buildTestQueryClient()
|
|
50
|
+
const options = featuresQueryOptions(buildClient(get))
|
|
51
|
+
|
|
52
|
+
await queryClient.fetchQuery(options)
|
|
53
|
+
jest.advanceTimersByTime(30 * 1000)
|
|
54
|
+
await queryClient.fetchQuery(options)
|
|
55
|
+
expect(get).toHaveBeenCalledTimes(1)
|
|
56
|
+
|
|
57
|
+
jest.advanceTimersByTime(31 * 1000)
|
|
58
|
+
await queryClient.fetchQuery(options)
|
|
59
|
+
expect(get).toHaveBeenCalledTimes(2)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -107,9 +107,14 @@ export const Message = memo(function MessageRow({
|
|
|
107
107
|
const messageIsReplyLabel = replyToReplyRootMessage ? 'Reply' : ''
|
|
108
108
|
const attachmentLabel = some(attachments) ? pluralize(attachments.length, 'attachment') : ''
|
|
109
109
|
const replyCountLabel = isReplyRootMessage ? replyCountText : ''
|
|
110
|
+
const saveStatusLabel = error
|
|
111
|
+
? `Failed to ${isPersisted ? 'edit' : 'send'}`
|
|
112
|
+
: pending
|
|
113
|
+
? messagePendingLabel
|
|
114
|
+
: ''
|
|
110
115
|
const accessibilityLabel = `${author?.name || ''} ${messageIsReplyLabel} ${attachmentLabel} ${
|
|
111
116
|
messageText || ''
|
|
112
|
-
} ${timestamp} ${replyCountLabel}`
|
|
117
|
+
} ${saveStatusLabel} ${timestamp} ${replyCountLabel}`
|
|
113
118
|
|
|
114
119
|
useEffect(() => {
|
|
115
120
|
if (pending) {
|
|
@@ -10,6 +10,7 @@ import { ViewProps } from 'react-native'
|
|
|
10
10
|
import { ApiClient, useApiClient } from '../hooks/use_api_client'
|
|
11
11
|
import { useAppState } from '../hooks/use_app_state'
|
|
12
12
|
import { appGrantsRequestArgs } from '../hooks/use_chat_permissions'
|
|
13
|
+
import { featuresQueryOptions } from '../hooks/use_features'
|
|
13
14
|
import { getRequestQueryKey, RequestQueryKey } from '../hooks/use_suspense_api'
|
|
14
15
|
import { emitAuthRefresh } from '../utils/auth_events'
|
|
15
16
|
import { ResponseError } from '../utils/response_error'
|
|
@@ -81,10 +82,13 @@ export function ApiProvider({ children }: ViewProps) {
|
|
|
81
82
|
// This needs to live in the provider so that it can access the api client
|
|
82
83
|
// and the chat query client
|
|
83
84
|
const PrefetchQueries = () => {
|
|
85
|
+
const client = useApiClient()
|
|
86
|
+
|
|
84
87
|
usePrefetchQuery({
|
|
85
88
|
queryKey: getRequestQueryKey(appGrantsRequestArgs),
|
|
86
89
|
queryFn: defaultQueryFn,
|
|
87
90
|
})
|
|
91
|
+
usePrefetchQuery(featuresQueryOptions(client))
|
|
88
92
|
|
|
89
93
|
return null
|
|
90
94
|
}
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
import { useSuspenseQuery } from '@tanstack/react-query'
|
|
1
|
+
import { queryOptions, useSuspenseQuery } from '@tanstack/react-query'
|
|
2
2
|
import { useCallback } from 'react'
|
|
3
3
|
import { ApiCollection } from '../types'
|
|
4
4
|
import type { FeatureResource } from '../types/resources/feature_resource'
|
|
5
5
|
import { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'
|
|
6
|
-
import { FIVE_MINUTES } from '../utils/time'
|
|
7
|
-
import { useApiClient } from './use_api_client'
|
|
6
|
+
import { FIVE_MINUTES, ONE_MINUTE } from '../utils/time'
|
|
7
|
+
import { ApiClient, useApiClient } from './use_api_client'
|
|
8
8
|
|
|
9
9
|
type FeatureName = (typeof availableFeatures)[keyof typeof availableFeatures]
|
|
10
10
|
|
|
11
|
+
type FeaturesCollection = ApiCollection<FeatureResource> & {
|
|
12
|
+
failure?: { status?: number }
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
export function useFeatures() {
|
|
12
16
|
const apiClient = useApiClient()
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const { data } = useSuspenseQuery({
|
|
16
|
-
queryKey: getFeaturesQueryKey(),
|
|
17
|
-
queryFn: () => {
|
|
18
|
-
return apiClient.chat
|
|
19
|
-
.get<ApiCollection<FeatureResource>>(requestArgs)
|
|
20
|
-
.catch(() => stableEmptyFeatures)
|
|
21
|
-
},
|
|
22
|
-
staleTime: FIVE_MINUTES,
|
|
23
|
-
})
|
|
17
|
+
const { data } = useSuspenseQuery(featuresQueryOptions(apiClient))
|
|
24
18
|
|
|
25
19
|
const features = data.data
|
|
26
20
|
|
|
@@ -36,6 +30,23 @@ export function useFeatures() {
|
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
32
|
|
|
33
|
+
export const featuresQueryOptions = (apiClient: ApiClient) =>
|
|
34
|
+
queryOptions({
|
|
35
|
+
queryKey: getFeaturesQueryKey(),
|
|
36
|
+
queryFn: (): Promise<FeaturesCollection> => {
|
|
37
|
+
return apiClient.chat
|
|
38
|
+
.get<ApiCollection<FeatureResource>>(getFeaturesRequestArgs())
|
|
39
|
+
.catch(error => ({ ...stableEmptyFeatures, failure: { status: error?.status } }))
|
|
40
|
+
},
|
|
41
|
+
staleTime: query => {
|
|
42
|
+
const failure = query.state.data?.failure
|
|
43
|
+
if (!failure) return FIVE_MINUTES
|
|
44
|
+
|
|
45
|
+
return failure.status === 429 ? ONE_MINUTE : 0
|
|
46
|
+
},
|
|
47
|
+
gcTime: Infinity,
|
|
48
|
+
})
|
|
49
|
+
|
|
39
50
|
export const availableFeatures = {
|
|
40
51
|
gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',
|
|
41
52
|
message_reporting: 'ROLLOUT_MOBILE_message_reporting',
|
|
@@ -44,6 +55,7 @@ export const availableFeatures = {
|
|
|
44
55
|
conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
|
|
45
56
|
video_moderation: 'ROLLOUT_MOBILE_video_moderation',
|
|
46
57
|
dm_search_clear_fix: 'ROLLOUT_MOBILE_dm_search_clear_fix',
|
|
58
|
+
search: 'ROLLOUT_search',
|
|
47
59
|
} as const satisfies Record<string, `ROLLOUT_${string}`>
|
|
48
60
|
|
|
49
61
|
const stableEmptyFeatures: ApiCollection<FeatureResource> = {
|
|
@@ -212,9 +212,11 @@ function FormContent({
|
|
|
212
212
|
</View>
|
|
213
213
|
<Divider />
|
|
214
214
|
<Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>
|
|
215
|
-
<Heading variant="h3">
|
|
215
|
+
<Heading variant="h3">
|
|
216
|
+
Title <Text style={styles.required}>*</Text>
|
|
217
|
+
</Heading>
|
|
216
218
|
<AutoFocusAwareTextInput
|
|
217
|
-
placeholder="Topic of conversation
|
|
219
|
+
placeholder="Topic of conversation"
|
|
218
220
|
value={title}
|
|
219
221
|
onChangeText={setTitle}
|
|
220
222
|
style={styles.titleInput}
|
|
@@ -291,6 +293,9 @@ const useStyles = () => {
|
|
|
291
293
|
fontSize: 18,
|
|
292
294
|
color: colors.textColorDefaultPrimary,
|
|
293
295
|
},
|
|
296
|
+
required: {
|
|
297
|
+
color: colors.statusErrorText,
|
|
298
|
+
},
|
|
294
299
|
memberSection: {
|
|
295
300
|
padding: sectionPadding,
|
|
296
301
|
paddingBottom: 0,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { ChatGroupBadge } from '../chat_group_badge'
|
|
4
|
+
|
|
5
|
+
const mockSetParams = jest.fn()
|
|
6
|
+
|
|
7
|
+
jest.mock('@react-navigation/native', () => ({
|
|
8
|
+
...jest.requireActual('@react-navigation/native'),
|
|
9
|
+
useNavigation: () => ({ setParams: mockSetParams }),
|
|
10
|
+
useRoute: () => ({
|
|
11
|
+
params: { chat_group_graph_id: 'Groups/Group/1', title: 'Waco Family Group' },
|
|
12
|
+
}),
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
jest.mock('../../../../hooks/use_api', () => ({
|
|
16
|
+
useApiGet: () => ({ data: { name: 'Waco Family Group' } }),
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
describe('ChatGroupBadge', () => {
|
|
20
|
+
it('clears the group filter and its title when dismissed', () => {
|
|
21
|
+
const view = render(<ChatGroupBadge rowPaddingHorizontal={16} />)
|
|
22
|
+
|
|
23
|
+
fireEvent.press(view.getByText('Waco Family Group'))
|
|
24
|
+
|
|
25
|
+
expect(mockSetParams).toHaveBeenCalledTimes(1)
|
|
26
|
+
expect(mockSetParams.mock.calls[0][0]).toStrictEqual({
|
|
27
|
+
title: undefined,
|
|
28
|
+
chat_group_graph_id: undefined,
|
|
29
|
+
group_source_app_name: undefined,
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { ListHeaderComponent } from '../list_header_component'
|
|
4
|
+
|
|
5
|
+
const mockSetParams = jest.fn()
|
|
6
|
+
|
|
7
|
+
jest.mock('@react-navigation/native', () => ({
|
|
8
|
+
...jest.requireActual('@react-navigation/native'),
|
|
9
|
+
useNavigation: () => ({ setParams: mockSetParams, navigate: jest.fn() }),
|
|
10
|
+
useRoute: () => ({
|
|
11
|
+
params: { chat_group_graph_id: 'Groups/Group/1', title: 'Waco Family Group' },
|
|
12
|
+
}),
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
jest.mock('../../../../hooks/use_groups', () => ({
|
|
16
|
+
useCanDisplayGroups: () => true,
|
|
17
|
+
}))
|
|
18
|
+
jest.mock('../../../../hooks/use_direct_messages_eligible', () => ({
|
|
19
|
+
useDirectMessagesEligible: () => true,
|
|
20
|
+
}))
|
|
21
|
+
jest.mock('../../../../hooks/use_has_direct_messages', () => ({
|
|
22
|
+
useHasDirectMessages: () => true,
|
|
23
|
+
}))
|
|
24
|
+
jest.mock('../../../../hooks/use_chat_permissions', () => ({
|
|
25
|
+
useCanCreateConversations: () => false,
|
|
26
|
+
}))
|
|
27
|
+
jest.mock('../../../../hooks/use_new_conversation_entry', () => ({
|
|
28
|
+
useNewConversationEntry: () => 'select_type',
|
|
29
|
+
}))
|
|
30
|
+
jest.mock('../../../../hooks/use_current_person', () => ({
|
|
31
|
+
useCurrentPersonCache: () => ({ update: jest.fn() }),
|
|
32
|
+
}))
|
|
33
|
+
jest.mock('../../../../hooks/use_conversations_actions', () => ({
|
|
34
|
+
useMarkAllRead: () => ({ markAllRead: jest.fn(), isPending: false }),
|
|
35
|
+
}))
|
|
36
|
+
jest.mock('../../../../hooks/use_new_conversation_from_filter', () => ({
|
|
37
|
+
useNewConversationFromFilter: () => undefined,
|
|
38
|
+
}))
|
|
39
|
+
jest.mock('../../../../hooks/use_api', () => ({
|
|
40
|
+
useApiGet: () => ({ data: undefined }),
|
|
41
|
+
}))
|
|
42
|
+
|
|
43
|
+
const clearedFilter = {
|
|
44
|
+
title: undefined,
|
|
45
|
+
chat_group_graph_id: undefined,
|
|
46
|
+
group_source_app_name: undefined,
|
|
47
|
+
show_direct_messages: undefined,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe('ListHeaderComponent filter toggles', () => {
|
|
51
|
+
beforeEach(() => mockSetParams.mockClear())
|
|
52
|
+
|
|
53
|
+
it.each([
|
|
54
|
+
['Show all conversations', clearedFilter],
|
|
55
|
+
['Filter to group conversations', { ...clearedFilter, group_source_app_name: 'Groups' }],
|
|
56
|
+
['Filter to team conversations', { ...clearedFilter, group_source_app_name: 'Services' }],
|
|
57
|
+
['Filter to direct message conversations', { ...clearedFilter, show_direct_messages: true }],
|
|
58
|
+
])('%s drops the group title along with the group filter', (label, expected) => {
|
|
59
|
+
const view = render(<ListHeaderComponent />)
|
|
60
|
+
|
|
61
|
+
fireEvent.press(view.getByLabelText(label))
|
|
62
|
+
|
|
63
|
+
expect(mockSetParams).toHaveBeenCalledTimes(1)
|
|
64
|
+
expect(mockSetParams.mock.calls[0][0]).toStrictEqual(expected)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -17,6 +17,7 @@ import { useNewConversationFromFilter } from '../../../hooks/use_new_conversatio
|
|
|
17
17
|
import { GraphId } from '../../../types/resources/group_resource'
|
|
18
18
|
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../../utils'
|
|
19
19
|
import { Haptic } from '../../../utils/native_adapters'
|
|
20
|
+
import { ConversationFiltersParams } from '../../conversation_filters/screen_props'
|
|
20
21
|
import { ConversationsScreenProps } from '../conversations_screen'
|
|
21
22
|
import { ChatGroupBadge } from './chat_group_badge'
|
|
22
23
|
import { ListHeaderActionButton } from './list_header_action_button'
|
|
@@ -96,6 +97,19 @@ export const ListHeaderComponent = () => {
|
|
|
96
97
|
}
|
|
97
98
|
}, [navigation, route.params, entryMode, newConversationFromFilter])
|
|
98
99
|
|
|
100
|
+
const handleSetFilter = useCallback(
|
|
101
|
+
(params: ConversationFiltersParams) => {
|
|
102
|
+
navigation.setParams({
|
|
103
|
+
title: undefined,
|
|
104
|
+
chat_group_graph_id: undefined,
|
|
105
|
+
group_source_app_name: undefined,
|
|
106
|
+
show_direct_messages: undefined,
|
|
107
|
+
...params,
|
|
108
|
+
})
|
|
109
|
+
},
|
|
110
|
+
[navigation]
|
|
111
|
+
)
|
|
112
|
+
|
|
99
113
|
const handleChatSettings = useCallback(() => {
|
|
100
114
|
navigation.navigate('ChatSettings', {})
|
|
101
115
|
}, [navigation])
|
|
@@ -187,13 +201,7 @@ export const ListHeaderComponent = () => {
|
|
|
187
201
|
<ToggleButton
|
|
188
202
|
title={FilterTypes.All}
|
|
189
203
|
active={active === FilterTypes.All}
|
|
190
|
-
onPress={() =>
|
|
191
|
-
navigation.setParams({
|
|
192
|
-
chat_group_graph_id: undefined,
|
|
193
|
-
group_source_app_name: undefined,
|
|
194
|
-
show_direct_messages: undefined,
|
|
195
|
-
})
|
|
196
|
-
}
|
|
204
|
+
onPress={() => handleSetFilter({})}
|
|
197
205
|
accessibilityLabel="Show all conversations"
|
|
198
206
|
style={styles.filterButton}
|
|
199
207
|
/>
|
|
@@ -201,13 +209,7 @@ export const ListHeaderComponent = () => {
|
|
|
201
209
|
<ToggleButton
|
|
202
210
|
title={FilterTypes.Groups}
|
|
203
211
|
active={active === FilterTypes.Groups}
|
|
204
|
-
onPress={() =>
|
|
205
|
-
navigation.setParams({
|
|
206
|
-
chat_group_graph_id: undefined,
|
|
207
|
-
group_source_app_name: 'Groups',
|
|
208
|
-
show_direct_messages: undefined,
|
|
209
|
-
})
|
|
210
|
-
}
|
|
212
|
+
onPress={() => handleSetFilter({ group_source_app_name: 'Groups' })}
|
|
211
213
|
accessibilityLabel="Filter to group conversations"
|
|
212
214
|
style={styles.filterButton}
|
|
213
215
|
/>
|
|
@@ -216,13 +218,7 @@ export const ListHeaderComponent = () => {
|
|
|
216
218
|
<ToggleButton
|
|
217
219
|
title={FilterTypes.Teams}
|
|
218
220
|
active={active === FilterTypes.Teams}
|
|
219
|
-
onPress={() =>
|
|
220
|
-
navigation.setParams({
|
|
221
|
-
chat_group_graph_id: undefined,
|
|
222
|
-
group_source_app_name: 'Services',
|
|
223
|
-
show_direct_messages: undefined,
|
|
224
|
-
})
|
|
225
|
-
}
|
|
221
|
+
onPress={() => handleSetFilter({ group_source_app_name: 'Services' })}
|
|
226
222
|
accessibilityLabel="Filter to team conversations"
|
|
227
223
|
style={styles.filterButton}
|
|
228
224
|
/>
|
|
@@ -231,13 +227,7 @@ export const ListHeaderComponent = () => {
|
|
|
231
227
|
<ToggleButton
|
|
232
228
|
title={FilterTypes.DMs}
|
|
233
229
|
active={active === FilterTypes.DMs}
|
|
234
|
-
onPress={() =>
|
|
235
|
-
navigation.setParams({
|
|
236
|
-
chat_group_graph_id: undefined,
|
|
237
|
-
group_source_app_name: undefined,
|
|
238
|
-
show_direct_messages: true,
|
|
239
|
-
})
|
|
240
|
-
}
|
|
230
|
+
onPress={() => handleSetFilter({ show_direct_messages: true })}
|
|
241
231
|
accessibilityLabel="Filter to direct message conversations"
|
|
242
232
|
style={styles.filterButton}
|
|
243
233
|
/>
|