Skip to content

Commit

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

# Conflicts:
#	packages/core/src/js/feedback/FeedbackForm.tsx
  • Loading branch information
antonis committed Dec 17, 2024
2 parents 30ad951 + e4e23a6 commit 7e3daa7
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 36 deletions.
13 changes: 3 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,11 @@
email: "[email protected]",
message: "Hello World!",
associatedEventId: eventId, // optional
}, {
captureContext: {
tags: { "tag-key": "tag-value" },
},
attachments: [
{
filename: 'hello.txt',
data: 'Hello, World!',
},
],
});
```

To learn how to attach context data to the feedback visit [the documentation](https://docs.sentry.io/platforms/react-native/user-feedback/).

- User Feedback Form Component Beta ([#4320](https://github.com/getsentry/sentry-react-native/pull/4328))

To collect user feedback from inside your application add the `FeedbackForm` component.
Expand All @@ -46,6 +38,7 @@
```

- 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))

### Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ public class RNSentryModuleImpl {

public static final String NAME = "RNSentry";

private static final String NATIVE_SDK_NAME = "sentry.native.android.react-native";
private static final String ANDROID_SDK_NAME = "sentry.java.android.react-native";
private static final ILogger logger = new AndroidLogger(NAME);
private static final BuildInfoProvider buildInfo = new BuildInfoProvider(logger);
private static final String modulesPath = "modules.json";
Expand Down Expand Up @@ -191,13 +189,16 @@ protected void getSentryAndroidOptions(
@NotNull SentryAndroidOptions options, @NotNull ReadableMap rnOptions, ILogger logger) {
@Nullable SdkVersion sdkVersion = options.getSdkVersion();
if (sdkVersion == null) {
sdkVersion = new SdkVersion(ANDROID_SDK_NAME, BuildConfig.VERSION_NAME);
sdkVersion = new SdkVersion(RNSentryVersion.ANDROID_SDK_NAME, BuildConfig.VERSION_NAME);
} else {
sdkVersion.setName(ANDROID_SDK_NAME);
sdkVersion.setName(RNSentryVersion.ANDROID_SDK_NAME);
}
sdkVersion.addPackage(
RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME,
RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION);

options.setSentryClientName(sdkVersion.getName() + "/" + sdkVersion.getVersion());
options.setNativeSdkName(NATIVE_SDK_NAME);
options.setNativeSdkName(RNSentryVersion.NATIVE_SDK_NAME);
options.setSdkVersion(sdkVersion);

if (rnOptions.hasKey("debug") && rnOptions.getBoolean("debug")) {
Expand Down Expand Up @@ -970,10 +971,10 @@ private void setEventOriginTag(SentryEvent event) {
SdkVersion sdk = event.getSdk();
if (sdk != null) {
switch (sdk.getName()) {
case NATIVE_SDK_NAME:
case RNSentryVersion.NATIVE_SDK_NAME:
setEventEnvironmentTag(event, "native");
break;
case ANDROID_SDK_NAME:
case RNSentryVersion.ANDROID_SDK_NAME:
setEventEnvironmentTag(event, "java");
break;
default:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.sentry.react;

class RNSentryVersion {
static final String REACT_NATIVE_SDK_PACKAGE_NAME = "npm:@sentry/react-native";
static final String REACT_NATIVE_SDK_PACKAGE_VERSION = "6.4.0";
static final String NATIVE_SDK_NAME = "sentry.native.android.react-native";
static final String ANDROID_SDK_NAME = "sentry.java.android.react-native";
}
2 changes: 1 addition & 1 deletion packages/core/src/js/feedback/FeedbackForm.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FeedbackFormStyles } from './FeedbackForm.types';

const PURPLE = 'rgba(88, 74, 192, 1)';
const FORGROUND_COLOR = '#2b2233';
const BACKROUND_COLOR = '#fff';
const BACKROUND_COLOR = '#ffffff';
const BORDER_COLOR = 'rgba(41, 35, 47, 0.13)';

const defaultStyles: FeedbackFormStyles = {
Expand Down
27 changes: 14 additions & 13 deletions packages/core/src/js/feedback/FeedbackForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,42 +35,43 @@ const submitFeedback = async (feedbackParams: SendFeedbackParams, hint: EventHin
* Implements a feedback form screen that sends feedback to Sentry using Sentry.captureFeedback.
*/
export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFormState> {
private _config: FeedbackFormProps;
public static defaultProps: Partial<FeedbackFormProps> = {
...defaultConfiguration
}

public constructor(props: FeedbackFormProps) {
super(props);

const currentUser = {
useSentryUser: {
email: getCurrentScope().getUser().email || '',
name: getCurrentScope().getUser().name || '',
email: this.props?.useSentryUser?.email || getCurrentScope()?.getUser()?.email || '',
name: this.props?.useSentryUser?.name || getCurrentScope()?.getUser()?.name || '',
}
}

this._config = { ...defaultConfiguration, ...currentUser, ...props };
this.state = {
isVisible: true,
name: this._config.useSentryUser.name,
email: this._config.useSentryUser.email,
name: currentUser.useSentryUser.name,
email: currentUser.useSentryUser.email,
description: '',
};
}

public handleFeedbackSubmit: () => void = () => {
const { name, email, description } = this.state;
const { onSubmitSuccess, onSubmitError, onFormSubmitted } = this._config;
const text: FeedbackTextConfiguration = this._config;
const { onSubmitSuccess, onSubmitError, onFormSubmitted } = this.props;
const text: FeedbackTextConfiguration = this.props;

const trimmedName = name?.trim();
const trimmedEmail = email?.trim();
const trimmedDescription = description?.trim();

if ((this._config.isNameRequired && !trimmedName) || (this._config.isEmailRequired && !trimmedEmail) || !trimmedDescription) {
if ((this.props.isNameRequired && !trimmedName) || (this.props.isEmailRequired && !trimmedEmail) || !trimmedDescription) {
Alert.alert(text.errorTitle, text.formError);
return;
}

if (this._config.shouldValidateEmail && (this._config.isEmailRequired || trimmedEmail.length > 0) && !isValidEmail(trimmedEmail)) {
if (this.props.shouldValidateEmail && (this.props.isEmailRequired || trimmedEmail.length > 0) && !isValidEmail(trimmedEmail)) {
Alert.alert(text.errorTitle, text.emailError);
return;
}
Expand Down Expand Up @@ -111,9 +112,9 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
*/
public render(): React.ReactNode {
const { name, email, description } = this.state;
const { onFormClose } = this._config;
const config: FeedbackGeneralConfiguration = this._config;
const text: FeedbackTextConfiguration = this._config;
const { onFormClose } = this.props;
const config: FeedbackGeneralConfiguration = this.props;
const text: FeedbackTextConfiguration = this.props;
const styles: FeedbackFormStyles = { ...defaultStyles, ...this.props.styles };
const onCancel = (): void => {
onFormClose();
Expand Down
20 changes: 16 additions & 4 deletions packages/core/test/feedback/FeedbackForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ const mockOnFormClose = jest.fn();
const mockOnSubmitSuccess = jest.fn();
const mockOnFormSubmitted = jest.fn();
const mockOnSubmitError = jest.fn();
const mockGetUser = jest.fn(() => ({
email: '[email protected]',
name: 'Test User',
}));

jest.spyOn(Alert, 'alert');

jest.mock('@sentry/core', () => ({
...jest.requireActual('@sentry/core'),
getCurrentScope: jest.fn(() => ({
getUser: jest.fn(() => ({
email: '[email protected]',
name: 'Test User',
})),
getUser: mockGetUser,
})),
lastEventId: jest.fn(),
}));
Expand Down Expand Up @@ -89,6 +90,17 @@ describe('FeedbackForm', () => {
expect(emailInput.props.value).toBe('[email protected]');
});

it('ensure getUser is called only after the component is rendered', () => {
// Ensure getUser is not called before render
expect(mockGetUser).not.toHaveBeenCalled();

// Render the component
render(<FeedbackForm />);

// After rendering, check that getUser was called twice (email and name)
expect(mockGetUser).toHaveBeenCalledTimes(2);
});

it('shows an error message if required fields are empty', async () => {
const { getByText } = render(<FeedbackForm {...defaultProps} />);

Expand Down
5 changes: 4 additions & 1 deletion scripts/version-bump.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ const replace = require('replace-in-file');
const pjson = require('../packages/core/package.json');

replace({
files: ['packages/core/src/js/version.ts'],
files: [
'packages/core/src/js/version.ts',
'packages/core/android/src/main/java/io/sentry/react/RNSentryVersion.java',
],
from: /\d+\.\d+.\d+(?:-\w+(?:\.\w+)?)?/g,
to: pjson.version,
})
Expand Down

0 comments on commit 7e3daa7

Please sign in to comment.