--- help-contact-form ---
/** @format */

/**
 * External dependencies
 */

import PropTypes from 'prop-types';
import React from 'react';
import { debounce, isEqual, find } from 'lodash';
import { connect } from 'react-redux';
import { localize } from 'i18n-calypso';

/**
 * Internal dependencies
 */
import analytics from 'lib/analytics';
import config from 'config';
import FormLabel from 'components/forms/form-label';
import SegmentedControl from 'components/segmented-control';
import ControlItem from 'components/segmented-control/item';
import SelectDropdown from 'components/select-dropdown';
import DropdownItem from 'components/select-dropdown/item';
import FormTextarea from 'components/forms/form-textarea';
import FormTextInput from 'components/forms/form-text-input';
import FormButton from 'components/forms/form-button';
import SitesDropdown from 'components/sites-dropdown';
import ChatBusinessConciergeNotice from '../chat-business-concierge-notice';
import { selectSiteId } from 'state/help/actions';
import { getHelpSelectedSite } from 'state/help/selectors';
import wpcomLib from 'lib/wp';
import HelpResults from 'me/help/help-results';
import { bumpStat, recordTracksEvent, composeAnalytics } from 'state/analytics/actions';

/**
 * Module variables
 */
const wpcom = wpcomLib.undocumented();

const trackSibylClick = ( event, helpLink ) =>
        composeAnalytics(
                bumpStat( 'sibyl_question_clicks', helpLink.id ),
                recordTracksEvent( 'calypso_sibyl_question_click', {
                        question_id: helpLink.id,
                } )
        );

const trackSupportAfterSibylClick = () =>
        composeAnalytics( recordTracksEvent( 'calypso_sibyl_support_after_question_click' ) );

export class HelpContactForm extends React.PureComponent {
        static propTypes = {
                formDescription: PropTypes.node,
                buttonLabel: PropTypes.string.isRequired,
                onSubmit: PropTypes.func.isRequired,
                showHowCanWeHelpField: PropTypes.bool,
                showHowYouFeelField: PropTypes.bool,
                showSubjectField: PropTypes.bool,
                showSiteField: PropTypes.bool,
                showHelpLanguagePrompt: PropTypes.bool,
                selectedSite: PropTypes.object,
                siteFilter: PropTypes.func,
                siteList: PropTypes.object,
                disabled: PropTypes.bool,
                valueLink: PropTypes.shape( {
                        value: PropTypes.any,
                        requestChange: PropTypes.func.isRequired,
                } ),
        };

        static defaultProps = {
                formDescription: '',
                showHowCanWeHelpField: false,
                showHowYouFeelField: false,
                showSubjectField: false,
                showSiteField: false,
                showHelpLanguagePrompt: false,
                disabled: false,
                valueLink: {
                        value: null,
                        requestChange: () => {},
                },
        };

        /**
         * Setup our initial state
         * @return {Object} An object representing our initial state
         */
        state = this.props.valueLink.value || {
                howCanWeHelp: 'gettingStarted',
                howYouFeel: 'unspecified',
                message: '',
                subject: '',
                sibylClicked: false,
                qanda: [],
        };

        componentDidMount() {
                this.debouncedQandA = debounce( this.doQandASearch, 500 );
        }

        componentWillReceiveProps( nextProps ) {
                if ( ! nextProps.valueLink.value || isEqual( nextProps.valueLink.value, this.state ) ) {
                        return;
                }

                this.setState( nextProps.valueLink.value );
        }

        componentDidUpdate( prevProps, prevState ) {
                if ( prevState.subject !== this.state.subject || prevState.message !== this.state.message ) {
                        this.debouncedQandA();
                }
                this.props.valueLink.requestChange( this.state );
        }

        trackClickStats = ( selectionName, selectedOption ) => {
                const tracksEvent = {
                        howCanWeHelp: 'calypso_help_how_can_we_help_click',
                        howYouFeel: 'calypso_help_how_you_feel_click',
                }[ selectionName ];

                if ( tracksEvent ) {
                        analytics.tracks.recordEvent( tracksEvent, { selected_option: selectedOption } );
                }
        };

