Skip to content

Commit

Permalink
cart upselling block
Browse files Browse the repository at this point in the history
  • Loading branch information
Oksydan committed Dec 13, 2023
1 parent 304c40d commit 3619bae
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 14 deletions.
19 changes: 19 additions & 0 deletions _theme_dev/src/js/theme/components/useFavoriteProducts.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,29 @@ const useFavoriteProducts = () => {
});
});

const updateUpSellingBLock = async () => new Promise((resolve, reject) => {
if (!window?.refreshFavoriteUpSellingBlockUrl) {
return;
}

// refreshFavoriteUpSellingBlockUrl is a global variable set via Media::addJsDef
const { request } = useHttpRequest(window.refreshFavoriteUpSellingBlockUrl);

request
.post()
.json((data) => {
resolve(data);
})
.catch(() => {
reject(Error('Something went wrong'));
});
});

return {
getFavoriteProducts,
addToFavorite,
removeFromFavorite,
updateUpSellingBLock,
};
};

Expand Down
23 changes: 23 additions & 0 deletions _theme_dev/src/js/theme/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import useAlertToast from '@js/theme/components/useAlertToast';
import useFavoriteProducts from './components/useFavoriteProducts';
import useFavoriteDOMHandler from './components/useFavoriteDOMHandler';
import { parseToHtml } from '@js/utils/DOM/DOMHelpers';

Check failure on line 4 in _theme_dev/src/js/theme/index.js

View workflow job for this annotation

GitHub Actions / Code quality - ESLint

`@js/utils/DOM/DOMHelpers` import should occur before import of `./components/useFavoriteProducts`

DOMReady(() => {
const {
addToFavorite,
removeFromFavorite,
updateUpSellingBLock,
} = useFavoriteProducts();
const {
getProductIdsFromKey,
Expand Down Expand Up @@ -87,4 +89,25 @@ DOMReady(() => {
prestashop.on('updatedProductList', () => {
setTimeout(refreshButtons, 1);
});
prestashop.on('updatedCart', async () => {
const upSellingBlock = document.querySelector('.js-favorite-up-selling-block');

if (!upSellingBlock) {
return;
}

try {
const { content } = await updateUpSellingBLock();

if (content) {
upSellingBlock.replaceWith(parseToHtml(content));
prestashop.emit('updatedFavoriteUpSellingBlock', content);
}
} catch (error) {

Check failure on line 106 in _theme_dev/src/js/theme/index.js

View workflow job for this annotation

GitHub Actions / Code quality - ESLint

Empty block statement
}
});
prestashop.on('updatedFavoriteUpSellingBlock', () => {
setTimeout(refreshButtons, 1);
prestashop.pageSlider.refresh();
});
});
14 changes: 14 additions & 0 deletions controllers/front/ajax.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Oksydan\IsFavoriteProducts\DTO\FavoriteProduct as FavoriteProductDTO;
use Oksydan\IsFavoriteProducts\Hook\DisplayCrossSellingShoppingCart;
use Oksydan\IsFavoriteProducts\Hook\DisplayTop;
use Oksydan\IsFavoriteProducts\Services\FavoriteProductService;

Expand Down Expand Up @@ -90,6 +91,19 @@ public function displayAjaxAddFavoriteProduct(): void
$this->renderResponse();
}

public function displayAjaxRefreshUpSellingBlock(): void
{
ob_end_clean();
header('Content-Type: application/json');
$hook = $this->get(DisplayCrossSellingShoppingCart::class);

$this->ajaxRender(json_encode([
'content' => $hook->execute([]),
]));

exit;
}

public function displayAjaxRemoveFavoriteProduct(): void
{
$this->checkProductExistence();
Expand Down
10 changes: 10 additions & 0 deletions is_favoriteproducts.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,14 @@ private function getHookObject($methodName)

return $hook instanceof HookInterface ? $hook : null;
}

public function getCacheId($name = null)
{
return parent::getCacheId($name);
}

public function _clearCache($template, $cache_id = null, $compile_id = null)
{
return parent::_clearCache($template, $cache_id, $compile_id);
}
}
36 changes: 36 additions & 0 deletions src/Hook/AbstractCacheableDisplayHook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Hook;

abstract class AbstractCacheableDisplayHook extends AbstractDisplayHook
{
public function execute(array $params): string
{
if (!$this->shouldBlockBeDisplayed($params)) {
return '';
}

if (!$this->isTemplateCached()) {
$this->assignTemplateVariables($params);
}

return $this->module->fetch($this->getTemplateFullPath(), $this->getCacheKey());
}

protected function getCacheKey(): string
{
return $this->module->getCacheId($this->module->name . '|' . $this->context->cart->id);
}

protected function isTemplateCached(): bool
{
return $this->module->isCached($this->getTemplateFullPath(), $this->getCacheKey());
}

public function clearCache(): void
{
$this->module->_clearCache($this->getTemplateFullPath(), $this->getCacheKey());
}
}
31 changes: 31 additions & 0 deletions src/Hook/ActionCartSave.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Hook;

use Oksydan\IsFavoriteProducts\Services\FavoriteProductService;

class ActionCartSave extends AbstractHook
{
private DisplayCrossSellingShoppingCart $displayCrossSellingShoppingCart;

public function __construct(
\Is_favoriteproducts $module,
\Context $context,
FavoriteProductService $favoriteProductService,
DisplayCrossSellingShoppingCart $displayCrossSellingShoppingCart
) {
parent::__construct($module, $context, $favoriteProductService);
$this->displayCrossSellingShoppingCart = $displayCrossSellingShoppingCart;
}

public function execute(array $params): void
{
if (empty($this->context->cart->id)) {
return;
}

$this->displayCrossSellingShoppingCart->clearCache();
}
}
10 changes: 7 additions & 3 deletions src/Hook/ActionFrontControllerSetMedia.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
namespace Oksydan\IsFavoriteProducts\Hook;

use Oksydan\IsFavoriteProducts\DTO\FavoriteProduct;
use Oksydan\IsFavoriteProducts\Presenter\FavoriteProductJsonPresenter;
use Oksydan\IsFavoriteProducts\Presenter\FavoriteProductJsonJsonPresenter;
use Oksydan\IsFavoriteProducts\Services\FavoriteProductService;

class ActionFrontControllerSetMedia extends AbstractHook
{
private FavoriteProductJsonPresenter $productPresenter;
private FavoriteProductJsonJsonPresenter $productPresenter;

public function __construct(
\Is_favoriteproducts $module,
\Context $context,
FavoriteProductService $favoriteProductService,
FavoriteProductJsonPresenter $productPresenter
FavoriteProductJsonJsonPresenter $productPresenter
) {
parent::__construct($module, $context, $favoriteProductService);
$this->productPresenter = $productPresenter;
Expand All @@ -33,6 +33,10 @@ public function execute(array $params): void
'action' => 'removeFavoriteProduct',
'ajax' => '1',
]),
'refreshFavoriteUpSellingBlockUrl' => $this->context->link->getModuleLink($this->module->name, 'ajax', [
'action' => 'refreshUpSellingBlock',
'ajax' => '1',
]),
'favoriteProducts' => $this->getFavoriteProductsJsonData(),
'isFavoriteProductsListingPage' => $this->context->controller instanceof \Is_favoriteproductsFavoriteModuleFrontController,
]);
Expand Down
65 changes: 65 additions & 0 deletions src/Hook/DisplayCrossSellingShoppingCart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Hook;

