Mutate Product Before Cart
When a product is added to the cart, it goes through a stack of JavaScript promise classes. These promise classes can perform various operations like displaying popups, performing asynchronous requests, and more. This promise stack has access to the product before being added to the cart. You might then interact with it to add more properties, or (like on Gastro) load the modifiers popup.
Here, you'll learn how to mutate a product before it's added to the cart.
Injecting a view into the POS footer
We first need to add a view to the POS, which will ensure we can load our custom JavaScript code. For that, we'll need to get the right hook that triggers when the POS's footer is about to be rendered.
On NexoPOS, we use route names as prefixes to the footer and header actions. For example, the route to the POS is called "ns.dashboard.pos." So, if we want to add a view at the footer, we'll register an action with this hook: "ns-dashboard-pos-footer." Note that the dots are replaced by "hyphens." Similarly, if we want to add a view at the header, we'll use "ns-dashboard-pos-header" instead.
<?php
namespace Modules\YourModules\Providers;
use App\Classes\Output;
use App\Classes\Hook;
use Illuminate\Support\ServiceProvider as CoreServiceProvider;
class ServiceProvider extends CoreServiceProvider
{
public function register()
{
Hook::addAction( 'ns-dashoard-pos-footer', function( Output $view ) {
$view->addView( 'YourModule::footer' );
});
}
}
Here, we're loading the file "footer.blade.php," which should be located at the root of our module's "Resources" directory.
Adding Promise To the addToCartQueue
Now, we'll add a Promise Class to the addToCartQueue. This is a property of the POS object that is globally available in a JavaScript context when you're on the point of sale page.
<script type="text/javascript">
document.addEventListener( 'DOMContentLoaded', function() {
// when the page has loaded POS object is available.
class MyCustomPromise {
constructor( product ) {
this.product = product;
}
run() {
return new Promise( ( resolve, reject ) => {
// perform whatever you want here
console.log( this.product ); //
resolve({ name: 'Custom Name' });
});
}
}
POS.addToCartQueue.push( MyCustomPromise );
});
</script>
You might ensure that the class you define has a unique name. When the class is instantiated, the product is provided and should be stored. You might then access that product using the "run" method.
Note that you should resolve the attribute you would like to change. You should avoid resolving the whole object. This will affect all changes made by other Promise classes.
Interacting With Mutated Properties
Before the queue items are all resolved, you can, from your promise class access the changed value. These changes aren't yet effective on the product, so you can perform any adjustments before these properties are merged to the product object.
The method "run" accepts one parameter, that is, the current state of the change applied to the product so far.
<script type="text/javascript">
document.addEventListener( 'DOMContentLoaded', function() {
// when the page has loaded POS object is available.
class MyCustomPromise {
constructor( product ) {
this.product = product;
}
run( state ) {
return new Promise( ( resolve, reject ) => {
// we'll access unit selected
// with the promise class "ProductUnitPromise".
const unitQuantity = state.$quantities();
unitQuantity.sale_price_edit = 11;
// unitQuantity.sale_price_with_tax = 11; use it if the price with tax is prefered on the settings
// unitQuantity.sale_price_without_tax = 11; use it if the price without tax is prefered on the settings
resolve({
$quantities: () => unitQuantity
});
});
}
}
POS.addToCartQueue.push( MyCustomPromise );
});
</script>
In this example, we would like to adjust the sale_price before the product is added to the cart. We're relying on the ProductUnitPromise as that's the promise that lets the user choose the sale unit. From there, we'll use the property $quantities(), change the returned value, and resolve a new property.