Skip to content

feat(feedback): Screenshot button error flow #4757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/core/src/js/feedback/FeedbackWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,11 @@ export class FeedbackWidget extends React.Component<FeedbackWidgetProps, Feedbac
}

const screenshot = getCapturedScreenshot();
if (screenshot) {
if (screenshot === 'ErrorCapturingScreenshot') {
setTimeout(async () => {
feedbackAlertDialog(text.errorTitle, text.captureScreenshotError);
}, 100);
Copy link
Member

@krystofwoldrich krystofwoldrich Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delay is here to let the widget slide back up, a.k.a just for better visuals?

Copy link
Collaborator Author

@antonis antonis Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and to prevent the alert from hiding below the modal.

} else if (screenshot) {
this._setCapturedScreenshot(screenshot);
}

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/js/feedback/FeedbackWidget.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ export interface FeedbackTextConfiguration {
*/
emailError?: string;

/**
* The error message when the capture screenshot fails
*/
captureScreenshotError?: string;

/**
* Message when there is a generic error
*/
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/js/feedback/ScreenshotButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ import { defaultScreenshotButtonConfiguration } from './defaults';
import { defaultScreenshotButtonStyles } from './FeedbackWidget.styles';
import { getTheme } from './FeedbackWidget.theme';
import type { ScreenshotButtonProps, ScreenshotButtonStyles, ScreenshotButtonTextConfiguration } from './FeedbackWidget.types';
import { hideScreenshotButton, showFeedbackWidget, showScreenshotButton } from './FeedbackWidgetManager';
import { hideScreenshotButton, showFeedbackWidget } from './FeedbackWidgetManager';
import { screenshotIcon } from './icons';
import { lazyLoadFeedbackIntegration } from './lazy';

let capturedScreenshot: Screenshot | undefined;
let capturedScreenshot: Screenshot | 'ErrorCapturingScreenshot' | undefined;

const takeScreenshot = async (): Promise<void> => {
hideScreenshotButton();
setTimeout(async () => { // Delay capture to allow the button to hide
const screenshots: Screenshot[] | null = await NATIVE.captureScreenshot();
if (screenshots && screenshots.length > 0) {
capturedScreenshot = screenshots[0];
showFeedbackWidget();
} else {
showScreenshotButton();
capturedScreenshot = 'ErrorCapturingScreenshot';
}
showFeedbackWidget();
}, 100);
};

export const getCapturedScreenshot = (): Screenshot | undefined => {
export const getCapturedScreenshot = (): Screenshot | 'ErrorCapturingScreenshot' | undefined => {
const screenshot = capturedScreenshot;
capturedScreenshot = undefined;
return screenshot;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/js/feedback/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const TRIGGER_SCREENSHOT_LABEL = 'Take Screenshot';
const ERROR_TITLE = 'Error';
const FORM_ERROR = 'Please fill out all required fields.';
const EMAIL_ERROR = 'Please enter a valid email address.';
const CAPTURE_SCREENSHOT_ERROR = 'Error capturing screenshot. Please try again.';
const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!';
const ADD_SCREENSHOT_LABEL = 'Add a screenshot';
const CAPTURE_SCREENSHOT_LABEL = 'Take a screenshot';
Expand Down Expand Up @@ -79,6 +80,7 @@ export const defaultConfiguration: Partial<FeedbackWidgetProps> = {
errorTitle: ERROR_TITLE,
formError: FORM_ERROR,
emailError: EMAIL_ERROR,
captureScreenshotError: CAPTURE_SCREENSHOT_ERROR,
successMessageText: SUCCESS_MESSAGE_TEXT,
addScreenshotButtonLabel: ADD_SCREENSHOT_LABEL,
removeScreenshotButtonLabel: REMOVE_SCREENSHOT_LABEL,
Expand Down
11 changes: 6 additions & 5 deletions packages/core/test/feedback/ScreenshotButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getClient, setCurrentClient } from '@sentry/core';
import { fireEvent, render, waitFor } from '@testing-library/react-native';
import * as React from 'react';
import { Text } from 'react-native';
import { Alert, Text } from 'react-native';

import { FeedbackWidget } from '../../src/js/feedback/FeedbackWidget';
import type { ScreenshotButtonProps, ScreenshotButtonStyles } from '../../src/js/feedback/FeedbackWidget.types';
Expand All @@ -20,6 +20,8 @@ jest.mock('../../src/js/wrapper', () => ({
},
}));

jest.spyOn(Alert, 'alert');

const mockScreenshot: Screenshot = {
filename: 'test-screenshot.png',
contentType: 'image/png',
Expand Down Expand Up @@ -188,10 +190,10 @@ describe('ScreenshotButton', () => {
});
});

it('when the capture fails the capture button is still visible', async () => {
it('when the capture fails an error message is shown', async () => {
mockCaptureScreenshot.mockResolvedValue([]);

const { getByText, queryByText } = render(
const { getByText } = render(
<FeedbackWidgetProvider>
<Text>App Components</Text>
</FeedbackWidgetProvider>
Expand All @@ -213,8 +215,7 @@ describe('ScreenshotButton', () => {
});

await waitFor(() => {
const captureButton = queryByText('Take Screenshot');
expect(captureButton).not.toBeNull();
expect(Alert.alert).toHaveBeenCalledWith('Error', 'Error capturing screenshot. Please try again.');
});
});
});
Loading