Skip to content

Commit

Permalink
Merge pull request #10 from Oksydan/upselling
Browse files Browse the repository at this point in the history
Upselling block in cart
  • Loading branch information
Oksydan authored Dec 15, 2023
2 parents 304c40d + 012b97c commit 1611179
Show file tree
Hide file tree
Showing 25 changed files with 466 additions and 25 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
24 changes: 24 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 { parseToHtml } from '@js/utils/DOM/DOMHelpers';
import useFavoriteProducts from './components/useFavoriteProducts';
import useFavoriteDOMHandler from './components/useFavoriteDOMHandler';

DOMReady(() => {
const {
addToFavorite,
removeFromFavorite,
updateUpSellingBLock,
} = useFavoriteProducts();
const {
getProductIdsFromKey,
Expand Down Expand Up @@ -87,4 +89,26 @@ 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);
}
// eslint-disable-next-line no-empty
} catch (error) {
}
});
prestashop.on('updatedFavoriteUpSellingBlock', () => {
setTimeout(refreshButtons, 1);
prestashop.pageSlider.refresh();
});
});
5 changes: 0 additions & 5 deletions _theme_dev/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,6 @@ eslint-config-airbnb-base@^15.0.0:
object.entries "^1.1.5"
semver "^6.3.0"

eslint-import-resolver-alias@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97"
integrity sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==

eslint-import-resolver-node@^0.3.7:
version "0.3.7"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
Expand Down
5 changes: 5 additions & 0 deletions config/admin/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ services:
$module: '@oksydan.is_favoriteproducts.module'
$context: '@oksydan.is_favoriteproducts.context'
$dbPrefix: '%database_prefix%'
$cacheableHooksCollection: !tagged oksydan.is_favoriteproducts.cacheable_hook

_instanceof:
Oksydan\IsFavoriteProducts\Hook\AbstractCacheableDisplayHook:
tags: [ 'oksydan.is_favoriteproducts.cacheable_hook' ]

Oksydan\IsFavoriteProducts\:
resource: '../../src/*'
Expand Down
5 changes: 5 additions & 0 deletions config/front/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ services:
$module: '@oksydan.is_favoriteproducts.module'
$context: '@oksydan.is_favoriteproducts.context'
$dbPrefix: '%database_prefix%'
$cacheableHooksCollection: !tagged oksydan.is_favoriteproducts.cacheable_hook

_instanceof:
Oksydan\IsFavoriteProducts\Hook\AbstractCacheableDisplayHook:
tags: [ 'oksydan.is_favoriteproducts.cacheable_hook' ]

Oksydan\IsFavoriteProducts\:
resource: '../../src/*'
Expand Down
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
12 changes: 11 additions & 1 deletion is_favoriteproducts.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct()
$this->name = 'is_favoriteproducts';

$this->author = 'Igor Stępień';
$this->version = '1.0.1';
$this->version = '2.0.0';
$this->need_instance = 0;
$this->controllers = ['favorite'];
$this->bootstrap = true;
Expand Down 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);
}
}
26 changes: 26 additions & 0 deletions src/Cache/TemplateCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Cache;

use Oksydan\IsFavoriteProducts\Hook\DisplayCrossSellingShoppingCart;

class TemplateCache implements TemplateCacheInterface
{
public $cacheableHooksCollection;

public function __construct($cacheableHooksCollection)
{
$this->cacheableHooksCollection = $cacheableHooksCollection;
}

public function clearCartTemplateCache(): void
{
foreach ($this->cacheableHooksCollection as $hook) {
if ($hook instanceof DisplayCrossSellingShoppingCart) {
$hook->clearCache();
}
}
}
}
10 changes: 10 additions & 0 deletions src/Cache/TemplateCacheInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Cache;

interface TemplateCacheInterface
{
public function clearCartTemplateCache(): void;
}
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());
}
}
32 changes: 32 additions & 0 deletions src/Hook/ActionCartSave.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Oksydan\IsFavoriteProducts\Hook;

use Oksydan\IsFavoriteProducts\Cache\TemplateCache;
use Oksydan\IsFavoriteProducts\Services\FavoriteProductService;

class ActionCartSave extends AbstractHook
{
private TemplateCache $templateCache;

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

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

$this->templateCache->clearCartTemplateCache();
}
}
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 @@ -4,7 +4,7 @@

namespace Oksydan\IsFavoriteProducts\Hook;

class DisplayProductListReviews extends AbstractDisplayHook
class DisplayProductFavoriteButton extends AbstractDisplayHook
{
private const TEMPLATE_FILE = 'button.tpl';

Expand Down
Loading

0 comments on commit 1611179

Please sign in to comment.