diff --git a/bootstrap.php b/bootstrap.php index 5b54abe85..e2fde916d 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -47,6 +47,7 @@ require __DIR__ . '/inc/menu.php'; require __DIR__ . '/inc/mojo-themes.php'; require __DIR__ . '/inc/Notifications/bootstrap.php'; +require __DIR__ . '/inc/CTB/bootstrap.php'; require __DIR__ . '/inc/partners.php'; require __DIR__ . '/inc/performance.php'; require __DIR__ . '/inc/plugin-search.php'; diff --git a/inc/CTB/CTBApi.php b/inc/CTB/CTBApi.php new file mode 100644 index 000000000..bba9afcfc --- /dev/null +++ b/inc/CTB/CTBApi.php @@ -0,0 +1,93 @@ +[a-zA-Z0-9-]+)', + array( + 'methods' => \WP_REST_Server::READABLE, + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + 'callback' => function ( \WP_REST_Request $request ) { + + $response = wp_remote_get( + BH_HUB_URL . '/sites/v1/ctb/' . $request->get_param( 'id' ) . '', + array( + 'headers' => array( + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . HubConnection::get_auth_token(), + ), + 'timeout' => 20, + ) + ); + + if ( $response instanceof WP_Error ) { + return $response; + } + + return new \WP_REST_Response( json_decode( wp_remote_retrieve_body( $response ) ), wp_remote_retrieve_response_code( $response ) ); + }, + ) + ); + + // Add route for purchasing a CTB + register_rest_route( + 'bluehost/v1', + '/ctb/(?P[a-zA-Z0-9-]+)', + array( + 'methods' => \WP_REST_Server::CREATABLE, + 'permission_callback' => function () { + return current_user_can( 'manage_options' ); + }, + 'callback' => function ( \WP_REST_Request $request ) { + + $ctb_id = $request->get_param( 'id' ); + $payload = array( + 'ctb_id' => $ctb_id, + 'site_id' => SiteMeta::get_id(), + ); + + $response = wp_remote_post( + BH_HUB_URL . '/sites/v1/ctb/' . $ctb_id . '/purchase', + array( + 'headers' => array( + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . HubConnection::get_auth_token(), + ), + 'body' => wp_json_encode( $payload ), + 'timeout' => 20, + ) + ); + + if ( $response instanceof WP_Error ) { + return $response; + } + + return new \WP_REST_Response( json_decode( wp_remote_retrieve_body( $response ) ), wp_remote_retrieve_response_code( $response ) ); + }, + ) + ); + } + +} diff --git a/inc/CTB/bootstrap.php b/inc/CTB/bootstrap.php new file mode 100644 index 000000000..44369b629 --- /dev/null +++ b/inc/CTB/bootstrap.php @@ -0,0 +1,30 @@ +-1&&this._listeners[t].splice(i,1),this},e.prototype._fire=function(t,e){var i=this._listeners[t]||[],n=new CustomEvent(t,{detail:e});this.$el.dispatchEvent(n),i.forEach(function(t){t(this.$el,e)}.bind(this))},e.prototype._bindKeypress=function(e){this.$el.contains(document.activeElement)&&(this.shown&&27===e.which&&"alertdialog"!==this.$el.getAttribute("role")&&(e.preventDefault(),this.hide(e)),this.shown&&9===e.which&&function(e,n){var s=function(e){return i(t.join(","),e).filter((function(t){return!!(t.offsetWidth||t.offsetHeight||t.getClientRects().length)}))}(e),o=s.indexOf(document.activeElement);n.shiftKey&&0===o?(s[s.length-1].focus(),n.preventDefault()):n.shiftKey||o!==s.length-1||(s[0].focus(),n.preventDefault())}(this.$el,e))},e.prototype._maintainFocus=function(t){!this.shown||t.target.closest('[aria-modal="true"]')||t.target.closest("[data-a11y-dialog-ignore-focus-trap]")||n(this.$el)},"undefined"!=typeof document&&("loading"===document.readyState?document.addEventListener("DOMContentLoaded",s):window.requestAnimationFrame?window.requestAnimationFrame(s):window.setTimeout(s,16)),e})); diff --git a/inc/CTB/js/ctb.js b/inc/CTB/js/ctb.js new file mode 100644 index 000000000..ec9ad9eec --- /dev/null +++ b/inc/CTB/js/ctb.js @@ -0,0 +1,129 @@ +{ + const purchase = (e) => { + let modalWindow = e.target.closest('.ctb-modal-content'); + e.target.closest('.ctb-actions').innerHTML = '
'; + window.fetch( + `${ window.nfdNotifications.restApiUrl }bluehost/v1/ctb/${ e.target.getAttribute('data-ctb-id') }`, + { + credentials: 'same-origin', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-WP-Nonce': window.nfdNotifications.restApiNonce, + }, + } + ) + .then( response => { + purchaseStatus = (response.status === 200); + return response.json(); + }).then( data => { + if (data.content) { + modalWindow.innerHTML = data.content; + } else { + displayError(modalWindow, "purchase"); + } + }); + } + + const loadCtb = (e) => { + let modal = openModal(e); + let modalWindow = modal.querySelector('.ctb-modal-content') + window.fetch( + `${ window.nfdNotifications.restApiUrl }bluehost/v1/ctb/${ e.target.getAttribute('data-ctb-id') }`, + { + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + 'X-WP-Nonce': window.nfdNotifications.restApiNonce, + }, + } + ) + .then( response => { + return response.json(); + }).then( data => { + if (data.content) { + modalWindow.innerHTML = data.content; + } else { + displayError(modalWindow, 'load'); + } + }); + } + + const openModal = (e) => { + let el = document.createElement('div'); + el.setAttribute('id', 'ctb-modal-container'); + el.innerHTML = ` +
+
+
+
+
+
+ `; + e.target.insertAdjacentElement('afterend', el); + + ctbmodal = new A11yDialog(el); + ctbmodal.show(); + + purchaseStatus = false; + + document.querySelector('body').classList.toggle('noscroll'); + + el.addEventListener('click', function(event) { + if (event.target.dataset.action === 'purchase-ctb') { + purchase(event); + } + if (event.target.hasAttribute('data-a11y-dialog-destroy')) { + document.querySelector('body').classList.toggle('noscroll'); + closeModal(event.target); + } + }); + + return el; + } + + const closeModal = (e) => { + ctbmodal.destroy(); + if (purchaseStatus){ + dismissNotice(e); + } + } + + const displayError = (modalWindow, error) => { + let message = (error === 'purchase') ? 'complete the transaction' : 'load the product information'; + modalWindow.innerHTML = `
+

Sorry, we are unable to ${message} at this time.

+ +
`; + } + + const dismissNotice = (e) => { + const notice = e.closest('.bluehost-notice'); + if (notice) { + const id = notice.getAttribute('data-id'); + notice.parentNode.removeChild(notice); + window.fetch( + `${ window.nfdNotifications.restApiUrl }bluehost/v1/notifications/${ id }`, + { + credentials: 'same-origin', + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'X-WP-Nonce': window.nfdNotifications.restApiNonce, + }, + } + ); + } + } + + window.addEventListener( + 'load', + () => { + document.getElementById('wpbody').addEventListener('click', function(event) { + if (event.target.dataset.action === 'load-nfd-ctb') { + loadCtb(event); + } + }); + } + ); +} diff --git a/inc/Notifications/AdminNotices.php b/inc/Notifications/AdminNotices.php index 2cbae9142..40dd2e91d 100644 --- a/inc/Notifications/AdminNotices.php +++ b/inc/Notifications/AdminNotices.php @@ -16,6 +16,12 @@ class AdminNotices { */ public static function maybeRenderAdminNotices() { + // The notifications container is used apply event listeners to so new notifcations can be inserted + // dynamically, but still respond to the required events. + ?> +
+ id ) { @@ -33,14 +39,6 @@ public static function maybeRenderAdminNotices() { BLUEHOST_PLUGIN_VERSION, true ); - wp_localize_script( - 'bh-plugin-realtime-notices', - 'bluehostRealtimeNotices', - array( - 'restApiUrl' => esc_url_raw( rest_url() ), - 'restApiNonce' => wp_create_nonce( 'wp_rest' ), - ) - ); ?>