File "wpaas-feedback.js"
Full Path: /home/amervokv/ecomlive.net/wp-content/mu-plugins/gd-system-plugin/assets/js/src/wpaas-feedback.js
File size: 10.09 KB
MIME-type: text/x-java
Charset: utf-8
/** global wpaasFeedback */
import domReady from '@wordpress/dom-ready';
import apiFetch from '@wordpress/api-fetch';
import { render, useState, unmountComponentAtNode, useEffect } from '@wordpress/element';
import { close } from '@wordpress/icons';
import { Icon, RadioControl, Button } from '@wordpress/components';
import { ReactComponent as GoDaddyLogo } from './go-daddy-logo.svg';
import { logImpressionEvent, logInteractionEvent } from './instrumentation';
const surveyChoices = Array.from({ length: wpaasFeedback?.scoreChoices.max + 1 }, ( v, k ) => k + wpaasFeedback?.scoreChoices.min )
.map( ( choice ) => ( { label: choice, value: choice } ) );
const surveyLabels = wpaasFeedback?.labels;
const EID_PREFIX = `wp.${ wp.editPost ? 'editor' : 'wpadmin' }`;
const startedAt = new Date().toISOString();
const DISMISS_KEY = 'wpaas-nux-feedback-dismiss';
const SESSION_VIEW_KEY = 'wpaas-nux-feedback-session';
// hour min sec ms
const daysInMs = 24 * 60 * 60 * 1000;
const browserDismiss = (days = 90) => {
localStorage?.setItem( DISMISS_KEY, ( Date.now() + ( days * daysInMs ) ) );
}
const getDailySession = () => {
const defaultSession = { count: 0, lastView: Date.now() };
let session = localStorage?.getItem(SESSION_VIEW_KEY) || defaultSession;
if (typeof session !== 'string') {
return session;
}
try {
session = JSON.parse(session);
} catch {
// Someone played with the localstorage
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/error/daily_session.modal`,
type: 'custom',
data: {
message: 'Error Parsing Local Storage'
}
});
}
// Being careful with data that user can modify. Reset session if we are dealing with numbers.
if (typeof session?.count !== 'number' || typeof session?.lastView !== 'number') {
session = defaultSession;
}
return session;
}
const saveDailySession = (count = 0) => {
localStorage?.setItem(SESSION_VIEW_KEY, JSON.stringify({ count, lastView: Date.now() }));
}
const saveDismissSurvey = ({ forceLocalDismiss = false } = {}) => {
if (forceLocalDismiss) {
browserDismiss();
localStorage?.removeItem(SESSION_VIEW_KEY);
}
apiFetch( {
url: wpaasFeedback.apiBase + '/dismiss',
method: 'POST'
} ).catch((error) => {
// Log error to traffic here
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/error/dismiss.modal`,
type: 'custom',
data: {
message: error?.message
}
});
browserDismiss();
} );
}
const Feedback = () => {
const [ surveyScore, setSurveyScore ] = useState( null );
const [ surveyComment, setSurveyComment ] = useState( '' );
const [ contactChoice, setContactChoice ] = useState( null );
const [ dismissSurvey, setDismissSurvey ] = useState( false );
const [ showSuccess, setShowSuccess ] = useState( false );
useEffect( () => {
logImpressionEvent(`${ EID_PREFIX }.feedback/wpaas_nps.modal`);
}, [] );
useEffect( () => {
if ( dismissSurvey ) {
unmountComponentAtNode( wpaasFeedback.rootNode.getElementById( wpaasFeedback.mountPoint ) );
}
}, [ dismissSurvey ] );
if ( ! surveyLabels ) {
return null;
}
const handleDismissModal = () => {
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/modal/${ showSuccess ? 'success' : 'survey' }.close`
});
if ( ! showSuccess ) {
saveDismissSurvey();
}
setDismissSurvey( true );
}
const handleSubmitModal = () => {
setShowSuccess( true );
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/form/submit.button`
});
apiFetch( {
url: wpaasFeedback.apiBase + '/score',
method: 'POST',
data: {
'comment': surveyComment,
'endedAt': new Date().toISOString(),
'isWpAdmin' : wpaasFeedback.isWpAdmin,
'score': surveyScore,
startedAt,
'wpUri': String( window.location.href ).replace( window.location.origin, '' ),
'canContact': 'true' === contactChoice,
}
} ).catch((error) => {
// Log error to traffic here
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/error/score.modal`,
type: 'custom',
data: {
message: error?.message
}
});
browserDismiss();
} );
}
const surveyCommentMaxLength = wpaasFeedback?.commentLength;
return (
<div className="wpaas-feedback-modal__container">
<div className="wpaas-feedback-modal__header">
<Icon
className="wpaas-feedback-modal__header__close"
onClick={ handleDismissModal }
icon={ close }
/>
{ !showSuccess && (
<GoDaddyLogo />
)}
</div>
<div className="wpaas-feedback-modal__content">
{ showSuccess ? (
<>
<div className="wpaas-feedback__success">
<GoDaddyLogo />
<h4 className="wpaas-feedback__success__header">{ surveyLabels?.thank_you }</h4>
<Button disabled={ !surveyScore ? true : false } onClick={ handleDismissModal } isPrimary>
{ surveyLabels?.thank_you_button }
</Button>
</div>
</>
) : (
<>
<div className="wpaas-feedback__question-container">
<label className="wpaas-feedback__question-label">{ surveyLabels?.survey_question }</label>
<RadioControl
selected={ surveyScore }
options={ surveyChoices }
onChange={ ( value ) => setSurveyScore( Number( value ) ) }
/>
<div className="wpaas-feedback__survey-question__labels">
<p>{ surveyLabels?.not_likely }</p>
<p>{ surveyLabels?.neutral }</p>
<p>{ surveyLabels?.likely } </p>
</div>
</div>
<div className="wpaas-feedback__question-container">
<label className="wpaas-feedback__question-label">{ surveyLabels?.comment_text }</label>
<div className="wpaas-feedback__textarea__container">
<textarea
value={ surveyComment }
maxLength={ surveyCommentMaxLength }
onChange={ e => setSurveyComment( e.target.value )}
/>
<p className={`wpaas-feedback__textarea__count${ surveyComment.length === surveyCommentMaxLength ? '-bold' : '' }`}>{ surveyComment.length } / { surveyCommentMaxLength }</p>
</div>
</div>
<div className="wpaas-feedback__question-container contact">
<label className="wpaas-feedback__question-label">{ surveyLabels?.can_we_contact }</label>
<RadioControl
selected={ contactChoice }
options={ [ { label: 'Yes', value: 'true' }, { label: 'No', value: 'false' } ] }
onChange={ ( value ) => setContactChoice( value ) }
/>
</div>
<span>
<span dangerouslySetInnerHTML={{ __html: surveyLabels?.privacy_disclaimer }} />
</span>
<div className="wpaas-feedback__submit-form">
<Button
disabled={ surveyScore === null || contactChoice === null }
onClick={ handleSubmitModal }
isPrimary
>
{ surveyLabels?.submit_feedback }
</Button>
</div>
</>
)}
</div>
</div>
);
};
/**
* customElements need ES5 classes but babel compiles them which errors out. We could use a polyfill or the below.
* This is needed to circumvent babel crosscompiling.
*/
function BabelHTMLElement() {
return Reflect.construct( HTMLElement, [], this.__proto__.constructor );
}
Object.setPrototypeOf( BabelHTMLElement, HTMLElement );
Object.setPrototypeOf( BabelHTMLElement.prototype, HTMLElement.prototype );
/**
* See https://reactjs.org/docs/web-components.html#using-react-in-your-web-components
*/
class GoDaddyFeedback extends BabelHTMLElement {
connectedCallback() {
const mountPoint = document.createElement( 'div' );
mountPoint.id = 'wpaas-feedback';
function createStyle( url ) {
const style = document.createElement( 'link' );
style.setAttribute( 'rel', 'stylesheet' );
style.setAttribute( 'href', url );
style.setAttribute( 'media', 'all' );
return style;
}
const shadowRoot = this.attachShadow( { mode: 'open' } );
shadowRoot.appendChild( createStyle( wpaasFeedback.css ) );
shadowRoot.appendChild( mountPoint );
wpaasFeedback.rootNode = shadowRoot;
wpaasFeedback.mountPoint = mountPoint.id;
render(
<Feedback />,
mountPoint
);
}
}
function loadNpsComponent() {
const dailySession = getDailySession();
// If the last time the user saw the nps was more than 24 hours ago we reset counter.
if (Date.now() > (dailySession.lastView + (1 * daysInMs))) {
dailySession.count = 0;
}
if (dailySession.count >= 3) {
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/view_count.modal`,
type: 'custom',
data: {
count: dailySession.count
}
});
saveDismissSurvey({ forceLocalDismiss: true });
return;
}
saveDailySession(++dailySession.count);
// customElements always need hyphen in the name.
const customElementName = wpaasFeedback.containerId;
customElements.define( customElementName, GoDaddyFeedback );
const element = document.createElement( customElementName );
// The PHP script actually prints the following tag in the dom <div id="wpaas-feedback-container">.
// We replace with the custom element the div printed by PHP.
document.getElementById( customElementName ).replaceWith( element );
}
domReady( () => {
const userDismiss = localStorage?.getItem( DISMISS_KEY );
/*
* Do an extra safety check in case an optimization plugin picked up this script and cached it.
*/
const location = new URL(window.location);
/**
* Can't trust the global pagenow from PHP if the script is cached by third party plugin.
* Get the current pagenow from the url instead while removing the /wp-admin/ part.
*/
const pagenow = location.pathname.replace(/^\/wp-admin\/(.*)$/, '$1');
/**
* This is to force the NPS to show up for debugging purposes.
*/
const debug = location.search.includes(wpaasFeedback.debugParam);
if (debug) {
loadNpsComponent();
return;
}
if (
!wpaasFeedback.excludedPages
|| userDismiss && userDismiss > Date.now()
|| wpaasFeedback.excludedPages.includes(pagenow)
) {
return;
}
apiFetch( {
url: wpaasFeedback.apiBase + '/available',
method: 'POST'
} )
.then(loadNpsComponent)
.catch((error) => {
// Log error to traffic here
logInteractionEvent({
eid: `${ EID_PREFIX }.feedback/wpaas_nps/error/available.modal`,
type: 'custom',
data: {
message: error?.message
}
});
browserDismiss(1);
} );
} );