/** * External dependencies */ import { __ } from '@wordpress/i18n'; import { Modal, Button, TextareaControl } from '@wordpress/components'; import { useDispatch } from '@wordpress/data'; import { useState, useEffect } from '@wordpress/element'; import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies */ import './feedback-modal.scss'; import LikertScale from '../likert-scale/likert-scale'; import sanitizeHTML from '../../../lib/sanitize-html'; export default function FeedbackModal(): JSX.Element { const CUSTOMER_EFFORT_SCORE_ACTION = 'marketplace_redesign_2023'; const LOCALSTORAGE_KEY_DISMISSAL_COUNT = 'marketplace_redesign_2023_dismissals'; // ensure we don't ask for feedback if the user's already given feedback or declined to multiple times const LOCALSTORAGE_KEY_LAST_REQUESTED_DATE = 'marketplace_redesign_2023_last_shown_date'; // ensure we don't ask for feedback more than once per day const SUPPRESS_IF_DISMISSED_X_TIMES = 1; // if the user dismisses the snackbar this many times, stop asking for feedback const SUPPRESS_IF_AFTER_DATE = '2024-01-01'; // if this date is reached, stop asking for feedback // Save that we dismissed the dialog or snackbar TODAY so we don't show it again until tomorrow (if ever) const dismissToday = () => localStorage.setItem( LOCALSTORAGE_KEY_LAST_REQUESTED_DATE, new Date().toDateString() ); // Returns the number of times that the request for feedback has been dismissed const dismissedTimes = () => parseInt( localStorage.getItem( LOCALSTORAGE_KEY_DISMISSAL_COUNT ) || '0', 10 ); // Increment the number of times that the request for feedback has been dismissed const incrementDismissedTimes = () => { dismissToday(); localStorage.setItem( LOCALSTORAGE_KEY_DISMISSAL_COUNT, `${ dismissedTimes() + 1 }` ); }; // Dismiss forever (by incrementing the number of dismissals to a high number), e.g. when feedback is provided const dismissForever = () => { dismissToday(); localStorage.setItem( LOCALSTORAGE_KEY_DISMISSAL_COUNT, `${ SUPPRESS_IF_DISMISSED_X_TIMES }` ); }; // Returns true if dismissed forever (either by dismissing at least SUPPRESS_IF_DISMISSED_X_TIMES times, or by submitting feedback) const isDismissedForever = () => dismissedTimes() >= SUPPRESS_IF_DISMISSED_X_TIMES; const [ isOpen, setOpen ] = useState( false ); const [ thoughts, setThoughts ] = useState( '' ); const [ easyToFind, setEasyToFind ] = useState( 0 ); const [ easyToFindValidiationFailed, setEasyToFindValidiationFailed ] = useState( false ); const [ meetsMyNeeds, setMeetsMyNeeds ] = useState( 0 ); const [ meetsMyNeedsValidiationFailed, setMeetsMyNeedsValidiationFailed ] = useState( false ); const openModal = () => setOpen( true ); const closeModal = () => { incrementDismissedTimes(); setOpen( false ); }; const { createNotice } = useDispatch( 'core/notices' ); function maybeShowSnackbar() { // don't show if the user has already given feedback or otherwise suppressed: if ( isDismissedForever() ) { return; } // don't show if the user has already declined to provide feedback today: const today = new Date().toDateString(); if ( today === localStorage.getItem( LOCALSTORAGE_KEY_LAST_REQUESTED_DATE ) ) { return; } createNotice( 'success', __( 'How easy is it to find an extension?', 'woocommerce' ), { type: 'snackbar', icon: ( <> ), explicitDismiss: true, onDismiss: incrementDismissedTimes, actions: [ { onClick: openModal, label: 'Give feedback', }, ], } ); } // eslint-disable-next-line react-hooks/exhaustive-deps -- [] => we only want this effect to run once, on first render useEffect( maybeShowSnackbar, [] ); // We don't want the "How easy was it to find an extension?" dialog to appear forever: const FEEDBACK_DIALOG_CAN_APPEAR = new Date( SUPPRESS_IF_AFTER_DATE ) > new Date(); if ( ! FEEDBACK_DIALOG_CAN_APPEAR ) { return <>; } function easyToFindChanged( value: number ) { setEasyToFindValidiationFailed( false ); setEasyToFind( value ); } function meetsMyNeedsChanged( value: number ) { setMeetsMyNeedsValidiationFailed( false ); setMeetsMyNeeds( value ); } function submit() { // Validate: if ( easyToFind === 0 || meetsMyNeeds === 0 ) { if ( easyToFind === 0 ) setEasyToFindValidiationFailed( true ); if ( meetsMyNeeds === 0 ) setMeetsMyNeedsValidiationFailed( true ); return; } const comments = sanitizeHTML( thoughts ).__html; // Send event to CES: recordEvent( 'ces_feedback', { action: CUSTOMER_EFFORT_SCORE_ACTION, score: easyToFind, score_second_question: meetsMyNeeds, score_combined: easyToFind + meetsMyNeeds, comments, } ); // Close the modal: setOpen( false ); // Ensure we don't ask for feedback again: dismissForever(); } return ( <> { isOpen && (

{ __( 'Your feedback will help us create a better experience for people like you! Please tell us to what extent you agree or disagree with the statements below.', 'woocommerce' ) }

setThoughts( value ) } />