Skip to content

Commit

Permalink
Add view more link in facet
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreGauthier committed Dec 4, 2024
1 parent 2cebb34 commit 1d506ca
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 16 deletions.
76 changes: 76 additions & 0 deletions src/Controller/Frontend/ViewMoreController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
*
* @package Gally
* @author Gally Team <elasticsuite@smile.fr>
* @copyright 2024-present Smile
* @license Open Software License v. 3.0 (OSL-3.0)
*/

declare(strict_types=1);

namespace Gally\OroPlugin\Controller\Frontend;

use Gally\OroPlugin\Search\GallyRequestBuilder;
use Gally\Sdk\GraphQl\Request as SearchRequest;
use Gally\Sdk\Service\SearchManager;
use Oro\Bundle\DataGridBundle\Datagrid;
use Oro\Bundle\SearchBundle\Datagrid\Datasource\SearchDatasource;
use Oro\Bundle\SecurityBundle\Annotation\AclAncestor;
use Oro\Bundle\WebsiteSearchBundle\Event\BeforeSearchEvent;
use Oro\Bundle\WebsiteSearchBundle\Resolver\QueryPlaceholderResolverInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class ViewMoreController extends AbstractController
{
public const PRODUCT_SEARCH_DATAGRID = 'frontend-product-search-grid';

public function __construct(
private Datagrid\Manager $dataGridManager,
private Datagrid\RequestParameterBagFactory $parameterBagFactory,
private EventDispatcherInterface $eventDispatcher,
private QueryPlaceholderResolverInterface $queryPlaceholderResolver,
private GallyRequestBuilder $requestBuilder,
private SearchManager $searchManager,
) {
}

/**
* @Route("/filter_view_more", name="gally_filter_view_more", methods={"GET"})
*
* @AclAncestor("oro_product_frontend_view")
*/
public function getDataAction(Request $request): JsonResponse
{
$options = $this->searchManager->viewMoreProductFilterOption(
$this->getSearchRequest(),
$request->query->get('field')
);

return new JsonResponse($options);
}

private function getSearchRequest(): SearchRequest
{
$dataGrid = $this->dataGridManager->getDatagrid(
self::PRODUCT_SEARCH_DATAGRID,
$this->parameterBagFactory->fetchParameters(self::PRODUCT_SEARCH_DATAGRID)
);

/** @var SearchDatasource $datasource */
$datasource = $dataGrid->acceptDatasource()->getDatasource();
$query = $datasource->getSearchQuery();
$event = new BeforeSearchEvent($query->getQuery(), []);
$this->eventDispatcher->dispatch($event, BeforeSearchEvent::EVENT_NAME);
$this->queryPlaceholderResolver->replace($event->getQuery());

return $this->requestBuilder->build($event->getQuery(), []);
}
}
1 change: 1 addition & 0 deletions src/DependencyInjection/GallyOroExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function load(array $configs, ContainerBuilder $container)

$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$loader->load('controllers.yml');
}

public function getAlias(): string
Expand Down
16 changes: 16 additions & 0 deletions src/Resources/config/controllers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
services:
_defaults:
public: true

Gally\OroPlugin\Controller\Frontend\ViewMoreController:
arguments:
- '@oro_datagrid.datagrid.manager'
- '@oro_datagrid.datagrid.request_parameters_factory'
- '@event_dispatcher'
- '@Gally\OroPlugin\Resolver\QueryPlaceholderResolver'
- '@Gally\OroPlugin\Search\GallyRequestBuilder'
- '@Gally\Sdk\Service\SearchManager'
calls:
- [setContainer, ['@Psr\Container\ContainerInterface']]
tags:
- { name: container.service_subscriber }
6 changes: 6 additions & 0 deletions src/Resources/config/oro/routing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
gally_frontend_routes:
resource: "@GallyOroBundle/Controller/Frontend"
type: annotation
prefix: /gally
options:
frontend: true
76 changes: 76 additions & 0 deletions src/Resources/public/default/templates/search-autocomplete.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<%
function highlightWords(inputString, value) {
if (!!inputString && _.isString(inputString)) {
const highlightPattern = '<u class="search-autocomplete__highlight">$&</u>';
const inputWords = _.escape(inputString).split(' ');
const reg = new RegExp(inputWords.join('|'), 'gi');
return _.escape(value).replace(reg, highlightPattern);
} else {
return _.escape(value);
}
}
%>

