@planningcenter/chat-react-native 3.39.0-rc.1 → 3.39.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.
Files changed (183) hide show
  1. package/build/components/conversation/messages_disabled_banners.d.ts +6 -1
  2. package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
  3. package/build/components/conversation/messages_disabled_banners.js +8 -2
  4. package/build/components/conversation/messages_disabled_banners.js.map +1 -1
  5. package/build/components/primitive/form_sheet.d.ts +1 -0
  6. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  7. package/build/components/primitive/form_sheet.js +17 -7
  8. package/build/components/primitive/form_sheet.js.map +1 -1
  9. package/build/contexts/api_provider.js +2 -1
  10. package/build/contexts/api_provider.js.map +1 -1
  11. package/build/contexts/conversations_context.d.ts.map +1 -1
  12. package/build/contexts/conversations_context.js +6 -2
  13. package/build/contexts/conversations_context.js.map +1 -1
  14. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts.map +1 -1
  15. package/build/hooks/direct_messages/use_direct_message_candidates.js +1 -0
  16. package/build/hooks/direct_messages/use_direct_message_candidates.js.map +1 -1
  17. package/build/hooks/groups/use_group_chat_conversation_payload.d.ts.map +1 -1
  18. package/build/hooks/groups/use_group_chat_conversation_payload.js +2 -1
  19. package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -1
  20. package/build/hooks/index.d.ts +1 -0
  21. package/build/hooks/index.d.ts.map +1 -1
  22. package/build/hooks/index.js +1 -0
  23. package/build/hooks/index.js.map +1 -1
  24. package/build/hooks/services/use_services_chat_conversation_payload.d.ts.map +1 -1
  25. package/build/hooks/services/use_services_chat_conversation_payload.js +2 -1
  26. package/build/hooks/services/use_services_chat_conversation_payload.js.map +1 -1
  27. package/build/hooks/use_api.d.ts +5 -1
  28. package/build/hooks/use_api.d.ts.map +1 -1
  29. package/build/hooks/use_api.js +2 -1
  30. package/build/hooks/use_api.js.map +1 -1
  31. package/build/hooks/use_chat_configuration.d.ts.map +1 -1
  32. package/build/hooks/use_chat_configuration.js +2 -1
  33. package/build/hooks/use_chat_configuration.js.map +1 -1
  34. package/build/hooks/use_chat_permissions.d.ts.map +1 -1
  35. package/build/hooks/use_chat_permissions.js +4 -1
  36. package/build/hooks/use_chat_permissions.js.map +1 -1
  37. package/build/hooks/use_conversation.d.ts.map +1 -1
  38. package/build/hooks/use_conversation.js +1 -0
  39. package/build/hooks/use_conversation.js.map +1 -1
  40. package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
  41. package/build/hooks/use_conversation_jolt_events.js +2 -2
  42. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  43. package/build/hooks/use_current_person.d.ts.map +1 -1
  44. package/build/hooks/use_current_person.js +4 -2
  45. package/build/hooks/use_current_person.js.map +1 -1
  46. package/build/hooks/use_features.d.ts.map +1 -1
  47. package/build/hooks/use_features.js +2 -1
  48. package/build/hooks/use_features.js.map +1 -1
  49. package/build/hooks/use_groups.d.ts.map +1 -1
  50. package/build/hooks/use_groups.js +2 -1
  51. package/build/hooks/use_groups.js.map +1 -1
  52. package/build/hooks/use_groups_groups.d.ts.map +1 -1
  53. package/build/hooks/use_groups_groups.js +2 -1
  54. package/build/hooks/use_groups_groups.js.map +1 -1
  55. package/build/hooks/use_has_direct_messages.d.ts +2 -0
  56. package/build/hooks/use_has_direct_messages.d.ts.map +1 -0
  57. package/build/hooks/use_has_direct_messages.js +17 -0
  58. package/build/hooks/use_has_direct_messages.js.map +1 -0
  59. package/build/hooks/use_jolt.d.ts.map +1 -1
  60. package/build/hooks/use_jolt.js +2 -1
  61. package/build/hooks/use_jolt.js.map +1 -1
  62. package/build/hooks/use_organization.d.ts.map +1 -1
  63. package/build/hooks/use_organization.js +4 -1
  64. package/build/hooks/use_organization.js.map +1 -1
  65. package/build/hooks/use_person_settings.d.ts +6 -0
  66. package/build/hooks/use_person_settings.d.ts.map +1 -0
  67. package/build/hooks/use_person_settings.js +26 -0
  68. package/build/hooks/use_person_settings.js.map +1 -0
  69. package/build/navigation/index.d.ts +13 -0
  70. package/build/navigation/index.d.ts.map +1 -1
  71. package/build/navigation/index.js +9 -0
  72. package/build/navigation/index.js.map +1 -1
  73. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  74. package/build/screens/conversation_details_screen.js +2 -1
  75. package/build/screens/conversation_details_screen.js.map +1 -1
  76. package/build/screens/conversation_filters/components/conversation_filters.d.ts.map +1 -1
  77. package/build/screens/conversation_filters/components/conversation_filters.js +20 -5
  78. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  79. package/build/screens/conversation_filters/components/rows.d.ts +2 -1
  80. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  81. package/build/screens/conversation_filters/components/rows.js +2 -2
  82. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  83. package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -1
  84. package/build/screens/conversation_filters/context/conversation_filter_context.js +4 -0
  85. package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -1
  86. package/build/screens/conversation_filters/filter_types.d.ts +1 -0
  87. package/build/screens/conversation_filters/filter_types.d.ts.map +1 -1
  88. package/build/screens/conversation_filters/filter_types.js +1 -0
  89. package/build/screens/conversation_filters/filter_types.js.map +1 -1
  90. package/build/screens/conversation_filters/screen_props.d.ts +1 -0
  91. package/build/screens/conversation_filters/screen_props.d.ts.map +1 -1
  92. package/build/screens/conversation_filters/screen_props.js.map +1 -1
  93. package/build/screens/conversation_screen.d.ts.map +1 -1
  94. package/build/screens/conversation_screen.js +1 -1
  95. package/build/screens/conversation_screen.js.map +1 -1
  96. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts +1 -2
  97. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -1
  98. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +319 -10
  99. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
  100. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  101. package/build/screens/conversation_select_type_screen.js +4 -2
  102. package/build/screens/conversation_select_type_screen.js.map +1 -1
  103. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  104. package/build/screens/conversations/components/list_header_component.js +35 -17
  105. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  106. package/build/screens/conversations/conversations_screen.d.ts +1 -0
  107. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  108. package/build/screens/conversations/conversations_screen.js.map +1 -1
  109. package/build/screens/get_help_screen.d.ts.map +1 -1
  110. package/build/screens/get_help_screen.js +2 -18
  111. package/build/screens/get_help_screen.js.map +1 -1
  112. package/build/screens/index.d.ts +1 -0
  113. package/build/screens/index.d.ts.map +1 -1
  114. package/build/screens/index.js +1 -0
  115. package/build/screens/index.js.map +1 -1
  116. package/build/screens/settings_screen.d.ts +5 -0
  117. package/build/screens/settings_screen.d.ts.map +1 -0
  118. package/build/screens/settings_screen.js +56 -0
  119. package/build/screens/settings_screen.js.map +1 -0
  120. package/build/types/jolt_events/conversation_events.d.ts +2 -0
  121. package/build/types/jolt_events/conversation_events.d.ts.map +1 -1
  122. package/build/types/jolt_events/conversation_events.js.map +1 -1
  123. package/build/types/resources/conversation.d.ts +2 -0
  124. package/build/types/resources/conversation.d.ts.map +1 -1
  125. package/build/types/resources/conversation.js.map +1 -1
  126. package/build/types/resources/organization.d.ts +1 -0
  127. package/build/types/resources/organization.d.ts.map +1 -1
  128. package/build/types/resources/organization.js.map +1 -1
  129. package/build/types/resources/person.d.ts +1 -0
  130. package/build/types/resources/person.d.ts.map +1 -1
  131. package/build/types/resources/person.js.map +1 -1
  132. package/build/utils/request/conversation.d.ts +2 -1
  133. package/build/utils/request/conversation.d.ts.map +1 -1
  134. package/build/utils/request/conversation.js +15 -6
  135. package/build/utils/request/conversation.js.map +1 -1
  136. package/build/utils/time.d.ts +8 -0
  137. package/build/utils/time.d.ts.map +1 -0
  138. package/build/utils/time.js +15 -0
  139. package/build/utils/time.js.map +1 -0
  140. package/package.json +2 -2
  141. package/src/components/conversation/messages_disabled_banners.tsx +16 -2
  142. package/src/components/primitive/form_sheet.tsx +23 -6
  143. package/src/contexts/api_provider.tsx +4 -1
  144. package/src/contexts/conversations_context.tsx +6 -2
  145. package/src/hooks/direct_messages/use_direct_message_candidates.ts +1 -0
  146. package/src/hooks/groups/use_group_chat_conversation_payload.ts +2 -1
  147. package/src/hooks/index.ts +1 -0
  148. package/src/hooks/services/use_services_chat_conversation_payload.ts +2 -1
  149. package/src/hooks/use_api.ts +10 -1
  150. package/src/hooks/use_chat_configuration.ts +2 -1
  151. package/src/hooks/use_chat_permissions.ts +4 -1
  152. package/src/hooks/use_conversation.ts +1 -0
  153. package/src/hooks/use_conversation_jolt_events.ts +3 -2
  154. package/src/hooks/use_current_person.ts +4 -2
  155. package/src/hooks/use_features.ts +2 -1
  156. package/src/hooks/use_groups.ts +16 -12
  157. package/src/hooks/use_groups_groups.ts +19 -15
  158. package/src/hooks/use_has_direct_messages.ts +21 -0
  159. package/src/hooks/use_jolt.ts +2 -1
  160. package/src/hooks/use_organization.ts +4 -1
  161. package/src/hooks/use_person_settings.ts +29 -0
  162. package/src/navigation/index.tsx +11 -0
  163. package/src/screens/conversation_details_screen.tsx +2 -1
  164. package/src/screens/conversation_filters/components/conversation_filters.tsx +25 -5
  165. package/src/screens/conversation_filters/components/rows.tsx +16 -3
  166. package/src/screens/conversation_filters/context/conversation_filter_context.tsx +4 -0
  167. package/src/screens/conversation_filters/filter_types.ts +1 -0
  168. package/src/screens/conversation_filters/screen_props.ts +1 -0
  169. package/src/screens/conversation_screen.tsx +2 -1
  170. package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +513 -10
  171. package/src/screens/conversation_select_type_screen.tsx +6 -2
  172. package/src/screens/conversations/components/list_header_component.tsx +84 -34
  173. package/src/screens/conversations/conversations_screen.tsx +1 -0
  174. package/src/screens/get_help_screen.tsx +2 -29
  175. package/src/screens/index.ts +1 -0
  176. package/src/screens/settings_screen.tsx +67 -0
  177. package/src/types/jolt_events/conversation_events.ts +2 -0
  178. package/src/types/resources/conversation.ts +3 -0
  179. package/src/types/resources/organization.ts +1 -0
  180. package/src/types/resources/person.ts +1 -0
  181. package/src/utils/__tests__/conversation.test.ts +14 -0
  182. package/src/utils/request/conversation.ts +13 -5
  183. package/src/utils/time.ts +17 -0
