@planningcenter/chat-react-native 3.37.0-rc.2 → 3.37.0-rc.3
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/message.d.ts.map +1 -1
- package/build/components/conversation/message.js +3 -3
- package/build/components/conversation/message.js.map +1 -1
- package/build/components/index.d.ts +2 -0
- package/build/components/index.d.ts.map +1 -1
- package/build/components/index.js +2 -0
- package/build/components/index.js.map +1 -1
- package/build/components/page/component_error_boundary.d.ts +4 -0
- package/build/components/page/component_error_boundary.d.ts.map +1 -0
- package/build/components/page/component_error_boundary.js +8 -0
- package/build/components/page/component_error_boundary.js.map +1 -0
- package/build/components/page/error_boundary.d.ts +13 -10
- package/build/components/page/error_boundary.d.ts.map +1 -1
- package/build/components/page/error_boundary.js +20 -90
- package/build/components/page/error_boundary.js.map +1 -1
- package/build/components/page/page_error_boundary.d.ts +4 -0
- package/build/components/page/page_error_boundary.d.ts.map +1 -0
- package/build/components/page/page_error_boundary.js +80 -0
- package/build/components/page/page_error_boundary.js.map +1 -0
- package/build/navigation/screenLayout.d.ts.map +1 -1
- package/build/navigation/screenLayout.js +5 -3
- package/build/navigation/screenLayout.js.map +1 -1
- package/build/utils/native_adapters/log.d.ts +1 -1
- package/build/utils/native_adapters/log.d.ts.map +1 -1
- package/build/utils/native_adapters/log.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/message.tsx +6 -4
- package/src/components/index.tsx +2 -0
- package/src/components/page/__tests__/component_error_boundary.test.tsx +46 -0
- package/src/components/page/__tests__/error_boundary.test.tsx +93 -0
- package/src/components/page/__tests__/page_error_boundary.test.tsx +77 -0
- package/src/components/page/component_error_boundary.tsx +13 -0
- package/src/components/page/error_boundary.tsx +34 -118
- package/src/components/page/page_error_boundary.tsx +112 -0
- package/src/navigation/screenLayout.tsx +6 -3
- package/src/utils/native_adapters/log.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAoB,MAAM,OAAO,CAAA;AAoBxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAiB7C;;GAEG;AACH,UAAU,YAAa,SAAQ,eAAe;IAC5C,4BAA4B,EAAE,OAAO,CAAA;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,OAAO,CAAC,EACtB,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,GAAG,OAAO,EACX,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAoB,MAAM,OAAO,CAAA;AAoBxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAiB7C;;GAEG;AACH,UAAU,YAAa,SAAQ,eAAe;IAC5C,4BAA4B,EAAE,OAAO,CAAA;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,OAAO,CAAC,EACtB,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,GAAG,OAAO,EACX,EAAE,YAAY,qBA0Rd"}
|
|
@@ -14,7 +14,7 @@ import { pluralize } from '../../utils';
|
|
|
14
14
|
import { isNewMessage } from '../../utils/cache/messages_cache';
|
|
15
15
|
import { Haptic } from '../../utils/native_adapters';
|
|
16
16
|
import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL, MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH, platformFontWeightMedium, } from '../../utils/styles';
|
|
17
|
-
import
|
|
17
|
+
import { ComponentErrorBoundary } from '../page/component_error_boundary';
|
|
18
18
|
import { MessageAttachments } from './message_attachments';
|
|
19
19
|
import { MessageMarkdown } from './message_markdown';
|
|
20
20
|
import { MessageReadReceipts } from './message_read_receipts';
|
|
@@ -149,9 +149,9 @@ export function Message({ canDeleteNonAuthoredMessages, conversation_id, latestR
|
|
|
149
149
|
{isDeletedReplyRootMessage ? (<View style={styles.messageText}>
|
|
150
150
|
<Text style={styles.replyRootDeletedText}>{messageText}</Text>
|
|
151
151
|
</View>) : (<>
|
|
152
|
-
<
|
|
152
|
+
<ComponentErrorBoundary>
|
|
153
153
|
<MessageAttachments attachments={attachments} metaProps={metaProps} onMessageAttachmentLongPress={handleMessageAttachmentLongPress} onMessageLongPress={handleMessageLongPress}/>
|
|
154
|
-
</
|
|
154
|
+
</ComponentErrorBoundary>
|
|
155
155
|
{text && (<View style={styles.messageText}>
|
|
156
156
|
<MessageMarkdown text={text}/>
|
|
157
157
|
</View>)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { some } from 'lodash'\nimport React, { useEffect } from 'react'\nimport {\n AccessibilityActionEvent,\n Pressable,\n StyleSheet,\n useWindowDimensions,\n View,\n} from 'react-native'\nimport Animated from 'react-native-reanimated'\nimport { MessageReaction } from '../../components/conversation/message_reaction'\nimport { Avatar, Icon, Spinner, Text, TextButton, TextInlineButton } from '../../components/display'\nimport {\n useAnimatedMessageBackgroundColor,\n useInteractionGhostBackgroundColor,\n useTheme,\n} from '../../hooks'\nimport { useDeletingIds } from '../../hooks'\nimport { useConversationMessage } from '../../hooks/use_conversation_message'\nimport { useLiveRelativeTime } from '../../hooks/use_live_relative_time'\nimport { useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update'\nimport { MessageResource } from '../../types'\nimport { DenormalizedMessageAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { ReactionCountResource } from '../../types/resources/reaction'\nimport { pluralize } from '../../utils'\nimport { isNewMessage } from '../../utils/cache/messages_cache'\nimport { Haptic } from '../../utils/native_adapters'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n platformFontWeightMedium,\n} from '../../utils/styles'\nimport ErrorBoundary from '../page/error_boundary'\nimport { MessageAttachments } from './message_attachments'\nimport { MessageMarkdown } from './message_markdown'\nimport { MessageReadReceipts } from './message_read_receipts'\nimport { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from './reply_connectors'\n\n/** Message\n * Component for display of a message within a conversation list\n */\ninterface MessageProps extends MessageResource {\n canDeleteNonAuthoredMessages: boolean\n conversation_id: number\n latestReadMessageSortKey?: string\n inReplyScreen?: boolean\n}\n\nexport function Message({\n canDeleteNonAuthoredMessages,\n conversation_id,\n latestReadMessageSortKey,\n inReplyScreen,\n ...message\n}: MessageProps) {\n const { text, reactionCounts, pending, error, attachments, author } = message\n const deletingMessageIds = useDeletingIds('deleteMessage')\n const isDeleting = deletingMessageIds.has(message.id)\n const styles = useMessageStyles(message.mine, isDeleting)\n const navigation = useNavigation()\n const { colors } = useTheme()\n const hasReactions = reactionCounts.length > 0\n const [showMessageMetaToggle, setShowMessageMetaToggle] = React.useState(false)\n const showMessageMeta =\n showMessageMetaToggle || message.myLatestInConversation || !!pending || !!error || false\n const timestamp = useLiveRelativeTime(message.createdAt)\n const wasEdited = Boolean(message.textEditedAt)\n const isPersisted = !isNewMessage(message)\n const [temporarilyHidePendingState, setTemporarilyHidePendingState] = React.useState(true)\n const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)\n const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =\n useAnimatedMessageBackgroundColor()\n const { message: replyRootMessage } = useConversationMessage({\n conversation_id,\n messageId: message.replyRootId || '',\n enabled: !!message.replyRootId,\n })\n\n const metaProps = {\n authorName: author.name,\n createdAt: message.createdAt,\n }\n\n const renderAuthor = (!message.mine && message.renderAuthor) || false\n const showReplyCountButton = !inReplyScreen && message.replyRootId === message.id\n const isReplyRootMessage = message.replyRootId === message.id\n const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt\n const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId\n\n const replyCountText = pluralize(message.replyCount, 'reply')\n const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'\n const replyRootAuthorName = message.replyRootId ? replyRootMessage?.author.name : author.name\n const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text\n\n const messageBottomMargin =\n message.lastInGroup || message.nextIsReplyShadowMessage\n ? 16\n : hasReactions || showMessageMeta || showReplyCountButton\n ? 8\n : 4\n\n const messageIsReplyLabel = replyToReplyRootMessage ? 'Reply' : ''\n const attachmentLabel = some(attachments) ? pluralize(attachments.length, 'attachment') : ''\n const replyCountLabel = isReplyRootMessage ? replyCountText : ''\n const accessibilityLabel = `${author?.name || ''} ${messageIsReplyLabel} ${attachmentLabel} ${messageText || ''} ${timestamp} ${replyCountLabel}`\n\n useEffect(() => {\n if (pending) {\n const timer = setTimeout(() => {\n setTemporarilyHidePendingState(false)\n }, 2000)\n return () => clearTimeout(timer)\n }\n return () => {}\n }, [pending])\n\n const retryFailedSaveMutation = useMessageCreateOrUpdate({\n conversationId: conversation_id,\n message,\n })\n\n const handleRetry = () => {\n if (text && error) {\n retryFailedSaveMutation.mutateAsync({\n text,\n attachments: message.attachmentsForCreate,\n })\n }\n }\n\n const handleMessagePress = () => {\n setShowMessageMetaToggle(!showMessageMetaToggle)\n }\n\n const handleMessageLongPress = () => {\n if (!isPersisted) return\n\n Haptic.impactLight()\n navigation.navigate('MessageActions', {\n message_id: message.id,\n conversation_id,\n canDeleteNonAuthoredMessages,\n inReplyScreen,\n reply_root_author_name: replyRootAuthorName,\n })\n }\n\n const handleReactionLongPress = (reaction: ReactionCountResource) => {\n Haptic.impactLight()\n navigation.navigate('Reactions', {\n message_id: message.id,\n conversation_id,\n reaction_value: reaction.value,\n })\n }\n\n const handleMessageAttachmentLongPress = (attachment: DenormalizedMessageAttachmentResource) => {\n Haptic.impactLight()\n navigation.navigate('AttachmentActions', {\n attachmentId: attachment?.id,\n attachmentContentType: attachment?.attributes.contentType,\n attachmentUrl: attachment?.attributes.url,\n conversation_id,\n canDeleteNonAuthoredMessages,\n myMessage: message.mine,\n })\n }\n\n const handleNavigateToReplyPress = () => {\n navigation.navigate('ConversationReply', {\n conversation_id,\n reply_root_id: message.id,\n reply_root_author_name: author.name,\n })\n }\n\n const accessibilityActions = [\n {\n name: 'navigateToReplies',\n label: 'Navigate to replies',\n },\n ]\n\n const handleAccessibilityAction = (event: AccessibilityActionEvent) => {\n if (event.nativeEvent.actionName === 'navigateToReplies') {\n handleNavigateToReplyPress()\n }\n }\n\n return (\n <Pressable\n onLongPress={isDeleting ? undefined : handleMessageLongPress}\n onPress={isDeleting ? undefined : handleMessagePress}\n onPressIn={isDeleting ? undefined : handleMessagePressIn}\n onPressOut={isDeleting ? undefined : handleMessagePressOut}\n android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}\n accessibilityRole=\"button\"\n accessibilityLabel={accessibilityLabel}\n accessibilityHint=\"Long press to view message actions like reacting and copying.\"\n accessibilityActions={isReplyRootMessage ? accessibilityActions : undefined}\n onAccessibilityAction={isReplyRootMessage ? handleAccessibilityAction : undefined}\n disabled={isDeletedReplyRootMessage || isDeleting}\n >\n <Animated.View style={[styles.message, animatedBackgroundColor]}>\n {!message.mine && (\n <View>\n {renderAuthor ? (\n <Avatar\n size={'md'}\n sourceUri={author.avatar}\n style={styles.avatar}\n maxFontSizeMultiplier={1}\n minFontSizeMultiplier={1}\n fallbackIconName={isDeletedReplyRootMessage ? 'publishing.trash' : 'general.person'}\n showFallback={isDeletedReplyRootMessage}\n />\n ) : (\n <View style={styles.avatarPlaceholder} />\n )}\n <TheirReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n </View>\n )}\n <View style={[styles.messageContent, { marginBottom: messageBottomMargin }]}>\n {renderAuthor && !isDeletedReplyRootMessage && (\n <Text variant=\"footnote\" style={styles.authorName}>\n {author.name}\n </Text>\n )}\n <View\n style={styles.messageBubble}\n onLayout={e => setMessageBubbleHeight(e.nativeEvent.layout.height)}\n >\n {isDeletedReplyRootMessage ? (\n <View style={styles.messageText}>\n <Text style={styles.replyRootDeletedText}>{messageText}</Text>\n </View>\n ) : (\n <>\n <ErrorBoundary>\n <MessageAttachments\n attachments={attachments}\n metaProps={metaProps}\n onMessageAttachmentLongPress={handleMessageAttachmentLongPress}\n onMessageLongPress={handleMessageLongPress}\n />\n </ErrorBoundary>\n {text && (\n <View style={styles.messageText}>\n <MessageMarkdown text={text} />\n </View>\n )}\n </>\n )}\n </View>\n {showReplyCountButton && (\n <TextButton\n variant=\"footnote\"\n onPress={handleNavigateToReplyPress}\n style={styles.messageReplyCount}\n accessibilityHint=\"Navigates to reply screen for this message\"\n accessibilityRole=\"link\"\n >\n {replyCountText}\n </TextButton>\n )}\n {hasReactions && !isDeletedReplyRootMessage && (\n <View style={styles.messageReactions}>\n {reactionCounts.map(reaction => (\n <MessageReaction\n key={reaction.value}\n reaction={reaction}\n onLongPress={handleReactionLongPress}\n message={message}\n conversationId={conversation_id}\n />\n ))}\n </View>\n )}\n {showMessageMeta && !isDeletedReplyRootMessage && (\n <View style={styles.messageMeta}>\n {message.mine && !pending && !error && (\n <MessageReadReceipts\n message={message}\n latestReadMessageSortKey={latestReadMessageSortKey}\n />\n )}\n {error ? (\n <View style={styles.errorContainer}>\n {retryFailedSaveMutation.isPending ? (\n <Spinner size={12} />\n ) : (\n <Icon name=\"general.exclamationTriangle\" size={12} style={styles.errorIcon} />\n )}\n <Text variant=\"footnote\" style={styles.errorText}>\n Failed to {isPersisted ? 'edit' : 'send'} |{' '}\n <TextInlineButton\n onPress={handleRetry}\n variant=\"footnote\"\n appearance=\"danger\"\n disabled={retryFailedSaveMutation.isPending}\n >\n Try again\n </TextInlineButton>\n </Text>\n </View>\n ) : pending && (!temporarilyHidePendingState || isPersisted) ? (\n <View style={styles.pendingIndicatorContainer}>\n <Icon\n name=\"general.outlinedClock\"\n size={12}\n color={colors.iconColorDefaultSecondary}\n />\n <Text variant=\"footnote\">{messagePendingLabel}</Text>\n </View>\n ) : isPersisted ? (\n <Text variant=\"footnote\">{timestamp}</Text>\n ) : null}\n {!pending && !error && wasEdited && (\n <Text variant=\"footnote\">\n |{' '}\n <Text variant=\"footnote\" style={styles.editedText}>\n Edited\n </Text>\n </Text>\n )}\n </View>\n )}\n </View>\n {message.mine && (\n <MyReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </Animated.View>\n </Pressable>\n )\n}\n\nconst useMessageStyles = (mine: boolean, isDeleting: boolean) => {\n const { colors } = useTheme()\n const myMessageBackgroundColor = useInteractionGhostBackgroundColor()\n const { width } = useWindowDimensions()\n const tabletWidth = width >= 744 // Smallest iPad Mini's width\n\n const messageBubbleBackgroundColor = mine ? myMessageBackgroundColor : colors.fillColorNeutral070\n\n return StyleSheet.create({\n message: {\n gap: 8,\n flexDirection: mine ? 'row-reverse' : 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n opacity: isDeleting ? 0.5 : 1,\n },\n messageContent: {\n flex: 1,\n gap: 4,\n },\n avatar: {\n marginBottom: AVATAR_CONNECTOR_SPACING,\n },\n avatarPlaceholder: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH, // Same width as avatar\n },\n authorName: {\n fontWeight: platformFontWeightMedium,\n },\n messageBubble: {\n backgroundColor: messageBubbleBackgroundColor,\n borderRadius: 8,\n maxWidth: tabletWidth ? 360 : '80%',\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageText: {\n paddingVertical: 6,\n paddingHorizontal: 8,\n },\n messageReactions: {\n flexDirection: 'row',\n gap: 4,\n justifyContent: mine ? 'flex-end' : 'flex-start',\n },\n messageReplyCount: {\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageMeta: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: mine ? 'flex-end' : 'flex-start',\n gap: 4,\n },\n editedText: {\n fontWeight: platformFontWeightMedium,\n },\n pendingIndicatorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorIcon: {\n color: colors.statusErrorIcon,\n },\n errorText: {\n color: colors.statusErrorText,\n },\n replyRootDeletedText: {\n color: colors.textColorDefaultSecondary,\n fontStyle: 'italic',\n },\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { some } from 'lodash'\nimport React, { useEffect } from 'react'\nimport {\n AccessibilityActionEvent,\n Pressable,\n StyleSheet,\n useWindowDimensions,\n View,\n} from 'react-native'\nimport Animated from 'react-native-reanimated'\nimport { MessageReaction } from '../../components/conversation/message_reaction'\nimport { Avatar, Icon, Spinner, Text, TextButton, TextInlineButton } from '../../components/display'\nimport {\n useAnimatedMessageBackgroundColor,\n useInteractionGhostBackgroundColor,\n useTheme,\n} from '../../hooks'\nimport { useDeletingIds } from '../../hooks'\nimport { useConversationMessage } from '../../hooks/use_conversation_message'\nimport { useLiveRelativeTime } from '../../hooks/use_live_relative_time'\nimport { useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update'\nimport { MessageResource } from '../../types'\nimport { DenormalizedMessageAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { ReactionCountResource } from '../../types/resources/reaction'\nimport { pluralize } from '../../utils'\nimport { isNewMessage } from '../../utils/cache/messages_cache'\nimport { Haptic } from '../../utils/native_adapters'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n platformFontWeightMedium,\n} from '../../utils/styles'\nimport { ComponentErrorBoundary } from '../page/component_error_boundary'\nimport { MessageAttachments } from './message_attachments'\nimport { MessageMarkdown } from './message_markdown'\nimport { MessageReadReceipts } from './message_read_receipts'\nimport { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from './reply_connectors'\n\n/** Message\n * Component for display of a message within a conversation list\n */\ninterface MessageProps extends MessageResource {\n canDeleteNonAuthoredMessages: boolean\n conversation_id: number\n latestReadMessageSortKey?: string\n inReplyScreen?: boolean\n}\n\nexport function Message({\n canDeleteNonAuthoredMessages,\n conversation_id,\n latestReadMessageSortKey,\n inReplyScreen,\n ...message\n}: MessageProps) {\n const { text, reactionCounts, pending, error, attachments, author } = message\n const deletingMessageIds = useDeletingIds('deleteMessage')\n const isDeleting = deletingMessageIds.has(message.id)\n const styles = useMessageStyles(message.mine, isDeleting)\n const navigation = useNavigation()\n const { colors } = useTheme()\n const hasReactions = reactionCounts.length > 0\n const [showMessageMetaToggle, setShowMessageMetaToggle] = React.useState(false)\n const showMessageMeta =\n showMessageMetaToggle || message.myLatestInConversation || !!pending || !!error || false\n const timestamp = useLiveRelativeTime(message.createdAt)\n const wasEdited = Boolean(message.textEditedAt)\n const isPersisted = !isNewMessage(message)\n const [temporarilyHidePendingState, setTemporarilyHidePendingState] = React.useState(true)\n const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)\n const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =\n useAnimatedMessageBackgroundColor()\n const { message: replyRootMessage } = useConversationMessage({\n conversation_id,\n messageId: message.replyRootId || '',\n enabled: !!message.replyRootId,\n })\n\n const metaProps = {\n authorName: author.name,\n createdAt: message.createdAt,\n }\n\n const renderAuthor = (!message.mine && message.renderAuthor) || false\n const showReplyCountButton = !inReplyScreen && message.replyRootId === message.id\n const isReplyRootMessage = message.replyRootId === message.id\n const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt\n const replyToReplyRootMessage = !isReplyRootMessage && !!message.replyRootId\n\n const replyCountText = pluralize(message.replyCount, 'reply')\n const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'\n const replyRootAuthorName = message.replyRootId ? replyRootMessage?.author.name : author.name\n const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text\n\n const messageBottomMargin =\n message.lastInGroup || message.nextIsReplyShadowMessage\n ? 16\n : hasReactions || showMessageMeta || showReplyCountButton\n ? 8\n : 4\n\n const messageIsReplyLabel = replyToReplyRootMessage ? 'Reply' : ''\n const attachmentLabel = some(attachments) ? pluralize(attachments.length, 'attachment') : ''\n const replyCountLabel = isReplyRootMessage ? replyCountText : ''\n const accessibilityLabel = `${author?.name || ''} ${messageIsReplyLabel} ${attachmentLabel} ${\n messageText || ''\n } ${timestamp} ${replyCountLabel}`\n\n useEffect(() => {\n if (pending) {\n const timer = setTimeout(() => {\n setTemporarilyHidePendingState(false)\n }, 2000)\n return () => clearTimeout(timer)\n }\n return () => {}\n }, [pending])\n\n const retryFailedSaveMutation = useMessageCreateOrUpdate({\n conversationId: conversation_id,\n message,\n })\n\n const handleRetry = () => {\n if (text && error) {\n retryFailedSaveMutation.mutateAsync({\n text,\n attachments: message.attachmentsForCreate,\n })\n }\n }\n\n const handleMessagePress = () => {\n setShowMessageMetaToggle(!showMessageMetaToggle)\n }\n\n const handleMessageLongPress = () => {\n if (!isPersisted) return\n\n Haptic.impactLight()\n navigation.navigate('MessageActions', {\n message_id: message.id,\n conversation_id,\n canDeleteNonAuthoredMessages,\n inReplyScreen,\n reply_root_author_name: replyRootAuthorName,\n })\n }\n\n const handleReactionLongPress = (reaction: ReactionCountResource) => {\n Haptic.impactLight()\n navigation.navigate('Reactions', {\n message_id: message.id,\n conversation_id,\n reaction_value: reaction.value,\n })\n }\n\n const handleMessageAttachmentLongPress = (attachment: DenormalizedMessageAttachmentResource) => {\n Haptic.impactLight()\n navigation.navigate('AttachmentActions', {\n attachmentId: attachment?.id,\n attachmentContentType: attachment?.attributes.contentType,\n attachmentUrl: attachment?.attributes.url,\n conversation_id,\n canDeleteNonAuthoredMessages,\n myMessage: message.mine,\n })\n }\n\n const handleNavigateToReplyPress = () => {\n navigation.navigate('ConversationReply', {\n conversation_id,\n reply_root_id: message.id,\n reply_root_author_name: author.name,\n })\n }\n\n const accessibilityActions = [\n {\n name: 'navigateToReplies',\n label: 'Navigate to replies',\n },\n ]\n\n const handleAccessibilityAction = (event: AccessibilityActionEvent) => {\n if (event.nativeEvent.actionName === 'navigateToReplies') {\n handleNavigateToReplyPress()\n }\n }\n\n return (\n <Pressable\n onLongPress={isDeleting ? undefined : handleMessageLongPress}\n onPress={isDeleting ? undefined : handleMessagePress}\n onPressIn={isDeleting ? undefined : handleMessagePressIn}\n onPressOut={isDeleting ? undefined : handleMessagePressOut}\n android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}\n accessibilityRole=\"button\"\n accessibilityLabel={accessibilityLabel}\n accessibilityHint=\"Long press to view message actions like reacting and copying.\"\n accessibilityActions={isReplyRootMessage ? accessibilityActions : undefined}\n onAccessibilityAction={isReplyRootMessage ? handleAccessibilityAction : undefined}\n disabled={isDeletedReplyRootMessage || isDeleting}\n >\n <Animated.View style={[styles.message, animatedBackgroundColor]}>\n {!message.mine && (\n <View>\n {renderAuthor ? (\n <Avatar\n size={'md'}\n sourceUri={author.avatar}\n style={styles.avatar}\n maxFontSizeMultiplier={1}\n minFontSizeMultiplier={1}\n fallbackIconName={isDeletedReplyRootMessage ? 'publishing.trash' : 'general.person'}\n showFallback={isDeletedReplyRootMessage}\n />\n ) : (\n <View style={styles.avatarPlaceholder} />\n )}\n <TheirReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n </View>\n )}\n <View style={[styles.messageContent, { marginBottom: messageBottomMargin }]}>\n {renderAuthor && !isDeletedReplyRootMessage && (\n <Text variant=\"footnote\" style={styles.authorName}>\n {author.name}\n </Text>\n )}\n <View\n style={styles.messageBubble}\n onLayout={e => setMessageBubbleHeight(e.nativeEvent.layout.height)}\n >\n {isDeletedReplyRootMessage ? (\n <View style={styles.messageText}>\n <Text style={styles.replyRootDeletedText}>{messageText}</Text>\n </View>\n ) : (\n <>\n <ComponentErrorBoundary>\n <MessageAttachments\n attachments={attachments}\n metaProps={metaProps}\n onMessageAttachmentLongPress={handleMessageAttachmentLongPress}\n onMessageLongPress={handleMessageLongPress}\n />\n </ComponentErrorBoundary>\n {text && (\n <View style={styles.messageText}>\n <MessageMarkdown text={text} />\n </View>\n )}\n </>\n )}\n </View>\n {showReplyCountButton && (\n <TextButton\n variant=\"footnote\"\n onPress={handleNavigateToReplyPress}\n style={styles.messageReplyCount}\n accessibilityHint=\"Navigates to reply screen for this message\"\n accessibilityRole=\"link\"\n >\n {replyCountText}\n </TextButton>\n )}\n {hasReactions && !isDeletedReplyRootMessage && (\n <View style={styles.messageReactions}>\n {reactionCounts.map(reaction => (\n <MessageReaction\n key={reaction.value}\n reaction={reaction}\n onLongPress={handleReactionLongPress}\n message={message}\n conversationId={conversation_id}\n />\n ))}\n </View>\n )}\n {showMessageMeta && !isDeletedReplyRootMessage && (\n <View style={styles.messageMeta}>\n {message.mine && !pending && !error && (\n <MessageReadReceipts\n message={message}\n latestReadMessageSortKey={latestReadMessageSortKey}\n />\n )}\n {error ? (\n <View style={styles.errorContainer}>\n {retryFailedSaveMutation.isPending ? (\n <Spinner size={12} />\n ) : (\n <Icon name=\"general.exclamationTriangle\" size={12} style={styles.errorIcon} />\n )}\n <Text variant=\"footnote\" style={styles.errorText}>\n Failed to {isPersisted ? 'edit' : 'send'} |{' '}\n <TextInlineButton\n onPress={handleRetry}\n variant=\"footnote\"\n appearance=\"danger\"\n disabled={retryFailedSaveMutation.isPending}\n >\n Try again\n </TextInlineButton>\n </Text>\n </View>\n ) : pending && (!temporarilyHidePendingState || isPersisted) ? (\n <View style={styles.pendingIndicatorContainer}>\n <Icon\n name=\"general.outlinedClock\"\n size={12}\n color={colors.iconColorDefaultSecondary}\n />\n <Text variant=\"footnote\">{messagePendingLabel}</Text>\n </View>\n ) : isPersisted ? (\n <Text variant=\"footnote\">{timestamp}</Text>\n ) : null}\n {!pending && !error && wasEdited && (\n <Text variant=\"footnote\">\n |{' '}\n <Text variant=\"footnote\" style={styles.editedText}>\n Edited\n </Text>\n </Text>\n )}\n </View>\n )}\n </View>\n {message.mine && (\n <MyReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </Animated.View>\n </Pressable>\n )\n}\n\nconst useMessageStyles = (mine: boolean, isDeleting: boolean) => {\n const { colors } = useTheme()\n const myMessageBackgroundColor = useInteractionGhostBackgroundColor()\n const { width } = useWindowDimensions()\n const tabletWidth = width >= 744 // Smallest iPad Mini's width\n\n const messageBubbleBackgroundColor = mine ? myMessageBackgroundColor : colors.fillColorNeutral070\n\n return StyleSheet.create({\n message: {\n gap: 8,\n flexDirection: mine ? 'row-reverse' : 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n opacity: isDeleting ? 0.5 : 1,\n },\n messageContent: {\n flex: 1,\n gap: 4,\n },\n avatar: {\n marginBottom: AVATAR_CONNECTOR_SPACING,\n },\n avatarPlaceholder: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH, // Same width as avatar\n },\n authorName: {\n fontWeight: platformFontWeightMedium,\n },\n messageBubble: {\n backgroundColor: messageBubbleBackgroundColor,\n borderRadius: 8,\n maxWidth: tabletWidth ? 360 : '80%',\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageText: {\n paddingVertical: 6,\n paddingHorizontal: 8,\n },\n messageReactions: {\n flexDirection: 'row',\n gap: 4,\n justifyContent: mine ? 'flex-end' : 'flex-start',\n },\n messageReplyCount: {\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageMeta: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: mine ? 'flex-end' : 'flex-start',\n gap: 4,\n },\n editedText: {\n fontWeight: platformFontWeightMedium,\n },\n pendingIndicatorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorIcon: {\n color: colors.statusErrorIcon,\n },\n errorText: {\n color: colors.statusErrorText,\n },\n replyRootDeletedText: {\n color: colors.textColorDefaultSecondary,\n fontStyle: 'italic',\n },\n })\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './conversations/conversations';
|
|
2
|
+
export * from './page/component_error_boundary';
|
|
2
3
|
export * from './page/error_boundary';
|
|
4
|
+
export * from './page/page_error_boundary';
|
|
3
5
|
export * from './display';
|
|
4
6
|
export * from './group_conversation_list';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,WAAW,CAAA;AACzB,cAAc,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,WAAW,CAAA;AACzB,cAAc,2BAA2B,CAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './conversations/conversations';
|
|
2
|
+
export * from './page/component_error_boundary';
|
|
2
3
|
export * from './page/error_boundary';
|
|
4
|
+
export * from './page/page_error_boundary';
|
|
3
5
|
export * from './display';
|
|
4
6
|
export * from './group_conversation_list';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,WAAW,CAAA;AACzB,cAAc,2BAA2B,CAAA","sourcesContent":["export * from './conversations/conversations'\nexport * from './page/error_boundary'\nexport * from './display'\nexport * from './group_conversation_list'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.tsx"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,WAAW,CAAA;AACzB,cAAc,2BAA2B,CAAA","sourcesContent":["export * from './conversations/conversations'\nexport * from './page/component_error_boundary'\nexport * from './page/error_boundary'\nexport * from './page/page_error_boundary'\nexport * from './display'\nexport * from './group_conversation_list'\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
import { ErrorBoundaryProps } from './error_boundary';
|
|
3
|
+
export declare function ComponentErrorBoundary({ children, ...props }: PropsWithChildren<ErrorBoundaryProps>): React.JSX.Element;
|
|
4
|
+
//# sourceMappingURL=component_error_boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component_error_boundary.d.ts","sourceRoot":"","sources":["../../../src/components/page/component_error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,EAAiB,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAEpE,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,qBAMvC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ErrorBoundary } from './error_boundary';
|
|
3
|
+
export function ComponentErrorBoundary({ children, ...props }) {
|
|
4
|
+
return (<ErrorBoundary scope="component" fallback={null} {...props}>
|
|
5
|
+
{children}
|
|
6
|
+
</ErrorBoundary>);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=component_error_boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component_error_boundary.js","sourceRoot":"","sources":["../../../src/components/page/component_error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAA;AAEpE,MAAM,UAAU,sBAAsB,CAAC,EACrC,QAAQ,EACR,GAAG,KAAK,EAC8B;IACtC,OAAO,CACL,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CACzD;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,aAAa,CAAC,CACjB,CAAA;AACH,CAAC","sourcesContent":["import React, { PropsWithChildren } from 'react'\nimport { ErrorBoundary, ErrorBoundaryProps } from './error_boundary'\n\nexport function ComponentErrorBoundary({\n children,\n ...props\n}: PropsWithChildren<ErrorBoundaryProps>) {\n return (\n <ErrorBoundary scope=\"component\" fallback={null} {...props}>\n {children}\n </ErrorBoundary>\n )\n}\n"]}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ReportErrorScope } from '../../utils/native_adapters/log';
|
|
3
|
+
export type ErrorBoundaryFallback = React.ReactNode | ((error: Error, reset: () => void) => React.ReactNode);
|
|
4
|
+
export type ErrorBoundaryProps = {
|
|
5
|
+
scope?: ReportErrorScope;
|
|
6
|
+
screenName?: string;
|
|
7
|
+
fallback?: ErrorBoundaryFallback;
|
|
8
|
+
};
|
|
3
9
|
type ErrorBoundaryState = {
|
|
4
|
-
error:
|
|
5
|
-
unsubscriber: () => void;
|
|
10
|
+
error: Error | null;
|
|
6
11
|
};
|
|
7
|
-
declare class ErrorBoundary extends React.Component<PropsWithChildren<{
|
|
8
|
-
onReset?: () => void;
|
|
9
|
-
}>> {
|
|
12
|
+
export declare class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBoundaryProps>, ErrorBoundaryState> {
|
|
10
13
|
state: ErrorBoundaryState;
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState;
|
|
15
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
|
|
13
16
|
handleReset: () => void;
|
|
14
|
-
render():
|
|
17
|
+
render(): React.ReactNode;
|
|
15
18
|
}
|
|
16
|
-
export
|
|
19
|
+
export {};
|
|
17
20
|
//# sourceMappingURL=error_boundary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error_boundary.d.ts","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error_boundary.d.ts","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAGlE,MAAM,MAAM,qBAAqB,GAC7B,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC,CAAA;AAE1D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,qBAAqB,CAAA;CACjC,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB,CAAA;AAED,qBAAa,aAAc,SAAQ,KAAK,CAAC,SAAS,CAChD,iBAAiB,CAAC,kBAAkB,CAAC,EACrC,kBAAkB,CACnB;IACC,KAAK,EAAE,kBAAkB,CAAkB;IAE3C,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS;IAW1D,WAAW,aAEV;IAED,MAAM;CAQP"}
|
|
@@ -1,101 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
4
|
-
import { onAuthRefresh } from '../../utils/auth_events';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Log } from '../../utils/native_adapters/configuration';
|
|
5
3
|
import { ResponseError } from '../../utils/response_error';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
error
|
|
10
|
-
unsubscriber: () => { },
|
|
11
|
-
};
|
|
12
|
-
componentDidCatch(error) {
|
|
13
|
-
this.handleError(error);
|
|
4
|
+
export class ErrorBoundary extends React.Component {
|
|
5
|
+
state = { error: null };
|
|
6
|
+
static getDerivedStateFromError(error) {
|
|
7
|
+
return { error };
|
|
14
8
|
}
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
componentDidCatch(error, errorInfo) {
|
|
10
|
+
if (error instanceof ResponseError)
|
|
11
|
+
return;
|
|
12
|
+
Log.reportError(error, {
|
|
13
|
+
componentStack: errorInfo.componentStack ?? undefined,
|
|
14
|
+
scope: this.props.scope,
|
|
15
|
+
screenName: this.props.screenName,
|
|
16
|
+
tags: { team: 'chat', package: 'chat-react-native' },
|
|
17
|
+
});
|
|
17
18
|
}
|
|
18
19
|
handleReset = () => {
|
|
19
|
-
this.props.onReset?.();
|
|
20
20
|
this.setState({ error: null });
|
|
21
21
|
};
|
|
22
22
|
render() {
|
|
23
|
-
if (this.state.error)
|
|
24
|
-
return <ErrorView error={this.state.error} onReset={this.handleReset}/>;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
23
|
+
if (!this.state.error)
|
|
27
24
|
return this.props.children;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
function
|
|
32
|
-
const { reset } = useQueryErrorResetBoundary();
|
|
33
|
-
const handleReset = useCallback(() => {
|
|
34
|
-
reset();
|
|
35
|
-
onReset();
|
|
36
|
-
}, [reset, onReset]);
|
|
37
|
-
useEffect(() => handleReset, [handleReset]);
|
|
38
|
-
if (error instanceof ResponseError) {
|
|
39
|
-
return <ResponseErrorView response={error.response} onReset={handleReset}/>;
|
|
40
|
-
}
|
|
41
|
-
if (isNetworkError(error)) {
|
|
42
|
-
return (<ErrorContent heading={'Problem connecting!'} body={'Check your internet connection and try again.'}/>);
|
|
25
|
+
const { fallback } = this.props;
|
|
26
|
+
if (fallback === undefined)
|
|
27
|
+
return null;
|
|
28
|
+
return typeof fallback === 'function' ? fallback(this.state.error, this.handleReset) : fallback;
|
|
43
29
|
}
|
|
44
|
-
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'}/>;
|
|
45
|
-
}
|
|
46
|
-
function isNetworkError(error) {
|
|
47
|
-
const isError = error instanceof Error;
|
|
48
|
-
const networkFailedMessages = [
|
|
49
|
-
'Network request failed',
|
|
50
|
-
'Network request timed out',
|
|
51
|
-
'Failed to fetch',
|
|
52
|
-
];
|
|
53
|
-
if (!isError)
|
|
54
|
-
return false;
|
|
55
|
-
return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message);
|
|
56
|
-
}
|
|
57
|
-
function ResponseErrorView({ response, onReset }) {
|
|
58
|
-
const { status } = response;
|
|
59
|
-
const heading = useMemo(() => {
|
|
60
|
-
switch (status) {
|
|
61
|
-
case 403:
|
|
62
|
-
return 'Permission required';
|
|
63
|
-
case 404:
|
|
64
|
-
return 'Content not found';
|
|
65
|
-
default:
|
|
66
|
-
return 'Oops!';
|
|
67
|
-
}
|
|
68
|
-
}, [status]);
|
|
69
|
-
const body = useMemo(() => {
|
|
70
|
-
switch (status) {
|
|
71
|
-
case 403:
|
|
72
|
-
return 'Contact your administrator for access.';
|
|
73
|
-
case 404:
|
|
74
|
-
return 'If you believe something should be here, please reach out to your administrator.';
|
|
75
|
-
default:
|
|
76
|
-
return 'Something unexpected happened.';
|
|
77
|
-
}
|
|
78
|
-
}, [status]);
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
if (status !== 401)
|
|
81
|
-
return;
|
|
82
|
-
return onAuthRefresh(onReset);
|
|
83
|
-
}, [status, onReset]);
|
|
84
|
-
return <ErrorContent heading={heading} body={body}/>;
|
|
85
|
-
}
|
|
86
|
-
function ErrorContent({ heading, body }) {
|
|
87
|
-
const navigation = useNavigation();
|
|
88
|
-
return (<BlankState.Root>
|
|
89
|
-
<BlankState.Imagery name="people.noTextMessage"/>
|
|
90
|
-
<BlankState.Content>
|
|
91
|
-
<BlankState.Heading>{heading}</BlankState.Heading>
|
|
92
|
-
<BlankState.Text>{body}</BlankState.Text>
|
|
93
|
-
</BlankState.Content>
|
|
94
|
-
<BlankState.Button title="Go back" onPress={navigation.goBack} size="md" accessibilityRole="link"/>
|
|
95
|
-
<BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>
|
|
96
|
-
Report a bug
|
|
97
|
-
</BlankState.TextButton>
|
|
98
|
-
</BlankState.Root>);
|
|
99
30
|
}
|
|
100
|
-
export default ErrorBoundary;
|
|
101
31
|
//# sourceMappingURL=error_boundary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error_boundary.js","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"error_boundary.js","sourceRoot":"","sources":["../../../src/components/page/error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,2CAA2C,CAAA;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAgB1D,MAAM,OAAO,aAAc,SAAQ,KAAK,CAAC,SAGxC;IACC,KAAK,GAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IAE3C,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,KAAK,EAAE,CAAA;IAClB,CAAC;IAED,iBAAiB,CAAC,KAAY,EAAE,SAA0B;QACxD,IAAI,KAAK,YAAY,aAAa;YAAE,OAAM;QAE1C,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE;YACrB,cAAc,EAAE,SAAS,CAAC,cAAc,IAAI,SAAS;YACrD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;YACvB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;YACjC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE;SACrD,CAAC,CAAA;IACJ,CAAC;IAED,WAAW,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAChC,CAAC,CAAA;IAED,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;QAEjD,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAC/B,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,IAAI,CAAA;QAEvC,OAAO,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;IACjG,CAAC;CACF","sourcesContent":["import React, { PropsWithChildren } from 'react'\nimport { Log } from '../../utils/native_adapters/configuration'\nimport { ReportErrorScope } from '../../utils/native_adapters/log'\nimport { ResponseError } from '../../utils/response_error'\n\nexport type ErrorBoundaryFallback =\n | React.ReactNode\n | ((error: Error, reset: () => void) => React.ReactNode)\n\nexport type ErrorBoundaryProps = {\n scope?: ReportErrorScope\n screenName?: string\n fallback?: ErrorBoundaryFallback\n}\n\ntype ErrorBoundaryState = {\n error: Error | null\n}\n\nexport class ErrorBoundary extends React.Component<\n PropsWithChildren<ErrorBoundaryProps>,\n ErrorBoundaryState\n> {\n state: ErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error }\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n if (error instanceof ResponseError) return\n\n Log.reportError(error, {\n componentStack: errorInfo.componentStack ?? undefined,\n scope: this.props.scope,\n screenName: this.props.screenName,\n tags: { team: 'chat', package: 'chat-react-native' },\n })\n }\n\n handleReset = () => {\n this.setState({ error: null })\n }\n\n render() {\n if (!this.state.error) return this.props.children\n\n const { fallback } = this.props\n if (fallback === undefined) return null\n\n return typeof fallback === 'function' ? fallback(this.state.error, this.handleReset) : fallback\n }\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
import { ErrorBoundaryProps } from './error_boundary';
|
|
3
|
+
export declare function PageErrorBoundary({ children, ...props }: PropsWithChildren<ErrorBoundaryProps>): React.JSX.Element;
|
|
4
|
+
//# sourceMappingURL=page_error_boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page_error_boundary.d.ts","sourceRoot":"","sources":["../../../src/components/page/page_error_boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAmC,MAAM,OAAO,CAAA;AAIjF,OAAO,EAAwC,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAM3F,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,qBAM9F"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native';
|
|
2
|
+
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
|
|
3
|
+
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
4
|
+
import { onAuthRefresh } from '../../utils/auth_events';
|
|
5
|
+
import { ResponseError } from '../../utils/response_error';
|
|
6
|
+
import BlankState from '../primitive/blank_state_primitive';
|
|
7
|
+
import { ErrorBoundary } from './error_boundary';
|
|
8
|
+
const renderPageFallback = (error, reset) => (<ErrorView error={error} reset={reset}/>);
|
|
9
|
+
export function PageErrorBoundary({ children, ...props }) {
|
|
10
|
+
return (<ErrorBoundary scope="screen" fallback={renderPageFallback} {...props}>
|
|
11
|
+
{children}
|
|
12
|
+
</ErrorBoundary>);
|
|
13
|
+
}
|
|
14
|
+
function ErrorView({ error, reset }) {
|
|
15
|
+
const { reset: resetQueries } = useQueryErrorResetBoundary();
|
|
16
|
+
const handleReset = useCallback(() => {
|
|
17
|
+
resetQueries();
|
|
18
|
+
reset();
|
|
19
|
+
}, [resetQueries, reset]);
|
|
20
|
+
useEffect(() => handleReset, [handleReset]);
|
|
21
|
+
if (error instanceof ResponseError) {
|
|
22
|
+
return <ResponseErrorView response={error.response} onReset={handleReset}/>;
|
|
23
|
+
}
|
|
24
|
+
if (isNetworkError(error)) {
|
|
25
|
+
return (<ErrorContent heading={'Problem connecting!'} body={'Check your internet connection and try again.'}/>);
|
|
26
|
+
}
|
|
27
|
+
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'}/>;
|
|
28
|
+
}
|
|
29
|
+
function isNetworkError(error) {
|
|
30
|
+
const networkFailedMessages = [
|
|
31
|
+
'Network request failed',
|
|
32
|
+
'Network request timed out',
|
|
33
|
+
'Failed to fetch',
|
|
34
|
+
];
|
|
35
|
+
return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message);
|
|
36
|
+
}
|
|
37
|
+
function ResponseErrorView({ response, onReset }) {
|
|
38
|
+
const { status } = response;
|
|
39
|
+
const heading = useMemo(() => {
|
|
40
|
+
switch (status) {
|
|
41
|
+
case 403:
|
|
42
|
+
return 'Permission required';
|
|
43
|
+
case 404:
|
|
44
|
+
return 'Content not found';
|
|
45
|
+
default:
|
|
46
|
+
return 'Oops!';
|
|
47
|
+
}
|
|
48
|
+
}, [status]);
|
|
49
|
+
const body = useMemo(() => {
|
|
50
|
+
switch (status) {
|
|
51
|
+
case 403:
|
|
52
|
+
return 'Contact your administrator for access.';
|
|
53
|
+
case 404:
|
|
54
|
+
return 'If you believe something should be here, please reach out to your administrator.';
|
|
55
|
+
default:
|
|
56
|
+
return 'Something unexpected happened.';
|
|
57
|
+
}
|
|
58
|
+
}, [status]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (status !== 401)
|
|
61
|
+
return;
|
|
62
|
+
return onAuthRefresh(onReset);
|
|
63
|
+
}, [status, onReset]);
|
|
64
|
+
return <ErrorContent heading={heading} body={body}/>;
|
|
65
|
+
}
|
|
66
|
+
function ErrorContent({ heading, body }) {
|
|
67
|
+
const navigation = useNavigation();
|
|
68
|
+
return (<BlankState.Root>
|
|
69
|
+
<BlankState.Imagery name="people.noTextMessage"/>
|
|
70
|
+
<BlankState.Content>
|
|
71
|
+
<BlankState.Heading>{heading}</BlankState.Heading>
|
|
72
|
+
<BlankState.Text>{body}</BlankState.Text>
|
|
73
|
+
</BlankState.Content>
|
|
74
|
+
<BlankState.Button title="Go back" onPress={navigation.goBack} size="md" accessibilityRole="link"/>
|
|
75
|
+
<BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>
|
|
76
|
+
Report a bug
|
|
77
|
+
</BlankState.TextButton>
|
|
78
|
+
</BlankState.Root>);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=page_error_boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page_error_boundary.js","sourceRoot":"","sources":["../../../src/components/page/page_error_boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,KAAK,EAAE,EAAqB,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC1D,OAAO,UAAU,MAAM,oCAAoC,CAAA;AAC3D,OAAO,EAAE,aAAa,EAA6C,MAAM,kBAAkB,CAAA;AAE3F,MAAM,kBAAkB,GAA0B,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAClE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAG,CAC1C,CAAA;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAyC;IAC7F,OAAO,CACL,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,KAAK,CAAC,CACpE;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,aAAa,CAAC,CACjB,CAAA;AACH,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAuC;IACtE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,0BAA0B,EAAE,CAAA;IAE5D,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,YAAY,EAAE,CAAA;QACd,KAAK,EAAE,CAAA;IACT,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAA;IAEzB,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAE3C,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;QACnC,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,EAAG,CAAA;IAC9E,CAAC;IAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CACL,CAAC,YAAY,CACX,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAC/B,IAAI,CAAC,CAAC,+CAA+C,CAAC,EACtD,CACH,CAAA;IACH,CAAC;IAED,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,gCAAgC,CAAC,EAAG,CAAA;AACnF,CAAC;AAED,SAAS,cAAc,CAAC,KAAY;IAClC,MAAM,qBAAqB,GAAG;QAC5B,wBAAwB;QACxB,2BAA2B;QAC3B,iBAAiB;KAClB,CAAA;IAED,OAAO,IAAI,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAA+C;IAC3F,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IAE3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,GAAG;gBACN,OAAO,qBAAqB,CAAA;YAC9B,KAAK,GAAG;gBACN,OAAO,mBAAmB,CAAA;YAC5B;gBACE,OAAO,OAAO,CAAA;QAClB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,GAAG;gBACN,OAAO,wCAAwC,CAAA;YACjD,KAAK,GAAG;gBACN,OAAO,kFAAkF,CAAA;YAC3F;gBACE,OAAO,gCAAgC,CAAA;QAC3C,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,GAAG;YAAE,OAAM;QAE1B,OAAO,aAAa,CAAC,OAAO,CAAC,CAAA;IAC/B,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAErB,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAG,CAAA;AACvD,CAAC;AAED,SAAS,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAqC;IACxE,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,OAAO,CACL,CAAC,UAAU,CAAC,IAAI,CACd;MAAA,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAC/C;MAAA,CAAC,UAAU,CAAC,OAAO,CACjB;QAAA,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,CACjD;QAAA,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,IAAI,CAC1C;MAAA,EAAE,UAAU,CAAC,OAAO,CACpB;MAAA,CAAC,UAAU,CAAC,MAAM,CAChB,KAAK,CAAC,SAAS,CACf,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAC3B,IAAI,CAAC,IAAI,CACT,iBAAiB,CAAC,MAAM,EAE1B;MAAA,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CACrE;;MACF,EAAE,UAAU,CAAC,UAAU,CACzB;IAAA,EAAE,UAAU,CAAC,IAAI,CAAC,CACnB,CAAA;AACH,CAAC","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { useQueryErrorResetBoundary } from '@tanstack/react-query'\nimport React, { PropsWithChildren, useCallback, useEffect, useMemo } from 'react'\nimport { onAuthRefresh } from '../../utils/auth_events'\nimport { ResponseError } from '../../utils/response_error'\nimport BlankState from '../primitive/blank_state_primitive'\nimport { ErrorBoundary, ErrorBoundaryFallback, ErrorBoundaryProps } from './error_boundary'\n\nconst renderPageFallback: ErrorBoundaryFallback = (error, reset) => (\n <ErrorView error={error} reset={reset} />\n)\n\nexport function PageErrorBoundary({ children, ...props }: PropsWithChildren<ErrorBoundaryProps>) {\n return (\n <ErrorBoundary scope=\"screen\" fallback={renderPageFallback} {...props}>\n {children}\n </ErrorBoundary>\n )\n}\n\nfunction ErrorView({ error, reset }: { error: Error; reset: () => void }) {\n const { reset: resetQueries } = useQueryErrorResetBoundary()\n\n const handleReset = useCallback(() => {\n resetQueries()\n reset()\n }, [resetQueries, reset])\n\n useEffect(() => handleReset, [handleReset])\n\n if (error instanceof ResponseError) {\n return <ResponseErrorView response={error.response} onReset={handleReset} />\n }\n\n if (isNetworkError(error)) {\n return (\n <ErrorContent\n heading={'Problem connecting!'}\n body={'Check your internet connection and try again.'}\n />\n )\n }\n\n return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />\n}\n\nfunction isNetworkError(error: Error) {\n const networkFailedMessages = [\n 'Network request failed',\n 'Network request timed out',\n 'Failed to fetch',\n ]\n\n return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message)\n}\n\nfunction ResponseErrorView({ response, onReset }: { response: Response; onReset: () => void }) {\n const { status } = response\n\n const heading = useMemo(() => {\n switch (status) {\n case 403:\n return 'Permission required'\n case 404:\n return 'Content not found'\n default:\n return 'Oops!'\n }\n }, [status])\n\n const body = useMemo(() => {\n switch (status) {\n case 403:\n return 'Contact your administrator for access.'\n case 404:\n return 'If you believe something should be here, please reach out to your administrator.'\n default:\n return 'Something unexpected happened.'\n }\n }, [status])\n\n useEffect(() => {\n if (status !== 401) return\n\n return onAuthRefresh(onReset)\n }, [status, onReset])\n\n return <ErrorContent heading={heading} body={body} />\n}\n\nfunction ErrorContent({ heading, body }: { heading: string; body: string }) {\n const navigation = useNavigation()\n\n return (\n <BlankState.Root>\n <BlankState.Imagery name=\"people.noTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>{heading}</BlankState.Heading>\n <BlankState.Text>{body}</BlankState.Text>\n </BlankState.Content>\n <BlankState.Button\n title=\"Go back\"\n onPress={navigation.goBack}\n size=\"md\"\n accessibilityRole=\"link\"\n />\n <BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>\n Report a bug\n </BlankState.TextButton>\n </BlankState.Root>\n )\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenLayout.d.ts","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screenLayout.d.ts","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAA;CAAE,qBAQ1E;AAED,wBAAgB,8BAA8B,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAA;CAAE,qBAQ5F"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { Suspense } from 'react';
|
|
3
|
-
import ErrorBoundary from '../components/page/error_boundary';
|
|
4
4
|
import { DefaultLoading } from '../components/page/loading';
|
|
5
|
+
import { PageErrorBoundary } from '../components/page/page_error_boundary';
|
|
5
6
|
import { ChatAccessGate } from './chat_access_gate';
|
|
6
7
|
export function ScreenLayout({ children }) {
|
|
7
|
-
|
|
8
|
+
const route = useRoute();
|
|
9
|
+
return (<PageErrorBoundary screenName={route.name}>
|
|
8
10
|
<Suspense fallback={<DefaultLoading />}>{children}</Suspense>
|
|
9
|
-
</
|
|
11
|
+
</PageErrorBoundary>);
|
|
10
12
|
}
|
|
11
13
|
export function ScreenLayoutWithChatAccessGate({ children }) {
|
|
12
14
|
return (<ScreenLayout>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenLayout.js","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"screenLayout.js","sourceRoot":"","sources":["../../src/navigation/screenLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAoC;IACzE,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IAExB,OAAO,CACL,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CACxC;MAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,AAAD,EAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAC9D;IAAA,EAAE,iBAAiB,CAAC,CACrB,CAAA;AACH,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,EAAE,QAAQ,EAAoC;IAC3F,OAAO,CACL,CAAC,YAAY,CACX;MAAA,CAAC,cAAc,CACb;QAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,AAAD,EAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAC9D;MAAA,EAAE,cAAc,CAClB;IAAA,EAAE,YAAY,CAAC,CAChB,CAAA;AACH,CAAC","sourcesContent":["import { useRoute } from '@react-navigation/native'\nimport React from 'react'\nimport { Suspense } from 'react'\nimport { DefaultLoading } from '../components/page/loading'\nimport { PageErrorBoundary } from '../components/page/page_error_boundary'\nimport { ChatAccessGate } from './chat_access_gate'\n\nexport function ScreenLayout({ children }: { children: React.ReactElement }) {\n const route = useRoute()\n\n return (\n <PageErrorBoundary screenName={route.name}>\n <Suspense fallback={<DefaultLoading />}>{children}</Suspense>\n </PageErrorBoundary>\n )\n}\n\nexport function ScreenLayoutWithChatAccessGate({ children }: { children: React.ReactElement }) {\n return (\n <ScreenLayout>\n <ChatAccessGate>\n <Suspense fallback={<DefaultLoading />}>{children}</Suspense>\n </ChatAccessGate>\n </ScreenLayout>\n )\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/log.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../../src/utils/native_adapters/log.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAA;AAE9D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC,CAAA;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAChD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAClE;AAED,qBAAa,UAAU;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACjC,aAAa,CAAC,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;gBAEnC,MAAM,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAOlD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;IAMrC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;IAMpC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,kBAAkB;CAQvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/log.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,UAAU;IACrB,OAAO,CAAS;IAChB,OAAO,CAA4B;IACnC,MAAM,CAA2B;IACjC,aAAa,CAAkC;IAE/C,YAAY,SAAoC,EAAE;QAChD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAA;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAA;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;QACzB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,WAAW,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,WAAW,CAAC,KAAY,EAAE,OAA4B;QACpD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC/B,CAAC;CACF","sourcesContent":["export type ReportErrorScope = 'screen' | '
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../../src/utils/native_adapters/log.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,UAAU;IACrB,OAAO,CAAS;IAChB,OAAO,CAA4B;IACnC,MAAM,CAA2B;IACjC,aAAa,CAAkC;IAE/C,YAAY,SAAoC,EAAE;QAChD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAA;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAA;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;QACzB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,WAAW,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QACnC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAA;IACjC,CAAC;IAED,WAAW,CAAC,KAAY,EAAE,OAA4B;QACpD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC/B,CAAC;CACF","sourcesContent":["export type ReportErrorScope = 'screen' | 'component' | 'http'\n\nexport type ReportErrorContext = {\n componentStack?: string\n scope?: ReportErrorScope\n screenName?: string\n tags?: Record<string, string>\n extra?: Record<string, unknown>\n}\n\ninterface LogAdapterConfig {\n enabled: boolean\n error: (message: string, ...args: any[]) => void\n info: (message: string, ...args: any[]) => void\n reportError: (error: Error, context?: ReportErrorContext) => void\n}\n\nexport class LogAdapter {\n enabled: boolean\n onError?: LogAdapterConfig['error']\n onInfo?: LogAdapterConfig['info']\n onReportError?: LogAdapterConfig['reportError']\n\n constructor(config: Partial<LogAdapterConfig> = {}) {\n this.enabled = config.enabled ?? false\n this.onError = config.error\n this.onInfo = config.info\n this.onReportError = config.reportError\n }\n\n error(message: string, ...args: any[]) {\n if (!this.enabled) return\n\n this.onError?.(message, ...args)\n }\n\n info(message: string, ...args: any[]) {\n if (!this.enabled) return\n\n this.onInfo?.(message, ...args)\n }\n\n reportError(error: Error, context?: ReportErrorContext) {\n if (this.onReportError) {\n this.onReportError(error, context)\n return\n }\n\n console.error(error, context)\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.37.0-rc.
|
|
3
|
+
"version": "3.37.0-rc.3",
|
|
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": "0dbe10dae358e399f7fc130a434045c9aa6931e1"
|
|
76
76
|
}
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,
|
|
32
32
|
platformFontWeightMedium,
|
|
33
33
|
} from '../../utils/styles'
|
|
34
|
-
import
|
|
34
|
+
import { ComponentErrorBoundary } from '../page/component_error_boundary'
|
|
35
35
|
import { MessageAttachments } from './message_attachments'
|
|
36
36
|
import { MessageMarkdown } from './message_markdown'
|
|
37
37
|
import { MessageReadReceipts } from './message_read_receipts'
|
|
@@ -103,7 +103,9 @@ export function Message({
|
|
|
103
103
|
const messageIsReplyLabel = replyToReplyRootMessage ? 'Reply' : ''
|
|
104
104
|
const attachmentLabel = some(attachments) ? pluralize(attachments.length, 'attachment') : ''
|
|
105
105
|
const replyCountLabel = isReplyRootMessage ? replyCountText : ''
|
|
106
|
-
const accessibilityLabel = `${author?.name || ''} ${messageIsReplyLabel} ${attachmentLabel} ${
|
|
106
|
+
const accessibilityLabel = `${author?.name || ''} ${messageIsReplyLabel} ${attachmentLabel} ${
|
|
107
|
+
messageText || ''
|
|
108
|
+
} ${timestamp} ${replyCountLabel}`
|
|
107
109
|
|
|
108
110
|
useEffect(() => {
|
|
109
111
|
if (pending) {
|
|
@@ -237,14 +239,14 @@ export function Message({
|
|
|
237
239
|
</View>
|
|
238
240
|
) : (
|
|
239
241
|
<>
|
|
240
|
-
<
|
|
242
|
+
<ComponentErrorBoundary>
|
|
241
243
|
<MessageAttachments
|
|
242
244
|
attachments={attachments}
|
|
243
245
|
metaProps={metaProps}
|
|
244
246
|
onMessageAttachmentLongPress={handleMessageAttachmentLongPress}
|
|
245
247
|
onMessageLongPress={handleMessageLongPress}
|
|
246
248
|
/>
|
|
247
|
-
</
|
|
249
|
+
</ComponentErrorBoundary>
|
|
248
250
|
{text && (
|
|
249
251
|
<View style={styles.messageText}>
|
|
250
252
|
<MessageMarkdown text={text} />
|
package/src/components/index.tsx
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { render } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Text } from 'react-native'
|
|
4
|
+
import { Log } from '../../../utils/native_adapters/configuration'
|
|
5
|
+
import { ComponentErrorBoundary } from '../component_error_boundary'
|
|
6
|
+
|
|
7
|
+
function Boom({ thrown }: { thrown: unknown }) {
|
|
8
|
+
throw thrown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('ComponentErrorBoundary', () => {
|
|
12
|
+
let reportError: jest.SpyInstance
|
|
13
|
+
let consoleError: jest.SpyInstance
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
reportError = jest.spyOn(Log, 'reportError').mockImplementation(() => {})
|
|
17
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
reportError.mockRestore()
|
|
22
|
+
consoleError.mockRestore()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('defaults the reporter scope to "component" and renders nothing on catch', () => {
|
|
26
|
+
const { toJSON } = render(
|
|
27
|
+
<ComponentErrorBoundary>
|
|
28
|
+
<Boom thrown={new Error('attachment boom')} />
|
|
29
|
+
</ComponentErrorBoundary>
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
expect(toJSON()).toBeNull()
|
|
33
|
+
expect(reportError.mock.calls[0][1]).toMatchObject({ scope: 'component' })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('lets callers override the defaults', () => {
|
|
37
|
+
const { getByText } = render(
|
|
38
|
+
<ComponentErrorBoundary scope="screen" fallback={<Text>overridden</Text>}>
|
|
39
|
+
<Boom thrown={new Error('boom')} />
|
|
40
|
+
</ComponentErrorBoundary>
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
expect(getByText('overridden')).toBeTruthy()
|
|
44
|
+
expect(reportError.mock.calls[0][1]).toMatchObject({ scope: 'screen' })
|
|
45
|
+
})
|
|
46
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { render } from '@testing-library/react-native'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Text } from 'react-native'
|
|
4
|
+
import { FailedResponse } from '../../../types/api_primitives'
|
|
5
|
+
import { Log } from '../../../utils/native_adapters/configuration'
|
|
6
|
+
import { ResponseError } from '../../../utils/response_error'
|
|
7
|
+
import { ErrorBoundary } from '../error_boundary'
|
|
8
|
+
|
|
9
|
+
function Boom({ thrown }: { thrown: unknown }) {
|
|
10
|
+
throw thrown
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('ErrorBoundary', () => {
|
|
14
|
+
let reportError: jest.SpyInstance
|
|
15
|
+
let consoleError: jest.SpyInstance
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
reportError = jest.spyOn(Log, 'reportError').mockImplementation(() => {})
|
|
19
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
reportError.mockRestore()
|
|
24
|
+
consoleError.mockRestore()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('reports caught errors with the component stack and chat tags', () => {
|
|
28
|
+
const error = new TypeError('Invalid time value')
|
|
29
|
+
|
|
30
|
+
render(
|
|
31
|
+
<ErrorBoundary scope="screen" screenName="ConversationScreen" fallback={null}>
|
|
32
|
+
<Boom thrown={error} />
|
|
33
|
+
</ErrorBoundary>
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
expect(reportError).toHaveBeenCalledTimes(1)
|
|
37
|
+
const [reportedError, context] = reportError.mock.calls[0]
|
|
38
|
+
expect(reportedError).toBe(error)
|
|
39
|
+
expect(context).toMatchObject({
|
|
40
|
+
scope: 'screen',
|
|
41
|
+
screenName: 'ConversationScreen',
|
|
42
|
+
tags: { team: 'chat', package: 'chat-react-native' },
|
|
43
|
+
})
|
|
44
|
+
expect(typeof context.componentStack).toBe('string')
|
|
45
|
+
expect(context.componentStack.length).toBeGreaterThan(0)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('does not report ResponseError — those are owned by the HTTP layer', () => {
|
|
49
|
+
const failure = { status: 500, statusText: 'Server Error', errors: [] } as FailedResponse
|
|
50
|
+
|
|
51
|
+
render(
|
|
52
|
+
<ErrorBoundary fallback={null}>
|
|
53
|
+
<Boom thrown={new ResponseError(failure)} />
|
|
54
|
+
</ErrorBoundary>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
expect(reportError).not.toHaveBeenCalled()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('renders the provided fallback element when a child throws', () => {
|
|
61
|
+
const { getByText } = render(
|
|
62
|
+
<ErrorBoundary fallback={<Text>custom fallback</Text>}>
|
|
63
|
+
<Boom thrown={new Error('boom')} />
|
|
64
|
+
</ErrorBoundary>
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
expect(getByText('custom fallback')).toBeTruthy()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('renders nothing when no fallback is provided', () => {
|
|
71
|
+
const { toJSON } = render(
|
|
72
|
+
<ErrorBoundary>
|
|
73
|
+
<Boom thrown={new Error('boom')} />
|
|
74
|
+
</ErrorBoundary>
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
expect(toJSON()).toBeNull()
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('calls a fallback render function with the caught error and a reset handler', () => {
|
|
81
|
+
const fallback = jest.fn().mockReturnValue(<Text>fn fallback</Text>)
|
|
82
|
+
const error = new Error('boom')
|
|
83
|
+
|
|
84
|
+
const { getByText } = render(
|
|
85
|
+
<ErrorBoundary fallback={fallback}>
|
|
86
|
+
<Boom thrown={error} />
|
|
87
|
+
</ErrorBoundary>
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
expect(getByText('fn fallback')).toBeTruthy()
|
|
91
|
+
expect(fallback).toHaveBeenCalledWith(error, expect.any(Function))
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { NavigationContainer } from '@react-navigation/native'
|
|
2
|
+
import { QueryClientProvider } from '@tanstack/react-query'
|
|
3
|
+
import { render } from '@testing-library/react-native'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { buildTestQueryClient } from '../../../__utils__/query_client'
|
|
6
|
+
import { Log } from '../../../utils/native_adapters/configuration'
|
|
7
|
+
import { PageErrorBoundary } from '../page_error_boundary'
|
|
8
|
+
|
|
9
|
+
jest.mock('../../primitive/blank_state_primitive', () => {
|
|
10
|
+
const { Text } = require('react-native')
|
|
11
|
+
const { createElement } = require('react')
|
|
12
|
+
const passthrough = ({ children }: { children?: unknown }) => children
|
|
13
|
+
const asText = ({ children }: { children?: unknown }) => createElement(Text, null, children)
|
|
14
|
+
const empty = () => null
|
|
15
|
+
return {
|
|
16
|
+
__esModule: true,
|
|
17
|
+
default: {
|
|
18
|
+
Root: passthrough,
|
|
19
|
+
Imagery: empty,
|
|
20
|
+
Content: passthrough,
|
|
21
|
+
Heading: asText,
|
|
22
|
+
Text: asText,
|
|
23
|
+
Button: empty,
|
|
24
|
+
TextButton: asText,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
function Boom({ thrown }: { thrown: unknown }) {
|
|
30
|
+
throw thrown
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const renderWithProviders = (ui: React.ReactElement) =>
|
|
34
|
+
render(
|
|
35
|
+
<QueryClientProvider client={buildTestQueryClient()}>
|
|
36
|
+
<NavigationContainer>{ui}</NavigationContainer>
|
|
37
|
+
</QueryClientProvider>
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
describe('PageErrorBoundary', () => {
|
|
41
|
+
let reportError: jest.SpyInstance
|
|
42
|
+
let consoleError: jest.SpyInstance
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
reportError = jest.spyOn(Log, 'reportError').mockImplementation(() => {})
|
|
46
|
+
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
reportError.mockRestore()
|
|
51
|
+
consoleError.mockRestore()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('defaults the reporter scope to "screen"', () => {
|
|
55
|
+
renderWithProviders(
|
|
56
|
+
<PageErrorBoundary screenName="ConversationScreen">
|
|
57
|
+
<Boom thrown={new Error('boom')} />
|
|
58
|
+
</PageErrorBoundary>
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
expect(reportError.mock.calls[0][1]).toMatchObject({
|
|
62
|
+
scope: 'screen',
|
|
63
|
+
screenName: 'ConversationScreen',
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('renders the full Oops fallback when no fallback is provided', () => {
|
|
68
|
+
const { getByText } = renderWithProviders(
|
|
69
|
+
<PageErrorBoundary>
|
|
70
|
+
<Boom thrown={new Error('boom')} />
|
|
71
|
+
</PageErrorBoundary>
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
expect(getByText('Oops!')).toBeTruthy()
|
|
75
|
+
expect(getByText('Something unexpected happened.')).toBeTruthy()
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from 'react'
|
|
2
|
+
import { ErrorBoundary, ErrorBoundaryProps } from './error_boundary'
|
|
3
|
+
|
|
4
|
+
export function ComponentErrorBoundary({
|
|
5
|
+
children,
|
|
6
|
+
...props
|
|
7
|
+
}: PropsWithChildren<ErrorBoundaryProps>) {
|
|
8
|
+
return (
|
|
9
|
+
<ErrorBoundary scope="component" fallback={null} {...props}>
|
|
10
|
+
{children}
|
|
11
|
+
</ErrorBoundary>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -1,137 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { onAuthRefresh } from '../../utils/auth_events'
|
|
1
|
+
import React, { PropsWithChildren } from 'react'
|
|
2
|
+
import { Log } from '../../utils/native_adapters/configuration'
|
|
3
|
+
import { ReportErrorScope } from '../../utils/native_adapters/log'
|
|
5
4
|
import { ResponseError } from '../../utils/response_error'
|
|
6
|
-
|
|
5
|
+
|
|
6
|
+
export type ErrorBoundaryFallback =
|
|
7
|
+
| React.ReactNode
|
|
8
|
+
| ((error: Error, reset: () => void) => React.ReactNode)
|
|
9
|
+
|
|
10
|
+
export type ErrorBoundaryProps = {
|
|
11
|
+
scope?: ReportErrorScope
|
|
12
|
+
screenName?: string
|
|
13
|
+
fallback?: ErrorBoundaryFallback
|
|
14
|
+
}
|
|
7
15
|
|
|
8
16
|
type ErrorBoundaryState = {
|
|
9
|
-
error:
|
|
10
|
-
unsubscriber: () => void
|
|
17
|
+
error: Error | null
|
|
11
18
|
}
|
|
12
19
|
|
|
13
|
-
class ErrorBoundary extends React.Component<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
20
|
+
export class ErrorBoundary extends React.Component<
|
|
21
|
+
PropsWithChildren<ErrorBoundaryProps>,
|
|
22
|
+
ErrorBoundaryState
|
|
23
|
+
> {
|
|
24
|
+
state: ErrorBoundaryState = { error: null }
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
27
|
+
return { error }
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
31
|
+
if (error instanceof ResponseError) return
|
|
32
|
+
|
|
33
|
+
Log.reportError(error, {
|
|
34
|
+
componentStack: errorInfo.componentStack ?? undefined,
|
|
35
|
+
scope: this.props.scope,
|
|
36
|
+
screenName: this.props.screenName,
|
|
37
|
+
tags: { team: 'chat', package: 'chat-react-native' },
|
|
38
|
+
})
|
|
25
39
|
}
|
|
26
40
|
|
|
27
41
|
handleReset = () => {
|
|
28
|
-
this.props.onReset?.()
|
|
29
42
|
this.setState({ error: null })
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
render() {
|
|
33
|
-
if (this.state.error)
|
|
34
|
-
return <ErrorView error={this.state.error} onReset={this.handleReset} />
|
|
35
|
-
} else {
|
|
36
|
-
return this.props.children
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
46
|
+
if (!this.state.error) return this.props.children
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
const { fallback } = this.props
|
|
49
|
+
if (fallback === undefined) return null
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
reset()
|
|
46
|
-
onReset()
|
|
47
|
-
}, [reset, onReset])
|
|
48
|
-
|
|
49
|
-
useEffect(() => handleReset, [handleReset])
|
|
50
|
-
|
|
51
|
-
if (error instanceof ResponseError) {
|
|
52
|
-
return <ResponseErrorView response={error.response} onReset={handleReset} />
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (isNetworkError(error)) {
|
|
56
|
-
return (
|
|
57
|
-
<ErrorContent
|
|
58
|
-
heading={'Problem connecting!'}
|
|
59
|
-
body={'Check your internet connection and try again.'}
|
|
60
|
-
/>
|
|
61
|
-
)
|
|
51
|
+
return typeof fallback === 'function' ? fallback(this.state.error, this.handleReset) : fallback
|
|
62
52
|
}
|
|
63
|
-
|
|
64
|
-
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />
|
|
65
53
|
}
|
|
66
|
-
|
|
67
|
-
function isNetworkError(error: ResponseError | Error | TypeError | null) {
|
|
68
|
-
const isError = error instanceof Error
|
|
69
|
-
const networkFailedMessages = [
|
|
70
|
-
'Network request failed',
|
|
71
|
-
'Network request timed out',
|
|
72
|
-
'Failed to fetch',
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
if (!isError) return false
|
|
76
|
-
|
|
77
|
-
return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function ResponseErrorView({ response, onReset }: { response: Response; onReset: () => void }) {
|
|
81
|
-
const { status } = response
|
|
82
|
-
|
|
83
|
-
const heading = useMemo(() => {
|
|
84
|
-
switch (status) {
|
|
85
|
-
case 403:
|
|
86
|
-
return 'Permission required'
|
|
87
|
-
case 404:
|
|
88
|
-
return 'Content not found'
|
|
89
|
-
default:
|
|
90
|
-
return 'Oops!'
|
|
91
|
-
}
|
|
92
|
-
}, [status])
|
|
93
|
-
|
|
94
|
-
const body = useMemo(() => {
|
|
95
|
-
switch (status) {
|
|
96
|
-
case 403:
|
|
97
|
-
return 'Contact your administrator for access.'
|
|
98
|
-
case 404:
|
|
99
|
-
return 'If you believe something should be here, please reach out to your administrator.'
|
|
100
|
-
default:
|
|
101
|
-
return 'Something unexpected happened.'
|
|
102
|
-
}
|
|
103
|
-
}, [status])
|
|
104
|
-
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (status !== 401) return
|
|
107
|
-
|
|
108
|
-
return onAuthRefresh(onReset)
|
|
109
|
-
}, [status, onReset])
|
|
110
|
-
|
|
111
|
-
return <ErrorContent heading={heading} body={body} />
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function ErrorContent({ heading, body }: { heading: string; body: string }) {
|
|
115
|
-
const navigation = useNavigation()
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<BlankState.Root>
|
|
119
|
-
<BlankState.Imagery name="people.noTextMessage" />
|
|
120
|
-
<BlankState.Content>
|
|
121
|
-
<BlankState.Heading>{heading}</BlankState.Heading>
|
|
122
|
-
<BlankState.Text>{body}</BlankState.Text>
|
|
123
|
-
</BlankState.Content>
|
|
124
|
-
<BlankState.Button
|
|
125
|
-
title="Go back"
|
|
126
|
-
onPress={navigation.goBack}
|
|
127
|
-
size="md"
|
|
128
|
-
accessibilityRole="link"
|
|
129
|
-
/>
|
|
130
|
-
<BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>
|
|
131
|
-
Report a bug
|
|
132
|
-
</BlankState.TextButton>
|
|
133
|
-
</BlankState.Root>
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export default ErrorBoundary
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native'
|
|
2
|
+
import { useQueryErrorResetBoundary } from '@tanstack/react-query'
|
|
3
|
+
import React, { PropsWithChildren, useCallback, useEffect, useMemo } from 'react'
|
|
4
|
+
import { onAuthRefresh } from '../../utils/auth_events'
|
|
5
|
+
import { ResponseError } from '../../utils/response_error'
|
|
6
|
+
import BlankState from '../primitive/blank_state_primitive'
|
|
7
|
+
import { ErrorBoundary, ErrorBoundaryFallback, ErrorBoundaryProps } from './error_boundary'
|
|
8
|
+
|
|
9
|
+
const renderPageFallback: ErrorBoundaryFallback = (error, reset) => (
|
|
10
|
+
<ErrorView error={error} reset={reset} />
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export function PageErrorBoundary({ children, ...props }: PropsWithChildren<ErrorBoundaryProps>) {
|
|
14
|
+
return (
|
|
15
|
+
<ErrorBoundary scope="screen" fallback={renderPageFallback} {...props}>
|
|
16
|
+
{children}
|
|
17
|
+
</ErrorBoundary>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function ErrorView({ error, reset }: { error: Error; reset: () => void }) {
|
|
22
|
+
const { reset: resetQueries } = useQueryErrorResetBoundary()
|
|
23
|
+
|
|
24
|
+
const handleReset = useCallback(() => {
|
|
25
|
+
resetQueries()
|
|
26
|
+
reset()
|
|
27
|
+
}, [resetQueries, reset])
|
|
28
|
+
|
|
29
|
+
useEffect(() => handleReset, [handleReset])
|
|
30
|
+
|
|
31
|
+
if (error instanceof ResponseError) {
|
|
32
|
+
return <ResponseErrorView response={error.response} onReset={handleReset} />
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (isNetworkError(error)) {
|
|
36
|
+
return (
|
|
37
|
+
<ErrorContent
|
|
38
|
+
heading={'Problem connecting!'}
|
|
39
|
+
body={'Check your internet connection and try again.'}
|
|
40
|
+
/>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isNetworkError(error: Error) {
|
|
48
|
+
const networkFailedMessages = [
|
|
49
|
+
'Network request failed',
|
|
50
|
+
'Network request timed out',
|
|
51
|
+
'Failed to fetch',
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ResponseErrorView({ response, onReset }: { response: Response; onReset: () => void }) {
|
|
58
|
+
const { status } = response
|
|
59
|
+
|
|
60
|
+
const heading = useMemo(() => {
|
|
61
|
+
switch (status) {
|
|
62
|
+
case 403:
|
|
63
|
+
return 'Permission required'
|
|
64
|
+
case 404:
|
|
65
|
+
return 'Content not found'
|
|
66
|
+
default:
|
|
67
|
+
return 'Oops!'
|
|
68
|
+
}
|
|
69
|
+
}, [status])
|
|
70
|
+
|
|
71
|
+
const body = useMemo(() => {
|
|
72
|
+
switch (status) {
|
|
73
|
+
case 403:
|
|
74
|
+
return 'Contact your administrator for access.'
|
|
75
|
+
case 404:
|
|
76
|
+
return 'If you believe something should be here, please reach out to your administrator.'
|
|
77
|
+
default:
|
|
78
|
+
return 'Something unexpected happened.'
|
|
79
|
+
}
|
|
80
|
+
}, [status])
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (status !== 401) return
|
|
84
|
+
|
|
85
|
+
return onAuthRefresh(onReset)
|
|
86
|
+
}, [status, onReset])
|
|
87
|
+
|
|
88
|
+
return <ErrorContent heading={heading} body={body} />
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function ErrorContent({ heading, body }: { heading: string; body: string }) {
|
|
92
|
+
const navigation = useNavigation()
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<BlankState.Root>
|
|
96
|
+
<BlankState.Imagery name="people.noTextMessage" />
|
|
97
|
+
<BlankState.Content>
|
|
98
|
+
<BlankState.Heading>{heading}</BlankState.Heading>
|
|
99
|
+
<BlankState.Text>{body}</BlankState.Text>
|
|
100
|
+
</BlankState.Content>
|
|
101
|
+
<BlankState.Button
|
|
102
|
+
title="Go back"
|
|
103
|
+
onPress={navigation.goBack}
|
|
104
|
+
size="md"
|
|
105
|
+
accessibilityRole="link"
|
|
106
|
+
/>
|
|
107
|
+
<BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>
|
|
108
|
+
Report a bug
|
|
109
|
+
</BlankState.TextButton>
|
|
110
|
+
</BlankState.Root>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native'
|
|
1
2
|
import React from 'react'
|
|
2
3
|
import { Suspense } from 'react'
|
|
3
|
-
import ErrorBoundary from '../components/page/error_boundary'
|
|
4
4
|
import { DefaultLoading } from '../components/page/loading'
|
|
5
|
+
import { PageErrorBoundary } from '../components/page/page_error_boundary'
|
|
5
6
|
import { ChatAccessGate } from './chat_access_gate'
|
|
6
7
|
|
|
7
8
|
export function ScreenLayout({ children }: { children: React.ReactElement }) {
|
|
9
|
+
const route = useRoute()
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
|
-
<
|
|
12
|
+
<PageErrorBoundary screenName={route.name}>
|
|
10
13
|
<Suspense fallback={<DefaultLoading />}>{children}</Suspense>
|
|
11
|
-
</
|
|
14
|
+
</PageErrorBoundary>
|
|
12
15
|
)
|
|
13
16
|
}
|
|
14
17
|
|