@planningcenter/chat-react-native 3.5.0-rc.1 → 3.5.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/attachments/audio_attachment.d.ts +2 -2
- package/build/components/conversation/attachments/audio_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/audio_attachment.js +2 -2
- package/build/components/conversation/attachments/audio_attachment.js.map +1 -1
- package/build/components/conversation/attachments/expanded_link.d.ts +2 -2
- package/build/components/conversation/attachments/expanded_link.d.ts.map +1 -1
- package/build/components/conversation/attachments/expanded_link.js +2 -2
- package/build/components/conversation/attachments/expanded_link.js.map +1 -1
- package/build/components/conversation/attachments/generic_file_attachment.d.ts +2 -2
- package/build/components/conversation/attachments/generic_file_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/generic_file_attachment.js +2 -2
- package/build/components/conversation/attachments/generic_file_attachment.js.map +1 -1
- package/build/components/conversation/attachments/giphy_attachment.d.ts +2 -2
- package/build/components/conversation/attachments/giphy_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/giphy_attachment.js +18 -5
- package/build/components/conversation/attachments/giphy_attachment.js.map +1 -1
- package/build/components/conversation/attachments/image_attachment.d.ts +2 -2
- package/build/components/conversation/attachments/image_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/image_attachment.js +3 -3
- package/build/components/conversation/attachments/image_attachment.js.map +1 -1
- package/build/components/conversation/attachments/video_attachment.d.ts +2 -2
- package/build/components/conversation/attachments/video_attachment.d.ts.map +1 -1
- package/build/components/conversation/attachments/video_attachment.js +2 -2
- package/build/components/conversation/attachments/video_attachment.js.map +1 -1
- package/build/components/conversation/empty_conversation_blank_state.js +1 -1
- package/build/components/conversation/empty_conversation_blank_state.js.map +1 -1
- package/build/components/conversation/message.d.ts +5 -2
- package/build/components/conversation/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +11 -9
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/conversation/message_attachments.d.ts +3 -2
- package/build/components/conversation/message_attachments.d.ts.map +1 -1
- package/build/components/conversation/message_attachments.js +9 -9
- package/build/components/conversation/message_attachments.js.map +1 -1
- package/build/components/conversations/conversation_actions.d.ts.map +1 -1
- package/build/components/conversations/conversation_actions.js +1 -1
- package/build/components/conversations/conversation_actions.js.map +1 -1
- package/build/components/conversations/conversation_preview.d.ts.map +1 -1
- package/build/components/conversations/conversation_preview.js +13 -3
- package/build/components/conversations/conversation_preview.js.map +1 -1
- package/build/components/conversations/conversations.js +3 -3
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/display/action_button.d.ts +4 -1
- package/build/components/display/action_button.d.ts.map +1 -1
- package/build/components/display/action_button.js +20 -5
- package/build/components/display/action_button.js.map +1 -1
- package/build/components/display/avatar.d.ts +4 -1
- package/build/components/display/avatar.d.ts.map +1 -1
- package/build/components/display/avatar.js +3 -2
- package/build/components/display/avatar.js.map +1 -1
- package/build/components/display/avatar_group.d.ts +4 -1
- package/build/components/display/avatar_group.d.ts.map +1 -1
- package/build/components/display/avatar_group.js +6 -3
- package/build/components/display/avatar_group.js.map +1 -1
- package/build/components/display/blank_state.d.ts +7 -2
- package/build/components/display/blank_state.d.ts.map +1 -1
- package/build/components/display/blank_state.js +6 -5
- package/build/components/display/blank_state.js.map +1 -1
- package/build/components/display/child_notice.d.ts +2 -1
- package/build/components/display/child_notice.d.ts.map +1 -1
- package/build/components/display/child_notice.js +4 -4
- package/build/components/display/child_notice.js.map +1 -1
- package/build/components/display/heading.d.ts +2 -3
- package/build/components/display/heading.d.ts.map +1 -1
- package/build/components/display/heading.js.map +1 -1
- package/build/components/display/icon.d.ts +2 -1
- package/build/components/display/icon.d.ts.map +1 -1
- package/build/components/display/icon.js +3 -0
- package/build/components/display/icon.js.map +1 -1
- package/build/components/display/icon_button.d.ts +4 -0
- package/build/components/display/icon_button.d.ts.map +1 -1
- package/build/components/display/icon_button.js +32 -0
- package/build/components/display/icon_button.js.map +1 -1
- package/build/components/display/image_attachment_preview.d.ts +14 -0
- package/build/components/display/image_attachment_preview.d.ts.map +1 -0
- package/build/components/display/image_attachment_preview.js +42 -0
- package/build/components/display/image_attachment_preview.js.map +1 -0
- package/build/components/display/index.d.ts +2 -0
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +2 -0
- package/build/components/display/index.js.map +1 -1
- package/build/components/display/keyboard_view.d.ts +2 -1
- package/build/components/display/keyboard_view.d.ts.map +1 -1
- package/build/components/display/keyboard_view.js +13 -11
- package/build/components/display/keyboard_view.js.map +1 -1
- package/build/components/display/person.d.ts.map +1 -1
- package/build/components/display/person.js +4 -1
- package/build/components/display/person.js.map +1 -1
- package/build/components/display/platform_modal_header_buttons.d.ts +15 -0
- package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -0
- package/build/components/display/platform_modal_header_buttons.js +43 -0
- package/build/components/display/platform_modal_header_buttons.js.map +1 -0
- package/build/components/display/video_attachment_preview.d.ts +8 -0
- package/build/components/display/video_attachment_preview.d.ts.map +1 -0
- package/build/components/display/video_attachment_preview.js +71 -0
- package/build/components/display/video_attachment_preview.js.map +1 -0
- package/build/components/group_conversation_list.d.ts +1 -1
- package/build/components/group_conversation_list.d.ts.map +1 -1
- package/build/components/group_conversation_list.js +8 -6
- package/build/components/group_conversation_list.js.map +1 -1
- package/build/components/page/error_boundary.d.ts.map +1 -1
- package/build/components/page/error_boundary.js +4 -1
- package/build/components/page/error_boundary.js.map +1 -1
- package/build/components/primitive/avatar_primitive.d.ts +6 -1
- package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
- package/build/components/primitive/avatar_primitive.js +24 -3
- package/build/components/primitive/avatar_primitive.js.map +1 -1
- package/build/contexts/chat_context.d.ts +1 -0
- package/build/contexts/chat_context.d.ts.map +1 -1
- package/build/contexts/chat_context.js +5 -3
- package/build/contexts/chat_context.js.map +1 -1
- package/build/hooks/groups/use_group_members_for_new_conversation.d.ts +14 -196
- package/build/hooks/groups/use_group_members_for_new_conversation.d.ts.map +1 -1
- package/build/hooks/groups/use_group_members_for_new_conversation.js +2 -2
- package/build/hooks/groups/use_group_members_for_new_conversation.js.map +1 -1
- package/build/hooks/use_conversation.d.ts.map +1 -1
- package/build/hooks/use_conversation.js +7 -1
- package/build/hooks/use_conversation.js.map +1 -1
- package/build/hooks/use_giphy.js.map +1 -1
- package/build/hooks/use_report_bug_action.d.ts +5 -0
- package/build/hooks/use_report_bug_action.d.ts.map +1 -0
- package/build/hooks/use_report_bug_action.js +30 -0
- package/build/hooks/use_report_bug_action.js.map +1 -0
- package/build/navigation/index.d.ts +5 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +5 -0
- package/build/navigation/index.js.map +1 -1
- package/build/screens/attachment_actions/attachment_actions_screen.d.ts +6 -2
- package/build/screens/attachment_actions/attachment_actions_screen.d.ts.map +1 -1
- package/build/screens/attachment_actions/attachment_actions_screen.js +16 -16
- package/build/screens/attachment_actions/attachment_actions_screen.js.map +1 -1
- package/build/screens/attachment_actions/hooks/useDeleteAttachment.d.ts +10 -0
- package/build/screens/attachment_actions/hooks/useDeleteAttachment.d.ts.map +1 -0
- package/build/screens/attachment_actions/hooks/useDeleteAttachment.js +29 -0
- package/build/screens/attachment_actions/hooks/useDeleteAttachment.js.map +1 -0
- package/build/screens/bug_report_screen.d.ts +5 -0
- package/build/screens/bug_report_screen.d.ts.map +1 -0
- package/build/screens/bug_report_screen.js +237 -0
- package/build/screens/bug_report_screen.js.map +1 -0
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +29 -10
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_new/components/form_list.d.ts +3 -1
- package/build/screens/conversation_new/components/form_list.d.ts.map +1 -1
- package/build/screens/conversation_new/components/form_list.js +6 -2
- package/build/screens/conversation_new/components/form_list.js.map +1 -1
- package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
- package/build/screens/conversation_new/components/groups_form.js +3 -6
- package/build/screens/conversation_new/components/groups_form.js.map +1 -1
- package/build/screens/conversation_new/components/services_form.js +1 -1
- package/build/screens/conversation_new/components/services_form.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +3 -5
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +7 -2
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.d.ts.map +1 -1
- package/build/screens/design_system_screen.js +29 -4
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/types/resources/denormalized_attachment_resource.d.ts +2 -2
- package/build/types/resources/denormalized_attachment_resource.js.map +1 -1
- package/build/types/resources/member_ability.d.ts +1 -0
- package/build/types/resources/member_ability.d.ts.map +1 -1
- package/build/types/resources/member_ability.js.map +1 -1
- package/build/utils/request/conversation.d.ts +2 -1
- package/build/utils/request/conversation.d.ts.map +1 -1
- package/build/utils/request/conversation.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/attachments/audio_attachment.tsx +3 -3
- package/src/components/conversation/attachments/expanded_link.tsx +3 -8
- package/src/components/conversation/attachments/generic_file_attachment.tsx +3 -3
- package/src/components/conversation/attachments/giphy_attachment.tsx +23 -8
- package/src/components/conversation/attachments/image_attachment.tsx +4 -4
- package/src/components/conversation/attachments/video_attachment.tsx +3 -3
- package/src/components/conversation/empty_conversation_blank_state.tsx +1 -1
- package/src/components/conversation/message.tsx +20 -8
- package/src/components/conversation/message_attachments.tsx +18 -11
- package/src/components/conversations/conversation_actions.tsx +1 -0
- package/src/components/conversations/conversation_preview.tsx +24 -3
- package/src/components/conversations/conversations.tsx +3 -3
- package/src/components/display/action_button.tsx +32 -4
- package/src/components/display/avatar.tsx +17 -2
- package/src/components/display/avatar_group.tsx +19 -3
- package/src/components/display/blank_state.tsx +21 -8
- package/src/components/display/child_notice.tsx +7 -4
- package/src/components/display/heading.tsx +2 -2
- package/src/components/display/icon.tsx +4 -1
- package/src/components/display/icon_button.tsx +32 -0
- package/src/components/display/image_attachment_preview.tsx +74 -0
- package/src/components/display/index.ts +2 -0
- package/src/components/display/keyboard_view.tsx +16 -17
- package/src/components/display/person.tsx +4 -1
- package/src/components/display/platform_modal_header_buttons.tsx +83 -0
- package/src/components/display/video_attachment_preview.tsx +105 -0
- package/src/components/group_conversation_list.tsx +14 -7
- package/src/components/page/error_boundary.tsx +4 -1
- package/src/components/primitive/avatar_primitive.tsx +42 -4
- package/src/contexts/chat_context.tsx +6 -3
- package/src/hooks/groups/use_group_members_for_new_conversation.ts +6 -4
- package/src/hooks/use_conversation.ts +7 -1
- package/src/hooks/use_giphy.ts +2 -2
- package/src/hooks/use_report_bug_action.ts +37 -0
- package/src/navigation/index.tsx +5 -0
- package/src/screens/attachment_actions/attachment_actions_screen.tsx +35 -16
- package/src/screens/attachment_actions/hooks/useDeleteAttachment.tsx +46 -0
- package/src/screens/bug_report_screen.tsx +334 -0
- package/src/screens/conversation_details_screen.tsx +41 -7
- package/src/screens/conversation_new/components/form_list.tsx +17 -1
- package/src/screens/conversation_new/components/groups_form.tsx +6 -5
- package/src/screens/conversation_new/components/services_form.tsx +3 -1
- package/src/screens/conversation_screen.tsx +9 -5
- package/src/screens/conversations/conversations_screen.tsx +11 -1
- package/src/screens/design_system_screen.tsx +68 -3
- package/src/types/resources/denormalized_attachment_resource.ts +2 -2
- package/src/types/resources/member_ability.ts +1 -0
- package/src/utils/request/conversation.ts +2 -1
|
@@ -7,10 +7,10 @@ import { PlatformPressable } from '@react-navigation/elements'
|
|
|
7
7
|
|
|
8
8
|
export function ExpandedLink({
|
|
9
9
|
attachment,
|
|
10
|
-
|
|
10
|
+
onMessageLongPress,
|
|
11
11
|
}: {
|
|
12
12
|
attachment: DenormalizedExpandedLinkAttachmentResource
|
|
13
|
-
|
|
13
|
+
onMessageLongPress: () => void
|
|
14
14
|
}) {
|
|
15
15
|
const styles = useStyles()
|
|
16
16
|
const { attributes } = attachment
|
|
@@ -23,12 +23,7 @@ export function ExpandedLink({
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
<PlatformPressable
|
|
27
|
-
style={styles.container}
|
|
28
|
-
onPress={openUrl}
|
|
29
|
-
onLongPress={() => onAttachmentLongPress(attachment)}
|
|
30
|
-
accessibilityHint="Long press for more options"
|
|
31
|
-
>
|
|
26
|
+
<PlatformPressable style={styles.container} onPress={openUrl} onLongPress={onMessageLongPress}>
|
|
32
27
|
{imageUrl && (
|
|
33
28
|
<Image source={{ uri: imageUrl }} style={[styles.image, { aspectRatio }]} alt={title} />
|
|
34
29
|
)}
|
|
@@ -9,10 +9,10 @@ import { PlatformPressable } from '@react-navigation/elements'
|
|
|
9
9
|
|
|
10
10
|
export function GenericFileAttachment({
|
|
11
11
|
attachment,
|
|
12
|
-
|
|
12
|
+
onMessageAttachmentLongPress,
|
|
13
13
|
}: {
|
|
14
14
|
attachment: DenormalizedMessageAttachmentResource
|
|
15
|
-
|
|
15
|
+
onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void
|
|
16
16
|
}) {
|
|
17
17
|
const styles = useStyles()
|
|
18
18
|
const { url, filename, contentType } = attachment.attributes
|
|
@@ -21,7 +21,7 @@ export function GenericFileAttachment({
|
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
23
|
<PlatformPressable
|
|
24
|
-
onLongPress={() =>
|
|
24
|
+
onLongPress={() => onMessageAttachmentLongPress(attachment)}
|
|
25
25
|
accessibilityHint="Long press for more options"
|
|
26
26
|
>
|
|
27
27
|
<AttachmentCard>
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { Text, Image, StyleSheet, Linking
|
|
2
|
+
import { Text, Image, StyleSheet, Linking } from 'react-native'
|
|
3
3
|
import { tokens } from '../../../vendor/tapestry/tokens'
|
|
4
4
|
import { useTheme } from '../../../hooks'
|
|
5
5
|
import { DenormalizedGiphyAttachmentResource } from '../../../types/resources/denormalized_attachment_resource'
|
|
6
|
+
import { PlatformPressable } from '@react-navigation/elements'
|
|
6
7
|
|
|
7
8
|
export function GiphyAttachment({
|
|
8
9
|
attachment,
|
|
9
|
-
|
|
10
|
+
onMessageLongPress,
|
|
10
11
|
}: {
|
|
11
12
|
attachment: DenormalizedGiphyAttachmentResource
|
|
12
|
-
|
|
13
|
+
onMessageLongPress: () => void
|
|
13
14
|
}) {
|
|
14
15
|
const styles = useStyles()
|
|
15
16
|
const { title, titleLink, giphy } = attachment
|
|
16
|
-
const { url
|
|
17
|
+
const { url } = giphy.fixedWidth
|
|
18
|
+
const { width, height } = assertKeysAreNumbers(giphy.fixedWidth)
|
|
17
19
|
|
|
18
20
|
function handlePress() {
|
|
19
21
|
if (titleLink) {
|
|
@@ -23,11 +25,10 @@ export function GiphyAttachment({
|
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
return (
|
|
26
|
-
<
|
|
28
|
+
<PlatformPressable
|
|
27
29
|
onPress={handlePress}
|
|
30
|
+
onLongPress={onMessageLongPress}
|
|
28
31
|
style={styles.container}
|
|
29
|
-
onLongPress={() => onAttachmentLongPress(attachment)}
|
|
30
|
-
accessibilityHint="Long press for more options"
|
|
31
32
|
>
|
|
32
33
|
<Image
|
|
33
34
|
source={{ uri: url }}
|
|
@@ -37,10 +38,24 @@ export function GiphyAttachment({
|
|
|
37
38
|
<Text style={styles.link}>
|
|
38
39
|
<Text style={styles.tag}>/giphy</Text> {title}
|
|
39
40
|
</Text>
|
|
40
|
-
</
|
|
41
|
+
</PlatformPressable>
|
|
41
42
|
)
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
const assertKeysAreNumbers = (obj: Object): Record<any, number> => {
|
|
46
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, assertNumber(value)]))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const assertNumber = (value: string): number => {
|
|
50
|
+
if (typeof value === 'number') return value
|
|
51
|
+
|
|
52
|
+
if (typeof value === 'string' && !isNaN(Number(value))) {
|
|
53
|
+
return Number(value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return 0
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
const useStyles = () => {
|
|
45
60
|
const { colors } = useTheme()
|
|
46
61
|
return StyleSheet.create({
|
|
@@ -38,11 +38,11 @@ export type MetaProps = {
|
|
|
38
38
|
export function ImageAttachment({
|
|
39
39
|
attachment,
|
|
40
40
|
metaProps,
|
|
41
|
-
|
|
41
|
+
onMessageAttachmentLongPress,
|
|
42
42
|
}: {
|
|
43
43
|
attachment: DenormalizedMessageAttachmentResource
|
|
44
44
|
metaProps: MetaProps
|
|
45
|
-
|
|
45
|
+
onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void
|
|
46
46
|
}) {
|
|
47
47
|
const { attributes } = attachment
|
|
48
48
|
const { url, urlMedium, filename, metadata = {} } = attributes
|
|
@@ -83,12 +83,12 @@ export function ImageAttachment({
|
|
|
83
83
|
<PlatformPressable
|
|
84
84
|
style={styles.container}
|
|
85
85
|
onPress={() => setVisible(true)}
|
|
86
|
-
onLongPress={() =>
|
|
86
|
+
onLongPress={() => onMessageAttachmentLongPress(attachment)}
|
|
87
87
|
accessibilityHint="Long press for more options"
|
|
88
88
|
>
|
|
89
89
|
<Image
|
|
90
90
|
source={{ uri: urlMedium || url }}
|
|
91
|
-
style={
|
|
91
|
+
style={styles.image}
|
|
92
92
|
wrapperStyle={styles.imageWrapper}
|
|
93
93
|
alt={filename}
|
|
94
94
|
/>
|
|
@@ -8,10 +8,10 @@ import { PlatformPressable } from '@react-navigation/elements'
|
|
|
8
8
|
|
|
9
9
|
export function VideoAttachment({
|
|
10
10
|
attachment,
|
|
11
|
-
|
|
11
|
+
onMessageAttachmentLongPress,
|
|
12
12
|
}: {
|
|
13
13
|
attachment: DenormalizedMessageAttachmentResource
|
|
14
|
-
|
|
14
|
+
onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void
|
|
15
15
|
}) {
|
|
16
16
|
const { attributes } = attachment
|
|
17
17
|
const { width = MESSAGE_ATTACHMENT_WIDTH_SINGLE, height = MESSAGE_ATTACHMENT_WIDTH_SINGLE } =
|
|
@@ -39,7 +39,7 @@ export function VideoAttachment({
|
|
|
39
39
|
return (
|
|
40
40
|
<View style={styles.container} ref={viewRef}>
|
|
41
41
|
<PlatformPressable
|
|
42
|
-
onLongPress={() =>
|
|
42
|
+
onLongPress={() => onMessageAttachmentLongPress(attachment)}
|
|
43
43
|
accessibilityHint="Long press for more options"
|
|
44
44
|
>
|
|
45
45
|
<Video.Player
|
|
@@ -11,16 +11,22 @@ import { ReactionCountResource } from '../../types/resources/reaction'
|
|
|
11
11
|
import { MessageAttachments } from './message_attachments'
|
|
12
12
|
import ErrorBoundary from '../page/error_boundary'
|
|
13
13
|
import { MessageMarkdown } from './message_markdown'
|
|
14
|
-
import {
|
|
14
|
+
import { DenormalizedMessageAttachmentResource } from '../../types/resources/denormalized_attachment_resource'
|
|
15
15
|
|
|
16
16
|
/** Message
|
|
17
17
|
* Component for display of a message within a conversation list
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
interface MessageProps extends MessageResource {
|
|
20
|
+
canDeleteNonAuthoredMessages: boolean
|
|
21
|
+
conversation_id: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Message(props: MessageProps) {
|
|
25
|
+
const { conversation_id, canDeleteNonAuthoredMessages, text, reactionCounts } = props
|
|
21
26
|
const styles = useMessageStyles(props)
|
|
22
27
|
const navigation = useNavigation()
|
|
23
|
-
|
|
28
|
+
|
|
29
|
+
const handleMessageLongPress = () => {
|
|
24
30
|
navigation.navigate('MessageActions', {
|
|
25
31
|
message_id: props.id,
|
|
26
32
|
conversation_id,
|
|
@@ -34,9 +40,14 @@ export function Message(props: MessageResource & { conversation_id: number }) {
|
|
|
34
40
|
})
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
const
|
|
43
|
+
const handleMessageAttachmentLongPress = (attachment: DenormalizedMessageAttachmentResource) => {
|
|
38
44
|
navigation.navigate('AttachmentActions', {
|
|
39
|
-
attachment,
|
|
45
|
+
attachmentId: attachment?.id,
|
|
46
|
+
attachmentContentType: attachment?.attributes.contentType,
|
|
47
|
+
attachmentUrl: attachment?.attributes.url,
|
|
48
|
+
conversation_id,
|
|
49
|
+
canDeleteNonAuthoredMessages,
|
|
50
|
+
myMessage: props.mine,
|
|
40
51
|
})
|
|
41
52
|
}
|
|
42
53
|
|
|
@@ -54,12 +65,13 @@ export function Message(props: MessageResource & { conversation_id: number }) {
|
|
|
54
65
|
)}
|
|
55
66
|
<View style={styles.messageContent}>
|
|
56
67
|
{!props.mine && <Text variant="tertiary">{props.author.name}</Text>}
|
|
57
|
-
<PlatformPressable style={styles.messageBubble} onLongPress={
|
|
68
|
+
<PlatformPressable style={styles.messageBubble} onLongPress={handleMessageLongPress}>
|
|
58
69
|
<ErrorBoundary>
|
|
59
70
|
<MessageAttachments
|
|
60
71
|
attachments={props.attachments}
|
|
61
72
|
metaProps={metaProps}
|
|
62
|
-
|
|
73
|
+
onMessageAttachmentLongPress={handleMessageAttachmentLongPress}
|
|
74
|
+
onMessageLongPress={handleMessageLongPress}
|
|
63
75
|
/>
|
|
64
76
|
</ErrorBoundary>
|
|
65
77
|
{text && (
|
|
@@ -14,10 +14,11 @@ import { ImageAttachment, type MetaProps } from './attachments/image_attachment'
|
|
|
14
14
|
export function MessageAttachments(props: {
|
|
15
15
|
attachments: DenormalizedAttachmentResource[]
|
|
16
16
|
metaProps: MetaProps
|
|
17
|
-
|
|
17
|
+
onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void
|
|
18
|
+
onMessageLongPress: () => void
|
|
18
19
|
}) {
|
|
19
20
|
const styles = useStyles()
|
|
20
|
-
const { attachments, metaProps,
|
|
21
|
+
const { attachments, metaProps, onMessageAttachmentLongPress, onMessageLongPress } = props
|
|
21
22
|
if (!attachments || attachments.length === 0) return null
|
|
22
23
|
return (
|
|
23
24
|
<View style={styles.attachmentsContainer}>
|
|
@@ -29,7 +30,7 @@ export function MessageAttachments(props: {
|
|
|
29
30
|
key={attachment.id}
|
|
30
31
|
attachment={attachment}
|
|
31
32
|
metaProps={metaProps}
|
|
32
|
-
|
|
33
|
+
onMessageAttachmentLongPress={onMessageAttachmentLongPress}
|
|
33
34
|
/>
|
|
34
35
|
)
|
|
35
36
|
case 'giphy':
|
|
@@ -37,7 +38,7 @@ export function MessageAttachments(props: {
|
|
|
37
38
|
<GiphyAttachment
|
|
38
39
|
key={attachment.id || attachment.titleLink}
|
|
39
40
|
attachment={attachment}
|
|
40
|
-
|
|
41
|
+
onMessageLongPress={onMessageLongPress}
|
|
41
42
|
/>
|
|
42
43
|
)
|
|
43
44
|
case 'ExpandedLink':
|
|
@@ -45,7 +46,7 @@ export function MessageAttachments(props: {
|
|
|
45
46
|
<ExpandedLink
|
|
46
47
|
key={attachment.id}
|
|
47
48
|
attachment={attachment}
|
|
48
|
-
|
|
49
|
+
onMessageLongPress={onMessageLongPress}
|
|
49
50
|
/>
|
|
50
51
|
)
|
|
51
52
|
default:
|
|
@@ -59,11 +60,11 @@ export function MessageAttachments(props: {
|
|
|
59
60
|
function MessageAttachment({
|
|
60
61
|
attachment,
|
|
61
62
|
metaProps,
|
|
62
|
-
|
|
63
|
+
onMessageAttachmentLongPress,
|
|
63
64
|
}: {
|
|
64
65
|
attachment: DenormalizedMessageAttachmentResource
|
|
65
66
|
metaProps: MetaProps
|
|
66
|
-
|
|
67
|
+
onMessageAttachmentLongPress: (attachment: DenormalizedMessageAttachmentResource) => void
|
|
67
68
|
}) {
|
|
68
69
|
const { attributes } = attachment
|
|
69
70
|
const contentType = attributes?.contentType
|
|
@@ -74,22 +75,28 @@ function MessageAttachment({
|
|
|
74
75
|
<ImageAttachment
|
|
75
76
|
attachment={attachment}
|
|
76
77
|
metaProps={metaProps}
|
|
77
|
-
|
|
78
|
+
onMessageAttachmentLongPress={onMessageAttachmentLongPress}
|
|
78
79
|
/>
|
|
79
80
|
)
|
|
80
81
|
case 'video':
|
|
81
82
|
return (
|
|
82
|
-
<VideoAttachment
|
|
83
|
+
<VideoAttachment
|
|
84
|
+
attachment={attachment}
|
|
85
|
+
onMessageAttachmentLongPress={onMessageAttachmentLongPress}
|
|
86
|
+
/>
|
|
83
87
|
)
|
|
84
88
|
case 'audio':
|
|
85
89
|
return (
|
|
86
|
-
<AudioAttachment
|
|
90
|
+
<AudioAttachment
|
|
91
|
+
attachment={attachment}
|
|
92
|
+
onMessageAttachmentLongPress={onMessageAttachmentLongPress}
|
|
93
|
+
/>
|
|
87
94
|
)
|
|
88
95
|
default:
|
|
89
96
|
return (
|
|
90
97
|
<GenericFileAttachment
|
|
91
98
|
attachment={attachment}
|
|
92
|
-
|
|
99
|
+
onMessageAttachmentLongPress={onMessageAttachmentLongPress}
|
|
93
100
|
/>
|
|
94
101
|
)
|
|
95
102
|
}
|
|
@@ -61,6 +61,7 @@ export function ConversationActions({
|
|
|
61
61
|
overshootRight={false}
|
|
62
62
|
onSwipeableOpenStartDrag={handleSwipeableOpen}
|
|
63
63
|
onSwipeableClose={() => setDisabled(false)}
|
|
64
|
+
renderRightActions={() => <></>}
|
|
64
65
|
renderLeftActions={() => (
|
|
65
66
|
<LeftActions conversation={conversation} onClose={handleSwipeableClose} />
|
|
66
67
|
)}
|
|
@@ -33,19 +33,37 @@ export const ConversationPreview = ({
|
|
|
33
33
|
muted,
|
|
34
34
|
} = conversation
|
|
35
35
|
|
|
36
|
+
const emptyConversation = !lastMessageCreatedAt
|
|
37
|
+
const hasAvatarUrls = previewAvatarUrls && previewAvatarUrls.length > 0
|
|
38
|
+
const shouldShowFallback = emptyConversation || !hasAvatarUrls
|
|
39
|
+
const fallbackIconName = emptyConversation ? 'people.noTextMessage' : 'general.person'
|
|
40
|
+
|
|
41
|
+
const conversationPreviewText = lastMessageTextPreview
|
|
42
|
+
? `${lastMessageAuthorName}: ${lastMessageTextPreview}`
|
|
43
|
+
: 'Send your first message'
|
|
44
|
+
|
|
36
45
|
return (
|
|
37
46
|
<ConversationActions
|
|
38
47
|
conversation={conversation}
|
|
39
48
|
style={[styles.previewRow, style]}
|
|
40
49
|
onPress={onPress}
|
|
41
50
|
>
|
|
42
|
-
<AvatarGroup
|
|
51
|
+
<AvatarGroup
|
|
52
|
+
size="lg"
|
|
53
|
+
sourceUris={previewAvatarUrls || []}
|
|
54
|
+
showFallback={shouldShowFallback}
|
|
55
|
+
fallbackIconName={fallbackIconName}
|
|
56
|
+
/>
|
|
43
57
|
<View style={styles.conversationBody}>
|
|
44
58
|
<Heading numberOfLines={1} variant="h3" style={styles.title}>
|
|
45
59
|
{title}
|
|
46
60
|
</Heading>
|
|
47
|
-
<Text
|
|
48
|
-
|
|
61
|
+
<Text
|
|
62
|
+
variant="tertiary"
|
|
63
|
+
numberOfLines={2}
|
|
64
|
+
style={emptyConversation && styles.emptyConversationPreviewText}
|
|
65
|
+
>
|
|
66
|
+
{conversationPreviewText}
|
|
49
67
|
</Text>
|
|
50
68
|
<ConversationBadges visible={showBadges} badges={badges} />
|
|
51
69
|
</View>
|
|
@@ -103,6 +121,9 @@ const useStyles = () => {
|
|
|
103
121
|
flex: 1,
|
|
104
122
|
rowGap: 2,
|
|
105
123
|
},
|
|
124
|
+
emptyConversationPreviewText: {
|
|
125
|
+
color: colors.interaction,
|
|
126
|
+
},
|
|
106
127
|
metaContainer: {
|
|
107
128
|
rowGap: 4,
|
|
108
129
|
alignItems: 'flex-end',
|
|
@@ -4,7 +4,7 @@ import React from 'react'
|
|
|
4
4
|
import { StyleSheet, View } from 'react-native'
|
|
5
5
|
import { useConversationsContext } from '../../contexts/conversations_context'
|
|
6
6
|
import { useTheme } from '../../hooks'
|
|
7
|
-
import {
|
|
7
|
+
import { BlankState } from '../display'
|
|
8
8
|
import { ConversationPreview } from './conversation_preview'
|
|
9
9
|
|
|
10
10
|
interface ConversationsProps {
|
|
@@ -41,7 +41,7 @@ export const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {
|
|
|
41
41
|
ListHeaderComponent={ListHeaderComponent}
|
|
42
42
|
ListEmptyComponent={
|
|
43
43
|
<View style={styles.listEmpty}>
|
|
44
|
-
<
|
|
44
|
+
<BlankState iconName="general.outlinedTextMessage" title="No conversations" />
|
|
45
45
|
</View>
|
|
46
46
|
}
|
|
47
47
|
renderItem={({ item }) => (
|
|
@@ -68,7 +68,7 @@ const useStyles = () => {
|
|
|
68
68
|
flex: 1,
|
|
69
69
|
justifyContent: 'center',
|
|
70
70
|
alignItems: 'center',
|
|
71
|
-
paddingVertical:
|
|
71
|
+
paddingVertical: 32,
|
|
72
72
|
},
|
|
73
73
|
})
|
|
74
74
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
-
import { Animated, LayoutAnimation, StyleSheet } from 'react-native'
|
|
2
|
+
import { Animated, LayoutAnimation, StyleSheet, View } from 'react-native'
|
|
3
3
|
import { Button } from './button'
|
|
4
4
|
import { useEffect } from 'react'
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
6
6
|
import { useTheme } from '../../hooks'
|
|
7
7
|
import { Text } from './text'
|
|
8
|
+
import { IconString } from './icon'
|
|
8
9
|
|
|
9
10
|
export const ActionButton = ({
|
|
10
11
|
visible = true,
|
|
@@ -12,12 +13,16 @@ export const ActionButton = ({
|
|
|
12
13
|
onPress,
|
|
13
14
|
title,
|
|
14
15
|
infoText,
|
|
16
|
+
buttonIconNameLeft,
|
|
17
|
+
secondaryButton,
|
|
15
18
|
}: {
|
|
16
19
|
visible?: boolean
|
|
17
20
|
disabled?: boolean
|
|
18
21
|
onPress: () => void
|
|
19
22
|
title: string
|
|
20
23
|
infoText?: string
|
|
24
|
+
buttonIconNameLeft?: IconString
|
|
25
|
+
secondaryButton?: React.ReactNode
|
|
21
26
|
}) => {
|
|
22
27
|
const styles = useStyles()
|
|
23
28
|
const [show, setShow] = useState(visible)
|
|
@@ -38,7 +43,18 @@ export const ActionButton = ({
|
|
|
38
43
|
{infoText}
|
|
39
44
|
</Text>
|
|
40
45
|
)}
|
|
41
|
-
<
|
|
46
|
+
<View style={styles.buttonRow}>
|
|
47
|
+
{secondaryButton}
|
|
48
|
+
<Button
|
|
49
|
+
variant="fill"
|
|
50
|
+
size="lg"
|
|
51
|
+
onPress={onPress}
|
|
52
|
+
title={title}
|
|
53
|
+
disabled={disabled}
|
|
54
|
+
style={secondaryButton ? null : styles.fullWidthButton}
|
|
55
|
+
iconNameLeft={buttonIconNameLeft}
|
|
56
|
+
/>
|
|
57
|
+
</View>
|
|
42
58
|
</Animated.View>
|
|
43
59
|
)
|
|
44
60
|
}
|
|
@@ -46,16 +62,28 @@ export const ActionButton = ({
|
|
|
46
62
|
const useStyles = () => {
|
|
47
63
|
const { bottom } = useSafeAreaInsets()
|
|
48
64
|
const { colors } = useTheme()
|
|
65
|
+
const containerVerticalPadding = 16
|
|
49
66
|
|
|
50
67
|
return StyleSheet.create({
|
|
51
68
|
container: {
|
|
52
|
-
|
|
69
|
+
backgroundColor: colors.surfaceColor090,
|
|
53
70
|
paddingHorizontal: 24,
|
|
54
|
-
|
|
71
|
+
paddingTop: containerVerticalPadding,
|
|
72
|
+
paddingBottom: bottom + containerVerticalPadding,
|
|
55
73
|
borderTopWidth: 1,
|
|
56
74
|
borderTopColor: colors.fillColorNeutral060,
|
|
57
75
|
gap: 16,
|
|
58
76
|
},
|
|
77
|
+
buttonRow: {
|
|
78
|
+
flexDirection: 'row',
|
|
79
|
+
justifyContent: 'space-between',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
gap: 16,
|
|
82
|
+
flexWrap: 'wrap-reverse',
|
|
83
|
+
},
|
|
84
|
+
fullWidthButton: {
|
|
85
|
+
flexGrow: 1,
|
|
86
|
+
},
|
|
59
87
|
infoText: {
|
|
60
88
|
textAlign: 'center',
|
|
61
89
|
},
|
|
@@ -4,18 +4,33 @@ import AvatarPrimitive, {
|
|
|
4
4
|
type AvatarPresenceProps,
|
|
5
5
|
type AvatarRootProps,
|
|
6
6
|
} from '../primitive/avatar_primitive'
|
|
7
|
+
import { type IconString } from './icon'
|
|
7
8
|
|
|
8
9
|
interface AvatarProps {
|
|
9
10
|
sourceUri: AvatarImageProps['sourceUri']
|
|
10
11
|
size?: AvatarRootProps['size']
|
|
11
12
|
presence?: AvatarPresenceProps['presence']
|
|
13
|
+
showFallback?: boolean
|
|
14
|
+
fallbackIconName?: IconString
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
export function Avatar({
|
|
17
|
+
export function Avatar({
|
|
18
|
+
presence,
|
|
19
|
+
size = 'lg',
|
|
20
|
+
sourceUri,
|
|
21
|
+
showFallback = false,
|
|
22
|
+
fallbackIconName = 'general.person',
|
|
23
|
+
}: AvatarProps) {
|
|
24
|
+
const shouldShowFallback = showFallback || !sourceUri
|
|
25
|
+
|
|
15
26
|
return (
|
|
16
27
|
<AvatarPrimitive.Root size={size}>
|
|
17
28
|
<AvatarPrimitive.Mask>
|
|
18
|
-
|
|
29
|
+
{shouldShowFallback ? (
|
|
30
|
+
<AvatarPrimitive.ImageFallback name={fallbackIconName} />
|
|
31
|
+
) : (
|
|
32
|
+
<AvatarPrimitive.Image sourceUri={sourceUri} />
|
|
33
|
+
)}
|
|
19
34
|
</AvatarPrimitive.Mask>
|
|
20
35
|
{presence && <AvatarPrimitive.Presence presence={presence} />}
|
|
21
36
|
</AvatarPrimitive.Root>
|
|
@@ -3,18 +3,34 @@ import AvatarPrimitive, {
|
|
|
3
3
|
type AvatarGroupProps,
|
|
4
4
|
type AvatarRootProps,
|
|
5
5
|
} from '../primitive/avatar_primitive'
|
|
6
|
+
import { type IconString } from './icon'
|
|
6
7
|
|
|
7
8
|
interface AvatarGroupDisplayProps {
|
|
8
9
|
sourceUris: AvatarGroupProps['sourceUris']
|
|
10
|
+
showFallback?: boolean
|
|
11
|
+
fallbackIconName?: IconString
|
|
9
12
|
size?: AvatarRootProps['size']
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
export function AvatarGroup({
|
|
15
|
+
export function AvatarGroup({
|
|
16
|
+
sourceUris,
|
|
17
|
+
showFallback = false,
|
|
18
|
+
fallbackIconName = 'general.person',
|
|
19
|
+
size = 'lg',
|
|
20
|
+
}: AvatarGroupDisplayProps) {
|
|
21
|
+
const shouldShowFallback = showFallback || !sourceUris || sourceUris.length === 0
|
|
22
|
+
|
|
13
23
|
return (
|
|
14
24
|
<AvatarPrimitive.Root size={size}>
|
|
15
25
|
<AvatarPrimitive.Mask>
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
{shouldShowFallback ? (
|
|
27
|
+
<AvatarPrimitive.ImageFallback name={fallbackIconName} />
|
|
28
|
+
) : (
|
|
29
|
+
<>
|
|
30
|
+
<AvatarPrimitive.Group sourceUris={sourceUris} />
|
|
31
|
+
<AvatarPrimitive.GroupLoader />
|
|
32
|
+
</>
|
|
33
|
+
)}
|
|
18
34
|
</AvatarPrimitive.Mask>
|
|
19
35
|
</AvatarPrimitive.Root>
|
|
20
36
|
)
|
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
import { View, type ViewStyle, StyleSheet } from 'react-native'
|
|
2
|
-
import { Heading } from './heading'
|
|
3
|
-
import { Icon, type IconString } from './icon'
|
|
4
|
-
import { Text } from './text'
|
|
2
|
+
import { Heading, type HeadingProps } from './heading'
|
|
3
|
+
import { Icon, type IconString, type IconStyle } from './icon'
|
|
4
|
+
import { Text, type TextProps } from './text'
|
|
5
5
|
import { useTheme } from '../../hooks'
|
|
6
6
|
import { Button, type ButtonProps } from './button'
|
|
7
7
|
|
|
8
8
|
interface BlankStateProps {
|
|
9
9
|
iconName?: IconString
|
|
10
|
+
iconStyle?: IconStyle
|
|
10
11
|
title: string
|
|
12
|
+
titleStyle?: HeadingProps['style']
|
|
11
13
|
subtitle?: string
|
|
14
|
+
subtitleStyle?: TextProps['style']
|
|
12
15
|
style?: ViewStyle
|
|
13
16
|
buttonProps?: ButtonProps
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
export const BlankState = ({
|
|
19
|
+
export const BlankState = ({
|
|
20
|
+
iconName,
|
|
21
|
+
title,
|
|
22
|
+
titleStyle,
|
|
23
|
+
subtitle,
|
|
24
|
+
subtitleStyle,
|
|
25
|
+
style,
|
|
26
|
+
iconStyle,
|
|
27
|
+
buttonProps,
|
|
28
|
+
}: BlankStateProps) => {
|
|
17
29
|
const styles = useStyles()
|
|
18
30
|
|
|
19
31
|
return (
|
|
20
32
|
<View style={[styles.container, style]}>
|
|
21
|
-
{iconName && <Icon name={iconName} size={32} style={styles.icon} />}
|
|
33
|
+
{iconName && <Icon name={iconName} size={32} style={[styles.icon, iconStyle]} />}
|
|
34
|
+
|
|
22
35
|
<View style={styles.content}>
|
|
23
|
-
<Heading variant="h3" style={styles.baseText}>
|
|
36
|
+
<Heading variant="h3" style={[styles.baseText, titleStyle]}>
|
|
24
37
|
{title}
|
|
25
38
|
</Heading>
|
|
26
39
|
{subtitle && (
|
|
27
|
-
<Text variant="tertiary" style={styles.baseText}>
|
|
40
|
+
<Text variant="tertiary" style={[styles.baseText, subtitleStyle]}>
|
|
28
41
|
{subtitle}
|
|
29
42
|
</Text>
|
|
30
43
|
)}
|
|
@@ -46,7 +59,7 @@ const useStyles = () => {
|
|
|
46
59
|
padding: 16,
|
|
47
60
|
},
|
|
48
61
|
icon: {
|
|
49
|
-
color: colors.
|
|
62
|
+
color: colors.iconColorDefaultDisabled,
|
|
50
63
|
},
|
|
51
64
|
content: {
|
|
52
65
|
alignItems: 'center',
|
|
@@ -13,10 +13,11 @@ import { Text } from './text'
|
|
|
13
13
|
|
|
14
14
|
interface ChildNoticeProps {
|
|
15
15
|
childMembers: MemberResource[]
|
|
16
|
+
showMembers?: boolean
|
|
16
17
|
style?: ViewStyle
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export function ChildNotice({ childMembers, style }: ChildNoticeProps) {
|
|
20
|
+
export function ChildNotice({ childMembers, showMembers = false, style }: ChildNoticeProps) {
|
|
20
21
|
const styles = useStyles()
|
|
21
22
|
const heading = `${pluralize(childMembers.length, 'member')} under age 13`
|
|
22
23
|
|
|
@@ -30,9 +31,11 @@ export function ChildNotice({ childMembers, style }: ChildNoticeProps) {
|
|
|
30
31
|
<BannerPrimitive.Text>
|
|
31
32
|
Under age members cannot chat. They won't see conversations or notifications.
|
|
32
33
|
</BannerPrimitive.Text>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
{showMembers && (
|
|
35
|
+
<View style={styles.childrenWrapper}>
|
|
36
|
+
{childMembers?.map(child => <Child key={child.id} child={child} />)}
|
|
37
|
+
</View>
|
|
38
|
+
)}
|
|
36
39
|
</BannerCollapsible>
|
|
37
40
|
)
|
|
38
41
|
}
|
|
@@ -13,7 +13,7 @@ import { platformFontWeightBold } from '../../utils/styles'
|
|
|
13
13
|
// ====== Component ================
|
|
14
14
|
// =================================
|
|
15
15
|
|
|
16
|
-
interface
|
|
16
|
+
export interface HeadingProps extends ReactNativeTextProps {
|
|
17
17
|
/**
|
|
18
18
|
* Changes the styles and size of the text.
|
|
19
19
|
* Semantically all React Native headings have the same 'hierarchical' level.
|
|
@@ -21,7 +21,7 @@ interface TextProps extends ReactNativeTextProps {
|
|
|
21
21
|
variant?: 'h1' | 'h2' | 'h3' | 'h4'
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function Heading({ style, variant = 'h1', children, ...props }:
|
|
24
|
+
export function Heading({ style, variant = 'h1', children, ...props }: HeadingProps) {
|
|
25
25
|
const styles = useStyles()
|
|
26
26
|
const variantStyleMap = {
|
|
27
27
|
h1: styles.heading1,
|