        doQandASearch = () => {
                const query = this.state.subject + ' ' + this.state.message;
                const areSameQuestions = ( existingQuestions, newQuestions ) => {
                        const existingIDs = existingQuestions.map( question => question.id );
                        existingIDs.sort();
                        const newIDs = newQuestions.map( question => question.id );
                        newIDs.sort();
                        return existingIDs.toString() === newIDs.toString();
                };
                wpcom
                        .getQandA( query, config( 'happychat_support_blog' ) )
                        .then( qanda =>
                                this.setState( {
                                        qanda,
                                        // only keep sibylClicked true if the user is seeing the same set of questions
                                        // we don't want to track "questions -> question click -> different questions -> support click",
                                        // so we need to set sibylClicked to false here if the questions have changed
                                        sibylClicked: this.state.sibylClicked && areSameQuestions( this.state.qanda, qanda ),
                                } )
                        )
                        .catch( () => this.setState( { qanda: [], sibylClicked: false } ) );
        };

        trackSibylClick = ( event, helpLink ) => {
                this.props.trackSibylClick( event, helpLink );
                this.setState( { sibylClicked: true } );
        };

        /**
         * Render both a SegmentedControl and SelectDropdown component.
         *
         * The SegmentedControl is used for desktop and the SelectDropdown is used for mobile.
         * CSS will control which one is displayed to the user.
         *
         * @param  {string} selectionName    The name that will be used to store the value of a selected option appearing in selectionOptions.
         * @param  {object} selectionOptions An array of objects consisting of a value and a label. It can also have a property called subtext
         *                                   value is used when setting state, label is used for display in the selection component, and subtext
         *                                   is used for the second line of text displayed in the SegmentedControl
         * @return {object}                  A JSX object containing both the SegmentedControl and the SelectDropdown.
         */
        renderFormSelection = ( selectionName, selectionOptions ) => {
                const { translate } = this.props;
                const options = selectionOptions.map( option => ( {
                        label: option.label,
                        subtext: option.subtext ? (
                                <span className="help-contact-form__selection-subtext">{ option.subtext }</span>
                        ) : null,
                        props: {
                                key: option.value,
                                selected: option.value === this.state[ selectionName ],
                                value: option.value,
                                title: option.label,
                                onClick: () => {
                                        this.setState( { [ selectionName ]: option.value } );
                                        this.trackClickStats( selectionName, option.value );
                                },
                        },
                } ) );
                const selectedItem = find( options, 'props.selected' );

                return (
                        <div className="help-contact-form__selection">
                                <SegmentedControl primary>
                                        { options.map( option => (
                                                <ControlItem { ...option.props }>
                                                        { option.label }
                                                        { option.subtext }
                                                </ControlItem>
                                        ) ) }
                                </SegmentedControl>
                                <SelectDropdown
                                        selectedText={ selectedItem ? selectedItem.label : translate( 'Select an option' ) }
                                >
                                        { options.map( option => (
                                                <DropdownItem { ...option.props }>{ option.label }</DropdownItem>
                                        ) ) }
                                </SelectDropdown>
                        </div>
                );
        };

        /**
         * Determine if this form is ready to submit
         * @return {bool}       Return true if this form can be submitted
         */
        canSubmitForm = () => {
                const { disabled, showSubjectField } = this.props;
                const { subject, message } = this.state;

                if ( disabled ) {
                        return false;
                }

                if ( showSubjectField && ! subject.trim() ) {
                        return false;
                }

                return !! message.trim();
        };

        /**
         * Start a chat using the info set in state
         * @param  {object} event Event object
         */
        submitForm = () => {
                const { howCanWeHelp, howYouFeel, message, subject } = this.state;

                if ( this.state.sibylClicked ) {
                        // track that the user had clicked a Sibyl result, but still contacted support
                        this.props.trackSupportAfterSibylClick();
                        this.setState( { sibylClicked: false } );
                }

                this.props.onSubmit( {
                        howCanWeHelp,
                        howYouFeel,
                        message,
                        subject,
                        site: this.props.selectedSite,
                } );
        };

