From 5b44aa962f5c50eacff08a8c3feee5fb8db752cb Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Fri, 22 Mar 2024 12:14:47 -0500
Subject: Wrap Button children in an error boundary (#3340)

* Wrap Button children in an error boundary

* Check for Trans component
---
 src/components/Button.tsx | 63 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 14 deletions(-)

(limited to 'src/components/Button.tsx')

diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index 0e22944a3..67c33fa0c 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -1,19 +1,21 @@
 import React from 'react'
 import {
+  AccessibilityProps,
   Pressable,
-  Text,
   PressableProps,
+  StyleProp,
+  StyleSheet,
+  Text,
   TextProps,
-  ViewStyle,
-  AccessibilityProps,
-  View,
   TextStyle,
-  StyleSheet,
-  StyleProp,
+  View,
+  ViewStyle,
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
+import {Trans} from '@lingui/macro'
 
-import {useTheme, atoms as a, tokens, android, flatten} from '#/alf'
+import {logger} from '#/logger'
+import {android, atoms as a, flatten, tokens, useTheme} from '#/alf'
 import {Props as SVGIconProps} from '#/components/icons/common'
 import {normalizeTextStyles} from '#/components/Typography'
 
@@ -403,18 +405,51 @@ export function Button({
         </View>
       )}
       <Context.Provider value={context}>
-        {typeof children === 'string' ? (
-          <ButtonText>{children}</ButtonText>
-        ) : typeof children === 'function' ? (
-          children(context)
-        ) : (
-          children
-        )}
+        <ButtonTextErrorBoundary>
+          {/* @ts-ignore */}
+          {typeof children === 'string' || children?.type === Trans ? (
+            /* @ts-ignore */
+            <ButtonText>{children}</ButtonText>
+          ) : typeof children === 'function' ? (
+            children(context)
+          ) : (
+            children
+          )}
+        </ButtonTextErrorBoundary>
       </Context.Provider>
     </Pressable>
   )
 }
 
+export class ButtonTextErrorBoundary extends React.Component<
+  React.PropsWithChildren<{}>,
+  {hasError: boolean; error: Error | undefined}
+> {
+  public state = {
+    hasError: false,
+    error: undefined,
+  }
+
+  public static getDerivedStateFromError(error: Error) {
+    return {hasError: true, error}
+  }
+
+  public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+    logger.error('ButtonTextErrorBoundary caught an error', {
+      message: error.message,
+      errorInfo,
+    })
+  }
+
+  public render() {
+    if (this.state.hasError) {
+      return <ButtonText>ERROR</ButtonText>
+    }
+
+    return this.props.children
+  }
+}
+
 export function useSharedButtonTextStyles() {
   const t = useTheme()
   const {color, variant, disabled, size} = useButtonContext()
-- 
cgit 1.4.1