<div class="search-autocomplete">
<div class="search-autocomplete__content dropdown-menu">
<% if (total_count > 0) { %>
<ul class="search-autocomplete__list" id="<%- comboboxId %>" role="listbox">
<%_.each(categories, function(category) { %>
<li class="search-autocomplete__item" role="option">
<a href="<%- category.url %>" class="search-autocomplete-category" title="<%- _.__('oro.product.search.search_in_category.tooltip', { text: inputString, category: category.tree[category.tree.length - 1] }, category.count) %>">
<div class="search-autocomplete-category__image">
<span class="fa-search fa--no-offset"></span>
</div>
<div class="search-autocomplete-category__info">
<div class="search-autocomplete-category__head">
<%= inputString %>
</div>
<div class="search-autocomplete-category__body">
<% let lastCategory = category.tree.pop(); %>
<%_.each(category.tree, function(categoryLeaf) { %>
<span><%= categoryLeaf %> > </span>
<% }) %>
<span class="last-category"><%= lastCategory %></span>
</div>
</div>
</a>
</li>
<% }) %>
<%_.each(products, function(product) { %>
<li class="search-autocomplete__item" role="option">
<a href="<%- product.url %>" class="search-autocomplete-product" title="<%- product.name %>">
<div class="search-autocomplete-product__image">
<picture>
<% if (product.imageWebp && product.imageWebp !== product.image) { %>
<source srcset="<%- product.imageWebp %>" type="image/webp">
<% } %>
<img src="<%- product.image %>" alt="<%- product.name %>">
</picture>
</div>
<div class="search-autocomplete-product__info">
<div class="search-autocomplete-product__head">
<div class="search-autocomplete-product__title"><%= highlightWords(inputString, product.name) %></div>
<% if (product.formatted_price) { %>
<div class="search-autocomplete-product__price"><%- product.formatted_price %></div>
<% } %>
</div>
<div class="search-autocomplete-product__body">
<div class="search-autocomplete-product__sku"><%= highlightWords(inputString, product.sku) %></div>
<div class="search-autocomplete-product__status <%- product.inventory_status %>"><%- product.inventory_status_label %></div>
</div>
</div>
</a>
</li>
<% }) %>
<li class="search-autocomplete__item" role="option">
<button class="btn btn--link btn--no-offset search-autocomplete__submit"
type="submit"
><%- _.__('oro.product.autocomplete.popup.button.all.label', { productCount: total_count }, total_count) %> <span class="fa-angle-right" aria-hidden="true"></span>
</button>
</li>
</ul>
<% } else { %>
<div class="search-autocomplete__no-found"><%- _.__('oro.product.autocomplete.no_found') %></div>
<% } %>
</div>
</div>
70 changes: 70 additions & 0 deletions src/Resources/public/js/filter/gally-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
define(function(require) {
'use strict';

const $ = require('jquery');
const routing = require('routing');
const MultiSelectFilter = require('oro/filter/multiselect-filter');
const LoadingMaskView = require('oroui/js/app/views/loading-mask-view');
const __ = require('orotranslation/js/translator');

/**
* Gally select filter: filter values as multiple select options and
* add a view more button if all the options are not displayed
*
* @export oro/filter/gally-filter
* @class oro.filter.GallyFilter
* @extends oro.filter.MultiSelectFilter
*/
const GallyFilter = MultiSelectFilter.extend({

custom_data: {},

/**
* @inheritdoc
*/
initialize: function (options) {
GallyFilter.__super__.initialize.call(this, options);
const viewMoreLabel = __('gally.filter.showMore.label');
this.showMoreLink = $('<a/>', {href: '#', html: viewMoreLabel, click: this.showMore.bind(this)});
},

/**
* @inheritdoc
*/
render: function() {
GallyFilter.__super__.render.call(this);

if (this.custom_data.hasMore) {
this.selectWidget.multiselect('open');
this.selectWidget.getWidget().append(this.showMoreLink);
this.selectWidget.multiselect('close');
}
if (!this.subview('loading')) {
this.subview('loading', new LoadingMaskView({container: this.$el}));
}
},

showMore: function() {
this.subview('loading').show();
let urlParams = Object.fromEntries(new URLSearchParams(window.location.search));
urlParams['field'] = this.name;

$.ajax({
url: routing.generate('gally_filter_view_more', urlParams),
method: 'GET',
success: function (response) {
this.custom_data.hasMore = false;
this.showMoreLink.hide();
this._setChoices(response);
this.render();
this.subview('loading').hide();
}.bind(this),
error: function (xhr) {
this.subview('loading').hide();
}.bind(this),
});
}
});

return GallyFilter;
});
4 changes: 4 additions & 0 deletions src/Resources/translations/jsmessages.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gally:
filter:
showMore:
label: "Show more"
4 changes: 4 additions & 0 deletions src/Resources/translations/jsmessages.fr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gally:
filter:
showMore:
label: "Voir plus"
3 changes: 3 additions & 0 deletions src/Resources/translations/messages.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ gally:
password:
label: "Password"
tooltip: "Password used to connect to Gally."
filter:
showMore:
label: "Show more"
3 changes: 3 additions & 0 deletions src/Resources/translations/messages.fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ gally:
password:
label: "Mot de passe"
tooltip: "Mot de passe utilisé pour se connecter à Gally."
filter:
showMore:
label: "Voir plus"
6 changes: 6 additions & 0 deletions src/Resources/views/layouts/default/config/jsmodules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
aliases:
oro/filter/gally-filter$: bundles/gallyoro/js/filter/gally-filter