@@ -1,25 +1,334 @@
1
- import React from 'react';
2
- import { StyleSheet, View } from 'react-native';
3
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
- import { Heading, Text } from '../../components';
1
+ import { PlatformPressable } from '@react-navigation/elements';
2
+ import { StackActions, useNavigation } from '@react-navigation/native';
3
+ import { useEffect, useState } from 'react';
4
+ import { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native';
5
+ import { Avatar, Badge, Banner, Icon, Spinner, Text } from '../../components';
6
+ import { ActionButton } from '../../components/display/action_button';
7
+ import { ComponentErrorBoundary } from '../../components/page/component_error_boundary';
8
+ import { useTheme } from '../../hooks';
9
+ import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations';
10
+ import { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates';
11
+ import { useDirectMessageConversationValidate } from '../../hooks/direct_messages/use_direct_message_conversation_validate';
12
+ import { useFindOrCreateDirectMessageConversation } from '../../hooks/direct_messages/use_find_or_create_direct_message_conversation';
13
+ const MAX_RECIPIENTS = 9;
5
14
  export function ConversationSelectDirectMessageRecipientsScreen(_props) {
6
15
  const styles = useStyles();
16
+ const navigation = useNavigation();
17
+ const [searchTerm, setSearchTerm] = useState('');
18
+ const [debouncedTerm, setDebouncedTerm] = useState('');
19
+ const [selectedPeople, setSelectedPeople] = useState(new Map());
20
+ useEffect(() => {
21
+ const timer = setTimeout(() => setDebouncedTerm(searchTerm), 200);
22
+ return () => clearTimeout(timer);
23
+ }, [searchTerm]);
24
+ const selectPerson = (person) => {
25
+ if (selectedPeople.size >= MAX_RECIPIENTS)
26
+ return;
27
+ setSelectedPeople(prev => new Map(prev).set(person.id, person));
28
+ setSearchTerm('');
29
+ setDebouncedTerm('');
30
+ };
31
+ const removePerson = (id) => {
32
+ setSelectedPeople(prev => {
33
+ const next = new Map(prev);
34
+ next.delete(id);
35
+ return next;
36
+ });
37
+ };
38
+ const recipientIds = [...selectedPeople.keys()];
39
+ const { warnings, validationPending } = useDirectMessageConversationValidate({ recipientIds });
40
+ const handleSuccess = (conversationId) => {
41
+ navigation.getParent()?.goBack();
42
+ navigation.dispatch(StackActions.push('Conversation', { conversation_id: conversationId }));
43
+ };
44
+ const { findOrCreateConversation, directMessageExists, isFinding, isError } = useFindOrCreateDirectMessageConversation({ recipientIds, onSuccess: handleSuccess });
45
+ const buttonText = (() => {
46
+ if (selectedPeople.size === 0)
47
+ return 'Start conversation';
48
+ if (selectedPeople.size === 1) {
49
+ const firstName = selectedPeople.values().next().value.name.split(' ')[0];
50
+ return directMessageExists ? `Open message with ${firstName}` : `Message ${firstName}`;
51
+ }
52
+ return directMessageExists
53
+ ? `Open direct message (${selectedPeople.size})`
54
+ : `Start direct message (${selectedPeople.size})`;
55
+ })();
7
56
  return (<View style={styles.container}>
8
- <Heading variant="h2">New direct message</Heading>
9
- <Text variant="secondary">Coming soon</Text>
57
+ {isError && (<Banner appearance="error" description="There was an issue starting the conversation. Please try again." style={styles.errorBanner}/>)}
58
+ <ToField selectedPeople={selectedPeople} searchTerm={searchTerm} onSearchChange={setSearchTerm} onRemove={removePerson} onClear={() => setSelectedPeople(new Map())}/>
59
+ <View style={styles.candidateResultsContainer}>
60
+ <ComponentErrorBoundary key={debouncedTerm} fallback={<Banner appearance="error" description="Couldn't load people right now. Try again." style={styles.errorBanner}/>}>
61
+ <CandidateResults term={debouncedTerm} selectedPeople={selectedPeople} onSelect={selectPerson}/>
62
+ </ComponentErrorBoundary>
63
+ </View>
64
+ <ActionButton title={buttonText} disabled={selectedPeople.size === 0 || validationPending || warnings.length > 0 || isFinding} loading={validationPending || isFinding} onPress={() => findOrCreateConversation(recipientIds)} warnings={warnings}/>
10
65
  </View>);
11
66
  }
67
+ function ToField({ selectedPeople, searchTerm, onSearchChange, onRemove, onClear, }) {
68
+ const styles = useStyles();
69
+ const { colors } = useTheme();
70
+ const hasSelections = selectedPeople.size > 0;
71
+ return (<View style={styles.toField}>
72
+ <View style={styles.toFieldHeader}>
73
+ <Text style={styles.toLabel}>To</Text>
74
+ {hasSelections && (<Pressable onPress={onClear} hitSlop={8}>
75
+ <Text style={styles.clearButton}>Clear</Text>
76
+ </Pressable>)}
77
+ </View>
78
+ <View style={styles.toInputArea}>
79
+ {[...selectedPeople.values()].map(person => (<PersonChip key={person.id} person={person} onRemove={onRemove}/>))}
80
+ <TextInput autoFocus placeholder="Search" placeholderTextColor={colors.textColorDefaultPlaceholder} value={searchTerm} onChangeText={onSearchChange} style={styles.toTextInput} returnKeyType="search"/>
81
+ </View>
82
+ </View>);
83
+ }
84
+ function PersonChip({ person, onRemove, }) {
85
+ const styles = useStyles();
86
+ return (<View style={styles.chip}>
87
+ <Avatar sourceUri={person.avatar} size="sm" showFallback/>
88
+ <Text style={styles.chipName}>{person.name}</Text>
89
+ <Pressable onPress={() => onRemove(person.id)} hitSlop={8} accessibilityLabel={`Remove ${person.name}`}>
90
+ <Icon name="general.x" size={12} style={styles.chipRemoveIcon}/>
91
+ </Pressable>
92
+ </View>);
93
+ }
94
+ function CandidateResults({ term, selectedPeople, onSelect, }) {
95
+ const styles = useStyles();
96
+ const { data, isFetching } = useDirectMessageCandidates(term);
97
+ const { groups, teams } = useDirectMessageAffiliations();
98
+ if (term.length < 1) {
99
+ if (selectedPeople.size > 0)
100
+ return null;
101
+ return (<View style={styles.emptyState}>
102
+ <Icon name="churchCenter.people" size={40} style={styles.emptyStateIcon}/>
103
+ <Text style={styles.emptyStateTitle}>Search for people to direct message</Text>
104
+ <Text variant="secondary" style={styles.emptyStateSubtitle}>
105
+ Start a conversation with people in your groups and teams.
106
+ </Text>
107
+ </View>);
108
+ }
109
+ const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS;
110
+ if (isAtLimit) {
111
+ return (<View style={styles.emptyState}>
112
+ <Text variant="secondary" style={styles.emptyStateSubtitle}>
113
+ You can add up to {MAX_RECIPIENTS} people to a direct message.
114
+ </Text>
115
+ </View>);
116
+ }
117
+ const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id));
118
+ const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0);
119
+ if (isFetching && unselectedCandidates.length === 0) {
120
+ return (<View style={styles.emptyState}>
121
+ <Spinner />
122
+ </View>);
123
+ }
124
+ if (!isFetching && unselectedCandidates.length === 0) {
125
+ return (<View style={styles.emptyState}>
126
+ <Icon name="general.search" size={32} style={styles.emptyStateIcon}/>
127
+ <Text style={styles.emptyStateTitle}>No matches for "{term}"</Text>
128
+ <Text variant="secondary" style={styles.emptyStateSubtitle}>
129
+ Try a different name, or check that you share a group or team with them.
130
+ </Text>
131
+ </View>);
132
+ }
133
+ return (<CandidateList candidates={unselectedCandidates} hasTruncated={hasTruncated} groups={groups} teams={teams} onSelect={onSelect}/>);
134
+ }
135
+ function candidateBadges(candidate) {
136
+ const badges = [];
137
+ if (candidate.directMessagesDisabled)
138
+ badges.push({ title: 'DMs off' });
139
+ if (candidate.under_18)
140
+ badges.push({ title: 'Under 18' });
141
+ return badges;
142
+ }
143
+ function candidateAffiliationNames(candidate, groups, teams) {
144
+ return [
145
+ ...candidate.groups.flatMap(id => {
146
+ const name = groups.get(id);
147
+ return name ? [name] : [];
148
+ }),
149
+ ...candidate.teams.flatMap(id => {
150
+ const name = teams.get(id);
151
+ return name ? [name] : [];
152
+ }),
153
+ ];
154
+ }
155
+ function CandidateList({ candidates, hasTruncated, groups, teams, onSelect, }) {
156
+ const styles = useStyles();
157
+ const available = candidates.filter(c => !c.directMessagesDisabled);
158
+ const dmDisabled = candidates.filter(c => c.directMessagesDisabled);
159
+ return (<FlatList data={available} keyExtractor={item => item.id} renderItem={({ item }) => (<CandidateItem candidate={item} badges={candidateBadges(item)} affiliationNames={candidateAffiliationNames(item, groups, teams)} onSelect={() => onSelect(item)}/>)} ListHeaderComponent={<View style={styles.resultsHeader}>
160
+ <Text style={styles.resultsHeading}>Results</Text>
161
+ </View>} ListFooterComponent={<>
162
+ {dmDisabled.length > 0 && (<>
163
+ <View style={styles.unavailableHeader}>
164
+ <Text variant="secondary" style={styles.unavailableLabel}>
165
+ Unavailable for direct messages
166
+ </Text>
167
+ </View>
168
+ {dmDisabled.map(candidate => (<CandidateItem key={candidate.id} candidate={candidate} badges={candidateBadges(candidate)} affiliationNames={candidateAffiliationNames(candidate, groups, teams)} disabled/>))}
169
+ </>)}
170
+ {hasTruncated && (<View style={styles.truncatedFooter}>
171
+ <Text variant="secondary" style={styles.truncatedText}>
172
+ Keep typing to narrow your results.
173
+ </Text>
174
+ </View>)}
175
+ </>}/>);
176
+ }
177
+ function CandidateItem({ candidate, badges, affiliationNames, onSelect, disabled = false, }) {
178
+ const styles = useStyles();
179
+ return (<PlatformPressable onPress={disabled ? undefined : onSelect} accessibilityRole="button" accessibilityLabel={`Select ${candidate.name}`} accessibilityState={{ disabled }}>
180
+ <View style={[styles.row, disabled && styles.candidateDisabled]}>
181
+ <Avatar sourceUri={candidate.avatar} size="lg" showFallback/>
182
+ <View style={styles.rowInfo}>
183
+ <Text style={styles.rowName}>{candidate.name}</Text>
184
+ {affiliationNames.length > 0 && (<Text style={styles.rowAffiliations} numberOfLines={2}>
185
+ {affiliationNames.join(', ')}
186
+ </Text>)}
187
+ {badges.length > 0 && (<View style={styles.badgeRow}>
188
+ {badges.map(({ title }) => (<Badge key={title} label={title}/>))}
189
+ </View>)}
190
+ </View>
191
+ </View>
192
+ </PlatformPressable>);
193
+ }
12
194
  const useStyles = () => {
13
- const { bottom } = useSafeAreaInsets();
195
+ const { colors } = useTheme();
14
196
  return StyleSheet.create({
15
197
  container: {
16
198
  flex: 1,
17
- padding: 16,
18
- paddingBottom: 16 + bottom,
199
+ },
200
+ candidateResultsContainer: {
201
+ flex: 1,
202
+ },
203
+ toField: {
204
+ paddingHorizontal: 16,
205
+ paddingTop: 16,
206
+ paddingBottom: 8,
207
+ },
208
+ toFieldHeader: {
209
+ flexDirection: 'row',
210
+ justifyContent: 'space-between',
19
211
  alignItems: 'center',
20
- justifyContent: 'center',
212
+ marginBottom: 8,
213
+ },
214
+ toLabel: {
215
+ fontWeight: '600',
216
+ color: colors.textColorDefaultSecondary,
217
+ },
218
+ clearButton: {
219
+ color: colors.interaction,
220
+ },
221
+ toInputArea: {
222
+ flexDirection: 'row',
223
+ flexWrap: 'wrap',
224
+ alignItems: 'center',
225
+ gap: 6,
226
+ borderWidth: 1,
227
+ borderColor: colors.borderColorDefaultBase,
228
+ borderRadius: 8,
229
+ paddingHorizontal: 10,
230
+ paddingVertical: 8,
231
+ },
232
+ toTextInput: {
233
+ flex: 1,
234
+ minWidth: 80,
235
+ color: colors.textColorDefaultPrimary,
236
+ fontSize: 16,
237
+ paddingVertical: 2,
238
+ },
239
+ chip: {
240
+ flexDirection: 'row',
241
+ alignItems: 'center',
242
+ gap: 4,
243
+ borderWidth: 1,
244
+ borderColor: colors.borderColorDefaultBase,
245
+ borderRadius: 100,
246
+ paddingLeft: 4,
247
+ paddingRight: 6,
248
+ paddingVertical: 3,
249
+ },
250
+ chipName: {
251
+ fontSize: 14,
252
+ },
253
+ chipRemoveIcon: {
254
+ color: colors.iconColorDefaultSecondary,
255
+ },
256
+ errorBanner: {
257
+ margin: 16,
258
+ },
259
+ emptyState: {
260
+ alignItems: 'center',
261
+ paddingTop: 32,
262
+ paddingHorizontal: 32,
21
263
  gap: 8,
22
264
  },
265
+ emptyStateIcon: {
266
+ color: colors.iconColorDefaultSecondary,
267
+ marginBottom: 4,
268
+ },
269
+ emptyStateTitle: {
270
+ fontWeight: '600',
271
+ textAlign: 'center',
272
+ },
273
+ emptyStateSubtitle: {
274
+ textAlign: 'center',
275
+ fontSize: 14,
276
+ },
277
+ row: {
278
+ flexDirection: 'row',
279
+ alignItems: 'flex-start',
280
+ gap: 12,
281
+ paddingHorizontal: 16,
282
+ paddingVertical: 12,
283
+ borderBottomWidth: 1,
284
+ borderColor: colors.borderColorDefaultDim,
285
+ },
286
+ rowInfo: {
287
+ flex: 1,
288
+ gap: 2,
289
+ },
290
+ rowName: {
291
+ fontSize: 15,
292
+ fontWeight: '500',
293
+ },
294
+ rowAffiliations: {
295
+ fontSize: 12,
296
+ color: colors.textColorDefaultSecondary,
297
+ },
298
+ badgeRow: {
299
+ flexDirection: 'row',
300
+ flexWrap: 'wrap',
301
+ gap: 4,
302
+ marginTop: 4,
303
+ },
304
+ candidateDisabled: {
305
+ opacity: 0.5,
306
+ },
307
+ resultsHeader: {
308
+ paddingHorizontal: 16,
309
+ paddingTop: 16,
310
+ paddingBottom: 8,
311
+ },
312
+ resultsHeading: {
313
+ fontWeight: '600',
314
+ },
315
+ unavailableHeader: {
316
+ paddingHorizontal: 16,
317
+ paddingTop: 16,
318
+ paddingBottom: 8,
319
+ },
320
+ unavailableLabel: {
321
+ fontSize: 13,
322
+ },
323
+ truncatedFooter: {
324
+ paddingHorizontal: 16,
325
+ paddingTop: 12,
326
+ paddingBottom: 8,
327
+ },
328
+ truncatedText: {
329
+ fontSize: 13,
330
+ textAlign: 'center',
331
+ },
23
332
  });
24
333
  };
