@planningcenter/chat-react-native 3.39.0-rc.9 → 3.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/conversation/conversation_start_banner.d.ts +10 -0
- package/build/components/conversation/conversation_start_banner.d.ts.map +1 -0
- package/build/components/conversation/conversation_start_banner.js +68 -0
- package/build/components/conversation/conversation_start_banner.js.map +1 -0
- package/build/components/conversation/messages_disabled_banners.d.ts +6 -1
- package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
- package/build/components/conversation/messages_disabled_banners.js +8 -2
- package/build/components/conversation/messages_disabled_banners.js.map +1 -1
- package/build/components/primitive/form_sheet.d.ts +1 -0
- package/build/components/primitive/form_sheet.d.ts.map +1 -1
- package/build/components/primitive/form_sheet.js +17 -7
- package/build/components/primitive/form_sheet.js.map +1 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +2 -0
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
- package/build/hooks/use_conversation_jolt_events.js +2 -2
- package/build/hooks/use_conversation_jolt_events.js.map +1 -1
- package/build/hooks/use_current_person.d.ts.map +1 -1
- package/build/hooks/use_current_person.js +1 -0
- package/build/hooks/use_current_person.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +2 -1
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +9 -3
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_type_screen.js +4 -2
- package/build/screens/conversation_select_type_screen.js.map +1 -1
- package/build/types/jolt_events/conversation_events.d.ts +2 -0
- package/build/types/jolt_events/conversation_events.d.ts.map +1 -1
- package/build/types/jolt_events/conversation_events.js.map +1 -1
- package/build/types/resources/conversation.d.ts +3 -0
- package/build/types/resources/conversation.d.ts.map +1 -1
- package/build/types/resources/conversation.js.map +1 -1
- package/build/types/resources/person.d.ts +1 -0
- package/build/types/resources/person.d.ts.map +1 -1
- package/build/types/resources/person.js.map +1 -1
- package/build/utils/request/conversation.d.ts.map +1 -1
- package/build/utils/request/conversation.js +1 -0
- package/build/utils/request/conversation.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/conversation_start_banner.tsx +102 -0
- package/src/components/conversation/messages_disabled_banners.tsx +16 -2
- package/src/components/primitive/form_sheet.tsx +23 -6
- package/src/hooks/use_conversation.ts +2 -0
- package/src/hooks/use_conversation_jolt_events.ts +3 -2
- package/src/hooks/use_current_person.ts +1 -0
- package/src/screens/conversation_details_screen.tsx +2 -1
- package/src/screens/conversation_screen.tsx +13 -3
- package/src/screens/conversation_select_type_screen.tsx +6 -2
- package/src/types/jolt_events/conversation_events.ts +2 -0
- package/src/types/resources/conversation.ts +4 -0
- package/src/types/resources/person.ts +1 -0
- package/src/utils/request/conversation.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,EAC1C,IAAI,EACJ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,MACgB,EAAE,EAAc,EAAE;IACtD,IAAI,MAAc,CAAA;IAClB,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,GAAG,OAAO,CAAA;IAClB,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,uBAAuB,CAAA;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,mBAAmB,CAAA;IAC9B,CAAC;IAED,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE;YACJ,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,eAAe;YACtB,MAAM;YACN,IAAI;YACJ,KAAK,EAAE,mBAAmB;YAC1B,qBAAqB;YACrB,MAAM,EAAE;gBACN,YAAY,EAAE;oBACZ,YAAY;oBACZ,QAAQ;oBACR,UAAU;oBACV,QAAQ;oBACR,wBAAwB;oBACxB,0BAA0B;oBAC1B,yBAAyB;oBACzB,2BAA2B;oBAC3B,qBAAqB;oBACrB,oBAAoB;oBACpB,mBAAmB;oBACnB,qBAAqB;oBACrB,yBAAyB;oBACzB,gBAAgB;oBAChB,OAAO;oBACP,kBAAkB;oBAClB,OAAO;oBACP,cAAc;oBACd,YAAY;iBACb;gBACD,iBAAiB,EAAE,CAAC,UAAU,CAAC;gBAC/B,iBAAiB,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC;aAC7D;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,oBAAoB,CAAC;SAC1C;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'disabled',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,EAC1C,IAAI,EACJ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,MACgB,EAAE,EAAc,EAAE;IACtD,IAAI,MAAc,CAAA;IAClB,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,GAAG,OAAO,CAAA;IAClB,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,uBAAuB,CAAA;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,mBAAmB,CAAA;IAC9B,CAAC;IAED,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE;YACJ,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,eAAe;YACtB,MAAM;YACN,IAAI;YACJ,KAAK,EAAE,mBAAmB;YAC1B,qBAAqB;YACrB,MAAM,EAAE;gBACN,YAAY,EAAE;oBACZ,YAAY;oBACZ,QAAQ;oBACR,UAAU;oBACV,iBAAiB;oBACjB,QAAQ;oBACR,wBAAwB;oBACxB,0BAA0B;oBAC1B,yBAAyB;oBACzB,2BAA2B;oBAC3B,qBAAqB;oBACrB,oBAAoB;oBACpB,mBAAmB;oBACnB,qBAAqB;oBACrB,yBAAyB;oBACzB,gBAAgB;oBAChB,OAAO;oBACP,kBAAkB;oBAClB,OAAO;oBACP,cAAc;oBACd,YAAY;iBACb;gBACD,iBAAiB,EAAE,CAAC,UAAU,CAAC;gBAC/B,iBAAiB,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC;aAC7D;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,oBAAoB,CAAC;SAC1C;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'disabled',\n 'disabled_reason',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\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
|
|
3
|
+
"version": "3.39.0",
|
|
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": "83c19a53141b104151555769a3043529974a6755"
|
|
76
76
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { StyleSheet, View } from 'react-native'
|
|
3
|
+
import { useTheme } from '../../hooks'
|
|
4
|
+
import type { ConversationResource } from '../../types'
|
|
5
|
+
import { tokens } from '../../vendor/tapestry/tokens'
|
|
6
|
+
import { ConversationAvatar } from '../display/conversation_avatar'
|
|
7
|
+
import { Heading } from '../display/heading'
|
|
8
|
+
import { Icon } from '../display/icon'
|
|
9
|
+
import { Text } from '../display/text'
|
|
10
|
+
|
|
11
|
+
type ConversationStartBannerData = Pick<
|
|
12
|
+
ConversationResource,
|
|
13
|
+
| 'title'
|
|
14
|
+
| 'customAvatarType'
|
|
15
|
+
| 'customAvatarKey'
|
|
16
|
+
| 'customAvatarColor'
|
|
17
|
+
| 'customAvatarImageUrl'
|
|
18
|
+
| 'previewAvatarUrls'
|
|
19
|
+
| 'directMessage'
|
|
20
|
+
>
|
|
21
|
+
|
|
22
|
+
interface ConversationStartBannerProps {
|
|
23
|
+
conversation: ConversationStartBannerData
|
|
24
|
+
hasMessages: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function ConversationStartBanner({
|
|
28
|
+
conversation,
|
|
29
|
+
hasMessages,
|
|
30
|
+
}: ConversationStartBannerProps) {
|
|
31
|
+
const styles = useStyles()
|
|
32
|
+
const { colors } = useTheme()
|
|
33
|
+
const introText = hasMessages
|
|
34
|
+
? 'This is the beginning of your conversation.'
|
|
35
|
+
: 'This conversation is hidden from everyone until you send a message.'
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={styles.container}>
|
|
39
|
+
<ConversationAvatar conversation={conversation} size="2xl" />
|
|
40
|
+
<Heading variant="h3" style={styles.title}>
|
|
41
|
+
{conversation.title}
|
|
42
|
+
</Heading>
|
|
43
|
+
<Text style={styles.subtitle}>{introText}</Text>
|
|
44
|
+
{conversation.directMessage && (
|
|
45
|
+
<View style={styles.safetyNotice}>
|
|
46
|
+
<Icon
|
|
47
|
+
name="general.shieldExclamation"
|
|
48
|
+
size={16}
|
|
49
|
+
color={colors.statusWarningComposedIcon}
|
|
50
|
+
style={styles.safetyIcon}
|
|
51
|
+
/>
|
|
52
|
+
<Text style={styles.safetyText}>
|
|
53
|
+
{
|
|
54
|
+
"This is your church's communication platform. Be kind, stay safe, and report anything concerning."
|
|
55
|
+
}
|
|
56
|
+
</Text>
|
|
57
|
+
</View>
|
|
58
|
+
)}
|
|
59
|
+
</View>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const useStyles = () => {
|
|
64
|
+
const { colors } = useTheme()
|
|
65
|
+
|
|
66
|
+
return StyleSheet.create({
|
|
67
|
+
container: {
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
paddingHorizontal: 16,
|
|
70
|
+
paddingVertical: 24,
|
|
71
|
+
gap: 8,
|
|
72
|
+
},
|
|
73
|
+
title: {
|
|
74
|
+
textAlign: 'center',
|
|
75
|
+
},
|
|
76
|
+
subtitle: {
|
|
77
|
+
textAlign: 'center',
|
|
78
|
+
color: colors.textColorDefaultSecondary,
|
|
79
|
+
fontSize: tokens.fontSizeSm,
|
|
80
|
+
},
|
|
81
|
+
safetyNotice: {
|
|
82
|
+
flexDirection: 'row',
|
|
83
|
+
alignItems: 'flex-start',
|
|
84
|
+
gap: 8,
|
|
85
|
+
marginTop: 4,
|
|
86
|
+
padding: 12,
|
|
87
|
+
backgroundColor: colors.statusWarningComposedBackground,
|
|
88
|
+
borderColor: colors.statusWarningBorder,
|
|
89
|
+
borderWidth: 1,
|
|
90
|
+
borderRadius: 8,
|
|
91
|
+
width: '100%',
|
|
92
|
+
},
|
|
93
|
+
safetyIcon: {
|
|
94
|
+
marginTop: 1,
|
|
95
|
+
},
|
|
96
|
+
safetyText: {
|
|
97
|
+
flex: 1,
|
|
98
|
+
color: colors.statusWarningComposedText,
|
|
99
|
+
fontSize: tokens.fontSizeSm,
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StyleSheet, View, type ViewStyle } from 'react-native'
|
|
2
2
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
3
3
|
import { useTheme } from '../../hooks'
|
|
4
|
+
import type { ConversationDisabledReason } from '../../types'
|
|
4
5
|
import { ADULT_REQUIREMENT_BODY } from '../../utils'
|
|
5
6
|
import { Text } from '../display'
|
|
6
7
|
|
|
@@ -21,10 +22,23 @@ export const MemberMessagesDisabledBanner = () => {
|
|
|
21
22
|
)
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
const DISABLED_REASON_TEXT: Record<ConversationDisabledReason, string> = {
|
|
26
|
+
safety_check: ADULT_REQUIREMENT_BODY,
|
|
27
|
+
direct_messages_disabled: 'Direct messages have been turned off by someone in this conversation.',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DEFAULT_DISABLED_TEXT = 'This conversation has been disabled.'
|
|
31
|
+
|
|
32
|
+
interface ConversationDisabledBannerProps {
|
|
33
|
+
disabledReason?: ConversationDisabledReason
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const ConversationDisabledBanner = ({ disabledReason }: ConversationDisabledBannerProps) => {
|
|
25
37
|
const styles = useStyles()
|
|
38
|
+
const description =
|
|
39
|
+
(disabledReason && DISABLED_REASON_TEXT[disabledReason]) ?? DEFAULT_DISABLED_TEXT
|
|
26
40
|
|
|
27
|
-
return <MessagesDisabledBanner description={
|
|
41
|
+
return <MessagesDisabledBanner description={description} style={styles.memberBanner} />
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
interface MessagesDisabledBannerProps {
|
|
@@ -242,6 +242,7 @@ interface FormSheetActionProps {
|
|
|
242
242
|
accessibilityRole?: AccessibilityRole
|
|
243
243
|
appearance?: FormSheetActionAppearanceUnion
|
|
244
244
|
disabled?: boolean
|
|
245
|
+
disabledReason?: string
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
function FormSheetAction({
|
|
@@ -253,14 +254,17 @@ function FormSheetAction({
|
|
|
253
254
|
accessibilityRole = 'button',
|
|
254
255
|
appearance = 'neutral',
|
|
255
256
|
disabled = false,
|
|
257
|
+
disabledReason,
|
|
256
258
|
}: FormSheetActionProps) {
|
|
257
|
-
const styles = useStyles({ appearance })
|
|
259
|
+
const styles = useStyles({ appearance, disabled })
|
|
258
260
|
|
|
259
261
|
return (
|
|
260
262
|
<PlatformPressable
|
|
261
263
|
onPress={onPress}
|
|
262
264
|
accessibilityLabel={accessibilityLabel}
|
|
263
|
-
accessibilityHint={
|
|
265
|
+
accessibilityHint={
|
|
266
|
+
accessibilityHint ?? (disabled && disabledReason ? disabledReason : undefined)
|
|
267
|
+
}
|
|
264
268
|
accessibilityRole={accessibilityRole}
|
|
265
269
|
style={styles.actionPressable}
|
|
266
270
|
disabled={disabled}
|
|
@@ -268,7 +272,12 @@ function FormSheetAction({
|
|
|
268
272
|
{iconName && (
|
|
269
273
|
<Icon name={iconName} size={16} accessibilityElementsHidden style={styles.actionIcon} />
|
|
270
274
|
)}
|
|
271
|
-
<
|
|
275
|
+
<View style={styles.actionTextBlock}>
|
|
276
|
+
<Text style={styles.actionTitle}>{title}</Text>
|
|
277
|
+
{disabled && disabledReason && (
|
|
278
|
+
<Text style={styles.actionDisabledReason}>{disabledReason}</Text>
|
|
279
|
+
)}
|
|
280
|
+
</View>
|
|
272
281
|
</PlatformPressable>
|
|
273
282
|
)
|
|
274
283
|
}
|
|
@@ -281,9 +290,10 @@ FormSheetAction.displayName = 'FormSheet.Action'
|
|
|
281
290
|
|
|
282
291
|
interface Styles {
|
|
283
292
|
appearance?: FormSheetActionAppearanceUnion
|
|
293
|
+
disabled?: boolean
|
|
284
294
|
}
|
|
285
295
|
|
|
286
|
-
const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
|
|
296
|
+
const useStyles = ({ appearance = 'neutral', disabled = false }: Styles = {}) => {
|
|
287
297
|
const { colors } = useTheme()
|
|
288
298
|
const { height } = useWindowDimensions()
|
|
289
299
|
const { bottom, top } = useSafeAreaInsets()
|
|
@@ -368,10 +378,17 @@ const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
|
|
|
368
378
|
gap: 8,
|
|
369
379
|
},
|
|
370
380
|
actionIcon: {
|
|
371
|
-
color: appearanceColorsMap[appearance].iconColor,
|
|
381
|
+
color: disabled ? colors.textColorDefaultDisabled : appearanceColorsMap[appearance].iconColor,
|
|
382
|
+
},
|
|
383
|
+
actionTextBlock: {
|
|
384
|
+
flex: 1,
|
|
372
385
|
},
|
|
373
386
|
actionTitle: {
|
|
374
|
-
color: appearanceColorsMap[appearance].textColor,
|
|
387
|
+
color: disabled ? colors.textColorDefaultDisabled : appearanceColorsMap[appearance].textColor,
|
|
388
|
+
},
|
|
389
|
+
actionDisabledReason: {
|
|
390
|
+
color: colors.textColorDefaultDisabled,
|
|
391
|
+
fontSize: 12,
|
|
375
392
|
},
|
|
376
393
|
})
|
|
377
394
|
}
|
|
@@ -28,7 +28,9 @@ export const getConversationRequestArgs = ({ conversation_id }: { conversation_i
|
|
|
28
28
|
'custom_avatar_key',
|
|
29
29
|
'custom_avatar_color',
|
|
30
30
|
'custom_avatar_image_url',
|
|
31
|
+
'direct_message',
|
|
31
32
|
'disabled',
|
|
33
|
+
'disabled_reason',
|
|
32
34
|
'member_ability',
|
|
33
35
|
'muted',
|
|
34
36
|
'replies_disabled',
|
|
@@ -26,7 +26,8 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
26
26
|
|
|
27
27
|
const handleUpdatedConversation = useCallback(
|
|
28
28
|
(e: JoltConversationEvent) => {
|
|
29
|
-
const { last_message_idempotent_key, last_message_author_id, disabled } =
|
|
29
|
+
const { last_message_idempotent_key, last_message_author_id, disabled, disabled_reason } =
|
|
30
|
+
e.data.data
|
|
30
31
|
|
|
31
32
|
if (last_message_idempotent_key && last_message_author_id === currentPersonId) {
|
|
32
33
|
completeMessageCreationConversationTracking({
|
|
@@ -37,7 +38,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
37
38
|
|
|
38
39
|
queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {
|
|
39
40
|
if (!prev?.data) return prev
|
|
40
|
-
return { ...prev, data: { ...prev.data, disabled } }
|
|
41
|
+
return { ...prev, data: { ...prev.data, disabled, disabledReason: disabled_reason } }
|
|
41
42
|
})
|
|
42
43
|
|
|
43
44
|
queryClient.invalidateQueries({ queryKey })
|
|
@@ -122,6 +122,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
|
|
|
122
122
|
const canDelete = conversation.memberAbility?.canDelete || false
|
|
123
123
|
const isLeader = conversation.memberAbility?.leader || false
|
|
124
124
|
const isDisabled = conversation.disabled ?? false
|
|
125
|
+
const showAdultRequirementNotice = isDisabled && conversation.disabledReason === 'safety_check'
|
|
125
126
|
|
|
126
127
|
const {
|
|
127
128
|
data: members,
|
|
@@ -350,7 +351,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
|
|
|
350
351
|
sectionInnerStyle: styles.sectionInnerGenderNotice,
|
|
351
352
|
},
|
|
352
353
|
{
|
|
353
|
-
type:
|
|
354
|
+
type: showAdultRequirementNotice ? SectionTypes.view : SectionTypes.hidden,
|
|
354
355
|
data: {
|
|
355
356
|
children: <AdultRequirementNotice />,
|
|
356
357
|
},
|
|
@@ -12,7 +12,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
12
12
|
import { FlatList, Platform, StyleSheet, View } from 'react-native'
|
|
13
13
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
14
14
|
import { Badge, Icon, Text } from '../components'
|
|
15
|
-
import {
|
|
15
|
+
import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
|
|
16
16
|
import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'
|
|
17
17
|
import { Message } from '../components/conversation/message'
|
|
18
18
|
import { MessageForm } from '../components/conversation/message_form'
|
|
@@ -166,7 +166,9 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
166
166
|
<View style={styles.container}>
|
|
167
167
|
<KeyboardView>
|
|
168
168
|
{noMessages ? (
|
|
169
|
-
<
|
|
169
|
+
<View style={styles.emptyState}>
|
|
170
|
+
<ConversationStartBanner conversation={conversation} hasMessages={false} />
|
|
171
|
+
</View>
|
|
170
172
|
) : (
|
|
171
173
|
<FlatList
|
|
172
174
|
inverted
|
|
@@ -176,6 +178,9 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
|
|
|
176
178
|
keyExtractor={item => item.id}
|
|
177
179
|
onScroll={trackScroll}
|
|
178
180
|
scrollEventThrottle={10}
|
|
181
|
+
ListFooterComponent={
|
|
182
|
+
<ConversationStartBanner conversation={conversation} hasMessages={true} />
|
|
183
|
+
}
|
|
179
184
|
renderItem={({ item }) => {
|
|
180
185
|
if (item.type === 'DateSeparator') {
|
|
181
186
|
return <InlineDateSeparator {...item} />
|
|
@@ -239,7 +244,8 @@ function ConversationBottomBar({
|
|
|
239
244
|
replyRootId,
|
|
240
245
|
currentlyEditingMessage,
|
|
241
246
|
}: ConversationBottomBarProps) {
|
|
242
|
-
if (conversation.disabled)
|
|
247
|
+
if (conversation.disabled)
|
|
248
|
+
return <ConversationDisabledBanner disabledReason={conversation.disabledReason} />
|
|
243
249
|
if (!canReply) return <MemberMessagesDisabledBanner />
|
|
244
250
|
return (
|
|
245
251
|
<MessageForm.Root
|
|
@@ -386,6 +392,10 @@ const useStyles = () => {
|
|
|
386
392
|
backgroundColor: navigationTheme.colors.card,
|
|
387
393
|
paddingBottom: bottom,
|
|
388
394
|
},
|
|
395
|
+
emptyState: {
|
|
396
|
+
flex: 1,
|
|
397
|
+
justifyContent: 'center',
|
|
398
|
+
},
|
|
389
399
|
listContainer: {
|
|
390
400
|
paddingVertical: 12,
|
|
391
401
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { StaticScreenProps, 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 type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
|
|
@@ -27,13 +28,14 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
|
|
|
27
28
|
const navigation = useNavigation()
|
|
28
29
|
const entryMode = useNewConversationEntry()
|
|
29
30
|
const { featureEnabled } = useFeatures()
|
|
31
|
+
const { directMessagesDisabled, under_18 } = useCurrentPerson()
|
|
30
32
|
const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
|
|
31
33
|
route.params || {}
|
|
32
34
|
|
|
33
35
|
const filterParams = { chat_group_graph_id, group_source_app_name }
|
|
34
36
|
const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'
|
|
35
37
|
const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'
|
|
36
|
-
const
|
|
38
|
+
const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)
|
|
37
39
|
|
|
38
40
|
const handleFilterPress = () => {
|
|
39
41
|
if (!newConversationFromFilter) return
|
|
@@ -101,10 +103,12 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
|
|
|
101
103
|
accessibilityHint="Opens team selection screen"
|
|
102
104
|
/>
|
|
103
105
|
)}
|
|
104
|
-
{
|
|
106
|
+
{dmFeatureEnabled && !under_18 && (
|
|
105
107
|
<FormSheet.Action
|
|
106
108
|
title="Direct message"
|
|
107
109
|
onPress={handleDirectMessagePress}
|
|
110
|
+
disabled={directMessagesDisabled}
|
|
111
|
+
disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined}
|
|
108
112
|
accessibilityHint="Opens direct message recipient selection screen"
|
|
109
113
|
/>
|
|
110
114
|
)}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'
|
|
2
|
+
import type { ConversationDisabledReason } from '../resources/conversation'
|
|
2
3
|
|
|
3
4
|
type DateString = string
|
|
4
5
|
interface BaseConversationEventData extends Record<string, unknown> {
|
|
@@ -15,6 +16,7 @@ interface BaseConversationEventData extends Record<string, unknown> {
|
|
|
15
16
|
latest_read_message_sort_key?: string
|
|
16
17
|
organization_id: number
|
|
17
18
|
disabled: boolean
|
|
19
|
+
disabled_reason?: ConversationDisabledReason
|
|
18
20
|
replies_disabled: boolean
|
|
19
21
|
subtitle?: string
|
|
20
22
|
title: string
|
|
@@ -4,6 +4,8 @@ import { ConversationMembershipResource } from './conversation_membership'
|
|
|
4
4
|
import { GroupResource } from './group_resource'
|
|
5
5
|
import { MemberAbilityResource } from './member_ability'
|
|
6
6
|
|
|
7
|
+
export type ConversationDisabledReason = 'safety_check' | 'direct_messages_disabled'
|
|
8
|
+
|
|
7
9
|
export interface ConversationResource {
|
|
8
10
|
type: 'Conversation'
|
|
9
11
|
id: number
|
|
@@ -12,7 +14,9 @@ export interface ConversationResource {
|
|
|
12
14
|
conversationMembership?: Partial<ConversationMembershipResource>
|
|
13
15
|
createdAt: string
|
|
14
16
|
deleted?: boolean
|
|
17
|
+
directMessage?: boolean
|
|
15
18
|
disabled?: boolean
|
|
19
|
+
disabledReason?: ConversationDisabledReason
|
|
16
20
|
genderOption?: string | null
|
|
17
21
|
groups?: GroupResource[]
|
|
18
22
|
previewAvatarUrls?: string[]
|