All files / app/payment SpamProtectionField.tsx

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109  4x 4x   4x 4x 4x                                 10x   10x           10x       10x       4x 9x   9x 3x     6x     4x 14x   14x                 4x 14x 14x   14x 7x     7x                         4x 7x           14x   4x     4x 3x         10x 1x   1x   4x   4x  
import { CheckoutSelectors } from '@bigcommerce/checkout-sdk';
import { noop } from 'lodash';
import React, { Component, MouseEvent, ReactNode } from 'react';
 
import { withCheckout, CheckoutContextProps } from '../checkout';
import { TranslatedString } from '../locale';
import { LoadingOverlay } from '../ui/loading';
 
export interface SpamProtectionProps {
    didExceedSpamLimit?: boolean;
    onUnhandledError?(error: Error): void;
}
 
interface SpamProtectionState {
    shouldShowRetryButton: boolean;
}
 
interface WithCheckoutSpamProtectionProps {
    isExecutingSpamCheck: boolean;
    executeSpamCheck(): Promise<CheckoutSelectors>;
}
 
function mapToSpamProtectionProps(
    { checkoutService, checkoutState }: CheckoutContextProps
): WithCheckoutSpamProtectionProps {
    return {
        isExecutingSpamCheck: checkoutState.statuses.isExecutingSpamCheck(),
        executeSpamCheck: checkoutService.executeSpamCheck,
    };
}
 
class SpamProtectionField extends Component<
    SpamProtectionProps & WithCheckoutSpamProtectionProps,
    SpamProtectionState
> {
    state = {
        shouldShowRetryButton: false,
    };
 
    async componentDidMount() {
        const { didExceedSpamLimit } = this.props;
 
        if (didExceedSpamLimit) {
            return;
        }
 
        this.verify();
    }
 
    render() {
        const { isExecutingSpamCheck } = this.props;
 
        return (
            <div className="spamProtection-container">
                <LoadingOverlay isLoading={ isExecutingSpamCheck }>
                    { this.renderContent() }
                </LoadingOverlay>
            </div>
        );
    }
 
    private renderContent(): ReactNode {
        const { didExceedSpamLimit } = this.props;
        const { shouldShowRetryButton } = this.state;
 
        if (!didExceedSpamLimit && !shouldShowRetryButton) {
            return;
        }
 
        return <div className="spamProtection-panel optimizedCheckout-overlay">
            <a
                className="spamProtection-panel-message optimizedCheckout-primaryContent"
                data-test="spam-protection-verify-button"
                onClick={ this.handleRetry }
            >
                <TranslatedString
                    id="spam_protection.verify_action"
                />
            </a>
        </div>;
    }
 
    private async verify(): Promise<void> {
        const {
            executeSpamCheck,
            onUnhandledError = noop,
        } = this.props;
 
        try {
            await executeSpamCheck();
        } catch (error) {
            this.setState({ shouldShowRetryButton: true });
 
            // Notify the parent component if the user experiences a problem other than cancelling the reCaptcha challenge.
            if (error && error.type !== 'spam_protection_challenge_not_completed') {
                onUnhandledError(error);
            }
        }
    }
 
    private handleRetry: (event: MouseEvent) => void = event => {
        event.preventDefault();
 
        this.verify();
    };
}
 
export default withCheckout(mapToSpamProtectionProps)(SpamProtectionField);