@planningcenter/chat-react-native 4.4.0-rc.0 → 4.4.0-rc.2

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 (51) hide show
  1. package/build/components/conversation/message.d.ts +3 -1
  2. package/build/components/conversation/message.d.ts.map +1 -1
  3. package/build/components/conversation/message.js +183 -158
  4. package/build/components/conversation/message.js.map +1 -1
  5. package/build/components/conversation/message_list.d.ts.map +1 -1
  6. package/build/components/conversation/message_list.js +143 -88
  7. package/build/components/conversation/message_list.js.map +1 -1
  8. package/build/hooks/use_animated_message_background_color.d.ts +1 -0
  9. package/build/hooks/use_animated_message_background_color.d.ts.map +1 -1
  10. package/build/hooks/use_animated_message_background_color.js +26 -9
  11. package/build/hooks/use_animated_message_background_color.js.map +1 -1
  12. package/build/hooks/use_product_analytics.d.ts +9 -0
  13. package/build/hooks/use_product_analytics.d.ts.map +1 -1
  14. package/build/hooks/use_product_analytics.js +4 -2
  15. package/build/hooks/use_product_analytics.js.map +1 -1
  16. package/build/hooks/use_search_enabled.d.ts +2 -0
  17. package/build/hooks/use_search_enabled.d.ts.map +1 -0
  18. package/build/hooks/use_search_enabled.js +18 -0
  19. package/build/hooks/use_search_enabled.js.map +1 -0
  20. package/build/screens/conversations/components/search_list_header_component.js +3 -3
  21. package/build/screens/conversations/components/search_list_header_component.js.map +1 -1
  22. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  23. package/build/screens/conversations/conversations_screen.js +2 -5
  24. package/build/screens/conversations/conversations_screen.js.map +1 -1
  25. package/build/screens/search/components/conversation_results.d.ts +1 -1
  26. package/build/screens/search/components/conversation_results.d.ts.map +1 -1
  27. package/build/screens/search/components/conversation_results.js +2 -2
  28. package/build/screens/search/components/conversation_results.js.map +1 -1
  29. package/build/screens/search/components/search_results_list.d.ts +7 -2
  30. package/build/screens/search/components/search_results_list.d.ts.map +1 -1
  31. package/build/screens/search/components/search_results_list.js +135 -105
  32. package/build/screens/search/components/search_results_list.js.map +1 -1
  33. package/build/screens/search/search_screen.d.ts.map +1 -1
  34. package/build/screens/search/search_screen.js +69 -31
  35. package/build/screens/search/search_screen.js.map +1 -1
  36. package/package.json +2 -2
  37. package/src/components/conversation/__tests__/message_list.test.tsx +71 -3
  38. package/src/components/conversation/message.tsx +12 -1
  39. package/src/components/conversation/message_list.tsx +26 -1
  40. package/src/hooks/use_animated_message_background_color.ts +37 -12
  41. package/src/hooks/use_product_analytics.ts +3 -1
  42. package/src/hooks/use_search_enabled.ts +9 -0
  43. package/src/screens/conversations/__tests__/conversations_screen.test.tsx +71 -0
  44. package/src/screens/conversations/components/search_list_header_component.tsx +1 -1
  45. package/src/screens/conversations/conversations_screen.tsx +2 -3
  46. package/src/screens/search/__tests__/search_screen.test.tsx +56 -2
  47. package/src/screens/search/components/__tests__/conversation_results.test.tsx +2 -2
  48. package/src/screens/search/components/__tests__/search_results_list.test.tsx +47 -2
  49. package/src/screens/search/components/conversation_results.tsx +7 -3
  50. package/src/screens/search/components/search_results_list.tsx +25 -4
  51. package/src/screens/search/search_screen.tsx +24 -4
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useEffect, useRef } from 'react'
2
2
  import { FlatList, StyleSheet, View } from 'react-native'
3
3
  import { Banner, Spinner, Text, TextButton } from '../../../components'
4
4
  import { useSearchResults } from '../../../hooks/use_search_results'
@@ -14,12 +14,18 @@ import { NoResultsBlankState } from './search_blank_states'
14
14
 
15
15
  const SEARCH_ERROR_MESSAGE = "Couldn't search right now. Try again."
16
16
 
17
+ export interface SearchResultCounts {
18
+ conversationResultCount: number
19
+ messageResultCount: number
20
+ }
21
+
17
22
  interface SearchResultsListProps {
18
23
  term: string
19
- onSelect: (result: SearchResultResource) => void
24
+ onSelect: (result: SearchResultResource, position: number) => void
25
+ onSettled: (term: string, counts: SearchResultCounts) => void
20
26
  }
21
27
 