25
334
  //# sourceMappingURL=conversation_select_direct_message_recipients_screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_direct_message_recipients_screen.js","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAGhD,MAAM,UAAU,+CAA+C,CAC7D,MAA+C;IAE/C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,OAAO,CACjD;MAAA,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAC7C;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAA;IAEtC,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,OAAO,EAAE,EAAE;YACX,aAAa,EAAE,EAAE,GAAG,MAAM;YAC1B,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,GAAG,EAAE,CAAC;SACP;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Heading, Text } from '../../components'\nimport { ConversationSelectRecipientsScreenProps } from './types/screen_props'\n\nexport function ConversationSelectDirectMessageRecipientsScreen(\n _props: ConversationSelectRecipientsScreenProps\n) {\n const styles = useStyles()\n\n return (\n <View style={styles.container}>\n <Heading variant=\"h2\">New direct message</Heading>\n <Text variant=\"secondary\">Coming soon</Text>\n </View>\n )\n}\n\nconst useStyles = () => {\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n padding: 16,\n paddingBottom: 16 + bottom,\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"conversation_select_direct_message_recipients_screen.js","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { StackActions, useNavigation } from '@react-navigation/native'\nimport { useEffect, useState } from 'react'\nimport { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native'\nimport { Avatar, Badge, Banner, Icon, Spinner, Text } from '../../components'\nimport { ActionButton } from '../../components/display/action_button'\nimport { ComponentErrorBoundary } from '../../components/page/component_error_boundary'\nimport { useTheme } from '../../hooks'\nimport { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations'\nimport { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates'\nimport { useDirectMessageConversationValidate } from '../../hooks/direct_messages/use_direct_message_conversation_validate'\nimport { useFindOrCreateDirectMessageConversation } from '../../hooks/direct_messages/use_find_or_create_direct_message_conversation'\nimport { DirectMessageCandidateResource } from '../../types/resources/direct_message_candidate'\nimport { ConversationSelectRecipientsScreenProps } from './types/screen_props'\n\nconst MAX_RECIPIENTS = 9\n\nexport function ConversationSelectDirectMessageRecipientsScreen(\n _props: ConversationSelectRecipientsScreenProps\n) {\n const styles = useStyles()\n const navigation = useNavigation()\n const [searchTerm, setSearchTerm] = useState('')\n const [debouncedTerm, setDebouncedTerm] = useState('')\n const [selectedPeople, setSelectedPeople] = useState<Map<string, DirectMessageCandidateResource>>(\n new Map()\n )\n\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedTerm(searchTerm), 200)\n return () => clearTimeout(timer)\n }, [searchTerm])\n\n const selectPerson = (person: DirectMessageCandidateResource) => {\n if (selectedPeople.size >= MAX_RECIPIENTS) return\n setSelectedPeople(prev => new Map(prev).set(person.id, person))\n setSearchTerm('')\n setDebouncedTerm('')\n }\n\n const removePerson = (id: string) => {\n setSelectedPeople(prev => {\n const next = new Map(prev)\n next.delete(id)\n return next\n })\n }\n\n const recipientIds = [...selectedPeople.keys()]\n const { warnings, validationPending } = useDirectMessageConversationValidate({ recipientIds })\n\n const handleSuccess = (conversationId: number) => {\n navigation.getParent()?.goBack()\n navigation.dispatch(StackActions.push('Conversation', { conversation_id: conversationId }))\n }\n\n const { findOrCreateConversation, directMessageExists, isFinding, isError } =\n useFindOrCreateDirectMessageConversation({ recipientIds, onSuccess: handleSuccess })\n\n const buttonText = (() => {\n if (selectedPeople.size === 0) return 'Start conversation'\n if (selectedPeople.size === 1) {\n const firstName = selectedPeople.values().next().value!.name.split(' ')[0]\n return directMessageExists ? `Open message with ${firstName}` : `Message ${firstName}`\n }\n return directMessageExists\n ? `Open direct message (${selectedPeople.size})`\n : `Start direct message (${selectedPeople.size})`\n })()\n\n return (\n <View style={styles.container}>\n {isError && (\n <Banner\n appearance=\"error\"\n description=\"There was an issue starting the conversation. Please try again.\"\n style={styles.errorBanner}\n />\n )}\n <ToField\n selectedPeople={selectedPeople}\n searchTerm={searchTerm}\n onSearchChange={setSearchTerm}\n onRemove={removePerson}\n onClear={() => setSelectedPeople(new Map())}\n />\n <View style={styles.candidateResultsContainer}>\n <ComponentErrorBoundary\n key={debouncedTerm}\n fallback={\n <Banner\n appearance=\"error\"\n description=\"Couldn't load people right now. Try again.\"\n style={styles.errorBanner}\n />\n }\n >\n <CandidateResults\n term={debouncedTerm}\n selectedPeople={selectedPeople}\n onSelect={selectPerson}\n />\n </ComponentErrorBoundary>\n </View>\n <ActionButton\n title={buttonText}\n disabled={\n selectedPeople.size === 0 || validationPending || warnings.length > 0 || isFinding\n }\n loading={validationPending || isFinding}\n onPress={() => findOrCreateConversation(recipientIds)}\n warnings={warnings}\n />\n </View>\n )\n}\n\nfunction ToField({\n selectedPeople,\n searchTerm,\n onSearchChange,\n onRemove,\n onClear,\n}: {\n selectedPeople: Map<string, DirectMessageCandidateResource>\n searchTerm: string\n onSearchChange: (term: string) => void\n onRemove: (id: string) => void\n onClear: () => void\n}) {\n const styles = useStyles()\n const { colors } = useTheme()\n const hasSelections = selectedPeople.size > 0\n\n return (\n <View style={styles.toField}>\n <View style={styles.toFieldHeader}>\n <Text style={styles.toLabel}>To</Text>\n {hasSelections && (\n <Pressable onPress={onClear} hitSlop={8}>\n <Text style={styles.clearButton}>Clear</Text>\n </Pressable>\n )}\n </View>\n <View style={styles.toInputArea}>\n {[...selectedPeople.values()].map(person => (\n <PersonChip key={person.id} person={person} onRemove={onRemove} />\n ))}\n <TextInput\n autoFocus\n placeholder=\"Search\"\n placeholderTextColor={colors.textColorDefaultPlaceholder}\n value={searchTerm}\n onChangeText={onSearchChange}\n style={styles.toTextInput}\n returnKeyType=\"search\"\n />\n </View>\n </View>\n )\n}\n\nfunction PersonChip({\n person,\n onRemove,\n}: {\n person: DirectMessageCandidateResource\n onRemove: (id: string) => void\n}) {\n const styles = useStyles()\n\n return (\n <View style={styles.chip}>\n <Avatar sourceUri={person.avatar} size=\"sm\" showFallback />\n <Text style={styles.chipName}>{person.name}</Text>\n <Pressable\n onPress={() => onRemove(person.id)}\n hitSlop={8}\n accessibilityLabel={`Remove ${person.name}`}\n >\n <Icon name=\"general.x\" size={12} style={styles.chipRemoveIcon} />\n </Pressable>\n </View>\n )\n}\n\nfunction CandidateResults({\n term,\n selectedPeople,\n onSelect,\n}: {\n term: string\n selectedPeople: Map<string, DirectMessageCandidateResource>\n onSelect: (candidate: DirectMessageCandidateResource) => void\n}) {\n const styles = useStyles()\n const { data, isFetching } = useDirectMessageCandidates(term)\n const { groups, teams } = useDirectMessageAffiliations()\n\n if (term.length < 1) {\n if (selectedPeople.size > 0) return null\n\n return (\n <View style={styles.emptyState}>\n <Icon name=\"churchCenter.people\" size={40} style={styles.emptyStateIcon} />\n <Text style={styles.emptyStateTitle}>Search for people to direct message</Text>\n <Text variant=\"secondary\" style={styles.emptyStateSubtitle}>\n Start a conversation with people in your groups and teams.\n </Text>\n </View>\n )\n }\n\n const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS\n\n if (isAtLimit) {\n return (\n <View style={styles.emptyState}>\n <Text variant=\"secondary\" style={styles.emptyStateSubtitle}>\n You can add up to {MAX_RECIPIENTS} people to a direct message.\n </Text>\n </View>\n )\n }\n\n const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id))\n const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)\n\n if (isFetching && unselectedCandidates.length === 0) {\n return (\n <View style={styles.emptyState}>\n <Spinner />\n </View>\n )\n }\n\n if (!isFetching && unselectedCandidates.length === 0) {\n return (\n <View style={styles.emptyState}>\n <Icon name=\"general.search\" size={32} style={styles.emptyStateIcon} />\n <Text style={styles.emptyStateTitle}>No matches for \"{term}\"</Text>\n <Text variant=\"secondary\" style={styles.emptyStateSubtitle}>\n Try a different name, or check that you share a group or team with them.\n </Text>\n </View>\n )\n }\n\n return (\n <CandidateList\n candidates={unselectedCandidates}\n hasTruncated={hasTruncated}\n groups={groups}\n teams={teams}\n onSelect={onSelect}\n />\n )\n}\n\nfunction candidateBadges(candidate: DirectMessageCandidateResource) {\n const badges = []\n if (candidate.directMessagesDisabled) badges.push({ title: 'DMs off' })\n if (candidate.under_18) badges.push({ title: 'Under 18' })\n return badges\n}\n\nfunction candidateAffiliationNames(\n candidate: DirectMessageCandidateResource,\n groups: Map<number, string>,\n teams: Map<number, string>\n) {\n return [\n ...candidate.groups.flatMap(id => {\n const name = groups.get(id)\n return name ? [name] : []\n }),\n ...candidate.teams.flatMap(id => {\n const name = teams.get(id)\n return name ? [name] : []\n }),\n ]\n}\n\nfunction CandidateList({\n candidates,\n hasTruncated,\n groups,\n teams,\n onSelect,\n}: {\n candidates: DirectMessageCandidateResource[]\n hasTruncated: boolean\n groups: Map<number, string>\n teams: Map<number, string>\n onSelect: (candidate: DirectMessageCandidateResource) => void\n}) {\n const styles = useStyles()\n const available = candidates.filter(c => !c.directMessagesDisabled)\n const dmDisabled = candidates.filter(c => c.directMessagesDisabled)\n\n return (\n <FlatList<DirectMessageCandidateResource>\n data={available}\n keyExtractor={item => item.id}\n renderItem={({ item }) => (\n <CandidateItem\n candidate={item}\n badges={candidateBadges(item)}\n affiliationNames={candidateAffiliationNames(item, groups, teams)}\n onSelect={() => onSelect(item)}\n />\n )}\n ListHeaderComponent={\n <View style={styles.resultsHeader}>\n <Text style={styles.resultsHeading}>Results</Text>\n </View>\n }\n ListFooterComponent={\n <>\n {dmDisabled.length > 0 && (\n <>\n <View style={styles.unavailableHeader}>\n <Text variant=\"secondary\" style={styles.unavailableLabel}>\n Unavailable for direct messages\n </Text>\n </View>\n {dmDisabled.map(candidate => (\n <CandidateItem\n key={candidate.id}\n candidate={candidate}\n badges={candidateBadges(candidate)}\n affiliationNames={candidateAffiliationNames(candidate, groups, teams)}\n disabled\n />\n ))}\n </>\n )}\n {hasTruncated && (\n <View style={styles.truncatedFooter}>\n <Text variant=\"secondary\" style={styles.truncatedText}>\n Keep typing to narrow your results.\n </Text>\n </View>\n )}\n </>\n }\n />\n )\n}\n\nfunction CandidateItem({\n candidate,\n badges,\n affiliationNames,\n onSelect,\n disabled = false,\n}: {\n candidate: DirectMessageCandidateResource\n badges: { title: string }[]\n affiliationNames: string[]\n onSelect?: () => void\n disabled?: boolean\n}) {\n const styles = useStyles()\n\n return (\n <PlatformPressable\n onPress={disabled ? undefined : onSelect}\n accessibilityRole=\"button\"\n accessibilityLabel={`Select ${candidate.name}`}\n accessibilityState={{ disabled }}\n >\n <View style={[styles.row, disabled && styles.candidateDisabled]}>\n <Avatar sourceUri={candidate.avatar} size=\"lg\" showFallback />\n <View style={styles.rowInfo}>\n <Text style={styles.rowName}>{candidate.name}</Text>\n {affiliationNames.length > 0 && (\n <Text style={styles.rowAffiliations} numberOfLines={2}>\n {affiliationNames.join(', ')}\n </Text>\n )}\n {badges.length > 0 && (\n <View style={styles.badgeRow}>\n {badges.map(({ title }) => (\n <Badge key={title} label={title} />\n ))}\n </View>\n )}\n </View>\n </View>\n </PlatformPressable>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n },\n candidateResultsContainer: {\n flex: 1,\n },\n toField: {\n paddingHorizontal: 16,\n paddingTop: 16,\n paddingBottom: 8,\n },\n toFieldHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 8,\n },\n toLabel: {\n fontWeight: '600',\n color: colors.textColorDefaultSecondary,\n },\n clearButton: {\n color: colors.interaction,\n },\n toInputArea: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 6,\n borderWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n borderRadius: 8,\n paddingHorizontal: 10,\n paddingVertical: 8,\n },\n toTextInput: {\n flex: 1,\n minWidth: 80,\n color: colors.textColorDefaultPrimary,\n fontSize: 16,\n paddingVertical: 2,\n },\n chip: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n borderWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n borderRadius: 100,\n paddingLeft: 4,\n paddingRight: 6,\n paddingVertical: 3,\n },\n chipName: {\n fontSize: 14,\n },\n chipRemoveIcon: {\n color: colors.iconColorDefaultSecondary,\n },\n errorBanner: {\n margin: 16,\n },\n emptyState: {\n alignItems: 'center',\n paddingTop: 32,\n paddingHorizontal: 32,\n gap: 8,\n },\n emptyStateIcon: {\n color: colors.iconColorDefaultSecondary,\n marginBottom: 4,\n },\n emptyStateTitle: {\n fontWeight: '600',\n textAlign: 'center',\n },\n emptyStateSubtitle: {\n textAlign: 'center',\n fontSize: 14,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 12,\n paddingHorizontal: 16,\n paddingVertical: 12,\n borderBottomWidth: 1,\n borderColor: colors.borderColorDefaultDim,\n },\n rowInfo: {\n flex: 1,\n gap: 2,\n },\n rowName: {\n fontSize: 15,\n fontWeight: '500',\n },\n rowAffiliations: {\n fontSize: 12,\n color: colors.textColorDefaultSecondary,\n },\n badgeRow: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n gap: 4,\n marginTop: 4,\n },\n\n candidateDisabled: {\n opacity: 0.5,\n },\n resultsHeader: {\n paddingHorizontal: 16,\n paddingTop: 16,\n paddingBottom: 8,\n },\n resultsHeading: {\n fontWeight: '600',\n },\n unavailableHeader: {\n paddingHorizontal: 16,\n paddingTop: 16,\n paddingBottom: 8,\n },\n unavailableLabel: {\n fontSize: 13,\n },\n truncatedFooter: {\n paddingHorizontal: 16,\n paddingTop: 12,\n paddingBottom: 8,\n },\n truncatedText: {\n fontSize: 13,\n textAlign: 'center',\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_type_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAG3D,eAAO,MAAM,mCAAmC,uEAE9C,CAAA;AAEF,MAAM,MAAM,iCAAiC,GAAG,iBAAiB,CAAC;IAChE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,yBAAyB,CAAC,EAAE,yBAAyB,CAAA;CACtD,CAAC,CAAA;AAOF,wBAAgB,4BAA4B,CAAC,EAAE,KAAK,EAAE,EAAE,iCAAiC,qBAuFxF"}