        /**
         * Render the contact form
         * @return {object} ReactJS JSX object
         */
        render() {
                const {
                        formDescription,
                        buttonLabel,
                        showHowCanWeHelpField,
                        showHowYouFeelField,
                        showSubjectField,
                        showSiteField,
                        showHelpLanguagePrompt,
                        translate,
                } = this.props;
                const howCanWeHelpOptions = [
                        {
                                value: 'gettingStarted',
                                label: translate( 'Help getting started' ),
                                subtext: translate( 'Can you show me how to…' ),
                        },
                        {
                                value: 'somethingBroken',
                                label: translate( 'Something is broken' ),
                                subtext: translate( 'Can you check this out…' ),
                        },
                        {
                                value: 'suggestion',
                                label: translate( 'I have a suggestion' ),
                                subtext: translate( 'I think it would be cool if…' ),
                        },
                ];
                const howYouFeelOptions = [
                        { value: 'unspecified', label: translate( "I'd rather not" ) },
                        { value: 'happy', label: translate( 'Happy' ) },
                        { value: 'confused', label: translate( 'Confused' ) },
                        { value: 'discouraged', label: translate( 'Discouraged' ) },
                        { value: 'upset', label: translate( 'Upset' ) },
                        { value: 'panicked', label: translate( 'Panicked' ) },
                ];

                return (
                        <div className="help-contact-form">
                                { formDescription && <p>{ formDescription }</p> }

                                <ChatBusinessConciergeNotice from="2017-07-19T00:00:00Z" to="2017-07-21T00:00:00Z" />

                                { showHowCanWeHelpField && (
                                        <div>
                                                <FormLabel>{ translate( 'How can we help?' ) }</FormLabel>
                                                { this.renderFormSelection( 'howCanWeHelp', howCanWeHelpOptions ) }
                                        </div>
                                ) }

                                { showHowYouFeelField && (
                                        <div>
                                                <FormLabel>{ translate( 'Mind sharing how you feel?' ) }</FormLabel>
                                                { this.renderFormSelection( 'howYouFeel', howYouFeelOptions ) }
                                        </div>
                                ) }

                                { showSiteField &&
                                        this.props.selectedSite && (
                                                <div className="help-contact-form__site-selection">
                                                        <FormLabel>{ translate( 'Which site do you need help with?' ) }</FormLabel>
                                                        <SitesDropdown
                                                                selectedSiteId={ this.props.selectedSite.ID }
                                                                onSiteSelect={ this.props.onChangeSite }
                                                        />
                                                </div>
                                        ) }

                                { showSubjectField && (
                                        <div className="help-contact-form__subject">
                                                <FormLabel>{ translate( 'Subject' ) }</FormLabel>
 <response clipped><NOTE>Due to the max output limit, only part of the full response has been shown to you.</NOTE>     case SUPPORT_TICKET:
                                return {
                                        onSubmit: this.submitKayakoTicket,
                                        buttonLabel: isSubmitting ? translate( 'Sending email' ) : translate( 'Email us' ),
                                        showSubjectField: true,
                                        showHowCanWeHelpField: true,
                                        showHowYouFeelField: true,
                                        showSiteField: hasMoreThanOneSite,
                                };

                        case SUPPORT_DIRECTLY:
                                return {
                                        onSubmit: this.submitDirectlyQuestion,
                                        buttonLabel: translate( 'Ask an Expert' ),
                                        formDescription: translate(
                                                'Get help from an {{strong}}Expert User{{/strong}} of WordPress.com. ' +
                                                        'These are other users, like yourself, who have been selected because ' +
                                                        'of their knowledge to help answer your questions.' +
                                                        '{{br/}}{{br/}}' +
                                                        '{{strong}}Please do not{{/strong}} provide financial or contact ' +
                                                        'information when submitting this form.',
                                                {
                                                        components: {
                                                                // Need to use linebreaks since the entire text is wrapped in a <p>...</p>
                                                                br: <br />,
                                                                strong: <strong />,
                                                        },
                                                }
                                        ),
                                        showSubjectField: false,
                                        showHowCanWeHelpField: false,
                                        showHowYouFeelField: false,
                                        showSiteField: false,
                                };

                        default:
                                return {
                                        onSubmit: this.submitSupportForumsTopic,
                                        buttonLabel: isSubmitting
                                                ? translate( 'Asking in the forums' )
                                                : translate( 'Ask in the forums' ),
                                        formDescription: translate(
                                                'Post a new question in our {{strong}}public forums{{/strong}}, ' +
                                                        'where it may be answered by helpful community members, ' +
                                                        'by submitting the form below. ' +
                                                        '{{strong}}Please do not{{/strong}} provide financial or ' +
                                                        'contact information when submitting this form.',
                                                {
                                                        components: {
                                                                strong: <strong />,
                                                        },
                                                }
                                        ),
                                        showSubjectField: true,
                                        showHowCanWeHelpField: false,
                                        showHowYouFeelField: false,
                                        showSiteField: false,
                                };
                }
        };

        getContactFormCommonProps = variationSlug => {
                const { isSubmitting } = this.state;
                const { currentUserLocale } = this.props;

                // Let the user know we only offer support in English.
                // We only need to show the message if:
                // 1. The user's locale doesn't match the live chat locale (usually English)
                // 2. The support request isn't sent to the forums. Because forum support
                //    requests are sent to the language specific forums (for popular languages)
                //    we don't tell the user that support is only offered in English.
                const showHelpLanguagePrompt =
                        config( 'support_locales' ).indexOf( currentUserLocale ) === -1 &&
                        SUPPORT_FORUM !== variationSlug;

                return {
                        disabled: isSubmitting,
                        showHelpLanguagePrompt: showHelpLanguagePrompt,
                        valueLink: {
                                value: savedContactForm,
                                requestChange: contactForm => ( savedContactForm = contactForm ),
                        },
                };
        };

        shouldShowTicketRequestErrorNotice = variationSlug => {
                const { ticketSupportRequestError } = this.props;

                return SUPPORT_HAPPYCHAT !== variationSlug && null != ticketSupportRequestError;
        };

        /**
         * Before determining which variation to assign, certain async data needs to be in place.
         * This function helps assess whether we're ready to say which variation the user should see.
         *
         * @returns {Boolean} Whether all the data is present to determine the variation to show
         */
        hasDataToDetermineVariation = () => {
                const ticketReadyOrError =
                        this.props.ticketSupportConfigurationReady || null != this.props.ticketSupportRequestError;
                const happychatReadyOrDisabled =
                        ! config.isEnabled( 'happychat' ) || this.props.isHappychatUserEligible !== null;

                return ticketReadyOrError && happychatReadyOrDisabled;
        };

        shouldShowPreloadForm = () => {
                const waitingOnDirectly =
                        this.getSupportVariation() === SUPPORT_DIRECTLY && ! this.props.isDirectlyReady;

                return (
                        this.props.isRequestingSites || ! this.hasDataToDetermineVariation() || waitingOnDirectly
                );
        };

        /**
         * Get the view for the contact page.
         * @return {object} A JSX object that should be rendered
         */
        getView = () => {
                const { confirmation } = this.state;
                const { translate, selectedSitePlanSlug } = this.props;

                if ( confirmation ) {
                        return <HelpContactConfirmation { ...confirmation } />;
                }

                if ( this.shouldShowPreloadForm() ) {
                        return (
                                <div className="help-contact__placeholder">
                                        <h4 className="help-contact__header">Loading contact form</h4>
                                        <div className="help-contact__textarea" />

                                        <h4 className="help-contact__header">Loading contact form</h4>
                                        <div className="help-contact__textarea" />

                                        <h4 className="help-contact__header">Loading contact form</h4>
                                        <div className="help-contact__textarea" />
                                </div>
                        );
                }

                const supportVariation = this.getSupportVariation();

                if ( supportVariation === SUPPORT_DIRECTLY && this.props.hasAskedADirectlyQuestion ) {
                        // We're taking the Directly confirmation outside the standard `confirmation` state object
                        // that other variations use, because we need this to persist even if the component is
                        // removed and re-mounted. Using `confirmation` in component state would mean you could
                        // ask a new Directy question every time you left the help section and came back.
                        const directlyConfirmation = {
                                title: translate( "We're on it!" ),
                                message: translate(
                                        'We sent your question to our {{strong}}Expert Users{{/strong}}. ' +
                                                'You will hear back via email as soon as an Expert has responded ' +
                                                '(usually within an hour). For now you can close this window or ' +
                                                'continue using WordPress.com.',
                                        {
                                                components: {
                                                        strong: <strong />,
                                                },
                                        }
                                ),
                        };
                        return <HelpContactConfirmation { ...directlyConfirmation } />;
                }

                const contactFormProps = Object.assign(
                        this.getContactFormCommonProps( supportVariation ),
                        this.getContactFormPropsVariation( supportVariation )
                );

                const currentDate = i18n.moment();

                // Customers sent to Directly and Forum are not affected by the Christmas closures
                const isUserAffectedByChristmas2017Closure =
                        supportVariation !== SUPPORT_DIRECTLY && supportVariation !== SUPPORT_FORUM;

                const isClosureNoticeInEffect =
                        currentDate.isBetween(
                                startShowingChristmas2017ClosureNoticeAt,
                                stopShowingChristmas2017ClosureNoticeAt
                        ) ||
                        currentDate.isBetween(
                                startShowingNewYear2018ClosureNoticeAt,
                                stopShowingNewYear2018ClosureNoticeAt
                        );

                const shouldShowClosureNotice = isUserAffectedByChristmas2017Closure && isClosureNoticeInEffect;

                return (
                        <div>
                                { shouldShowClosureNotice && <HelpContactClosed sitePlanSlug={ selectedSitePlanSlug } /> }
                                { this.shouldShowTicketRequestErrorNotice( supportVariation ) && (
                                        <Notice
                                                status="is-warning"
                                                text={ translate(
                                                        'We had trouble loading the support information for your account. ' +
                                                                'Please check your internet connection and reload the page, or try again later.'
                                                ) }
                                                showDismiss={ false }
                                        />
                                ) }
                                <HelpContactForm { ...contactFormProps } />
                        </div>
                );
        };

        render() {
                return (
                        <Main className="help-contact">
                                <HeaderCake onClick={ this.backToHelp } isCompact={ true }>
                                        { this.props.translate( 'Contact Us' ) }
                                </HeaderCake>
                                { ! this.props.isEmailVerified && <HelpUnverifiedWarning /> }
                                <Card className="help-contact__form">{ this.getView() }</Card>
                                { this.props.shouldStartHappychatConnection && <HappychatConnection /> }
                                <QueryTicketSupportConfiguration />
                                <QueryUserPurchases userId={ this.props.currentUser.ID } />
                        </Main>
                );
        }
}

export default connect(
        state => {
                const helpSelectedSiteId = getHelpSelectedSiteId( state );
                const selectedSitePlan = getSitePlan( state, helpSelectedSiteId );
                return {
                        currentUserLocale: getCurrentUserLocale( state ),
                        currentUser: getCurrentUser( state ),
                        getUserInfo: getHappychatUserInfo( state ),
                        hasAskedADirectlyQuestion: hasUserAskedADirectlyQuestion( state ),
                        isDirectlyFailed: isDirectlyFailed( state ),
                        isDirectlyReady: isDirectlyReady( state ),
                        isDirectlyUninitialized: isDirectlyUninitialized( state ),
                        isEmailVerified: isCurrentUserEmailVerified( state ),
                        isHappychatAvailable: isHappychatAvailable( state ),
                        isHappychatUserEligible: isHappychatUserEligible( state ),
                        ticketSupportConfigurationReady: isTicketSupportConfigurationReady( state ),
                        ticketSupportEligible: isTicketSupportEligible( state ),
                        ticketSupportRequestError: getTicketSupportRequestError( state ),
                        hasMoreThanOneSite: getCurrentUserSiteCount( state ) > 1,
                        shouldStartHappychatConnection: ! isRequestingSites( state ) && helpSelectedSiteId,
                        isRequestingSites: isRequestingSites( state ),
                        isSelectedHelpSiteOnPaidPlan: isCurrentPlanPaid( state, helpSelectedSiteId ),
                        selectedSitePlanSlug: selectedSitePlan && selectedSitePlan.product_slug,
                };
        },
        {
                openHappychat,
                sendHappychatMessage,
                sendUserInfo,
                askDirectlyQuestion,
                initializeDirectly,
        }
)( localize( HelpContact ) );
\n--- related tests existing ---
find: warning: you have specified the global option -maxdepth after the argument -path, but global options are not positional, i.e., -maxdepth affects tests specified before it as well as those specified after it.  Please specify global options before other arguments.
[The command completed with exit code 0.]
[Current working directory: /workspace/wp-calypso]
[Python interpreter: /usr/bin/python]
[Command finished with exit code 0]