@planningcenter/chat-react-native 4.4.1-qa-staging.17 → 4.4.1-qa-staging.18
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/conversations/archived_results_footer.d.ts +6 -0
- package/build/components/conversations/archived_results_footer.d.ts.map +1 -0
- package/build/components/conversations/archived_results_footer.js +51 -0
- package/build/components/conversations/archived_results_footer.js.map +1 -0
- package/build/components/conversations/conversation_actions.d.ts.map +1 -1
- package/build/components/conversations/conversation_actions.js +241 -206
- package/build/components/conversations/conversation_actions.js.map +1 -1
- package/build/components/conversations/conversation_preview.d.ts.map +1 -1
- package/build/components/conversations/conversation_preview.js +99 -93
- package/build/components/conversations/conversation_preview.js.map +1 -1
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +44 -35
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/display/filter_dropdown.d.ts +2 -1
- package/build/components/display/filter_dropdown.d.ts.map +1 -1
- package/build/components/display/filter_dropdown.js +63 -58
- package/build/components/display/filter_dropdown.js.map +1 -1
- package/build/components/display/icon_tile.d.ts +12 -0
- package/build/components/display/icon_tile.d.ts.map +1 -0
- package/build/components/display/icon_tile.js +109 -0
- package/build/components/display/icon_tile.js.map +1 -0
- package/build/components/display/index.d.ts +1 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +1 -0
- package/build/components/display/index.js.map +1 -1
- package/build/contexts/conversations_context.d.ts.map +1 -1
- package/build/contexts/conversations_context.js +21 -18
- package/build/contexts/conversations_context.js.map +1 -1
- package/build/hooks/index.d.ts +2 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +2 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/use_can_browse_archived_conversations.d.ts +2 -0
- package/build/hooks/use_can_browse_archived_conversations.d.ts.map +1 -0
- package/build/hooks/use_can_browse_archived_conversations.js +29 -0
- package/build/hooks/use_can_browse_archived_conversations.js.map +1 -0
- package/build/hooks/use_clear_conversation_filters.d.ts.map +1 -1
- package/build/hooks/use_clear_conversation_filters.js +2 -1
- package/build/hooks/use_clear_conversation_filters.js.map +1 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +32 -24
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_current_person.d.ts.map +1 -1
- package/build/hooks/use_current_person.js +1 -1
- package/build/hooks/use_current_person.js.map +1 -1
- package/build/hooks/use_jolt.d.ts.map +1 -1
- package/build/hooks/use_jolt.js +29 -8
- package/build/hooks/use_jolt.js.map +1 -1
- package/build/hooks/use_manual_archiving_enabled.d.ts +2 -0
- package/build/hooks/use_manual_archiving_enabled.d.ts.map +1 -0
- package/build/hooks/use_manual_archiving_enabled.js +18 -0
- package/build/hooks/use_manual_archiving_enabled.js.map +1 -0
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +2 -1
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filters/components/conversation_filters.d.ts.map +1 -1
- package/build/screens/conversation_filters/components/conversation_filters.js +80 -13
- package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
- package/build/screens/conversation_filters/components/rows.d.ts +9 -0
- package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
- package/build/screens/conversation_filters/components/rows.js +92 -1
- package/build/screens/conversation_filters/components/rows.js.map +1 -1
- package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -1
- package/build/screens/conversation_filters/context/conversation_filter_context.js +8 -4
- package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -1
- package/build/screens/conversation_filters/filter_types.d.ts +1 -0
- package/build/screens/conversation_filters/filter_types.d.ts.map +1 -1
- package/build/screens/conversation_filters/filter_types.js +1 -0
- package/build/screens/conversation_filters/filter_types.js.map +1 -1
- package/build/screens/conversation_filters/screen_props.d.ts +1 -0
- package/build/screens/conversation_filters/screen_props.d.ts.map +1 -1
- package/build/screens/conversation_filters/screen_props.js.map +1 -1
- package/build/screens/conversation_filters_screen.d.ts +1 -0
- package/build/screens/conversation_filters_screen.d.ts.map +1 -1
- package/build/screens/conversation_filters_screen.js +75 -49
- package/build/screens/conversation_filters_screen.js.map +1 -1
- package/build/screens/conversations/components/filter_dropdown_list_header_component.d.ts +2 -0
- package/build/screens/conversations/components/filter_dropdown_list_header_component.d.ts.map +1 -0
- package/build/screens/conversations/components/filter_dropdown_list_header_component.js +587 -0
- package/build/screens/conversations/components/filter_dropdown_list_header_component.js.map +1 -0
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/list_header_component.js +95 -90
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/components/search_list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/search_list_header_component.js +100 -95
- package/build/screens/conversations/components/search_list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts +1 -0
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +15 -2
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/types/resources/person.d.ts +1 -0
- package/build/types/resources/person.d.ts.map +1 -1
- package/build/types/resources/person.js.map +1 -1
- package/build/utils/date.d.ts.map +1 -1
- package/build/utils/date.js +5 -10
- package/build/utils/date.js.map +1 -1
- package/build/utils/native_adapters/menu.d.ts +1 -0
- package/build/utils/native_adapters/menu.d.ts.map +1 -1
- package/build/utils/native_adapters/menu.js +1 -0
- package/build/utils/native_adapters/menu.js.map +1 -1
- package/build/utils/request/conversation.d.ts +2 -1
- package/build/utils/request/conversation.d.ts.map +1 -1
- package/build/utils/request/conversation.js +4 -1
- package/build/utils/request/conversation.js.map +1 -1
- package/build/vendor/font_awesome_pro_solid_icons.d.ts +1 -0
- package/build/vendor/font_awesome_pro_solid_icons.d.ts.map +1 -1
- package/build/vendor/font_awesome_pro_solid_icons.js +5 -0
- package/build/vendor/font_awesome_pro_solid_icons.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/hooks/use_can_browse_archived_conversations.test.tsx +98 -0
- package/src/__tests__/screens/conversation_filters/components/conversation_filters.test.tsx +3 -0
- package/src/__tests__/screens/conversation_filters_screen.test.tsx +76 -0
- package/src/components/conversations/__tests__/conversation_actions.test.tsx +67 -0
- package/src/components/conversations/__tests__/conversation_preview.test.tsx +38 -3
- package/src/components/conversations/__tests__/conversations.test.tsx +82 -0
- package/src/components/conversations/__tests__/conversations_blank_state.test.tsx +1 -0
- package/src/components/conversations/archived_results_footer.tsx +36 -0
- package/src/components/conversations/conversation_actions.tsx +27 -19
- package/src/components/conversations/conversation_preview.tsx +30 -10
- package/src/components/conversations/conversations.tsx +15 -3
- package/src/components/display/__tests__/filter_dropdown.test.tsx +9 -1
- package/src/components/display/filter_dropdown.tsx +14 -13
- package/src/components/display/icon_tile.tsx +54 -0
- package/src/components/display/index.ts +1 -0
- package/src/contexts/conversations_context.tsx +2 -1
- package/src/hooks/__tests__/use_conversation_archive.test.tsx +22 -0
- package/src/hooks/__tests__/use_jolt.test.tsx +30 -8
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use_can_browse_archived_conversations.ts +17 -0
- package/src/hooks/use_clear_conversation_filters.ts +1 -0
- package/src/hooks/use_conversation.ts +4 -1
- package/src/hooks/use_current_person.ts +1 -0
- package/src/hooks/use_jolt.ts +33 -8
- package/src/hooks/use_manual_archiving_enabled.ts +10 -0
- package/src/screens/conversation_details_screen.tsx +2 -3
- package/src/screens/conversation_filters/__tests__/conversation_filters.test.tsx +101 -0
- package/src/screens/conversation_filters/components/conversation_filters.tsx +32 -2
- package/src/screens/conversation_filters/components/rows.tsx +29 -1
- package/src/screens/conversation_filters/context/conversation_filter_context.tsx +4 -0
- package/src/screens/conversation_filters/filter_types.ts +1 -0
- package/src/screens/conversation_filters/screen_props.ts +1 -0
- package/src/screens/conversation_filters_screen.tsx +20 -4
- package/src/screens/conversations/__tests__/conversations_screen.test.tsx +52 -0
- package/src/screens/conversations/components/__tests__/filter_dropdown_list_header_component.test.tsx +248 -0
- package/src/screens/conversations/components/__tests__/list_header_component.test.tsx +21 -4
- package/src/screens/conversations/components/filter_dropdown_list_header_component.tsx +284 -0
- package/src/screens/conversations/components/list_header_component.tsx +17 -12
- package/src/screens/conversations/components/search_list_header_component.tsx +17 -12
- package/src/screens/conversations/conversations_screen.tsx +15 -2
- package/src/types/resources/person.ts +1 -0
- package/src/utils/__tests__/conversation.test.ts +1 -0
- package/src/utils/__tests__/date.test.ts +4 -0
- package/src/utils/date.ts +5 -4
- package/src/utils/native_adapters/__tests__/menu.test.tsx +6 -2
- package/src/utils/native_adapters/menu.tsx +2 -0
- package/src/utils/request/conversation.ts +4 -0
- package/src/vendor/font_awesome_pro_solid_icons.ts +12 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { useHeaderHeight } from '@react-navigation/elements'
|
|
1
|
+
import { HeaderBackButton, useHeaderHeight } from '@react-navigation/elements'
|
|
2
2
|
import * as ReactNavigationNative from '@react-navigation/native'
|
|
3
|
-
import { RouteProp, useRoute } from '@react-navigation/native'
|
|
3
|
+
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
|
|
4
4
|
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
|
5
5
|
import React, { useCallback } from 'react'
|
|
6
6
|
import { LayoutChangeEvent, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
7
7
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
8
8
|
import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
|
|
9
|
+
import { useTheme } from '../hooks'
|
|
9
10
|
import { useFilterDropdownEnabled } from '../hooks/use_filter_dropdown_enabled'
|
|
10
11
|
import { ConversationFilters } from './conversation_filters/components/conversation_filters'
|
|
11
12
|
import {
|
|
@@ -87,17 +88,19 @@ export const ConversationFiltersScreen = (_props: ConversationFiltersScreenProps
|
|
|
87
88
|
return (
|
|
88
89
|
<FilterProvider>
|
|
89
90
|
<FormSheet.Root contentStyle={styles.contentContainer} showAndroidSheetGrabber={false}>
|
|
90
|
-
<
|
|
91
|
+
<ConversationFiltersHeader />
|
|
91
92
|
<Filters />
|
|
92
93
|
</FormSheet.Root>
|
|
93
94
|
</FilterProvider>
|
|
94
95
|
)
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
const
|
|
98
|
+
export const ConversationFiltersHeader = () => {
|
|
98
99
|
const { resetFilter, applyFilters, setFormSheetHeaderHeight } = useFilterContext()
|
|
100
|
+
const navigation = useNavigation()
|
|
99
101
|
const route = useRoute<RouteProp<ConversationFiltersScreenProps['route']>>()
|
|
100
102
|
const filterDropdownEnabled = useFilterDropdownEnabled()
|
|
103
|
+
const { colors } = useTheme()
|
|
101
104
|
const styles = useStyles()
|
|
102
105
|
|
|
103
106
|
const handleFormSheetHeaderLayout = useCallback(
|
|
@@ -110,6 +113,15 @@ const FormSheetHeaderWithContext = () => {
|
|
|
110
113
|
return (
|
|
111
114
|
<View onLayout={handleFormSheetHeaderLayout}>
|
|
112
115
|
<FormSheet.Header style={styles.header}>
|
|
116
|
+
{Platform.OS === 'android' && (
|
|
117
|
+
<HeaderBackButton
|
|
118
|
+
displayMode="minimal"
|
|
119
|
+
accessibilityLabel="Back"
|
|
120
|
+
tintColor={colors.iconColorDefaultPrimary}
|
|
121
|
+
onPress={navigation.goBack}
|
|
122
|
+
style={styles.backButton}
|
|
123
|
+
/>
|
|
124
|
+
)}
|
|
113
125
|
<FormSheet.HeaderTitle>
|
|
114
126
|
{filterDropdownEnabled ? 'More filters' : 'Filters'}
|
|
115
127
|
</FormSheet.HeaderTitle>
|
|
@@ -145,5 +157,9 @@ const useStyles = () => {
|
|
|
145
157
|
// separator the way the non-scrolling reaction sheet does.
|
|
146
158
|
borderBottomWidth: 0,
|
|
147
159
|
},
|
|
160
|
+
backButton: {
|
|
161
|
+
marginLeft: -3,
|
|
162
|
+
marginRight: 8,
|
|
163
|
+
},
|
|
148
164
|
})
|
|
149
165
|
}
|
|
@@ -2,6 +2,14 @@ import { QueryClientProvider } from '@tanstack/react-query'
|
|
|
2
2
|
import { render } from '@testing-library/react-native'
|
|
3
3
|
import React, { Suspense } from 'react'
|
|
4
4
|
import { buildTestQueryClient } from '../../../__utils__/query_client'
|
|
5
|
+
import {
|
|
6
|
+
AudioAdapter,
|
|
7
|
+
ChatAdapters,
|
|
8
|
+
ClipboardAdapter,
|
|
9
|
+
ImagePickerAdapter,
|
|
10
|
+
MenuAdapter,
|
|
11
|
+
VideoAdapter,
|
|
12
|
+
} from '../../../utils/native_adapters'
|
|
5
13
|
import { ConversationsScreen } from '../conversations_screen'
|
|
6
14
|
|
|
7
15
|
const mockGet = jest.fn()
|
|
@@ -28,6 +36,26 @@ jest.mock('../components/search_list_header_component', () => {
|
|
|
28
36
|
const { Text } = require('react-native')
|
|
29
37
|
return { SearchListHeaderComponent: () => <Text>Search header</Text> }
|
|
30
38
|
})
|
|
39
|
+
jest.mock('../components/filter_dropdown_list_header_component', () => {
|
|
40
|
+
const { Text } = require('react-native')
|
|
41
|
+
return { FilterDropdownListHeaderComponent: () => <Text>Filter dropdown header</Text> }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const configureAdapters = ({ menu }: { menu: boolean }) => {
|
|
45
|
+
ChatAdapters.configure({
|
|
46
|
+
clipboard: new ClipboardAdapter({
|
|
47
|
+
getStringAsync: async () => '',
|
|
48
|
+
setStringAsync: async () => {},
|
|
49
|
+
}),
|
|
50
|
+
audio: new AudioAdapter({ useAudio: () => ({}) as any }),
|
|
51
|
+
video: new VideoAdapter({ Player: (() => null) as any }),
|
|
52
|
+
imagePicker: new ImagePickerAdapter({
|
|
53
|
+
openCameraAsync: async () => ({ canceled: true, assets: null }),
|
|
54
|
+
openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
|
|
55
|
+
}),
|
|
56
|
+
...(menu ? { menu: new MenuAdapter({ View: () => null }) } : {}),
|
|
57
|
+
})
|
|
58
|
+
}
|
|
31
59
|
|
|
32
60
|
const renderWithFeatures = (enabledFeatures: string[]) => {
|
|
33
61
|
mockGet.mockResolvedValue({
|
|
@@ -51,6 +79,10 @@ const renderWithFeatures = (enabledFeatures: string[]) => {
|
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
describe('ConversationsScreen header gating', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
configureAdapters({ menu: true })
|
|
84
|
+
})
|
|
85
|
+
|
|
54
86
|
it('shows the search header with only the QA flag on', async () => {
|
|
55
87
|
const view = renderWithFeatures(['QA_MOBILE_search'])
|
|
56
88
|
|
|
@@ -63,6 +95,26 @@ describe('ConversationsScreen header gating', () => {
|
|
|
63
95
|
expect(await view.findByText('Search header')).toBeTruthy()
|
|
64
96
|
})
|
|
65
97
|
|
|
98
|
+
it('shows the filter dropdown header over the search header when its flag is on', async () => {
|
|
99
|
+
const view = renderWithFeatures(['QA_MOBILE_filter_dropdown', 'ROLLOUT_MOBILE_search'])
|
|
100
|
+
|
|
101
|
+
expect(await view.findByText('Filter dropdown header')).toBeTruthy()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('shows the filter dropdown header with only its rollout flag on', async () => {
|
|
105
|
+
const view = renderWithFeatures(['ROLLOUT_MOBILE_filter_dropdown'])
|
|
106
|
+
|
|
107
|
+
expect(await view.findByText('Filter dropdown header')).toBeTruthy()
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('falls back to the search header when the host has no menu adapter', async () => {
|
|
111
|
+
configureAdapters({ menu: false })
|
|
112
|
+
|
|
113
|
+
const view = renderWithFeatures(['QA_MOBILE_filter_dropdown', 'ROLLOUT_MOBILE_search'])
|
|
114
|
+
|
|
115
|
+
expect(await view.findByText('Search header')).toBeTruthy()
|
|
116
|
+
})
|
|
117
|
+
|
|
66
118
|
it('shows the default header with neither flag on', async () => {
|
|
67
119
|
const view = renderWithFeatures(['ROLLOUT_WEB_search'])
|
|
68
120
|
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Pressable, Text } from 'react-native'
|
|
4
|
+
import {
|
|
5
|
+
AudioAdapter,
|
|
6
|
+
ChatAdapters,
|
|
7
|
+
ClipboardAdapter,
|
|
8
|
+
ImagePickerAdapter,
|
|
9
|
+
MenuAction,
|
|
10
|
+
MenuAdapter,
|
|
11
|
+
MenuViewProps,
|
|
12
|
+
VideoAdapter,
|
|
13
|
+
} from '../../../../utils/native_adapters'
|
|
14
|
+
import { FilterDropdownListHeaderComponent } from '../filter_dropdown_list_header_component'
|
|
15
|
+
|
|
16
|
+
const mockNavigate = jest.fn()
|
|
17
|
+
const mockSetParams = jest.fn()
|
|
18
|
+
const mockRouteParams: Record<string, unknown> = {}
|
|
19
|
+
const mockCanDisplayGroups = jest.fn()
|
|
20
|
+
const mockSearchEnabled = jest.fn()
|
|
21
|
+
const mockCanBrowseArchived = jest.fn()
|
|
22
|
+
const mockGroupsByGraphId: Record<string, { name: string }> = {}
|
|
23
|
+
|
|
24
|
+
jest.mock('@react-navigation/native', () => ({
|
|
25
|
+
...jest.requireActual('@react-navigation/native'),
|
|
26
|
+
useNavigation: () => ({ setParams: mockSetParams, navigate: mockNavigate }),
|
|
27
|
+
useRoute: () => ({ params: mockRouteParams }),
|
|
28
|
+
}))
|
|
29
|
+
|
|
30
|
+
jest.mock('../../../../hooks/use_api', () => ({
|
|
31
|
+
useApiGet: ({ url }: { url: string }, { enabled }: { enabled: boolean }) => ({
|
|
32
|
+
data: enabled ? mockGroupsByGraphId[url.replace('/me/groups/', '')] : undefined,
|
|
33
|
+
}),
|
|
34
|
+
}))
|
|
35
|
+
jest.mock('../../../../hooks/use_groups', () => ({
|
|
36
|
+
useCanDisplayGroups: (args: { source_type: string }) => mockCanDisplayGroups(args),
|
|
37
|
+
}))
|
|
38
|
+
jest.mock('../../../../hooks/use_direct_messages_eligible', () => ({
|
|
39
|
+
useDirectMessagesEligible: () => true,
|
|
40
|
+
}))
|
|
41
|
+
jest.mock('../../../../hooks/use_has_direct_messages', () => ({
|
|
42
|
+
useHasDirectMessages: () => true,
|
|
43
|
+
}))
|
|
44
|
+
jest.mock('../../../../hooks/use_can_browse_archived_conversations', () => ({
|
|
45
|
+
useCanBrowseArchivedConversations: () => mockCanBrowseArchived(),
|
|
46
|
+
}))
|
|
47
|
+
jest.mock('../../../../hooks/use_chat_permissions', () => ({
|
|
48
|
+
useCanCreateConversations: () => true,
|
|
49
|
+
}))
|
|
50
|
+
jest.mock('../../../../hooks/use_new_conversation_entry', () => ({
|
|
51
|
+
useNewConversationEntry: () => 'select_type',
|
|
52
|
+
}))
|
|
53
|
+
jest.mock('../../../../hooks/use_current_person', () => ({
|
|
54
|
+
useCurrentPersonCache: () => ({ update: jest.fn() }),
|
|
55
|
+
}))
|
|
56
|
+
jest.mock('../../../../hooks/use_conversations_actions', () => ({
|
|
57
|
+
useMarkAllRead: () => ({ markAllRead: jest.fn(), isPending: false }),
|
|
58
|
+
}))
|
|
59
|
+
jest.mock('../../../../hooks/use_new_conversation_from_filter', () => ({
|
|
60
|
+
useNewConversationFromFilter: () => undefined,
|
|
61
|
+
}))
|
|
62
|
+
jest.mock('../../../../hooks/use_search_enabled', () => ({
|
|
63
|
+
useSearchEnabled: () => mockSearchEnabled(),
|
|
64
|
+
}))
|
|
65
|
+
|
|
66
|
+
const FakeMenuView = ({ actions, onPressAction, children }: MenuViewProps) => {
|
|
67
|
+
const flatten = (items: MenuAction[]): MenuAction[] =>
|
|
68
|
+
items.flatMap(item => (item.displayInline && item.subactions ? item.subactions : [item]))
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
{children}
|
|
73
|
+
{flatten(actions).map(action => (
|
|
74
|
+
<Pressable
|
|
75
|
+
key={action.id}
|
|
76
|
+
accessibilityRole="menuitem"
|
|
77
|
+
accessibilityLabel={action.title}
|
|
78
|
+
accessibilityState={{ selected: action.state === 'on' }}
|
|
79
|
+
onPress={() => onPressAction?.({ nativeEvent: { event: action.id ?? action.title } })}
|
|
80
|
+
>
|
|
81
|
+
<Text>{action.title}</Text>
|
|
82
|
+
</Pressable>
|
|
83
|
+
))}
|
|
84
|
+
</>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
beforeAll(() => {
|
|
89
|
+
ChatAdapters.configure({
|
|
90
|
+
clipboard: new ClipboardAdapter({
|
|
91
|
+
getStringAsync: async () => '',
|
|
92
|
+
setStringAsync: async () => {},
|
|
93
|
+
}),
|
|
94
|
+
audio: new AudioAdapter({ useAudio: () => ({}) as any }),
|
|
95
|
+
video: new VideoAdapter({ Player: (() => null) as any }),
|
|
96
|
+
imagePicker: new ImagePickerAdapter({
|
|
97
|
+
openCameraAsync: async () => ({ canceled: true, assets: null }),
|
|
98
|
+
openImageLibraryAsync: async () => ({ canceled: true, assets: null }),
|
|
99
|
+
}),
|
|
100
|
+
menu: new MenuAdapter({ View: FakeMenuView }),
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const setCapabilities = ({ groups, teams }: { groups: boolean; teams: boolean }) => {
|
|
105
|
+
mockCanDisplayGroups.mockImplementation(({ source_type }: { source_type: string }) =>
|
|
106
|
+
source_type === 'Group' ? groups : teams
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const setRouteParams = (params: Record<string, unknown>) => {
|
|
111
|
+
Object.keys(mockRouteParams).forEach(key => delete mockRouteParams[key])
|
|
112
|
+
Object.assign(mockRouteParams, params)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const menuItemNames = () =>
|
|
116
|
+
screen.getAllByRole('menuitem').map(item => item.props.accessibilityLabel)
|
|
117
|
+
|
|
118
|
+
describe('FilterDropdownListHeaderComponent', () => {
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
mockNavigate.mockClear()
|
|
121
|
+
mockSetParams.mockClear()
|
|
122
|
+
mockSearchEnabled.mockReturnValue(true)
|
|
123
|
+
mockCanBrowseArchived.mockReturnValue(false)
|
|
124
|
+
setCapabilities({ groups: true, teams: true })
|
|
125
|
+
setRouteParams({})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('offers every filter the person can use, then More filters', () => {
|
|
129
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
130
|
+
|
|
131
|
+
expect(menuItemNames()).toEqual(['All', 'Groups', 'Teams', 'DMs', 'More filters'])
|
|
132
|
+
expect(screen.getByRole('button', { name: 'All conversations' })).toBeTruthy()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('leaves out Teams and More filters when only DMs are filterable', () => {
|
|
136
|
+
setCapabilities({ groups: false, teams: false })
|
|
137
|
+
|
|
138
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
139
|
+
|
|
140
|
+
expect(menuItemNames()).toEqual(['All', 'DMs'])
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('selecting Groups filters to group conversations', () => {
|
|
144
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
145
|
+
|
|
146
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'Groups' }))
|
|
147
|
+
|
|
148
|
+
expect(mockSetParams).toHaveBeenCalledWith(
|
|
149
|
+
expect.objectContaining({ group_source_app_name: 'Groups', show_direct_messages: undefined })
|
|
150
|
+
)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('labels the trigger with the active filter and checks it', () => {
|
|
154
|
+
setRouteParams({ group_source_app_name: 'Services' })
|
|
155
|
+
|
|
156
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
157
|
+
|
|
158
|
+
expect(screen.getByRole('button', { name: 'Teams' })).toBeTruthy()
|
|
159
|
+
expect(screen.getByRole('menuitem', { name: 'Teams' }).props.accessibilityState.selected).toBe(
|
|
160
|
+
true
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it("labels the trigger with the group's name when filtered to one group from More filters", () => {
|
|
165
|
+
mockGroupsByGraphId['Group/1'] = { name: 'Youth Group' }
|
|
166
|
+
setRouteParams({ chat_group_graph_id: 'Group/1' })
|
|
167
|
+
|
|
168
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
169
|
+
|
|
170
|
+
expect(screen.getByRole('button', { name: 'Youth Group' })).toBeTruthy()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('falls back to the route title while the group is still loading', () => {
|
|
174
|
+
delete mockGroupsByGraphId['Group/2']
|
|
175
|
+
setRouteParams({ chat_group_graph_id: 'Group/2', title: 'Youth Group' })
|
|
176
|
+
|
|
177
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
178
|
+
|
|
179
|
+
expect(screen.getByRole('button', { name: 'Youth Group' })).toBeTruthy()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('offers More filters when archived conversations are the only extra filter', () => {
|
|
183
|
+
setCapabilities({ groups: false, teams: false })
|
|
184
|
+
mockCanBrowseArchived.mockReturnValue(true)
|
|
185
|
+
|
|
186
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
187
|
+
|
|
188
|
+
expect(menuItemNames()).toEqual(['All', 'DMs', 'More filters'])
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('labels the archived list and carries it into More filters', () => {
|
|
192
|
+
setRouteParams({ show_archived: true })
|
|
193
|
+
|
|
194
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
195
|
+
|
|
196
|
+
expect(screen.getByRole('button', { name: 'Archived' })).toBeTruthy()
|
|
197
|
+
|
|
198
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'More filters' }))
|
|
199
|
+
|
|
200
|
+
expect(mockNavigate).toHaveBeenCalledWith(
|
|
201
|
+
'ConversationFilters',
|
|
202
|
+
expect.objectContaining({ show_archived: true })
|
|
203
|
+
)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('leaves the archived list when another filter is picked', () => {
|
|
207
|
+
setRouteParams({ show_archived: true })
|
|
208
|
+
|
|
209
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
210
|
+
|
|
211
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'Groups' }))
|
|
212
|
+
|
|
213
|
+
expect(mockSetParams).toHaveBeenCalledWith(
|
|
214
|
+
expect.objectContaining({ group_source_app_name: 'Groups', show_archived: undefined })
|
|
215
|
+
)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('More filters opens the filters sheet', () => {
|
|
219
|
+
render(<FilterDropdownListHeaderComponent />)
|
|
220
|
+
|
|
221
|
+
fireEvent.press(screen.getByRole('menuitem', { name: 'More filters' }))
|
|
222
|
+
|
|
223
|
+
expect(mockNavigate).toHaveBeenCalledWith('ConversationFilters', expect.any(Object))
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('shows the search button only when search is enabled', () => {
|
|
227
|
+
mockSearchEnabled.mockReturnValue(false)
|
|
228
|
+
const view = render(<FilterDropdownListHeaderComponent />)
|
|
229
|
+
|
|
230
|
+
expect(view.queryByTestId('conversations-search-button')).toBeNull()
|
|
231
|
+
|
|
232
|
+
mockSearchEnabled.mockReturnValue(true)
|
|
233
|
+
view.rerender(<FilterDropdownListHeaderComponent />)
|
|
234
|
+
|
|
235
|
+
fireEvent.press(view.getByTestId('conversations-search-button'))
|
|
236
|
+
|
|
237
|
+
expect(mockNavigate).toHaveBeenCalledWith('Search')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('renders the search button after the other actions', () => {
|
|
241
|
+
const view = render(<FilterDropdownListHeaderComponent />)
|
|
242
|
+
|
|
243
|
+
const buttons = view.getAllByRole('button').map(button => button.props.accessibilityLabel)
|
|
244
|
+
|
|
245
|
+
expect(buttons.indexOf('Search')).toBeGreaterThan(buttons.indexOf('Chat settings'))
|
|
246
|
+
expect(buttons.indexOf('Search')).toBeGreaterThan(buttons.indexOf('New conversation'))
|
|
247
|
+
})
|
|
248
|
+
})
|
|
@@ -3,13 +3,12 @@ import React from 'react'
|
|
|
3
3
|
import { ListHeaderComponent } from '../list_header_component'
|
|
4
4
|
|
|
5
5
|
const mockSetParams = jest.fn()
|
|
6
|
+
let mockParams: Record<string, unknown> = {}
|
|
6
7
|
|
|
7
8
|
jest.mock('@react-navigation/native', () => ({
|
|
8
9
|
...jest.requireActual('@react-navigation/native'),
|
|
9
10
|
useNavigation: () => ({ setParams: mockSetParams, navigate: jest.fn() }),
|
|
10
|
-
useRoute: () => ({
|
|
11
|
-
params: { chat_group_graph_id: 'Groups/Group/1', title: 'Waco Family Group' },
|
|
12
|
-
}),
|
|
11
|
+
useRoute: () => ({ params: mockParams }),
|
|
13
12
|
}))
|
|
14
13
|
|
|
15
14
|
jest.mock('../../../../hooks/use_groups', () => ({
|
|
@@ -45,10 +44,14 @@ const clearedFilter = {
|
|
|
45
44
|
chat_group_graph_id: undefined,
|
|
46
45
|
group_source_app_name: undefined,
|
|
47
46
|
show_direct_messages: undefined,
|
|
47
|
+
show_archived: undefined,
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
describe('ListHeaderComponent filter toggles', () => {
|
|
51
|
-
beforeEach(() =>
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mockSetParams.mockClear()
|
|
53
|
+
mockParams = { chat_group_graph_id: 'Groups/Group/1', title: 'Waco Family Group' }
|
|
54
|
+
})
|
|
52
55
|
|
|
53
56
|
it.each([
|
|
54
57
|
['Show all conversations', clearedFilter],
|
|
@@ -64,3 +67,17 @@ describe('ListHeaderComponent filter toggles', () => {
|
|
|
64
67
|
expect(mockSetParams.mock.calls[0][0]).toStrictEqual(expected)
|
|
65
68
|
})
|
|
66
69
|
})
|
|
70
|
+
|
|
71
|
+
describe('ListHeaderComponent mark all read', () => {
|
|
72
|
+
it('shows Mark all read on the active list', () => {
|
|
73
|
+
mockParams = {}
|
|
74
|
+
|
|
75
|
+
expect(render(<ListHeaderComponent />).queryByText('Mark all read')).not.toBeNull()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('hides Mark all read on the archived list', () => {
|
|
79
|
+
mockParams = { show_archived: true }
|
|
80
|
+
|
|
81
|
+
expect(render(<ListHeaderComponent />).queryByText('Mark all read')).toBeNull()
|
|
82
|
+
})
|
|
83
|
+
})
|