1
+ {"version":3,"file":"conversation_select_type_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAG3D,eAAO,MAAM,mCAAmC,uEAE9C,CAAA;AAEF,MAAM,MAAM,iCAAiC,GAAG,iBAAiB,CAAC;IAChE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,yBAAyB,CAAC,EAAE,yBAAyB,CAAA;CACtD,CAAC,CAAA;AAOF,wBAAgB,4BAA4B,CAAC,EAAE,KAAK,EAAE,EAAE,iCAAiC,qBA0FxF"}
@@ -1,6 +1,7 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
2
  import React from 'react';
3
3
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet';
4
+ import { useCurrentPerson } from '../hooks/use_current_person';
4
5
  import { availableFeatures, useFeatures } from '../hooks/use_features';
5
6
  import { useNewConversationEntry } from '../hooks/use_new_conversation_entry';
6
7
  import { Haptic } from '../utils/native_adapters';
@@ -11,11 +12,12 @@ export function ConversationSelectTypeScreen({ route }) {
11
12
  const navigation = useNavigation();
12
13
  const entryMode = useNewConversationEntry();
13
14
  const { featureEnabled } = useFeatures();
15
+ const { directMessagesDisabled } = useCurrentPerson();
14
16
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } = route.params || {};
15
17
  const filterParams = { chat_group_graph_id, group_source_app_name };
