Skip to content

Commit beb77ad

Browse files
authored
Merge 71b28e8 into 8ab11b6
2 parents 8ab11b6 + 71b28e8 commit beb77ad

File tree

8 files changed

+68
-75
lines changed

8 files changed

+68
-75
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@
88
99
## Unreleased
1010

11+
### Features
12+
13+
- Adds new `captureFeedback` and deprecates the `captureUserFeedback` API ([#4320](https://github.com/getsentry/sentry-react-native/pull/4320))
14+
15+
16+
```jsx
17+
import * as Sentry from "@sentry/react-native";
18+
19+
const eventId = Sentry.lastEventId();
20+
21+
Sentry.captureFeedback({
22+
name: "John Doe",
23+
email: "john@doe.com",
24+
message: "Hello World!",
25+
associatedEventId: eventId, // optional
26+
});
27+
```
28+
1129
### Fixes
1230

1331
- Return `lastEventId` export from `@sentry/core` ([#4315](https://github.com/getsentry/sentry-react-native/pull/4315))

packages/core/src/js/client.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import type {
99
Outcome,
1010
SeverityLevel,
1111
TransportMakeRequestResponse,
12-
UserFeedback,
1312
} from '@sentry/types';
1413
import { dateTimestampInSeconds, logger, SentryError } from '@sentry/utils';
1514
import { Alert } from 'react-native';
@@ -20,7 +19,7 @@ import { getDefaultSidecarUrl } from './integrations/spotlight';
2019
import type { ReactNativeClientOptions } from './options';
2120
import type { mobileReplayIntegration } from './replay/mobilereplay';
2221
import { MOBILE_REPLAY_INTEGRATION_NAME } from './replay/mobilereplay';
23-
import { createUserFeedbackEnvelope, items } from './utils/envelope';
22+
import { items } from './utils/envelope';
2423
import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs';
2524
import { mergeOutcomes } from './utils/outcome';
2625
import { ReactNativeLibraries } from './utils/rnlibraries';
@@ -83,19 +82,6 @@ export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
8382
});
8483
}
8584

86-
/**
87-
* Sends user feedback to Sentry.
88-
*/
89-
public captureUserFeedback(feedback: UserFeedback): void {
90-
const envelope = createUserFeedbackEnvelope(feedback, {
91-
metadata: this._options._metadata,
92-
dsn: this.getDsn(),
93-
tunnel: undefined,
94-
});
95-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
96-
this.sendEnvelope(envelope);
97-
}
98-
9985
/**
10086
* @inheritdoc
10187
*/

packages/core/src/js/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export type {
44
SdkInfo,
55
Event,
66
Exception,
7+
SendFeedbackParams,
78
SeverityLevel,
89
StackFrame,
910
Stacktrace,
@@ -16,6 +17,7 @@ export {
1617
addBreadcrumb,
1718
captureException,
1819
captureEvent,
20+
captureFeedback,
1921
captureMessage,
2022
Scope,
2123
setContext,

packages/core/src/js/sdk.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* eslint-disable complexity */
2-
import { getClient, getGlobalScope,getIntegrationsToSetup, getIsolationScope,initAndBind, withScope as coreWithScope } from '@sentry/core';
2+
import { captureFeedback, getClient, getGlobalScope,getIntegrationsToSetup, getIsolationScope,initAndBind, withScope as coreWithScope } from '@sentry/core';
33
import {
44
defaultStackParser,
55
makeFetchTransport,
66
} from '@sentry/react';
7-
import type { Breadcrumb, BreadcrumbHint, Integration, Scope, UserFeedback } from '@sentry/types';
7+
import type { Breadcrumb, BreadcrumbHint, Integration, Scope, SendFeedbackParams, UserFeedback } from '@sentry/types';
88
import { logger, stackParserFromStackParserOptions } from '@sentry/utils';
99
import * as React from 'react';
1010

@@ -219,9 +219,16 @@ export async function close(): Promise<void> {
219219

220220
/**
221221
* Captures user feedback and sends it to Sentry.
222+
* @deprecated Use `Sentry.captureFeedback` instead.
222223
*/
223224
export function captureUserFeedback(feedback: UserFeedback): void {
224-
getClient<ReactNativeClient>()?.captureUserFeedback(feedback);
225+
const feedbackParams: SendFeedbackParams = {
226+
name: feedback.name,
227+
email: feedback.email,
228+
message: feedback.comments,
229+
associatedEventId: feedback.event_id,
230+
};
231+
captureFeedback(feedbackParams);
225232
}
226233

227234
/**

packages/core/test/client.test.ts

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
envelopeItems,
2020
firstArg,
2121
getMockSession,
22-
getMockUserFeedback,
2322
getSyncPromiseRejectOnFirstCall,
2423
} from './testutils';
2524

@@ -187,15 +186,6 @@ describe('Tests ReactNativeClient', () => {
187186
expect(mockTransport.send).not.toBeCalled();
188187
});
189188

190-
test('captureUserFeedback does not call transport when enabled false', () => {
191-
const mockTransport = createMockTransport();
192-
const client = createDisabledClientWith(mockTransport);
193-
194-
client.captureUserFeedback(getMockUserFeedback());
195-
196-
expect(mockTransport.send).not.toBeCalled();
197-
});
198-
199189
function createDisabledClientWith(transport: Transport) {
200190
return new ReactNativeClient({
201191
...DEFAULT_OPTIONS,
@@ -289,38 +279,6 @@ describe('Tests ReactNativeClient', () => {
289279
});
290280
});
291281

292-
describe('UserFeedback', () => {
293-
test('sends UserFeedback to native Layer', () => {
294-
const mockTransportSend: jest.Mock = jest.fn(() => Promise.resolve());
295-
const client = new ReactNativeClient({
296-
...DEFAULT_OPTIONS,
297-
dsn: EXAMPLE_DSN,
298-
transport: () => ({
299-
send: mockTransportSend,
300-
flush: jest.fn(),
301-
}),
302-
});
303-
304-
client.captureUserFeedback({
305-
comments: 'Test Comments',
306-
email: 'test@email.com',
307-
name: 'Test User',
308-
event_id: 'testEvent123',
309-
});
310-
311-
expect(mockTransportSend.mock.calls[0][firstArg][envelopeHeader].event_id).toEqual('testEvent123');
312-
expect(mockTransportSend.mock.calls[0][firstArg][envelopeItems][0][envelopeItemHeader].type).toEqual(
313-
'user_report',
314-
);
315-
expect(mockTransportSend.mock.calls[0][firstArg][envelopeItems][0][envelopeItemPayload]).toEqual({
316-
comments: 'Test Comments',
317-
email: 'test@email.com',
318-
name: 'Test User',
319-
event_id: 'testEvent123',
320-
});
321-
});
322-
});
323-
324282
describe('attachStacktrace', () => {
325283
let mockTransportSend: jest.Mock;
326284
let client: ReactNativeClient;
@@ -417,11 +375,6 @@ describe('Tests ReactNativeClient', () => {
417375
client.captureSession(getMockSession());
418376
expect(getSdkInfoFrom(mockTransportSend)).toStrictEqual(expectedSdkInfo);
419377
});
420-
421-
test('send SdkInfo in the user feedback envelope header', () => {
422-
client.captureUserFeedback(getMockUserFeedback());
423-
expect(getSdkInfoFrom(mockTransportSend)).toStrictEqual(expectedSdkInfo);
424-
});
425378
});
426379

427380
describe('event data enhancement', () => {

packages/core/test/testutils.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Session, Transport, UserFeedback } from '@sentry/types';
1+
import type { Session, Transport } from '@sentry/types';
22
import { rejectedSyncPromise } from '@sentry/utils';
33

44
export type MockInterface<T> = {
@@ -36,13 +36,6 @@ export const getMockSession = (): Session => ({
3636
}),
3737
});
3838

39-
export const getMockUserFeedback = (): UserFeedback => ({
40-
comments: 'comments_test_value',
41-
email: 'email_test_value',
42-
name: 'name_test_value',
43-
event_id: 'event_id_test_value',
44-
});
45-
4639
export const getSyncPromiseRejectOnFirstCall = <Y extends any[]>(reason: unknown): jest.Mock => {
4740
let shouldSyncReject = true;
4841
return jest.fn((..._args: Y) => {

samples/react-native-macos/src/components/UserFeedbackModal.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { View, StyleSheet, Text, TextInput, Image, Button } from 'react-native';
33
import * as Sentry from '@sentry/react-native';
4-
import { UserFeedback } from '@sentry/react-native';
4+
import { SendFeedbackParams, UserFeedback } from '@sentry/react-native';
55

66
export const DEFAULT_COMMENTS = "It's broken again! Please fix it.";
77

@@ -48,6 +48,23 @@ export function UserFeedbackModal(props: { onDismiss: () => void }) {
4848
}}
4949
/>
5050
<View style={styles.buttonSpacer} />
51+
<Button
52+
title="Send feedback without event"
53+
color="#6C5FC7"
54+
onPress={async () => {
55+
onDismiss();
56+
57+
const userFeedback: SendFeedbackParams = {
58+
message: comments,
59+
name: 'John Doe',
60+
email: 'john@doe.com',
61+
};
62+
63+
Sentry.captureFeedback(userFeedback);
64+
clearComments();
65+
}}
66+
/>
67+
<View style={styles.buttonSpacer} />
5168
<Button
5269
title="Close"
5370
color="#6C5FC7"

samples/react-native/src/components/UserFeedbackModal.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { View, StyleSheet, Text, TextInput, Image, Button } from 'react-native';
33
import * as Sentry from '@sentry/react-native';
4-
import { UserFeedback } from '@sentry/react-native';
4+
import { SendFeedbackParams, UserFeedback } from '@sentry/react-native';
55

66
export const DEFAULT_COMMENTS = "It's broken again! Please fix it.";
77

@@ -48,6 +48,23 @@ export function UserFeedbackModal(props: { onDismiss: () => void }) {
4848
}}
4949
/>
5050
<View style={styles.buttonSpacer} />
51+
<Button
52+
title="Send feedback without event"
53+
color="#6C5FC7"
54+
onPress={async () => {
55+
onDismiss();
56+
57+
const userFeedback: SendFeedbackParams = {
58+
message: comments,
59+
name: 'John Doe',
60+
email: 'john@doe.com',
61+
};
62+
63+
Sentry.captureFeedback(userFeedback);
64+
clearComments();
65+
}}
66+
/>
67+
<View style={styles.buttonSpacer} />
5168
<Button
5269
title="Close"
5370
color="#6C5FC7"

0 commit comments

Comments
 (0)