var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { captureFeedback, debug, getCurrentScope, getGlobalScope, getIsolationScope, lastEventId } from '@sentry/core';
import * as React from 'react';
import { Appearance, Image, Keyboard, Text, TextInput, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
import { isExpoGo, isWeb, notWeb } from '../utils/environment';
import { getDataFromUri, NATIVE } from '../wrapper';
import { sentryLogo } from './branding';
import { defaultConfiguration } from './defaults';
import defaultStyles from './FeedbackWidget.styles';
import { getTheme } from './FeedbackWidget.theme';
import { hideFeedbackButton, showScreenshotButton } from './FeedbackWidgetManager';
import { lazyLoadFeedbackIntegration } from './lazy';
import { getCapturedScreenshot } from './ScreenshotButton';
import { base64ToUint8Array, feedbackAlertDialog, isValidEmail } from './utils';
/**
 * @beta
 * Implements a feedback form screen that sends feedback to Sentry using Sentry.captureFeedback.
 */
export class FeedbackWidget extends React.Component {
    constructor(props) {
        var _a, _b, _c, _d, _e, _f;
        super(props);
        this._didSubmitForm = false;
        this.handleFeedbackSubmit = () => {
            const { name, email, description } = this.state;
            const { onSubmitSuccess, onSubmitError, onFormSubmitted } = this.props;
            const text = this.props;
            const trimmedName = name === null || name === void 0 ? void 0 : name.trim();
            const trimmedEmail = email === null || email === void 0 ? void 0 : email.trim();
            const trimmedDescription = description === null || description === void 0 ? void 0 : description.trim();
            if ((this.props.isNameRequired && !trimmedName) ||
                (this.props.isEmailRequired && !trimmedEmail) ||
                !trimmedDescription) {
                feedbackAlertDialog(text.errorTitle, text.formError);
                return;
            }
            if (this.props.shouldValidateEmail &&
                (this.props.isEmailRequired || trimmedEmail.length > 0) &&
                !isValidEmail(trimmedEmail)) {
                feedbackAlertDialog(text.errorTitle, text.emailError);
                return;
            }
            const attachments = this.state.filename && this.state.attachment
                ? [
                    {
                        filename: this.state.filename,
                        data: this.state.attachment,
                    },
                ]
                : undefined;
            const eventId = lastEventId();
            const userFeedback = {
                message: trimmedDescription,
                name: trimmedName,
                email: trimmedEmail,
                associatedEventId: eventId,
            };
            try {
                if (!onFormSubmitted) {
                    this.setState({ isVisible: false });
                }
                captureFeedback(userFeedback, attachments ? { attachments } : undefined);
                onSubmitSuccess({
                    name: trimmedName,
                    email: trimmedEmail,
                    message: trimmedDescription,
                    attachments: attachments,
                });
                feedbackAlertDialog(text.successMessageText, '');
                onFormSubmitted();
                this._didSubmitForm = true;
            }
            catch (error) {
                const errorString = `Feedback form submission failed: ${error}`;
                onSubmitError(new Error(errorString));
                feedbackAlertDialog(text.errorTitle, text.genericError);
                debug.error(`Feedback form submission failed: ${error}`);
            }
        };
        this.onScreenshotButtonPress = () => __awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d, _e;
            if (!this._hasScreenshot()) {
                const { imagePicker } = this.props;
                if (imagePicker) {
                    const launchImageLibrary = imagePicker.launchImageLibraryAsync
                        ? // expo-image-picker library is available
                            () => { var _a; return (_a = imagePicker.launchImageLibraryAsync) === null || _a === void 0 ? void 0 : _a.call(imagePicker, { mediaTypes: ['images'], base64: isWeb() }); }
                        : // react-native-image-picker library is available
                            imagePicker.launchImageLibrary
                                ? () => { var _a; return (_a = imagePicker.launchImageLibrary) === null || _a === void 0 ? void 0 : _a.call(imagePicker, { mediaType: 'photo', includeBase64: isWeb() }); }
                                : null;
                    if (!launchImageLibrary) {
                        debug.warn('No compatible image picker library found. Please provide a valid image picker library.');
                        if (__DEV__) {
                            feedbackAlertDialog('Development note', 'No compatible image picker library found. Please provide a compatible version of `expo-image-picker` or `react-native-image-picker`.');
                        }
                        return;
                    }
                    const result = yield launchImageLibrary();
                    if ((result === null || result === void 0 ? void 0 : result.assets) && result.assets.length > 0) {
                        if (isWeb()) {
                            const filename = (_a = result.assets[0]) === null || _a === void 0 ? void 0 : _a.fileName;
                            const imageUri = (_b = result.assets[0]) === null || _b === void 0 ? void 0 : _b.uri;
                            const base64 = (_c = result.assets[0]) === null || _c === void 0 ? void 0 : _c.base64;
                            const data = base64 ? base64ToUint8Array(base64) : undefined;
                            if (data) {
                                this.setState({ filename, attachment: data, attachmentUri: imageUri });
                            }
                            else {
                                debug.error('Failed to read image data on the web');
                            }
                        }
                        else {
                            const filename = (_d = result.assets[0]) === null || _d === void 0 ? void 0 : _d.fileName;
                            const imageUri = (_e = result.assets[0]) === null || _e === void 0 ? void 0 : _e.uri;
                            imageUri &&
                                getDataFromUri(imageUri)
                                    .then((data) => {
                                    if (data != null) {
                                        this.setState({ filename, attachment: data, attachmentUri: imageUri });
                                    }
                                    else {
                                        this._showImageRetrievalDevelopmentNote();
                                        debug.error('Failed to read image data from uri:', imageUri);
                                    }
                                })
                                    .catch((error) => {
                                    this._showImageRetrievalDevelopmentNote();
                                    debug.error('Failed to read image data from uri:', imageUri, 'error: ', error);
                                });
                        }
                    }
                }
                else {
                    // Defaulting to the onAddScreenshot callback
                    const { onAddScreenshot } = Object.assign(Object.assign({}, defaultConfiguration), this.props);
                    onAddScreenshot((uri) => {
                        getDataFromUri(uri).then((data) => {
                            if (data != null) {
                                this.setState({ filename: 'feedback_screenshot', attachment: data, attachmentUri: uri });
                            }
                            else {
                                this._showImageRetrievalDevelopmentNote();
                                debug.error('Failed to read image data from uri:', uri);
                            }
                        }).catch((error) => {
                            this._showImageRetrievalDevelopmentNote();
                            debug.error('Failed to read image data from uri:', uri, 'error: ', error);
                        });
                    });
                }
            }
            else {
                this.setState({ filename: undefined, attachment: undefined, attachmentUri: undefined });
            }
        });
        this._setCapturedScreenshot = (screenshot) => {
            if (screenshot.data != null) {
                debug.log('Setting captured screenshot:', screenshot.filename);
                NATIVE.encodeToBase64(screenshot.data)
                    .then(base64String => {
                    if (base64String != null) {
                        const dataUri = `data:${screenshot.contentType};base64,${base64String}`;
                        this.setState({ filename: screenshot.filename, attachment: screenshot.data, attachmentUri: dataUri });
                    }
                    else {
                        debug.error('Failed to read image data from:', screenshot.filename);
                    }
                })
                    .catch(error => {
                    debug.error('Failed to read image data from:', screenshot.filename, 'error: ', error);
                });
            }
            else {
                debug.error('Failed to read image data from:', screenshot.filename);
            }
        };
        this._saveFormState = () => {
            FeedbackWidget._savedState = Object.assign({}, this.state);
        };
        this._clearFormState = () => {
            FeedbackWidget._savedState = {
                name: '',
                email: '',
                description: '',
                filename: undefined,
                attachment: undefined,
                attachmentUri: undefined,
            };
        };
        this._hasScreenshot = () => {
            return this.state.filename !== undefined && this.state.attachment !== undefined && this.state.attachmentUri !== undefined;
        };
        this._getUser = () => {
            const currentUser = getCurrentScope().getUser();
            if (currentUser) {
                return currentUser;
            }
            const isolationUser = getIsolationScope().getUser();
            if (isolationUser) {
                return isolationUser;
            }
            return getGlobalScope().getUser();
        };
        this._showImageRetrievalDevelopmentNote = () => {
            if (isExpoGo()) {
                feedbackAlertDialog('Development note', 'The feedback widget cannot retrieve image data in Expo Go. Please build your app to test this functionality.');
            }
        };
        const currentUser = {
            useSentryUser: {
                email: ((_b = (_a = this.props) === null || _a === void 0 ? void 0 : _a.useSentryUser) === null || _b === void 0 ? void 0 : _b.email) || ((_c = this._getUser()) === null || _c === void 0 ? void 0 : _c.email) || '',
                name: ((_e = (_d = this.props) === null || _d === void 0 ? void 0 : _d.useSentryUser) === null || _e === void 0 ? void 0 : _e.name) || ((_f = this._getUser()) === null || _f === void 0 ? void 0 : _f.name) || '',
            }
        };
        this.state = {
            isVisible: true,
            name: FeedbackWidget._savedState.name || currentUser.useSentryUser.name,
            email: FeedbackWidget._savedState.email || currentUser.useSentryUser.email,
            description: FeedbackWidget._savedState.description || '',
            filename: FeedbackWidget._savedState.filename || undefined,
            attachment: FeedbackWidget._savedState.attachment || undefined,
            attachmentUri: FeedbackWidget._savedState.attachmentUri || undefined,
        };
        lazyLoadFeedbackIntegration();
    }
    /**
     * For testing purposes only.
     */
    static reset() {
        FeedbackWidget._savedState = {
            name: '',
            email: '',
            description: '',
            filename: undefined,
            attachment: undefined,
            attachmentUri: undefined,
        };
    }
    /**
     * Add a listener to the theme change event.
     */
    componentDidMount() {
        this._themeListener = Appearance.addChangeListener(() => {
            this.forceUpdate();
        });
    }
    /**
     * Save the state before unmounting the component and remove the theme listener.
     */
    componentWillUnmount() {
        if (this._didSubmitForm) {
            this._clearFormState();
            this._didSubmitForm = false;
        }
        else {
            this._saveFormState();
        }
        if (this._themeListener) {
            this._themeListener.remove();
        }
    }
    /**
     * Renders the feedback form screen.
     */
    render() {
        const theme = getTheme();
        const { name, email, description } = this.state;
        const { onFormClose } = this.props;
        const config = this.props;
        const imagePickerConfiguration = this.props;
        const text = this.props;
        const _defaultStyles = defaultStyles(theme);
        const _propStyles = this.props.styles || {};
        const autoCorrect = config.autoCorrect !== false;
        const spellCheck = config.spellCheck !== false;
        const styles = Object.keys(_defaultStyles).reduce((merged, key) => {
            merged[key] = Object.assign(Object.assign({}, _defaultStyles[key]), _propStyles[key]);
            return merged;
        }, {});
        const onCancel = () => {
            if (onFormClose) {
                onFormClose();
            }
            else {
                this.setState({ isVisible: false });
            }
        };
        if (!this.state.isVisible) {
            return null;
        }
        const screenshot = getCapturedScreenshot();
        if (screenshot === 'ErrorCapturingScreenshot') {
            setTimeout(() => __awaiter(this, void 0, void 0, function* () {
                feedbackAlertDialog(text.errorTitle, text.captureScreenshotError);
            }), 100);
        }
        else if (screenshot) {
            this._setCapturedScreenshot(screenshot);
        }
        return (React.createElement(TouchableWithoutFeedback, { onPress: notWeb() ? Keyboard.dismiss : undefined, accessible: false, accessibilityElementsHidden: false },
            React.createElement(View, { style: styles.container },
                React.createElement(View, { style: styles.titleContainer },
                    React.createElement(Text, { style: styles.title, testID: "sentry-feedback-form-title" }, text.formTitle),
                    config.showBranding && (React.createElement(Image, { source: { uri: sentryLogo }, style: styles.sentryLogo, testID: "sentry-logo" }))),
                config.showName && (React.createElement(React.Fragment, null,
                    React.createElement(Text, { style: styles.label },
                        text.nameLabel,
                        config.isNameRequired && ` ${text.isRequiredLabel}`),
                    React.createElement(TextInput, { style: styles.input, testID: "sentry-feedback-name-input", placeholder: text.namePlaceholder, value: name, onChangeText: value => this.setState({ name: value }), autoCorrect: false, spellCheck: false }))),
                config.showEmail && (React.createElement(React.Fragment, null,
                    React.createElement(Text, { style: styles.label },
                        text.emailLabel,
                        config.isEmailRequired && ` ${text.isRequiredLabel}`),
                    React.createElement(TextInput, { style: styles.input, testID: "sentry-feedback-email-input", placeholder: text.emailPlaceholder, keyboardType: 'email-address', autoCapitalize: "none", autoCorrect: false, spellCheck: false, value: email, onChangeText: value => this.setState({ email: value }) }))),
                React.createElement(Text, { style: styles.label },
                    text.messageLabel,
                    ` ${text.isRequiredLabel}`),
                React.createElement(TextInput, { style: [styles.input, styles.textArea], testID: "sentry-feedback-message-input", placeholder: text.messagePlaceholder, value: description, onChangeText: value => this.setState({ description: value }), multiline: true, autoCorrect: autoCorrect, spellCheck: spellCheck }),
                (config.enableScreenshot || imagePickerConfiguration.imagePicker || this._hasScreenshot()) && (React.createElement(View, { style: styles.screenshotContainer },
                    this.state.attachmentUri && (React.createElement(Image, { source: { uri: this.state.attachmentUri }, style: styles.screenshotThumbnail })),
                    React.createElement(TouchableOpacity, { style: styles.screenshotButton, onPress: this.onScreenshotButtonPress },
                        React.createElement(Text, { style: styles.screenshotText }, !this._hasScreenshot() ? text.addScreenshotButtonLabel : text.removeScreenshotButtonLabel)))),
                notWeb() && config.enableTakeScreenshot && !this.state.attachmentUri && (React.createElement(TouchableOpacity, { style: styles.takeScreenshotButton, onPress: () => {
                        hideFeedbackButton();
                        onCancel();
                        showScreenshotButton();
                    } },
                    React.createElement(Text, { style: styles.takeScreenshotText, testID: 'sentry-feedback-take-screenshot-button' }, text.captureScreenshotButtonLabel))),
                React.createElement(TouchableOpacity, { style: styles.submitButton, onPress: this.handleFeedbackSubmit },
                    React.createElement(Text, { style: styles.submitText, testID: "sentry-feedback-submit-button" }, text.submitButtonLabel)),
                React.createElement(TouchableOpacity, { style: styles.cancelButton, onPress: onCancel },
                    React.createElement(Text, { style: styles.cancelText }, text.cancelButtonLabel)))));
    }
}
FeedbackWidget.defaultProps = defaultConfiguration;
FeedbackWidget._savedState = {
    name: '',
    email: '',
    description: '',
    filename: undefined,
    attachment: undefined,
    attachmentUri: undefined,
};
//# sourceMappingURL=FeedbackWidget.js.map