16
18
  const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups';
17
19
  const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams';
18
- const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap);
20
+ const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap);
19
21
  const handleFilterPress = () => {
20
22
  if (!newConversationFromFilter)
21
23
  return;
@@ -59,7 +61,7 @@ export function ConversationSelectTypeScreen({ route }) {
59
61
  {newConversationFromFilter && (<FormSheet.Action title={`New conversation in ${newConversationFromFilter.name}`} onPress={handleFilterPress} accessibilityHint="Creates a conversation pre-scoped to the current filter"/>)}
60
62
  {canCreateGroups && (<FormSheet.Action title="Group" onPress={handleGroupPress} accessibilityHint="Opens group selection screen"/>)}
61
63
  {canCreateTeams && (<FormSheet.Action title="Team" onPress={handleTeamPress} accessibilityHint="Opens team selection screen"/>)}
62
- {canCreateDMs && (<FormSheet.Action title="Direct message" onPress={handleDirectMessagePress} accessibilityHint="Opens direct message recipient selection screen"/>)}
64
+ {dmFeatureEnabled && (<FormSheet.Action title="Direct message" onPress={handleDirectMessagePress} disabled={directMessagesDisabled} disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined} accessibilityHint="Opens direct message recipient selection screen"/>)}
63
65
  </FormSheet.Root>);
