@planningcenter/chat-react-native 3.39.0-rc.2 → 3.39.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +92 -19
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
- package/package.json +2 -2
- package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +155 -30
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation_select_direct_message_recipients_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation_select_direct_message_recipients_screen.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,uCAAuC,EAAE,MAAM,sBAAsB,CAAA;AAI9E,wBAAgB,+CAA+C,CAC7D,MAAM,EAAE,uCAAuC,+BAiGhD"}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { PlatformPressable } from '@react-navigation/elements';
|
|
2
|
+
import { StackActions, useNavigation } from '@react-navigation/native';
|
|
2
3
|
import { useEffect, useState } from 'react';
|
|
3
4
|
import { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { Avatar, Badge, Banner, Icon, Spinner, Text } from '../../components';
|
|
6
|
+
import { ActionButton } from '../../components/display/action_button';
|
|
6
7
|
import { ComponentErrorBoundary } from '../../components/page/component_error_boundary';
|
|
7
8
|
import { useTheme } from '../../hooks';
|
|
9
|
+
import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations';
|
|
8
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';
|
|
9
13
|
const MAX_RECIPIENTS = 9;
|
|
10
14
|
export function ConversationSelectDirectMessageRecipientsScreen(_props) {
|
|
11
15
|
const styles = useStyles();
|
|
16
|
+
const navigation = useNavigation();
|
|
12
17
|
const [searchTerm, setSearchTerm] = useState('');
|
|
13
18
|
const [debouncedTerm, setDebouncedTerm] = useState('');
|
|
14
19
|
const [selectedPeople, setSelectedPeople] = useState(new Map());
|
|
@@ -30,11 +35,33 @@ export function ConversationSelectDirectMessageRecipientsScreen(_props) {
|
|
|
30
35
|
return next;
|
|
31
36
|
});
|
|
32
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
|
+
})();
|
|
33
56
|
return (<View style={styles.container}>
|
|
57
|
+
{isError && (<Banner appearance="error" description="There was an issue starting the conversation. Please try again." style={styles.errorBanner}/>)}
|
|
34
58
|
<ToField selectedPeople={selectedPeople} searchTerm={searchTerm} onSearchChange={setSearchTerm} onRemove={removePerson} onClear={() => setSelectedPeople(new Map())}/>
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
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}/>
|
|
38
65
|
</View>);
|
|
39
66
|
}
|
|
40
67
|
function ToField({ selectedPeople, searchTerm, onSearchChange, onRemove, onClear, }) {
|
|
@@ -67,6 +94,7 @@ function PersonChip({ person, onRemove, }) {
|
|
|
67
94
|
function CandidateResults({ term, selectedPeople, onSelect, }) {
|
|
68
95
|
const styles = useStyles();
|
|
69
96
|
const { data, isFetching } = useDirectMessageCandidates(term);
|
|
97
|
+
const { groups, teams } = useDirectMessageAffiliations();
|
|
70
98
|
if (term.length < 1) {
|
|
71
99
|
if (selectedPeople.size > 0)
|
|
72
100
|
return null;
|
|
@@ -78,7 +106,8 @@ function CandidateResults({ term, selectedPeople, onSelect, }) {
|
|
|
78
106
|
</Text>
|
|
79
107
|
</View>);
|
|
80
108
|
}
|
|
81
|
-
|
|
109
|
+
const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS;
|
|
110
|
+
if (isAtLimit) {
|
|
82
111
|
return (<View style={styles.emptyState}>
|
|
83
112
|
<Text variant="secondary" style={styles.emptyStateSubtitle}>
|
|
84
113
|
You can add up to {MAX_RECIPIENTS} people to a direct message.
|
|
@@ -86,6 +115,7 @@ function CandidateResults({ term, selectedPeople, onSelect, }) {
|
|
|
86
115
|
</View>);
|
|
87
116
|
}
|
|
88
117
|
const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id));
|
|
118
|
+
const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0);
|
|
89
119
|
if (isFetching && unselectedCandidates.length === 0) {
|
|
90
120
|
return (<View style={styles.emptyState}>
|
|
91
121
|
<Spinner />
|
|
@@ -100,14 +130,33 @@ function CandidateResults({ term, selectedPeople, onSelect, }) {
|
|
|
100
130
|
</Text>
|
|
101
131
|
</View>);
|
|
102
132
|
}
|
|
103
|
-
|
|
104
|
-
|
|
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;
|
|
105
142
|
}
|
|
106
|
-
function
|
|
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, }) {
|
|
107
156
|
const styles = useStyles();
|
|
108
157
|
const available = candidates.filter(c => !c.directMessagesDisabled);
|
|
109
158
|
const dmDisabled = candidates.filter(c => c.directMessagesDisabled);
|
|
110
|
-
return (<FlatList data={available} keyExtractor={item => item.id} renderItem={({ item }) => <CandidateItem candidate={item}
|
|
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}>
|
|
111
160
|
<Text style={styles.resultsHeading}>Results</Text>
|
|
112
161
|
</View>} ListFooterComponent={<>
|
|
113
162
|
{dmDisabled.length > 0 && (<>
|
|
@@ -116,7 +165,7 @@ function CandidateList({ candidates, hasTruncated, onSelect, }) {
|
|
|
116
165
|
Unavailable for direct messages
|
|
117
166
|
</Text>
|
|
118
167
|
</View>
|
|
119
|
-
{dmDisabled.map(candidate => (<CandidateItem key={candidate.id} candidate={candidate} disabled/>))}
|
|
168
|
+
{dmDisabled.map(candidate => (<CandidateItem key={candidate.id} candidate={candidate} badges={candidateBadges(candidate)} affiliationNames={candidateAffiliationNames(candidate, groups, teams)} disabled/>))}
|
|
120
169
|
</>)}
|
|
121
170
|
{hasTruncated && (<View style={styles.truncatedFooter}>
|
|
122
171
|
<Text variant="secondary" style={styles.truncatedText}>
|
|
@@ -125,22 +174,31 @@ function CandidateList({ candidates, hasTruncated, onSelect, }) {
|
|
|
125
174
|
</View>)}
|
|
126
175
|
</>}/>);
|
|
127
176
|
}
|
|
128
|
-
function CandidateItem({ candidate,
|
|
177
|
+
function CandidateItem({ candidate, badges, affiliationNames, onSelect, disabled = false, }) {
|
|
129
178
|
const styles = useStyles();
|
|
130
|
-
return (<PlatformPressable onPress={disabled ? undefined :
|
|
179
|
+
return (<PlatformPressable onPress={disabled ? undefined : onSelect} accessibilityRole="button" accessibilityLabel={`Select ${candidate.name}`} accessibilityState={{ disabled }}>
|
|
131
180
|
<View style={[styles.row, disabled && styles.candidateDisabled]}>
|
|
132
181
|
<Avatar sourceUri={candidate.avatar} size="lg" showFallback/>
|
|
133
|
-
<
|
|
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>
|
|
134
191
|
</View>
|
|
135
192
|
</PlatformPressable>);
|
|
136
193
|
}
|
|
137
194
|
const useStyles = () => {
|
|
138
|
-
const { bottom } = useSafeAreaInsets();
|
|
139
195
|
const { colors } = useTheme();
|
|
140
196
|
return StyleSheet.create({
|
|
141
197
|
container: {
|
|
142
198
|
flex: 1,
|
|
143
|
-
|
|
199
|
+
},
|
|
200
|
+
candidateResultsContainer: {
|
|
201
|
+
flex: 1,
|
|
144
202
|
},
|
|
145
203
|
toField: {
|
|
146
204
|
paddingHorizontal: 16,
|
|
@@ -218,15 +276,30 @@ const useStyles = () => {
|
|
|
218
276
|
},
|
|
219
277
|
row: {
|
|
220
278
|
flexDirection: 'row',
|
|
221
|
-
alignItems: '
|
|
279
|
+
alignItems: 'flex-start',
|
|
222
280
|
gap: 12,
|
|
223
281
|
paddingHorizontal: 16,
|
|
224
282
|
paddingVertical: 12,
|
|
225
283
|
borderBottomWidth: 1,
|
|
226
|
-
borderColor: colors.
|
|
284
|
+
borderColor: colors.borderColorDefaultDim,
|
|
227
285
|
},
|
|
228
|
-
|
|
286
|
+
rowInfo: {
|
|
229
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,
|
|
230
303
|
},
|
|
231
304
|
candidateDisabled: {
|
|
232
305
|
opacity: 0.5,
|
|
@@ -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":"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","sourcesContent":["import { PlatformPressable } from '@react-navigation/elements'\nimport { useEffect, useState } from 'react'\nimport { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Avatar, Banner, Icon, Spinner, Text } from '../../components'\nimport { ComponentErrorBoundary } from '../../components/page/component_error_boundary'\nimport { useTheme } from '../../hooks'\nimport { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates'\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 [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 return (\n <View style={styles.container}>\n <ToField\n selectedPeople={selectedPeople}\n searchTerm={searchTerm}\n onSearchChange={setSearchTerm}\n onRemove={removePerson}\n onClear={() => setSelectedPeople(new Map())}\n />\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 )\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\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 if (selectedPeople.size >= MAX_RECIPIENTS) {\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\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 const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)\n\n return (\n <CandidateList\n candidates={unselectedCandidates}\n hasTruncated={hasTruncated}\n onSelect={onSelect}\n />\n )\n}\n\nfunction CandidateList({\n candidates,\n hasTruncated,\n onSelect,\n}: {\n candidates: DirectMessageCandidateResource[]\n hasTruncated: boolean\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 }) => <CandidateItem candidate={item} onPress={() => onSelect(item)} />}\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 key={candidate.id} candidate={candidate} disabled />\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 onPress,\n disabled = false,\n}: {\n candidate: DirectMessageCandidateResource\n onPress?: () => void\n disabled?: boolean\n}) {\n const styles = useStyles()\n\n return (\n <PlatformPressable\n onPress={disabled ? undefined : onPress}\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 <Text style={styles.rowName}>{candidate.name}</Text>\n </View>\n </PlatformPressable>\n )\n}\n\nconst useStyles = () => {\n const { bottom } = useSafeAreaInsets()\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n paddingBottom: bottom,\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: 'center',\n gap: 12,\n paddingHorizontal: 16,\n paddingVertical: 12,\n borderBottomWidth: 1,\n borderColor: colors.fillColorNeutral050Base,\n },\n rowName: {\n flex: 1,\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
|
+
{"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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.39.0-rc.
|
|
3
|
+
"version": "3.39.0-rc.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "./src/index.tsx",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"react-native-url-polyfill": "^2.0.0",
|
|
73
73
|
"typescript": "~5.9.2"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "8d382c46296f15192c7c37f40fe98538c5944999"
|
|
76
76
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { PlatformPressable } from '@react-navigation/elements'
|
|
2
|
+
import { StackActions, useNavigation } from '@react-navigation/native'
|
|
2
3
|
import { useEffect, useState } from 'react'
|
|
3
4
|
import { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { Avatar, Badge, Banner, Icon, Spinner, Text } from '../../components'
|
|
6
|
+
import { ActionButton } from '../../components/display/action_button'
|
|
6
7
|
import { ComponentErrorBoundary } from '../../components/page/component_error_boundary'
|
|
7
8
|
import { useTheme } from '../../hooks'
|
|
9
|
+
import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations'
|
|
8
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'
|
|
9
13
|
import { DirectMessageCandidateResource } from '../../types/resources/direct_message_candidate'
|
|
10
14
|
import { ConversationSelectRecipientsScreenProps } from './types/screen_props'
|
|
11
15
|
|
|
@@ -15,6 +19,7 @@ export function ConversationSelectDirectMessageRecipientsScreen(
|
|
|
15
19
|
_props: ConversationSelectRecipientsScreenProps
|
|
16
20
|
) {
|
|
17
21
|
const styles = useStyles()
|
|
22
|
+
const navigation = useNavigation()
|
|
18
23
|
const [searchTerm, setSearchTerm] = useState('')
|
|
19
24
|
const [debouncedTerm, setDebouncedTerm] = useState('')
|
|
20
25
|
const [selectedPeople, setSelectedPeople] = useState<Map<string, DirectMessageCandidateResource>>(
|
|
@@ -41,8 +46,37 @@ export function ConversationSelectDirectMessageRecipientsScreen(
|
|
|
41
46
|
})
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
const recipientIds = [...selectedPeople.keys()]
|
|
50
|
+
const { warnings, validationPending } = useDirectMessageConversationValidate({ recipientIds })
|
|
51
|
+
|
|
52
|
+
const handleSuccess = (conversationId: number) => {
|
|
53
|
+
navigation.getParent()?.goBack()
|
|
54
|
+
navigation.dispatch(StackActions.push('Conversation', { conversation_id: conversationId }))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { findOrCreateConversation, directMessageExists, isFinding, isError } =
|
|
58
|
+
useFindOrCreateDirectMessageConversation({ recipientIds, onSuccess: handleSuccess })
|
|
59
|
+
|
|
60
|
+
const buttonText = (() => {
|
|
61
|
+
if (selectedPeople.size === 0) return 'Start conversation'
|
|
62
|
+
if (selectedPeople.size === 1) {
|
|
63
|
+
const firstName = selectedPeople.values().next().value!.name.split(' ')[0]
|
|
64
|
+
return directMessageExists ? `Open message with ${firstName}` : `Message ${firstName}`
|
|
65
|
+
}
|
|
66
|
+
return directMessageExists
|
|
67
|
+
? `Open direct message (${selectedPeople.size})`
|
|
68
|
+
: `Start direct message (${selectedPeople.size})`
|
|
69
|
+
})()
|
|
70
|
+
|
|
44
71
|
return (
|
|
45
72
|
<View style={styles.container}>
|
|
73
|
+
{isError && (
|
|
74
|
+
<Banner
|
|
75
|
+
appearance="error"
|
|
76
|
+
description="There was an issue starting the conversation. Please try again."
|
|
77
|
+
style={styles.errorBanner}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
46
80
|
<ToField
|
|
47
81
|
selectedPeople={selectedPeople}
|
|
48
82
|
searchTerm={searchTerm}
|
|
@@ -50,22 +84,33 @@ export function ConversationSelectDirectMessageRecipientsScreen(
|
|
|
50
84
|
onRemove={removePerson}
|
|
51
85
|
onClear={() => setSelectedPeople(new Map())}
|
|
52
86
|
/>
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
<View style={styles.candidateResultsContainer}>
|
|
88
|
+
<ComponentErrorBoundary
|
|
89
|
+
key={debouncedTerm}
|
|
90
|
+
fallback={
|
|
91
|
+
<Banner
|
|
92
|
+
appearance="error"
|
|
93
|
+
description="Couldn't load people right now. Try again."
|
|
94
|
+
style={styles.errorBanner}
|
|
95
|
+
/>
|
|
96
|
+
}
|
|
97
|
+
>
|
|
98
|
+
<CandidateResults
|
|
99
|
+
term={debouncedTerm}
|
|
100
|
+
selectedPeople={selectedPeople}
|
|
101
|
+
onSelect={selectPerson}
|
|
60
102
|
/>
|
|
103
|
+
</ComponentErrorBoundary>
|
|
104
|
+
</View>
|
|
105
|
+
<ActionButton
|
|
106
|
+
title={buttonText}
|
|
107
|
+
disabled={
|
|
108
|
+
selectedPeople.size === 0 || validationPending || warnings.length > 0 || isFinding
|
|
61
109
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
onSelect={selectPerson}
|
|
67
|
-
/>
|
|
68
|
-
</ComponentErrorBoundary>
|
|
110
|
+
loading={validationPending || isFinding}
|
|
111
|
+
onPress={() => findOrCreateConversation(recipientIds)}
|
|
112
|
+
warnings={warnings}
|
|
113
|
+
/>
|
|
69
114
|
</View>
|
|
70
115
|
)
|
|
71
116
|
}
|
|
@@ -150,6 +195,7 @@ function CandidateResults({
|
|
|
150
195
|
}) {
|
|
151
196
|
const styles = useStyles()
|
|
152
197
|
const { data, isFetching } = useDirectMessageCandidates(term)
|
|
198
|
+
const { groups, teams } = useDirectMessageAffiliations()
|
|
153
199
|
|
|
154
200
|
if (term.length < 1) {
|
|
155
201
|
if (selectedPeople.size > 0) return null
|
|
@@ -165,7 +211,9 @@ function CandidateResults({
|
|
|
165
211
|
)
|
|
166
212
|
}
|
|
167
213
|
|
|
168
|
-
|
|
214
|
+
const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS
|
|
215
|
+
|
|
216
|
+
if (isAtLimit) {
|
|
169
217
|
return (
|
|
170
218
|
<View style={styles.emptyState}>
|
|
171
219
|
<Text variant="secondary" style={styles.emptyStateSubtitle}>
|
|
@@ -176,6 +224,7 @@ function CandidateResults({
|
|
|
176
224
|
}
|
|
177
225
|
|
|
178
226
|
const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id))
|
|
227
|
+
const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)
|
|
179
228
|
|
|
180
229
|
if (isFetching && unselectedCandidates.length === 0) {
|
|
181
230
|
return (
|
|
@@ -197,24 +246,52 @@ function CandidateResults({
|
|
|
197
246
|
)
|
|
198
247
|
}
|
|
199
248
|
|
|
200
|
-
const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)
|
|
201
|
-
|
|
202
249
|
return (
|
|
203
250
|
<CandidateList
|
|
204
251
|
candidates={unselectedCandidates}
|
|
205
252
|
hasTruncated={hasTruncated}
|
|
253
|
+
groups={groups}
|
|
254
|
+
teams={teams}
|
|
206
255
|
onSelect={onSelect}
|
|
207
256
|
/>
|
|
208
257
|
)
|
|
209
258
|
}
|
|
210
259
|
|
|
260
|
+
function candidateBadges(candidate: DirectMessageCandidateResource) {
|
|
261
|
+
const badges = []
|
|
262
|
+
if (candidate.directMessagesDisabled) badges.push({ title: 'DMs off' })
|
|
263
|
+
if (candidate.under_18) badges.push({ title: 'Under 18' })
|
|
264
|
+
return badges
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function candidateAffiliationNames(
|
|
268
|
+
candidate: DirectMessageCandidateResource,
|
|
269
|
+
groups: Map<number, string>,
|
|
270
|
+
teams: Map<number, string>
|
|
271
|
+
) {
|
|
272
|
+
return [
|
|
273
|
+
...candidate.groups.flatMap(id => {
|
|
274
|
+
const name = groups.get(id)
|
|
275
|
+
return name ? [name] : []
|
|
276
|
+
}),
|
|
277
|
+
...candidate.teams.flatMap(id => {
|
|
278
|
+
const name = teams.get(id)
|
|
279
|
+
return name ? [name] : []
|
|
280
|
+
}),
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
|
|
211
284
|
function CandidateList({
|
|
212
285
|
candidates,
|
|
213
286
|
hasTruncated,
|
|
287
|
+
groups,
|
|
288
|
+
teams,
|
|
214
289
|
onSelect,
|
|
215
290
|
}: {
|
|
216
291
|
candidates: DirectMessageCandidateResource[]
|
|
217
292
|
hasTruncated: boolean
|
|
293
|
+
groups: Map<number, string>
|
|
294
|
+
teams: Map<number, string>
|
|
218
295
|
onSelect: (candidate: DirectMessageCandidateResource) => void
|
|
219
296
|
}) {
|
|
220
297
|
const styles = useStyles()
|
|
@@ -225,7 +302,14 @@ function CandidateList({
|
|
|
225
302
|
<FlatList<DirectMessageCandidateResource>
|
|
226
303
|
data={available}
|
|
227
304
|
keyExtractor={item => item.id}
|
|
228
|
-
renderItem={({ item }) =>
|
|
305
|
+
renderItem={({ item }) => (
|
|
306
|
+
<CandidateItem
|
|
307
|
+
candidate={item}
|
|
308
|
+
badges={candidateBadges(item)}
|
|
309
|
+
affiliationNames={candidateAffiliationNames(item, groups, teams)}
|
|
310
|
+
onSelect={() => onSelect(item)}
|
|
311
|
+
/>
|
|
312
|
+
)}
|
|
229
313
|
ListHeaderComponent={
|
|
230
314
|
<View style={styles.resultsHeader}>
|
|
231
315
|
<Text style={styles.resultsHeading}>Results</Text>
|
|
@@ -241,7 +325,13 @@ function CandidateList({
|
|
|
241
325
|
</Text>
|
|
242
326
|
</View>
|
|
243
327
|
{dmDisabled.map(candidate => (
|
|
244
|
-
<CandidateItem
|
|
328
|
+
<CandidateItem
|
|
329
|
+
key={candidate.id}
|
|
330
|
+
candidate={candidate}
|
|
331
|
+
badges={candidateBadges(candidate)}
|
|
332
|
+
affiliationNames={candidateAffiliationNames(candidate, groups, teams)}
|
|
333
|
+
disabled
|
|
334
|
+
/>
|
|
245
335
|
))}
|
|
246
336
|
</>
|
|
247
337
|
)}
|
|
@@ -260,38 +350,57 @@ function CandidateList({
|
|
|
260
350
|
|
|
261
351
|
function CandidateItem({
|
|
262
352
|
candidate,
|
|
263
|
-
|
|
353
|
+
badges,
|
|
354
|
+
affiliationNames,
|
|
355
|
+
onSelect,
|
|
264
356
|
disabled = false,
|
|
265
357
|
}: {
|
|
266
358
|
candidate: DirectMessageCandidateResource
|
|
267
|
-
|
|
359
|
+
badges: { title: string }[]
|
|
360
|
+
affiliationNames: string[]
|
|
361
|
+
onSelect?: () => void
|
|
268
362
|
disabled?: boolean
|
|
269
363
|
}) {
|
|
270
364
|
const styles = useStyles()
|
|
271
365
|
|
|
272
366
|
return (
|
|
273
367
|
<PlatformPressable
|
|
274
|
-
onPress={disabled ? undefined :
|
|
368
|
+
onPress={disabled ? undefined : onSelect}
|
|
275
369
|
accessibilityRole="button"
|
|
276
370
|
accessibilityLabel={`Select ${candidate.name}`}
|
|
277
371
|
accessibilityState={{ disabled }}
|
|
278
372
|
>
|
|
279
373
|
<View style={[styles.row, disabled && styles.candidateDisabled]}>
|
|
280
374
|
<Avatar sourceUri={candidate.avatar} size="lg" showFallback />
|
|
281
|
-
<
|
|
375
|
+
<View style={styles.rowInfo}>
|
|
376
|
+
<Text style={styles.rowName}>{candidate.name}</Text>
|
|
377
|
+
{affiliationNames.length > 0 && (
|
|
378
|
+
<Text style={styles.rowAffiliations} numberOfLines={2}>
|
|
379
|
+
{affiliationNames.join(', ')}
|
|
380
|
+
</Text>
|
|
381
|
+
)}
|
|
382
|
+
{badges.length > 0 && (
|
|
383
|
+
<View style={styles.badgeRow}>
|
|
384
|
+
{badges.map(({ title }) => (
|
|
385
|
+
<Badge key={title} label={title} />
|
|
386
|
+
))}
|
|
387
|
+
</View>
|
|
388
|
+
)}
|
|
389
|
+
</View>
|
|
282
390
|
</View>
|
|
283
391
|
</PlatformPressable>
|
|
284
392
|
)
|
|
285
393
|
}
|
|
286
394
|
|
|
287
395
|
const useStyles = () => {
|
|
288
|
-
const { bottom } = useSafeAreaInsets()
|
|
289
396
|
const { colors } = useTheme()
|
|
290
397
|
|
|
291
398
|
return StyleSheet.create({
|
|
292
399
|
container: {
|
|
293
400
|
flex: 1,
|
|
294
|
-
|
|
401
|
+
},
|
|
402
|
+
candidateResultsContainer: {
|
|
403
|
+
flex: 1,
|
|
295
404
|
},
|
|
296
405
|
toField: {
|
|
297
406
|
paddingHorizontal: 16,
|
|
@@ -369,16 +478,32 @@ const useStyles = () => {
|
|
|
369
478
|
},
|
|
370
479
|
row: {
|
|
371
480
|
flexDirection: 'row',
|
|
372
|
-
alignItems: '
|
|
481
|
+
alignItems: 'flex-start',
|
|
373
482
|
gap: 12,
|
|
374
483
|
paddingHorizontal: 16,
|
|
375
484
|
paddingVertical: 12,
|
|
376
485
|
borderBottomWidth: 1,
|
|
377
|
-
borderColor: colors.
|
|
486
|
+
borderColor: colors.borderColorDefaultDim,
|
|
378
487
|
},
|
|
379
|
-
|
|
488
|
+
rowInfo: {
|
|
380
489
|
flex: 1,
|
|
490
|
+
gap: 2,
|
|
381
491
|
},
|
|
492
|
+
rowName: {
|
|
493
|
+
fontSize: 15,
|
|
494
|
+
fontWeight: '500',
|
|
495
|
+
},
|
|
496
|
+
rowAffiliations: {
|
|
497
|
+
fontSize: 12,
|
|
498
|
+
color: colors.textColorDefaultSecondary,
|
|
499
|
+
},
|
|
500
|
+
badgeRow: {
|
|
501
|
+
flexDirection: 'row',
|
|
502
|
+
flexWrap: 'wrap',
|
|
503
|
+
gap: 4,
|
|
504
|
+
marginTop: 4,
|
|
505
|
+
},
|
|
506
|
+
|
|
382
507
|
candidateDisabled: {
|
|
383
508
|
opacity: 0.5,
|
|
384
509
|
},
|