Skip to content

Commit

Permalink
Merge pull request #23788 from NeOMakinG/combinations-filters
Browse files Browse the repository at this point in the history
Add combinations filters to product page v2
  • Loading branch information
jolelievre committed Apr 14, 2021
2 parents 44042ad + b44b919 commit ad181f7
Show file tree
Hide file tree
Showing 22 changed files with 1,037 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,7 @@ export default class DynamicPaginator {
* @param {Number|null} startingPage If provided it will load the provided page data on page load
* @param {Object|null} selectorsMap If provided it will override css selectors used for all the actions.
*/
constructor(
containerSelector,
paginationService,
renderer,
startingPage = null,
selectorsMap = null,
) {
constructor(containerSelector, paginationService, renderer, startingPage = null, selectorsMap = null) {
this.$paginationContainer = $(containerSelector);
this.paginationService = paginationService;
this.renderer = renderer;
Expand Down Expand Up @@ -176,7 +170,8 @@ export default class DynamicPaginator {
const limit = this.getLimit();
const from = page === 1 ? 1 : Math.round((page - 1) * limit);
const to = page === this.pagesCount ? total : Math.round(page * limit);
const modifiedInfoText = infoLabel.data('pagination-info')
const modifiedInfoText = infoLabel
.data('pagination-info')
.replace(/%from%/g, from)
.replace(/%to%/g, to)
.replace(/%total%/g, total)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->

<template>
<div class="combinations-filters-dropdown">
<div class="dropdown">
<button
:class="[
'btn',
'dropdown-toggle',
selectedFilters.length > 0 ? 'btn-primary' : 'btn-outline-secondary',
'btn',
]"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
id="form_invoice_prefix"
>
{{ label }} {{ nbFiles }}
</button>
<div
class="dropdown-menu"
aria-labelledby="form_invoice_prefix"
@click="preventClose($event)"
>
<div
class="md-checkbox"
v-for="filter in children"
:key="filter.id"
>
<label class="dropdown-item">
<div class="md-checkbox-container">
<input
type="checkbox"
:checked="isChecked(filter)"
@change="toggleFilter(filter)"
>
<i class="md-checkbox-control" />
{{ filter.name }}
</div>
</label>
</div>
</div>
</div>
</div>
</template>

<script>
export default {
name: 'FilterDropdown',
data() {
return {
selectedFilters: [],
};
},
props: {
parentId: {
type: Number,
required: true,
},
children: {
type: Array,
required: true,
},
label: {
type: String,
required: true,
},
},
mounted() {
this.$parent.$on('clearAll', this.clear);
},
computed: {
nbFiles() {
return this.selectedFilters.length > 0
? `(${this.selectedFilters.length})`
: null;
},
},
methods: {
isChecked(filter) {
return this.selectedFilters.includes(filter);
},
toggleFilter(filter) {
if (this.selectedFilters.includes(filter)) {
this.$emit('removeFilter', filter, this.parentId);
this.selectedFilters = this.selectedFilters.filter(
(item) => item.id !== filter.id,
);
} else {
this.$emit('addFilter', filter, this.parentId);
this.selectedFilters.push(filter);
}
},
preventClose(event) {
event.stopPropagation();
},
clear() {
this.selectedFilters = [];
},
},
};
</script>

<style lang="scss" type="text/scss">
@import "~@scss/config/_settings.scss";
.combinations-filters-dropdown {
margin: 0 0.35rem;
.dropdown-item {
padding: 0.438rem 0.938rem;
padding-right: 1rem;
line-height: normal;
color: inherit;
border-bottom: 0;
.md-checkbox-container {
position: relative;
padding-left: 28px;
}
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<!--**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*-->
<template>
<div class="combinations-filters">
<label
for="caption-textarea"
class="control-label"
>Filter by:</label>

<div class="combinations-filters-line">
<filter-dropdown
:key="filter.id"
v-for="filter in filters"
:children="filter.attributes"
:parent-id="filter.id"
:label="filter.name"
@addFilter="addFilter"
@removeFilter="removeFilter"
/>
<button
type="button"
v-if="selectedFiltersNumber > 0"
class="btn btn-outline-secondary combinations-filters-clear"
@click="clearAll"
>
<i class="material-icons">close</i> Clear
{{ selectedFiltersNumber }} filters
</button>
</div>
</div>
</template>

<script>
import {getProductAttributeGroups} from '@pages/product/services/attribute-groups';
import FilterDropdown from '@pages/product/components/filters/FilterDropdown';
import ProductEventMap from '@pages/product/product-event-map';
const CombinationEvents = ProductEventMap.combinations;
export default {
name: 'Filters',
data() {
return {
filters: [],
selectedFilters: {},
};
},
props: {
productId: {
type: Number,
required: true,
},
eventEmitter: {
type: Object,
required: true,
},
},
components: {
FilterDropdown,
},
computed: {
selectedFiltersNumber() {
if (!this.selectedFilters) {
return 0;
}
return Object.values(this.selectedFilters).reduce((total, attributes) => total + attributes.length, 0);
},
},
mounted() {
this.initFilters();
},
methods: {
/**
* This methods is used to initialize product filters
*/
async initFilters() {
try {
this.filters = await getProductAttributeGroups(this.productId);
} catch (error) {
window.$.growl.error({message: error});
}
},
addFilter(filter, parentId) {
// If absent set new field with set method so that it's reactive
if (!this.selectedFilters[parentId]) {
this.$set(this.selectedFilters, parentId, []);
}
this.selectedFilters[parentId].push(filter);
this.updateFilters();
},
removeFilter(filter, parentId) {
if (!this.selectedFilters[parentId]) {
return;
}
this.selectedFilters[parentId] = this.selectedFilters[parentId].filter(
(e) => filter.id !== e.id,
);
this.updateFilters();
},
clearAll() {
this.selectedFilters = [];
this.$emit('clearAll');
this.eventEmitter.emit(CombinationEvents.updateAttributeGroups, this.selectedFilters);
},
updateFilters() {
this.eventEmitter.emit(CombinationEvents.updateAttributeGroups, this.selectedFilters);
},
},
};
</script>

<style lang="scss" type="text/scss">
@import "~@scss/config/_settings.scss";
.combinations-filters {
.control-label {
font-weight: 600;
color: #000;
margin-botton: 1rem;
}
&-line {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
margin: 0 -0.35rem;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/

import Vue from 'vue';
import Filters from '@pages/product/components/filters/Filters';

export default function initCombinationsFilters(combinationsFiltersSelector, eventEmitter) {
const container = document.querySelector(combinationsFiltersSelector);
const productId = Number(container.dataset.productId);

return new Vue({
el: combinationsFiltersSelector,
template: '<filters :productId=productId :eventEmitter=eventEmitter />',
components: {Filters},
data: {
productId,
eventEmitter,
},
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default class CombinationsGridRenderer {
const $row = $(this.getPrototypeRow(rowIndex));

// fill inputs
const $combinationCheckbox = $(ProductMap.combinations.tableRow.combinationCheckbox(rowIndex), $row);
const $combinationIdInput = $(ProductMap.combinations.tableRow.combinationIdInput(rowIndex), $row);
const $combinationNameInput = $(ProductMap.combinations.tableRow.combinationNameInput(rowIndex), $row);
const $quantityInput = $(ProductMap.combinations.tableRow.quantityInput(rowIndex), $row);
Expand All @@ -84,8 +85,9 @@ export default class CombinationsGridRenderer {
const $finalPriceInput = $(ProductMap.combinations.tableRow.finalPriceTeInput(rowIndex), $row);
$combinationIdInput.val(combination.id);
$combinationNameInput.val(combination.name);
// This adds the ID in the checkbox label
$combinationCheckbox.closest('label').append(combination.id);
// This adds a text after the cell children (do not use text which replaces everything)
$combinationIdInput.closest('td').append(combination.id);
$combinationNameInput.closest('td').append(combination.name);
$finalPriceInput.closest('td').append(combination.finalPriceTe);
$referenceInput.val(combination.reference);
Expand Down

0 comments on commit ad181f7

Please sign in to comment.