64
66
  }
65
67
  //# sourceMappingURL=conversation_select_type_screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_type_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'\nimport { availableFeatures, useFeatures } from '../hooks/use_features'\nimport { useNewConversationEntry } from '../hooks/use_new_conversation_entry'\nimport type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'\nimport { AppName } from '../types/resources/app_name'\nimport { GraphId } from '../types/resources/group_resource'\nimport { Haptic } from '../utils/native_adapters'\n\nexport const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({\n headerTitle: 'New conversation',\n})\n\nexport type ConversationSelectTypeScreenProps = StaticScreenProps<{\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n newConversationFromFilter?: NewConversationFromFilter\n}>\n\ntype NewConversationTypeScreen =\n | 'ConversationSelectGroupRecipients'\n | 'ConversationSelectTeamsILeadRecipients'\n | 'ConversationSelectDirectMessageRecipients'\n\nexport function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {\n const navigation = useNavigation()\n const entryMode = useNewConversationEntry()\n const { featureEnabled } = useFeatures()\n const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =\n route.params || {}\n\n const filterParams = { chat_group_graph_id, group_source_app_name }\n const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'\n const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'\n const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap)\n\n const handleFilterPress = () => {\n if (!newConversationFromFilter) return\n\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n if (newConversationFromFilter.sourceAppName === 'groups') {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Groups' as AppName,\n group_id: newConversationFromFilter.groupId,\n },\n })\n } else {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Services' as AppName,\n team_ids: newConversationFromFilter.teamIds,\n },\n })\n }\n })\n }\n\n const navigateToNewConversationType = (screen: NewConversationTypeScreen) => {\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => navigation.navigate('New', { screen, params: filterParams }))\n }\n\n const handleGroupPress = () => navigateToNewConversationType('ConversationSelectGroupRecipients')\n const handleTeamPress = () =>\n navigateToNewConversationType('ConversationSelectTeamsILeadRecipients')\n const handleDirectMessagePress = () =>\n navigateToNewConversationType('ConversationSelectDirectMessageRecipients')\n\n return (\n <FormSheet.Root>\n <FormSheet.Header>\n <FormSheet.HeaderTitle>Start a conversation by</FormSheet.HeaderTitle>\n </FormSheet.Header>\n {newConversationFromFilter && (\n <FormSheet.Action\n title={`New conversation in ${newConversationFromFilter.name}`}\n onPress={handleFilterPress}\n accessibilityHint=\"Creates a conversation pre-scoped to the current filter\"\n />\n )}\n {canCreateGroups && (\n <FormSheet.Action\n title=\"Group\"\n onPress={handleGroupPress}\n accessibilityHint=\"Opens group selection screen\"\n />\n )}\n {canCreateTeams && (\n <FormSheet.Action\n title=\"Team\"\n onPress={handleTeamPress}\n accessibilityHint=\"Opens team selection screen\"\n />\n )}\n {canCreateDMs && (\n <FormSheet.Action\n title=\"Direct message\"\n onPress={handleDirectMessagePress}\n accessibilityHint=\"Opens direct message recipient selection screen\"\n />\n )}\n </FormSheet.Root>\n )\n}\n"]}