use Oksydan\IsFavoriteProducts\DTO\FavoriteProduct;
use Oksydan\IsFavoriteProducts\Presenter\FrontProductProductPresenter;
use Oksydan\IsFavoriteProducts\Services\FavoriteProductService;
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray;

class DisplayCrossSellingShoppingCart extends AbstractCacheableDisplayHook
{
private FrontProductProductPresenter $productPresenter;

public function __construct(
\Is_favoriteproducts $module,
\Context $context,
FavoriteProductService $favoriteProductService,
FrontProductProductPresenter $productPresenter
) {
parent::__construct($module, $context, $favoriteProductService);
$this->productPresenter = $productPresenter;
}

private const TEMPLATE_FILE = 'displayCrossSellingShoppingCart.tpl';

protected function getTemplate(): string
{
return self::TEMPLATE_FILE;
}

protected function assignTemplateVariables(array $params)
{
$products = $this->favoriteProductService->getFavoriteProductsForCartUpSelling($this->getExcludedProducts());

$products = array_map(function (array $favoriteProduct) {
return $this->presentProduct($favoriteProduct);
}, $products);

$this->context->smarty->assign([
'products' => $products,
]);
}

private function getExcludedProducts(): array
{
$smartyCart = $this->context->smarty->getTemplateVars('cart');
$products = $smartyCart['products'] ?? [];
$productsCollection = [];

foreach ($products as $product) {
$productsCollection[] = (new FavoriteProduct())
->setIdProduct((int) $product['id_product'])
->setIdProductAttribute((int) $product['id_product_attribute']);
}

return $productsCollection;
}

private function presentProduct(array $product): ProductLazyArray
{
return $this->productPresenter->present($product);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Oksydan\IsFavoriteProducts\DTO\FavoriteProduct;

class FavoriteProductJsonPresenter implements PresenterInterface
class FavoriteProductJsonJsonPresenter implements JsonPresenterInterface
{
public function present(FavoriteProduct $favoriteProduct): string
{
Expand Down
12 changes: 12 additions & 0 deletions src/Presenter/FrontProductPresenterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Presenter;

use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray;

interface FrontProductPresenterInterface
{
public function present(array $product): ProductLazyArray;
}
40 changes: 40 additions & 0 deletions src/Presenter/FrontProductProductPresenter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Presenter;

use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray;

class FrontProductProductPresenter implements FrontProductPresenterInterface
{
protected \Context $context;

public function __construct(
\Context $context
) {
$this->context = $context;
}

/**
* @param array{id_product: int, id_product_attribute: int} $product
*
* @return ProductLazyArray
*/
public function present(array $product): ProductLazyArray
{
$presenterFactory = $this->presenterFactory();
$presenter = $presenterFactory->getPresenter();

return $presenter->present(
$presenterFactory->getPresentationSettings(),
(new \ProductAssembler($this->context))->assembleProduct($product),
$this->context->language
);
}

private function presenterFactory(): \ProductPresenterFactory
{
return new \ProductPresenterFactory($this->context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Oksydan\IsFavoriteProducts\DTO\FavoriteProduct;

interface PresenterInterface
interface JsonPresenterInterface
{
public function present(FavoriteProduct $favoriteProduct);
}
Loading

0 comments on commit 3619bae

Please sign in to comment.