dynamic-imports:
orodatagrid:
- oro/filter/gally-filter
1 change: 1 addition & 0 deletions src/Search/Extension/GallyDataGridExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ private function addFiltersFromGallyResult(DatagridConfiguration $config): void
} else {
$filter['choices'] = $gallyFilter['options'];
$filter['options']['gally_options'] = $gallyFilter['options'];
$filter['options']['has_more'] = $gallyFilter['hasMore'];
$filter['type'] = 'gally-select';
$filters[$gallyFilter['field']] = $filter;
}
Expand Down
18 changes: 3 additions & 15 deletions src/Search/Filter/Form/SelectFormFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

use Oro\Bundle\FilterBundle\Form\Type\Filter\ChoiceFilterType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand All @@ -32,6 +31,7 @@ class SelectFormFilter extends AbstractType
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('has_more', false);
$resolver->setDefault('gally_options', []);
$resolver->setNormalizer(
'gally_options',
Expand All @@ -40,22 +40,15 @@ function (Options $options, $value) {
}
);

// $resolver->setNormalizer( //todo might be removed
// 'class',
// function (Options $options, $value) {
// return null;
// }
// );

$resolver->setNormalizer(
'field_options',
function (Options $options, $value) {
$value['choices'] = $options['gally_options'];
$value['choice_loader'] = new ChoiceLoader();
$value['choice_value'] = function ($value = null, $data = null, $toto = null) {
$value['choice_value'] = function ($value = null) {
return $value;
};
$value['choice_filter'] = function ($value = null, $data = null, $toto = null) {
$value['choice_filter'] = function ($value = null) {
return $value;
};

Expand All @@ -71,11 +64,6 @@ function (Options $options, $value) {
);
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
$toto = 'blop';
}

/**
* {@inheritDoc}
*/
Expand Down
17 changes: 16 additions & 1 deletion src/Search/Filter/SelectFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@
*/
class SelectFilter extends BaseMultiChoiceFilter
{
private bool $hasMore = false;

/**
* {@inheritDoc}
*/
public function init($name, array $params)
{
parent::init($name, $params);

$this->params[FilterUtility::FRONTEND_TYPE_KEY] = 'multiselect';
$this->hasMore = $params['options']['has_more'] ?? false;
$this->params[FilterUtility::FRONTEND_TYPE_KEY] = 'gally';
}

/**
Expand Down Expand Up @@ -79,4 +82,16 @@ protected function getFormType(): string
{
return SelectFormFilter::class;
}

public function getMetadata(): array
{
$metadata = parent::getMetadata();

$metadata['custom_data'] = [
'hasMore' => $this->hasMore,
'hasMoreUrl' => '',
];

return $metadata;
}
}

0 comments on commit 1d506ca

Please sign in to comment.