1
+ {"version":3,"file":"conversation_select_type_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,SAAS,EAAE,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AAI7E,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AAEjD,MAAM,CAAC,MAAM,mCAAmC,GAAG,yBAAyB,CAAC;IAC3E,WAAW,EAAE,kBAAkB;CAChC,CAAC,CAAA;AAaF,MAAM,UAAU,4BAA4B,CAAC,EAAE,KAAK,EAAqC;IACvF,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,SAAS,GAAG,uBAAuB,EAAE,CAAA;IAC3C,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,EAAE,CAAA;IACxC,MAAM,EAAE,sBAAsB,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACrD,MAAM,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,GAC7E,KAAK,CAAC,MAAM,IAAI,EAAE,CAAA;IAEpB,MAAM,YAAY,GAAG,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAA;IACnE,MAAM,eAAe,GAAG,SAAS,KAAK,aAAa,IAAI,SAAS,KAAK,QAAQ,CAAA;IAC7E,MAAM,cAAc,GAAG,SAAS,KAAK,aAAa,IAAI,SAAS,KAAK,OAAO,CAAA;IAC3E,MAAM,gBAAgB,GAAG,cAAc,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAA;IAE9E,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,yBAAyB;YAAE,OAAM;QAEtC,MAAM,CAAC,WAAW,EAAE,CAAA;QACpB,UAAU,CAAC,MAAM,EAAE,CAAA;QACnB,qBAAqB,CAAC,GAAG,EAAE;YACzB,IAAI,yBAAyB,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;gBACzD,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE;oBACzB,MAAM,EAAE,iBAAiB;oBACzB,MAAM,EAAE;wBACN,GAAG,YAAY;wBACf,eAAe,EAAE,QAAmB;wBACpC,QAAQ,EAAE,yBAAyB,CAAC,OAAO;qBAC5C;iBACF,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE;oBACzB,MAAM,EAAE,iBAAiB;oBACzB,MAAM,EAAE;wBACN,GAAG,YAAY;wBACf,eAAe,EAAE,UAAqB;wBACtC,QAAQ,EAAE,yBAAyB,CAAC,OAAO;qBAC5C;iBACF,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,6BAA6B,GAAG,CAAC,MAAiC,EAAE,EAAE;QAC1E,MAAM,CAAC,WAAW,EAAE,CAAA;QACpB,UAAU,CAAC,MAAM,EAAE,CAAA;QACnB,qBAAqB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;IAC3F,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,6BAA6B,CAAC,mCAAmC,CAAC,CAAA;IACjG,MAAM,eAAe,GAAG,GAAG,EAAE,CAC3B,6BAA6B,CAAC,wCAAwC,CAAC,CAAA;IACzE,MAAM,wBAAwB,GAAG,GAAG,EAAE,CACpC,6BAA6B,CAAC,2CAA2C,CAAC,CAAA;IAE5E,OAAO,CACL,CAAC,SAAS,CAAC,IAAI,CACb;MAAA,CAAC,SAAS,CAAC,MAAM,CACf;QAAA,CAAC,SAAS,CAAC,WAAW,CAAC,uBAAuB,EAAE,SAAS,CAAC,WAAW,CACvE;MAAA,EAAE,SAAS,CAAC,MAAM,CAClB;MAAA,CAAC,yBAAyB,IAAI,CAC5B,CAAC,SAAS,CAAC,MAAM,CACf,KAAK,CAAC,CAAC,uBAAuB,yBAAyB,CAAC,IAAI,EAAE,CAAC,CAC/D,OAAO,CAAC,CAAC,iBAAiB,CAAC,CAC3B,iBAAiB,CAAC,yDAAyD,EAC3E,CACH,CACD;MAAA,CAAC,eAAe,IAAI,CAClB,CAAC,SAAS,CAAC,MAAM,CACf,KAAK,CAAC,OAAO,CACb,OAAO,CAAC,CAAC,gBAAgB,CAAC,CAC1B,iBAAiB,CAAC,8BAA8B,EAChD,CACH,CACD;MAAA,CAAC,cAAc,IAAI,CACjB,CAAC,SAAS,CAAC,MAAM,CACf,KAAK,CAAC,MAAM,CACZ,OAAO,CAAC,CAAC,eAAe,CAAC,CACzB,iBAAiB,CAAC,6BAA6B,EAC/C,CACH,CACD;MAAA,CAAC,gBAAgB,IAAI,CACnB,CAAC,SAAS,CAAC,MAAM,CACf,KAAK,CAAC,gBAAgB,CACtB,OAAO,CAAC,CAAC,wBAAwB,CAAC,CAClC,QAAQ,CAAC,CAAC,sBAAsB,CAAC,CACjC,cAAc,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,SAAS,CAAC,CACjF,iBAAiB,CAAC,iDAAiD,EACnE,CACH,CACH;IAAA,EAAE,SAAS,CAAC,IAAI,CAAC,CAClB,CAAA;AACH,CAAC","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'\nimport { useCurrentPerson } from '../hooks/use_current_person'\nimport { availableFeatures, useFeatures } from '../hooks/use_features'\nimport { useNewConversationEntry } from '../hooks/use_new_conversation_entry'\nimport type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'\nimport { AppName } from '../types/resources/app_name'\nimport { GraphId } from '../types/resources/group_resource'\nimport { Haptic } from '../utils/native_adapters'\n\nexport const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({\n headerTitle: 'New conversation',\n})\n\nexport type ConversationSelectTypeScreenProps = StaticScreenProps<{\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n newConversationFromFilter?: NewConversationFromFilter\n}>\n\ntype NewConversationTypeScreen =\n | 'ConversationSelectGroupRecipients'\n | 'ConversationSelectTeamsILeadRecipients'\n | 'ConversationSelectDirectMessageRecipients'\n\nexport function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {\n const navigation = useNavigation()\n const entryMode = useNewConversationEntry()\n const { featureEnabled } = useFeatures()\n const { directMessagesDisabled } = useCurrentPerson()\n const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =\n route.params || {}\n\n const filterParams = { chat_group_graph_id, group_source_app_name }\n const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'\n const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'\n const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)\n\n const handleFilterPress = () => {\n if (!newConversationFromFilter) return\n\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n if (newConversationFromFilter.sourceAppName === 'groups') {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Groups' as AppName,\n group_id: newConversationFromFilter.groupId,\n },\n })\n } else {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Services' as AppName,\n team_ids: newConversationFromFilter.teamIds,\n },\n })\n }\n })\n }\n\n const navigateToNewConversationType = (screen: NewConversationTypeScreen) => {\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => navigation.navigate('New', { screen, params: filterParams }))\n }\n\n const handleGroupPress = () => navigateToNewConversationType('ConversationSelectGroupRecipients')\n const handleTeamPress = () =>\n navigateToNewConversationType('ConversationSelectTeamsILeadRecipients')\n const handleDirectMessagePress = () =>\n navigateToNewConversationType('ConversationSelectDirectMessageRecipients')\n\n return (\n <FormSheet.Root>\n <FormSheet.Header>\n <FormSheet.HeaderTitle>Start a conversation by</FormSheet.HeaderTitle>\n </FormSheet.Header>\n {newConversationFromFilter && (\n <FormSheet.Action\n title={`New conversation in ${newConversationFromFilter.name}`}\n onPress={handleFilterPress}\n accessibilityHint=\"Creates a conversation pre-scoped to the current filter\"\n />\n )}\n {canCreateGroups && (\n <FormSheet.Action\n title=\"Group\"\n onPress={handleGroupPress}\n accessibilityHint=\"Opens group selection screen\"\n />\n )}\n {canCreateTeams && (\n <FormSheet.Action\n title=\"Team\"\n onPress={handleTeamPress}\n accessibilityHint=\"Opens team selection screen\"\n />\n )}\n {dmFeatureEnabled && (\n <FormSheet.Action\n title=\"Direct message\"\n onPress={handleDirectMessagePress}\n disabled={directMessagesDisabled}\n disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined}\n accessibilityHint=\"Opens direct message recipient selection screen\"\n />\n )}\n </FormSheet.Root>\n )\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"list_header_component.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversations/components/list_header_component.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAA;AA0BnD,eAAO,MAAM,mBAAmB,yBAqL/B,CAAA"}
1
+ {"version":3,"file":"list_header_component.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversations/components/list_header_component.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAA;AAiCnD,eAAO,MAAM,mBAAmB,yBAgO/B,CAAA"}
@@ -2,12 +2,10 @@ import { useNavigation, useRoute } from '@react-navigation/native';
2
2
  import React, { useCallback, useMemo } from 'react';
3
3
  import { Alert, ScrollView, StyleSheet, View } from 'react-native';
4
4
  import { Heading, TextButton, ToggleButton } from '../../../components';
5
- import { useAtFontScaleBreakpoint, useCurrentPersonCache, useTheme } from '../../../hooks';
6
- import { useCanCreateConversations } from '../../../hooks';
5
+ import { useAtFontScaleBreakpoint, useCanCreateConversations, useCurrentPersonCache, useDirectMessagesEnabled, useHasDirectMessages, useNewConversationEntry, useTheme, } from '../../../hooks';
7
6
  import { useAppName } from '../../../hooks/use_app_name';
8
7
  import { useMarkAllRead } from '../../../hooks/use_conversations_actions';
9
8
  import { useCanDisplayGroups } from '../../../hooks/use_groups';
10
- import { useNewConversationEntry } from '../../../hooks/use_new_conversation_entry';
11
9
  import { useNewConversationFromFilter } from '../../../hooks/use_new_conversation_from_filter';
12
10
  import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../../utils';
13
11
  import { Haptic } from '../../../utils/native_adapters';
@@ -19,14 +17,18 @@ var FilterTypes;
19
17
  FilterTypes["All"] = "All";
20
18
  FilterTypes["Groups"] = "Groups";
21
19
  FilterTypes["Teams"] = "Teams";
20
+ FilterTypes["DMs"] = "DMs";
22
21
  FilterTypes["More"] = "More";
23
22
  })(FilterTypes || (FilterTypes = {}));