22
- export function SearchResultsList({ term, onSelect }: SearchResultsListProps) {
28
+ export function SearchResultsList({ term, onSelect, onSettled }: SearchResultsListProps) {
23
29
  const {
24
30
  results,
25
31
  failedTypes,
@@ -32,6 +38,19 @@ export function SearchResultsList({ term, onSelect }: SearchResultsListProps) {
32
38
  } = useSearchResults(term)
33
39
  const conversationResults = results.filter(isConversationResult)
34
40
  const messageResults = results.filter(isMessageResult)
41
+ const settled = !isPending && !isError
42
+
43
+ const settledTermRef = useRef<string | undefined>(undefined)
44
+
45
+ useEffect(() => {
46
+ if (!settled || settledTermRef.current === term) return
47
+
48
+ settledTermRef.current = term
49
+ onSettled(term, {
50
+ conversationResultCount: conversationResults.length,
51
+ messageResultCount: messageResults.length,
52
+ })
53
+ }, [settled, term, conversationResults.length, messageResults.length, onSettled])
35
54
 
36
55
  return (
37
56
  <FlatList
@@ -40,7 +59,9 @@ export function SearchResultsList({ term, onSelect }: SearchResultsListProps) {
40
59
  keyboardShouldPersistTaps="handled"
41
60
  keyboardDismissMode="on-drag"
42
61
  contentContainerStyle={styles.content}
43
- renderItem={({ item }) => <MessageResultRow result={item} onPress={onSelect} />}
62
+ renderItem={({ item, index }) => (
63
+ <MessageResultRow result={item} onPress={() => onSelect(item, index)} />
64
+ )}
44
65
  ListHeaderComponent={
45
66
  <>
46
67
  {conversationResults.length > 0 && (
@@ -3,7 +3,7 @@ import {
3
3
  NativeStackNavigationOptions,
4
4
  NativeStackScreenProps,
5
5
  } from '@react-navigation/native-stack'
6
- import React, { useState } from 'react'
6
+ import React, { useRef, useState } from 'react'
7
7
  import { Keyboard, StyleSheet, View } from 'react-native'
8
8
  import { KeyboardView } from '../../components'
9
9
  import {
@@ -11,10 +11,11 @@ import {
11
11
  withMinimalBack,
12
12
  } from '../../components/display/platform_modal_header_buttons'
13
13
  import { useDebouncedSearchTerm } from '../../hooks/use_debounced_search_term'
14
+ import { analyticsEvents, useProductAnalytics } from '../../hooks/use_product_analytics'
14
15
  import type { SearchResultResource } from '../../types/resources/search_result'
15
16
  import { SearchPromptBlankState } from './components/search_blank_states'
16
17
  import { SearchField } from './components/search_field'
17
- import { SearchResultsList } from './components/search_results_list'
18
+ import { SearchResultsList, type SearchResultCounts } from './components/search_results_list'
18
19
 
19
20
  export const SearchScreenOptions = ({
20
21
  navigation,
@@ -28,9 +29,23 @@ export function SearchScreen() {
28
29
  const navigation = useNavigation()
29
30
  const [term, setTerm] = useState('')
30
31
  const debouncedTerm = useDebouncedSearchTerm(term)
32
+ const { publishEvent } = useProductAnalytics()
33
+ const publishedTerms = useRef(new Set<string>())
31
34
 
32
- const openResult = (result: SearchResultResource) => {
35
+ const publishSearch = (settledTerm: string, counts: SearchResultCounts) => {
36
+ if (publishedTerms.current.has(settledTerm)) return
37
+
38
+ publishedTerms.current.add(settledTerm)
39
+ publishEvent(analyticsEvents.search_performed, {
40
+ term_length: settledTerm.length,
41
+ conversation_result_count: counts.conversationResultCount,
42
+ message_result_count: counts.messageResultCount,
43
+ })
44
+ }
45
+
46
+ const openResult = (result: SearchResultResource, position: number) => {
33
47
  Keyboard.dismiss()
48
+ publishEvent(analyticsEvents.search_result_opened, { result_type: result.type, position })
34
49
 
35
50
  if (result.type === 'conversation') {
36
51
  navigation.navigate('Conversation', {
@@ -51,7 +66,12 @@ export function SearchScreen() {
51
66
  <View style={styles.container} testID="search-screen">
52
67
  <SearchField term={term} onChange={setTerm} />
53
68
  {debouncedTerm.length > 0 ? (
54
- <SearchResultsList key={debouncedTerm} term={debouncedTerm} onSelect={openResult} />
69
+ <SearchResultsList
70
+ key={debouncedTerm}
71
+ term={debouncedTerm}
72
+ onSelect={openResult}
73
+ onSettled={publishSearch}
74
+ />
55
75
  ) : (
56
76
  <SearchPromptBlankState />
57
77
  )}