Skip to content

Commit

Permalink
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/4…
Browse files Browse the repository at this point in the history
…359-Feedback-Form-NetworkError

# Conflicts:
#	packages/core/src/js/feedback/FeedbackForm.types.ts
  • Loading branch information
antonis committed Dec 19, 2024
2 parents d84ae63 + a931ba9 commit 1192b17
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 95 deletions.
17 changes: 14 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ To learn how to attach context data to the feedback visit [the documentation](ht
...
<FeedbackForm/>
```
or auto-inject it by calling the `showFeedbackForm`:
```jsx
import { showFeedbackForm } from '@sentry/react-native';
...
<Button
title="Show feedback form"
onPress={() => {
showFeedbackForm(_props.navigation);
}}
/>
```

- Export `Span` type from `@sentry/types` ([#4345](https://github.com/getsentry/sentry-react-native/pull/4345))
- Add RN SDK package to `sdk.packages` on Android ([#4380](https://github.com/getsentry/sentry-react-native/pull/4380))
Expand All @@ -59,9 +70,9 @@ To learn how to attach context data to the feedback visit [the documentation](ht
- Bump Android SDK from v7.18.0 to v7.19.0 ([#4329](https://github.com/getsentry/sentry-react-native/pull/4329), [#4365](https://github.com/getsentry/sentry-react-native/pull/4365))
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7190)
- [diff](https://github.com/getsentry/sentry-java/compare/7.18.0...7.19.0)
- Bump JavaScript SDK from v8.40.0 to v8.46.0 ([#4351](https://github.com/getsentry/sentry-react-native/pull/4351), [#4325](https://github.com/getsentry/sentry-react-native/pull/4325), [#4371](https://github.com/getsentry/sentry-react-native/pull/4371), [#4382](https://github.com/getsentry/sentry-react-native/pull/4382), [#4388](https://github.com/getsentry/sentry-react-native/pull/4388))
- [changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#8460)
- [diff](https://github.com/getsentry/sentry-javascript/compare/8.40.0...8.46.0)
- Bump JavaScript SDK from v8.40.0 to v8.47.0 ([#4351](https://github.com/getsentry/sentry-react-native/pull/4351), [#4325](https://github.com/getsentry/sentry-react-native/pull/4325), [#4371](https://github.com/getsentry/sentry-react-native/pull/4371), [#4382](https://github.com/getsentry/sentry-react-native/pull/4382), [#4388](https://github.com/getsentry/sentry-react-native/pull/4388), [#4393](https://github.com/getsentry/sentry-react-native/pull/4393))
- [changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md#8470)
- [diff](https://github.com/getsentry/sentry-javascript/compare/8.40.0...8.47.0)
- Bump Cocoa SDK from v8.41.0 to v8.42.0 ([#4387](https://github.com/getsentry/sentry-react-native/pull/4387))
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8420)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/8.41.0...8.42.0)
Expand Down
2 changes: 1 addition & 1 deletion dev-packages/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"devDependencies": {
"@babel/preset-env": "^7.25.3",
"@babel/preset-typescript": "^7.18.6",
"@sentry/core": "8.46.0",
"@sentry/core": "8.47.0",
"@sentry/react-native": "6.4.0",
"@types/node": "^20.9.3",
"@types/react": "^18.2.64",
Expand Down
16 changes: 8 additions & 8 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,21 @@
},
"dependencies": {
"@sentry/babel-plugin-component-annotate": "2.20.1",
"@sentry/browser": "8.46.0",
"@sentry/browser": "8.47.0",
"@sentry/cli": "2.39.1",
"@sentry/core": "8.46.0",
"@sentry/react": "8.46.0",
"@sentry/types": "8.46.0",
"@sentry/utils": "8.46.0"
"@sentry/core": "8.47.0",
"@sentry/react": "8.47.0",
"@sentry/types": "8.47.0",
"@sentry/utils": "8.47.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@expo/metro-config": "0.19.5",
"@mswjs/interceptors": "^0.25.15",
"@react-native/babel-preset": "0.76.3",
"@sentry-internal/eslint-config-sdk": "8.46.0",
"@sentry-internal/eslint-plugin-sdk": "8.46.0",
"@sentry-internal/typescript": "8.46.0",
"@sentry-internal/eslint-config-sdk": "8.47.0",
"@sentry-internal/eslint-plugin-sdk": "8.47.0",
"@sentry-internal/typescript": "8.47.0",
"@sentry/wizard": "3.36.0",
"@testing-library/react-native": "^12.7.2",
"@types/jest": "^29.5.3",
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/js/feedback/FeedbackForm.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const defaultStyles: FeedbackFormStyles = {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
textAlign: 'center',
textAlign: 'left',
flex: 1,
color: FORGROUND_COLOR,
},
label: {
Expand Down Expand Up @@ -57,6 +58,14 @@ const defaultStyles: FeedbackFormStyles = {
color: FORGROUND_COLOR,
fontSize: 16,
},
titleContainer: {
flexDirection: 'row',
width: '100%',
},
sentryLogo: {
width: 40,
height: 40,
},
};

export default defaultStyles;
45 changes: 44 additions & 1 deletion packages/core/src/js/feedback/FeedbackForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as React from 'react';
import type { KeyboardTypeOptions } from 'react-native';
import {
Alert,
Image,
Keyboard,
KeyboardAvoidingView,
SafeAreaView,
Expand All @@ -15,11 +16,37 @@ import {
View
} from 'react-native';

import { sentryLogo } from './branding';
import { defaultConfiguration } from './defaults';
import defaultStyles from './FeedbackForm.styles';
import type { FeedbackFormProps, FeedbackFormState, FeedbackFormStyles,FeedbackGeneralConfiguration, FeedbackTextConfiguration } from './FeedbackForm.types';
import { checkInternetConnection, isValidEmail } from './utils';

let feedbackFormHandler: (() => void) | null = null;

const setFeedbackFormHandler = (handler: () => void): void => {
feedbackFormHandler = handler;
};

const clearFeedbackFormHandler = (): void => {
feedbackFormHandler = null;
};

type Navigation = {
navigate: (screen: string, params?: Record<string, unknown>) => void;
};

export const showFeedbackForm = (navigation: Navigation): void => {
setFeedbackFormHandler(() => {
navigation?.navigate?.('FeedbackForm');
});
if (feedbackFormHandler) {
feedbackFormHandler();
} else {
logger.error('FeedbackForm handler is not set. Please ensure it is initialized.');
}
};

/**
* @beta
* Implements a feedback form screen that sends feedback to Sentry using Sentry.captureFeedback.
Expand Down Expand Up @@ -47,6 +74,13 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
};
}

/**
* Clear the handler when the component unmounts
*/
public componentWillUnmount(): void {
clearFeedbackFormHandler();
}

public handleFeedbackSubmit: () => void = () => {
const { name, email, description } = this.state;
const { onSubmitSuccess, onSubmitError, onFormSubmitted } = this.props;
Expand Down Expand Up @@ -116,7 +150,16 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
<ScrollView>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.container}>
<Text style={styles.title}>{text.formTitle}</Text>
<View style={styles.titleContainer}>
<Text style={styles.title}>{text.formTitle}</Text>
{config.showBranding && (
<Image
source={{ uri: sentryLogo }}
style={styles.sentryLogo}
testID='sentry-logo'
/>
)}
</View>

{config.showName && (
<>
Expand Down
20 changes: 19 additions & 1 deletion packages/core/src/js/feedback/FeedbackForm.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { FeedbackFormData } from '@sentry/core';
import type { TextStyle, ViewStyle } from 'react-native';
import type { ImageStyle, TextStyle, ViewStyle } from 'react-native';

/**
* The props for the feedback form
*/
export interface FeedbackFormProps extends FeedbackGeneralConfiguration, FeedbackTextConfiguration, FeedbackCallbacks {
styles?: FeedbackFormStyles;
}
Expand All @@ -9,6 +12,13 @@ export interface FeedbackFormProps extends FeedbackGeneralConfiguration, Feedbac
* General feedback configuration
*/
export interface FeedbackGeneralConfiguration {
/**
* Show the Sentry branding
*
* @default true
*/
showBranding?: boolean;

/**
* Should the email field be required?
*/
Expand Down Expand Up @@ -161,6 +171,9 @@ export interface FeedbackCallbacks {
onFormSubmitted?: () => void;
}

/**
* The styles for the feedback form
*/
export interface FeedbackFormStyles {
container?: ViewStyle;
title?: TextStyle;
Expand All @@ -171,8 +184,13 @@ export interface FeedbackFormStyles {
submitText?: TextStyle;
cancelButton?: ViewStyle;
cancelText?: TextStyle;
titleContainer?: ViewStyle;
sentryLogo?: ImageStyle;
}

/**
* The state of the feedback form
*/
export interface FeedbackFormState {
isVisible: boolean;
name: string;
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/js/feedback/branding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Base64 encoded PNG image of the Sentry logo (source https://sentry.io/branding/)
*/
export const sentryLogo =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAC4BAMAAABUVL5sAAAAD1BMVEUAAAA2Llo3LVk4LFg2LVmgcvrUAAAABHRSTlMAgL9ARyeO/QAAA7pJREFUeNrtWltynDAQFBIHIFUcgCQ6AIk5AAjd/0ypxFk3ouUCNJofl/rHy75a09MzI7Q2DQ0NDQ0NDQ0NDQ0N9eF+xPh9MKpwPv6FLss7R9yMImz8j8nowb9IglFDF6N+KCNIdqMFcGjpBbVUXdzHqKsXUhJGNb2g1vz6azRgX8XulUwMtVZjFsWkvFz10s0ooEO+9Vpxj/6rp9eI5VsdE6eJcDCxilqICiZWMHBSMkBVA2vq1SVrVyr6Ea5VMjHqjytTwcAgRVJ0DAy9VoWUTNT3tQysZGIYmGNTKHfK0q6oFkysYWCuHB0DaxX9yHLx5JKrhVC0TGwjWNRMvNAuW6PoR4TCepnqLLuiicEyKJq4g2C6Rc+hsInlgtHCF41OrD65INisObksbKy2/YJg9U08sGBTbRN3YaBQQu2i74/mcQil6vZr5C0dQpGbGKJvdOA1VDVxd5LHooPR5BJPdwql5vaLeq9FQZKJpa1kOoUSKpq45+m+ZK93aUpSwRyuafslUguCIZRZamKoBYQT80QmlqnF38p6bSIDcyg2q5fw/uo8dx0upZMLLdadQ1kgkNDEOOGiYYXjVKGJ8V00rEggcErurxAKCwQTi9RCAW7UFcUm5vPAOFNXFBY9DggQyp76jnIkOyBwaeqtyMScEu7w4JRNLnyQOjyvACcWpR145g6PV1fp9mvE0jMd3tWZXDR3/Ud2cSXZfmHhvNpEoFlgYsjFHX4AJc3kXXSTyEfDTrz94ptE1qvS9ouG1Ud2sQT5PVcHg3FL78FIYUpqxWK1yLzMxNzhHVaLzItMzB0eB/S4CDRHC+AzFTjhAiSSHx9tpgJXqnmhXi7VizM/F5v4V5oVqOIp81PpEW4Xt7PUA0kEe5WZ2PLt7ZopDg8Seue9GpxoU0WrHyFPgYlzmyrKPDxcpFeX3YRS5mGvxybmsC2tPhLJQxPzdsfliwMeLjAx9wcujoFIaEAX/KSYXz0s+9TE/E7LX0yF8lQvitl99sVjSgITl/yk6Lk48JjfGadnanHml8xjMvFTA+eL42CRwDKEZwbm4rBMyAmdH6UEz8HDTPj4d4ie1EJxJCQg56DXaxKOl0iGz0jcdebZluzhbFSA1yEZ2JzbHZKQe3I/EK4CErTHbwn84ZP+8Poxqrd/+I2cXJAw0v9VAkBiI3DhLryZEe6SXNeJk5HcHFu+Aom5wiIn2a7niZiE1WKMUhIOhNFJSQZzh0VG8tPcQufLSQI46sO9vcM0NDQ0NDQ0NDQ0NHxF/AFGJOBYBWrb5gAAAABJRU5ErkJggg==';
1 change: 1 addition & 0 deletions packages/core/src/js/feedback/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const defaultConfiguration: Partial<FeedbackFormProps> = {
},

// FeedbackGeneralConfiguration
showBranding: true,
isEmailRequired: false,
shouldValidateEmail: true,
isNameRequired: false,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,4 @@ export type { TimeToDisplayProps } from './tracing';

export { Mask, Unmask } from './replay/CustomMask';

export { FeedbackForm } from './feedback/FeedbackForm';
export { FeedbackForm, showFeedbackForm } from './feedback/FeedbackForm';
9 changes: 8 additions & 1 deletion packages/core/test/feedback/FeedbackForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ describe('FeedbackForm', () => {
});

it('renders correctly', () => {
const { getByPlaceholderText, getByText } = render(<FeedbackForm {...defaultProps} />);
const { getByPlaceholderText, getByText, getByTestId } = render(<FeedbackForm {...defaultProps} />);

expect(getByText(defaultProps.formTitle)).toBeTruthy();
expect(getByTestId('sentry-logo')).toBeTruthy(); // default showBranding is true
expect(getByText(defaultProps.nameLabel)).toBeTruthy();
expect(getByPlaceholderText(defaultProps.namePlaceholder)).toBeTruthy();
expect(getByText(defaultProps.emailLabel)).toBeTruthy();
Expand All @@ -78,6 +79,12 @@ describe('FeedbackForm', () => {
expect(getByText(defaultProps.cancelButtonLabel)).toBeTruthy();
});

it('does not render the sentry logo when showBranding is false', () => {
const { queryByTestId } = render(<FeedbackForm {...defaultProps} showBranding={false} />);

expect(queryByTestId('sentry-logo')).toBeNull();
});

it('name and email are prefilled when sentry user is set', () => {
const { getByPlaceholderText } = render(<FeedbackForm {...defaultProps} />);

Expand Down
4 changes: 2 additions & 2 deletions samples/react-native-macos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"@react-navigation/bottom-tabs": "^6.5.12",
"@react-navigation/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20",
"@sentry/core": "8.46.0",
"@sentry/react": "8.46.0",
"@sentry/core": "8.47.0",
"@sentry/react": "8.47.0",
"@sentry/react-native": "6.4.0",
"delay": "^6.0.0",
"react": "18.2.0",
Expand Down
7 changes: 7 additions & 0 deletions samples/react-native/src/Screens/ErrorsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from 'react-native';

import * as Sentry from '@sentry/react-native';
import { showFeedbackForm } from '@sentry/react-native';

import { setScopeProperties } from '../setScopeProperties';
import { StackNavigationProp } from '@react-navigation/stack';
Expand Down Expand Up @@ -226,6 +227,12 @@ const ErrorsScreen = (_props: Props) => {
_props.navigation.navigate('FeedbackForm');
}}
/>
<Button
title="Feedback form (autoinject)"
onPress={() => {
showFeedbackForm(_props.navigation);
}}
/>
<Button
title="Send user feedback"
onPress={() => {
Expand Down
Loading

0 comments on commit 1192b17

Please sign in to comment.