24
23
  export const ListHeaderComponent = () => {
25
24
  const navigation = useNavigation();
26
25
  const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' });
27
26
  const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' });
27
+ const directMessagesEnabled = useDirectMessagesEnabled();
28
+ const hasDirectMessages = useHasDirectMessages();
29
+ const canFilterByDMs = directMessagesEnabled && hasDirectMessages;
28
30
  const route = useRoute();
29
- const { chat_group_graph_id, group_source_app_name = '' } = route.params || {};
31
+ const { chat_group_graph_id, group_source_app_name = '', show_direct_messages, } = route.params || {};
30
32
  const currentPersonCache = useCurrentPersonCache();
31
33
  const { markAllRead, isPending } = useMarkAllRead();
32
34
  const canCreateConversations = useCanCreateConversations();
@@ -43,8 +45,11 @@ export const ListHeaderComponent = () => {
43
45
  else if (/services/i.test(group_source_app_name)) {
44
46
  return FilterTypes.Teams;
45
47
  }
48
+ else if (show_direct_messages) {
49
+ return FilterTypes.DMs;
50
+ }
46
51
  return FilterTypes.All;
47
- }, [chat_group_graph_id, group_source_app_name]);
52
+ }, [chat_group_graph_id, group_source_app_name, show_direct_messages]);
48
53
  const handleNewConversationNavigation = useCallback(() => {
49
54
  if (newConversationFromFilter || entryMode === 'select_type') {
50
55
  return navigation.navigate('ConversationSelectType', {
@@ -65,6 +70,9 @@ export const ListHeaderComponent = () => {
65
70
  });
66
71
  }
67
72
  }, [navigation, route.params, entryMode, newConversationFromFilter]);
73
+ const handleChatSettings = useCallback(() => {
74
+ navigation.navigate('ChatSettings', {});
75
+ }, [navigation]);
68
76
  const handleMoreOptions = useCallback(() => {
69
77
  navigation.navigate('ConversationsMoreActions');
70
78
  }, [navigation]);
@@ -72,8 +80,9 @@ export const ListHeaderComponent = () => {
72
80
  navigation.navigate('ConversationFilters', {
73
81
  chat_group_graph_id,
74
82
  group_source_app_name,
83
+ show_direct_messages,
75
84
  });
76
- }, [navigation, chat_group_graph_id, group_source_app_name]);
85
+ }, [navigation, chat_group_graph_id, group_source_app_name, show_direct_messages]);
77
86
  const handleMarkAllRead = useCallback(() => {
78
87
  currentPersonCache.update({ unreadCount: 0 });
79
88
  Haptic.notificationSuccess();
@@ -89,7 +98,8 @@ export const ListHeaderComponent = () => {
89
98
  }, [active, handleMarkAllRead]);
90
99
  const hasSomeSourceFilterCapability = canFilterByTeams || canFilterByGroups;
91
100
  const hasMultiSourceFilterCapabilities = canFilterByTeams && canFilterByGroups;
92
- const shouldShowHeaderFiltersButton = hasSomeSourceFilterCapability && !hasMultiSourceFilterCapabilities;
101
+ const showFilterRow = hasMultiSourceFilterCapabilities || canFilterByDMs;
102
+ const shouldShowHeaderFiltersButton = hasSomeSourceFilterCapability && !showFilterRow;
93
103
  const moreFiltersButtonA11yLabel = shouldShowHeaderFiltersButton
94
104
  ? 'View filters'
95
105
  : 'View more filters';
@@ -111,25 +121,33 @@ export const ListHeaderComponent = () => {
111
121
  </TextButton>
112
122
  </View>
113
123
  <View style={styles.actionsContainer}>
124
+ {directMessagesEnabled && (<ListHeaderActionButton name="general.cog" onPress={handleChatSettings} accessibilityLabel="Chat settings" maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}/>)}
114
125
  {canCreateConversations && (<ListHeaderActionButton name="churchCenter.signups" onPress={handleNewConversationNavigation} accessibilityLabel="New conversation" testID="conversations-new-conversation-button" maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}/>)}
115
126
  {appName !== 'services' && (<ListHeaderActionButton name="general.threeDots" onPress={handleMoreOptions} accessibilityLabel="More options" maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}/>)}
116
127
  {shouldShowHeaderFiltersButton && <ToggleButton {...moreFiltersButtonProps}/>}
117
128
  </View>
118
129
  </View>
119
- {hasMultiSourceFilterCapabilities && (<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.filterRow} accessibilityRole="toolbar">
130
+ {showFilterRow && (<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.filterRow} accessibilityRole="toolbar">
120
131
  <ToggleButton title={FilterTypes.All} active={active === FilterTypes.All} onPress={() => navigation.setParams({
121
132
  chat_group_graph_id: undefined,
122
133
  group_source_app_name: undefined,
134
+ show_direct_messages: undefined,
123
135
  })} accessibilityLabel="Show all conversations" style={styles.filterButton}/>
124
- <ToggleButton title={FilterTypes.Groups} active={active === FilterTypes.Groups} onPress={() => navigation.setParams({
125
- chat_group_graph_id: undefined,
126
- group_source_app_name: 'Groups',
127
- })} accessibilityLabel="Filter to group conversations" style={styles.filterButton}/>
128
-
129
- <ToggleButton title={FilterTypes.Teams} active={active === FilterTypes.Teams} onPress={() => navigation.setParams({
130
- chat_group_graph_id: undefined,
131
- group_source_app_name: 'Services',
132
- })} accessibilityLabel="Filter to team conversations" style={styles.filterButton}/>
136
+ {canFilterByGroups && (<ToggleButton title={FilterTypes.Groups} active={active === FilterTypes.Groups} onPress={() => navigation.setParams({
137
+ chat_group_graph_id: undefined,
138
+ group_source_app_name: 'Groups',
139
+ show_direct_messages: undefined,
140
+ })} accessibilityLabel="Filter to group conversations" style={styles.filterButton}/>)}
141
+ {canFilterByTeams && (<ToggleButton title={FilterTypes.Teams} active={active === FilterTypes.Teams} onPress={() => navigation.setParams({
142
+ chat_group_graph_id: undefined,
143
+ group_source_app_name: 'Services',
144
+ show_direct_messages: undefined,
145
+ })} accessibilityLabel="Filter to team conversations" style={styles.filterButton}/>)}
146
+ {canFilterByDMs && (<ToggleButton title={FilterTypes.DMs} active={active === FilterTypes.DMs} onPress={() => navigation.setParams({
147
+ chat_group_graph_id: undefined,
148
+ group_source_app_name: undefined,
149
+ show_direct_messages: true,
150
+ })} accessibilityLabel="Filter to direct message conversations" style={styles.filterButton}/>)}
133
151
  <ToggleButton {...moreFiltersButtonProps}/>
134
152
  </ScrollView>)}
135
153
  <ChatGroupBadge rowPaddingHorizontal={ROW_PADDING_HORIZONTAL}/>