diff --git a/src/App.tsx b/src/App.tsx index c00c435..e3d08ad 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,28 +21,24 @@ import ProductDetailScreen from './screens/ProductDetailScreen'; import ReduxScreen from './screens/ReduxScreen'; import CartScreen from './screens/CartScreen'; import CheckoutScreen from './screens/CheckoutScreen'; -import Toast from 'react-native-toast-message'; -import {RootState, store, showFeedbackActionButton} from './reduxApp'; -import {DSN} from './config'; +import {RootState, store} from './reduxApp'; import {SE} from '@env'; // SE is undefined if no .env file is set import {RootStackParamList} from './navigation'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; -import {LogBox, Platform, StyleSheet} from 'react-native'; +import {LogBox, Platform, Pressable, StyleSheet, Text, View} from 'react-native'; import {SafeAreaProvider} from 'react-native-safe-area-context'; import {SentryUserFeedbackActionButton} from './components/UserFeedbackModal'; +import {DSN} from './config'; console.log('> SE', SE); LogBox.ignoreAllLogs(); -const reactNavigationIntegration = - Sentry.reactNavigationIntegration({ - // How long it will wait for the route change to complete. Default is 1000ms - routeChangeTimeoutMs: 500, - enableTimeToInitialDisplay: true, - }); +const reactNavigationIntegration = Sentry.reactNavigationIntegration({ + routeChangeTimeoutMs: 500, + enableTimeToInitialDisplay: true, +}); -// Get app version from package.json, for fingerprinting const packageJson = require('../package.json'); Sentry.init({ @@ -50,25 +46,17 @@ Sentry.init({ debug: true, environment: 'dev', enableLogs: true, - beforeSend: (event) => { + beforeSend: event => { if (SE === 'tda') { - // Make issues unique to the release (app version) for Release Health event.fingerprint = ['{{ default }}', SE, packageJson.version]; } else if (SE) { - // Make issue for the SE event.fingerprint = ['{{ default }}', SE]; } - - if (!event.type) { - // Only show the feedback button for errors - store.dispatch(showFeedbackActionButton()); - } - return event; }, integrations: [ Sentry.reactNativeTracingIntegration({ - traceFetch: false, // RN uses XHR to implement fetch, this prevents duplicates + traceFetch: false, }), Sentry.mobileReplayIntegration({ maskAllImages: true, @@ -83,8 +71,8 @@ Sentry.init({ replaysSessionSampleRate: 1.0, enableUserInteractionTracing: true, enableAutoSessionTracking: true, - sessionTrackingIntervalMillis: 5000, // For testing, session close when 5 seconds (instead of the default 30) in the background. - maxBreadcrumbs: 150, // Extend from the default 100 breadcrumbs. + sessionTrackingIntervalMillis: 5000, + maxBreadcrumbs: 150, attachStacktrace: true, attachScreenshot: true, attachViewHierarchy: true, @@ -93,6 +81,15 @@ Sentry.init({ Sentry.setTag('se', SE); +const FallbackComponent = ({resetError}: {resetError: () => void}) => ( + + Something went wrong. + + Refresh + + +); + const Tab = createBottomTabNavigator(); const Stack = createStackNavigator(); @@ -116,10 +113,10 @@ const App = () => { customerType, email, se: SE, - version: packageJson.version, }); return ( + @@ -138,6 +135,7 @@ const App = () => { + ); }; @@ -242,11 +240,27 @@ const styles = StyleSheet.create({ gestureHandlerRootView: { flex: 1, }, -}); - -export default Sentry.wrap(App, { - touchEventBoundaryProps: { - ignoreNames: ['Provider', 'UselessName', /^SomeRegex/], - labelName: 'id', + fallback: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#fff', + }, + fallbackText: { + fontSize: 18, + marginBottom: 20, + color: '#000', + }, + fallbackButton: { + paddingHorizontal: 24, + paddingVertical: 12, + backgroundColor: '#002626', + borderRadius: 8, + }, + fallbackButtonText: { + color: '#fff', + fontWeight: 'bold', }, }); + +export default Sentry.wrap(App); diff --git a/src/components/ErrorBoundaryProduct.tsx b/src/components/ErrorBoundaryProduct.tsx new file mode 100644 index 0000000..fc20ada --- /dev/null +++ b/src/components/ErrorBoundaryProduct.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import {View, Text, StyleSheet} from 'react-native'; +import Icon from 'react-native-vector-icons/FontAwesome6'; +import {StyledButton} from './StyledButton'; + +const BuggyCart = (): React.ReactElement => { + return ( + { + throw new Error('Error boundary triggered from error product card'); + }} + style={{ + default: styles.addToCartButton, + pressed: styles.addToCartButton, + }} + /> + ); +}; + +export const ErrorBoundaryProduct = (): React.ReactElement => { + return ( + + + + + + + Error Product + Boundary error testing + + + + + + + ); +}; + +const styles = StyleSheet.create({ + cardContainer: { + width: '100%', + height: 200, + borderWidth: 1, + borderColor: '#e74c3c', + borderRadius: 6, + backgroundColor: '#ffffff', + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginVertical: 5, + }, + cardHero: { + width: '40%', + height: '100%', + backgroundColor: '#fdf0f0', + alignItems: 'center', + justifyContent: 'center', + }, + cardDetail: { + flex: 1, + height: '100%', + flexDirection: 'column', + }, + cardDetailContent: { + padding: 10, + flex: 1, + flexDirection: 'column', + justifyContent: 'space-between', + paddingBottom: 10, + }, + cardDetailAction: { + flex: 0, + }, + cardTitle: { + marginBottom: 5, + fontSize: 24, + fontWeight: '500', + color: '#c0392b', + }, + cardDescription: { + fontSize: 14, + color: '#555', + }, + addToCartButton: { + margin: 10, + }, +}); diff --git a/src/config.ts b/src/config.ts index 5fc10ea..765c48b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,5 @@ export const DSN = - 'https://b87682e62e4cc633d4c35c7154256c66@sandbox-mirror.sentry.gg/1'; + 'https://6d107379901d7674dce67c2cf3a735fe@o88872.ingest.us.sentry.io/4511095053615104'; // SENTRY_INTERNAL_DSN for testing // export const DSN = diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 01cfc06..8dbef45 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -6,6 +6,7 @@ import {BACKEND_URL} from '../config'; import {StackScreenProps} from '@react-navigation/stack'; import {RootStackParamList} from '../navigation'; import {ProfiledStyledProductCard} from '../components/StyledProductCard'; +import {ErrorBoundaryProduct} from '../components/ErrorBoundaryProduct'; import {Product} from '../types/Product'; type ExtendedSentryScope = Sentry.Scope & { @@ -108,6 +109,7 @@ const EmpowerPlant = ({navigation}: StackScreenProps) => { refreshing={toolData === null} data={toolData} contentContainerStyle={styles.productListContainer} + ListHeaderComponent={toolData ? : null} renderItem={({item}) => { return (