Skip to content

Commit

Permalink
Add Click To Buy functionality (#135)
Browse files Browse the repository at this point in the history
* Add CTB functionality

* Always load localized script variables

* Fix PHPCS issues

* Add notifications container to prevent duplicates
  • Loading branch information
earnjam authored Apr 13, 2022
1 parent 219a866 commit 09b0d69
Show file tree
Hide file tree
Showing 11 changed files with 404 additions and 35 deletions.
1 change: 1 addition & 0 deletions bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
93 changes: 93 additions & 0 deletions inc/CTB/CTBApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace Bluehost\CTB;

use Bluehost\SiteMeta;
use Endurance\WP\Module\Data\HubConnection;
use WP_Error;

/**
* Class CTBApi
*
* @package Bluehost\CTB
*/
class CTBApi {

/**
* Register notification routes.
*/
public static function registerRoutes() {

// Add route for fetching a CTB
register_rest_route(
'bluehost/v1',
'/ctb/(?P<id>[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<id>[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 ) );
},
)
);
}

}
30 changes: 30 additions & 0 deletions inc/CTB/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Bluehost\CTB;

add_action( 'rest_api_init', array( CTBApi::class, 'registerRoutes' ) );
add_action(
'admin_enqueue_scripts',
function() {
wp_register_script( 'a11y-dialog', plugins_url( 'inc/CTB/js/a11y-dialog.min.js', BLUEHOST_PLUGIN_FILE ), array(), '7.4.0', false );
wp_enqueue_script(
'bh-ctb',
plugins_url( 'inc/CTB/js/ctb.js', BLUEHOST_PLUGIN_FILE ),
array( 'a11y-dialog' ),
BLUEHOST_PLUGIN_VERSION,
true
);
}
);

add_action(
'admin_enqueue_scripts',
function() {
wp_enqueue_style(
'bh-ctb',
plugins_url( 'inc/CTB/ctb.css', BLUEHOST_PLUGIN_FILE ),
array(),
BLUEHOST_PLUGIN_VERSION
);
}
);
102 changes: 102 additions & 0 deletions inc/CTB/ctb.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
body.noscroll {
overflow-y: hidden;
}

#ctb-modal-container {
position: absolute;
}

#ctb-modal-container,
.ctb-modal-overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}

#ctb-modal-container {
z-index: 100000;
display: flex;
justify-content: center;
align-items: center;
}

#ctb-modal-container[aria-hidden='true'] {
display: none;
}

.ctb-modal-overlay {
background-color: rgba(43, 46, 56, 0.9);
}

.ctb-modal-content {
margin: auto;
z-index: 2;
position: relative;
background-color: white;
}

.ctb-modal img {
max-width:100%;
}


.ctb-modal button {
cursor:pointer;
}

.ctb-modal-content {
/* z-index: 20001; */
min-width: 500px;
max-width: 75%;
min-height: 250px;
background: white;
color: black;
display: flex;
justify-content: center;
align-items: center;
}

.ctb-loader {
width: 5rem;
height: 5rem;
border-radius: 50%;
background: #3575d3;
background: linear-gradient(to right, #3575d3 5%, rgba(0, 0, 0, 0) 32%);
position: relative;
will-change: transform;
-webkit-animation: ctbloader .9s infinite linear;
animation: ctbloader .9s infinite linear;
transform: translateZ(0);
}

.ctb-loader:before {
width: 50%;
height: 50%;
background: #3575d3;
border-radius: 100% 0 0 0;
position: absolute;
top: 0;
left: 0;
content: "";
}

.ctb-loader:after {
background: #fff;
width: 88%;
height: 88%;
border-radius: 50%;
content: "";
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}

@keyframes ctbloader {
0% {transform: rotate(0deg);}
100% {transform: rotate(360deg);}
}
2 changes: 2 additions & 0 deletions inc/CTB/js/a11y-dialog.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

129 changes: 129 additions & 0 deletions inc/CTB/js/ctb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
const purchase = (e) => {
let modalWindow = e.target.closest('.ctb-modal-content');
e.target.closest('.ctb-actions').innerHTML = '<div class="ctb-loader"></div>';
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 = `
<div class="ctb-modal">
<div class="ctb-modal-overlay" data-a11y-dialog-destroy></div>
<div role="document" class="ctb-modal-content">
<div class="ctb-loader"></div>
</div>
</div>
`;
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 = `<div style="text-align:center;">
<p>Sorry, we are unable to ${message} at this time.</p>
<button class="components-button bluehost is-primary" data-a11y-dialog-destroy>Cancel</button>
</div>`;
}

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);
}
});
}
);
}
Loading

0 comments on commit 09b0d69

Please sign in to comment.