Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
<?php
$config = new PrestaShop\CodingStandards\CsFixer\Config();
$config
->setUsingCache(true)
->getFinder()
->in(__DIR__)
->exclude('vendor');
return $config;

View File

@@ -0,0 +1,7 @@
module.exports = {
htmlWhitespaceSensitivity: 'ignore',
semi: true,
singleQuote: true,
vueIndentScriptAndStyle: true,
trailingComma: 'none'
};

View File

@@ -0,0 +1,16 @@
help:
@egrep "^#" Makefile
# target: docker-build|db - Setup/Build PHP & (node)JS dependencies
db: docker-build
docker-build: build-back build-front
build-back:
docker compose run --rm php sh -c "composer install"
build-back-prod:
docker compose run --rm php sh -c "composer install --no-dev -o"
build-front:
docker compose run --rm node sh -c "npm install"
docker compose run --rm node sh -c "npm run build"

View File

@@ -0,0 +1,78 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import blockwishlistModule from 'blockwishlistModule';
const tabButtons = document.querySelectorAll('.btn-group button');
const refreshButton = document.querySelector('.js-refresh');
let isLoading = false;
tabButtons.forEach((button) => {
button.addEventListener('click', () => {
if (!button.classList.contains('active')) {
tabButtons.forEach((elem) => {
elem.classList.remove('active');
});
button.classList.add('active');
const tabs = document.querySelectorAll('.wishlist-tab');
tabs.forEach((tab) => {
if (
tab.classList.contains('active')
&& tab.dataset.tab !== button.dataset.tab
) {
tab.classList.remove('active');
}
if (tab.dataset.tab === button.dataset.tab) {
tab.classList.add('active');
}
});
}
});
});
refreshButton.addEventListener('click', async () => {
if (!isLoading) {
isLoading = true;
const cacheButton = refreshButton.innerHTML;
refreshButton.innerHTML = '<i class="material-icons">hourglass_empty</i>';
const response = await fetch(`${blockwishlistModule.resetCacheUrl}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json, text/javascript, */*; q=0.01',
},
});
const {success} = await response.json();
if (success) {
location.reload();
} else {
isLoading = false;
refreshButton.innerHTML = cacheButton;
}
}
});

View File

@@ -0,0 +1,26 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
const {$} = window;
$(() => {
window.prestashop.component.initComponents([
'TranslatableInput',
]);
});

View File

@@ -0,0 +1,94 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist-stats {
.card {
&-text {
width: 100%;
padding: 10px 30px;
}
}
& &-topbar {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
margin-bottom: 20px;
.btn-group {
border: 1px solid #b7ced3;
border-radius: 3px;
button {
color: #363a41;
font-size: 14px;
letter-spacing: 0;
line-height: 19px;
background: none;
font-weight: 500;
transition: 0.25s ease-out;
&:not(:last-child) {
border-right: 1px solid #b7ced3;
}
&:hover,
&.active {
background-color: #25b9d7;
color: #fff;
}
}
}
.refresh {
color: #6c868e;
font-size: 14px;
font-weight: bold;
letter-spacing: 0;
line-height: 19px;
border: 1px solid #6c868e;
border-radius: 4px;
transition: 0.25s ease-out;
background: none;
&:hover {
background: #6c868e;
color: white;
}
}
}
.wishlist-tab {
display: none;
&.active {
display: block;
}
.column-image {
img {
max-width: 50px;
}
}
.column-conversionRate {
font-weight: bold;
}
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
@import '_stats';

View File

@@ -0,0 +1,125 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import EventBus from '@components/EventBus';
import ChooseList from '../ChooseList/ChooseList';
export default {
name: 'AddToWishlist',
components: {
ChooseList,
},
props: {
url: {
type: String,
required: true,
default: '#',
},
},
data() {
return {
value: '',
isHidden: true,
productAttributeId: 0,
productId: 0,
quantity: 0,
};
},
methods: {
/**
* Open and close the modal
*/
toggleModal(forceOpen) {
if (forceOpen === true) {
this.isHidden = false;
} else {
this.isHidden = !this.isHidden;
}
},
/**
* Dispatch an event to the Create component
*/
openNewWishlistModal() {
this.toggleModal();
EventBus.$emit('showCreateWishlist');
},
},
mounted() {
/**
* Register to the event showAddToWishList so others component can open the modal of the current component
*/
EventBus.$on('showAddToWishList', (event) => {
this.toggleModal(
event.detail.forceOpen ? event.detail.forceOpen : null,
);
if (event.detail.productId) {
this.productId = event.detail.productId;
}
if (typeof event.detail.productAttributeId === 'number') {
this.productAttributeId = event.detail.productAttributeId;
}
if (event.detail.quantity) {
this.quantity = event.detail.quantity;
}
});
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-add-to-new {
cursor: pointer;
transition: 0.2s ease-out;
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1rem;
&:hover {
opacity: 0.7;
}
i {
margin-right: 0.3125rem;
vertical-align: middle;
color: $blue;
margin-top: -0.125rem;
font-size: 1.25rem;
}
}
&-add-to {
.modal {
&-body {
padding: 0;
}
&-footer {
text-align: left;
}
}
}
}
</style>

View File

@@ -0,0 +1,29 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import AddToWishlist from './AddToWishlist';
const props = [
{
name: 'url',
type: String,
},
];
initApp(AddToWishlist, '.wishlist-add-to', props);

View File

@@ -0,0 +1,234 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<button
class="wishlist-button-add"
:class="{ 'wishlist-button-product': isProduct }"
@click="addToWishlist"
>
<i
class="material-icons"
v-if="isChecked"
>favorite</i>
<i
class="material-icons"
v-else
>favorite_border</i>
</button>
</template>
<script>
import removeFromList from '@graphqlFiles/mutations/removeFromList';
import prestashop from 'prestashop';
import EventBus from '@components/EventBus';
export default {
name: 'Button',
props: {
url: {
type: String,
required: true,
default: '#',
},
productId: {
type: Number,
required: true,
default: null,
},
productAttributeId: {
type: Number,
required: true,
default: null,
},
checked: {
type: Boolean,
required: false,
default: false,
},
isProduct: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
isChecked: this.checked === 'true',
idList: this.listId,
idProductAttribute: this.productAttributeId,
};
},
methods: {
/**
* Toggle the heart on this component, basically if the heart is filled,
* then this product is inside a wishlist, else it's not in a wishlist
*/
toggleCheck() {
this.isChecked = !this.isChecked;
},
/**
* If the product isn't in a wishlist, then open the "AddToWishlist" component modal,
* if he's in a wishlist, then launch a removeFromList mutation to remote the product from a wishlist
*/
async addToWishlist(event) {
event.preventDefault();
const quantity = document.querySelector(
'.product-quantity input#quantity_wanted',
);
if (!prestashop.customer.is_logged) {
EventBus.$emit('showLogin');
return;
}
if (!this.isChecked) {
EventBus.$emit('showAddToWishList', {
detail: {
productId: this.productId,
productAttributeId: parseInt(this.idProductAttribute, 10),
forceOpen: true,
quantity: quantity ? parseInt(quantity.value, 10) : 0,
},
});
} else {
const {data} = await this.$apollo.mutate({
mutation: removeFromList,
variables: {
productId: this.productId,
url: this.url,
productAttributeId: this.idProductAttribute,
listId: this.idList ? this.idList : this.listId,
},
});
const {removeFromList: response} = data;
EventBus.$emit('showToast', {
detail: {
type: response.success ? 'success' : 'error',
message: response.message,
},
});
if (!response.error) {
this.toggleCheck();
}
}
},
},
mounted() {
/**
* Register to event addedToWishlist to toggle the heart if the product has been added correctly
*/
EventBus.$on('addedToWishlist', (event) => {
if (
event.detail.productId === this.productId
&& parseInt(event.detail.productAttributeId, 10) === this.idProductAttribute
) {
this.isChecked = true;
this.idList = event.detail.listId;
}
});
// eslint-disable-next-line
const items = productsAlreadyTagged.filter(
(e) => parseInt(e.id_product, 10) === this.productId
&& parseInt(e.id_product_attribute, 10) === this.idProductAttribute,
);
if (items.length > 0) {
this.isChecked = true;
this.idList = parseInt(items[0].id_wishlist, 10);
}
if (this.isProduct) {
prestashop.on('updateProduct', ({eventType}) => {
if (eventType === 'updatedProductQuantity') {
this.isChecked = false;
}
});
prestashop.on('updatedProduct', (args) => {
const quantity = document.querySelector(
'.product-quantity input#quantity_wanted',
);
this.idProductAttribute = parseInt(args.id_product_attribute, 10);
// eslint-disable-next-line
const itemsFiltered = productsAlreadyTagged.filter(
(e) => parseInt(e.id_product, 10) === this.productId
&& e.quantity.toString() === quantity.value
&& parseInt(e.id_product_attribute, 10) === this.idProductAttribute,
);
if (itemsFiltered.length > 0) {
this.isChecked = true;
this.idList = parseInt(itemsFiltered[0].id_wishlist, 10);
} else {
this.isChecked = false;
}
});
}
},
};
</script>
<style lang="scss" type="text/scss">
.wishlist {
&-button {
&-product {
margin-left: 1.25rem;
}
&-add {
display: flex;
align-items: center;
justify-content: center;
height: 2.5rem;
width: 2.5rem;
min-width: 2.5rem;
padding-top: 0.1875rem;
background-color: #ffffff;
box-shadow: 0.125rem -0.125rem 0.25rem 0 rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
transition: 0.2s ease-out;
border: none;
&:hover {
opacity: 0.7;
}
&:focus {
outline: 0;
}
&:active {
transform: scale(1.2);
}
i {
color: #7a7a7a;
}
}
}
}
</style>

View File

@@ -0,0 +1,51 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Button from './Button';
const initButtons = () => {
const props = [
{
name: 'url',
type: String,
},
{
name: 'checked',
type: Boolean,
},
{
name: 'productId',
type: Number,
},
{
name: 'productAttributeId',
type: Number,
},
{
name: 'isProduct',
type: Boolean,
},
];
initApp(Button, '.wishlist-button', props);
};
initButtons();
export default initButtons;

View File

@@ -0,0 +1,239 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div class="wishlist-chooselist">
<ul class="wishlist-list">
<li
class="wishlist-list-item"
v-for="list of lists"
:key="list.id_wishlist"
@click="select(list.id_wishlist)"
>
<p>
{{ list.name }}
</p>
</li>
</ul>
<ContentLoader
v-if="$apollo.queries.lists.loading"
class="wishlist-list-loader"
height="105"
>
<rect
x="0"
y="12"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="36"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="60"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="84"
rx="3"
ry="0"
width="100%"
height="11"
/>
</ContentLoader>
<p
class="wishlist-list-empty"
v-if="lists && lists.length <= 0 && !$apollo.queries.lists.loading"
>
{{ emptyText }}
</p>
</div>
</template>
<script>
import getLists from '@graphqlFiles/queries/getlists';
import addtolist from '@graphqlFiles/mutations/addtolist';
import EventBus from '@components/EventBus';
import {ContentLoader} from 'vue-content-loader';
/**
* The role of this component is to render a list
* and make the possibility to choose one for the selected product
*/
export default {
name: 'ChooseList',
components: {
ContentLoader,
},
apollo: {
lists: {
query: getLists,
variables() {
return {
url: this.url,
};
},
},
},
props: {
productId: {
type: Number,
required: true,
default: 0,
},
quantity: {
type: Number,
required: true,
default: 0,
},
productAttributeId: {
type: Number,
required: true,
default: 0,
},
url: {
type: String,
required: true,
default: '',
},
emptyText: {
type: String,
required: true,
default: 'No list found',
},
addUrl: {
type: String,
required: true,
default: '',
},
},
methods: {
/**
* Select a list and add the product to it
*
* @param {Int} listId The id of the list selected
* @param {Int} userId The id of the user
* @param {Int} productId The id of the product
*/
async select(listId) {
const {data} = await this.$apollo.mutate({
mutation: addtolist,
variables: {
listId,
url: this.addUrl,
productId: this.productId,
quantity: this.quantity,
productAttributeId: this.productAttributeId,
},
});
const {addToList: response} = data;
/**
* Hide the modal inside the parent
*/
this.$emit('hide');
EventBus.$emit('showToast', {
detail: {
type: response.success ? 'success' : 'error',
message: response.message,
},
});
/**
* Send an event to the Heart the user previously clicked on
*/
EventBus.$emit('addedToWishlist', {
detail: {
productId: this.productId,
listId,
productAttributeId: this.productAttributeId,
},
});
},
},
mounted() {
/**
* Register to the event refetchList so if an other component update it, this one can update his list
*
* @param {String} 'refetchList' The event I decided to create to communicate between VueJS Apps
*/
EventBus.$on('refetchList', () => {
this.$apollo.queries.lists.refetch();
});
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-list {
max-height: 55vh;
overflow-y: auto;
border-top: 1px solid #e5e5e5;
border-bottom: 1px solid #e5e5e5;
margin: 0;
&-empty {
font-size: 30;
text-align: center;
padding: 30px;
padding-bottom: 1.25rem;
font-weight: bold;
color: #000;
}
& .wishlist-list-item {
padding: 0.875rem 0;
transition: 0.25s ease-out;
cursor: pointer;
margin-bottom: 0;
&:hover {
background: lighten($blue, 45%);
}
p {
font-size: 0.875rem;
letter-spacing: 0;
color: #232323;
margin-bottom: 0;
line-height: 1rem;
padding: 0 2.5rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,141 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import createList from '@graphqlFiles/mutations/createlist';
import EventBus from '@components/EventBus';
/**
* This component display a modal where you can create a wishlist
*/
export default {
name: 'Create',
props: {
url: {
type: String,
required: true,
default: '#',
},
title: {
type: String,
required: true,
default: 'New wishlist',
},
label: {
type: String,
required: true,
default: 'Wishlist name',
},
placeholder: {
type: String,
required: true,
default: 'Add name',
},
cancelText: {
type: String,
required: true,
default: 'Cancel',
},
lengthText: {
type: String,
required: true,
default: 'List title is too short',
},
createText: {
type: String,
required: true,
default: 'Create',
},
},
data() {
return {
value: '',
isHidden: true,
};
},
methods: {
/**
* Toggle the modal
*/
toggleModal() {
this.isHidden = !this.isHidden;
},
/**
* Launch a createList mutation to create a Wishlist
*/
async createWishlist() {
const titleWithoutSpaces = this.value.replace(/ /g, '');
if (titleWithoutSpaces < 1) {
EventBus.$emit('showToast', {
detail: {
type: 'error',
message: this.lengthText,
},
});
return false;
}
const {data: response} = await this.$apollo.mutate({
mutation: createList,
variables: {
name: this.value,
url: this.url,
},
});
EventBus.$emit('showToast', {
detail: {
type: response.createList.success ? 'success' : 'error',
message: response.createList.message,
},
});
/**
* As this is not a real SPA, we need to inform others VueJS apps that they need to refetch the list
*/
EventBus.$emit('refetchList');
/**
* Finally hide the modal after creating the list
* and reopen the wishlist modal
*/
this.toggleModal();
EventBus.$emit('showAddToWishList', {
detail: {
forceOpen: true,
},
});
return true;
},
},
mounted() {
/**
* Register to the event showCreateWishlist so others components can toggle this modal
*
* @param {String} 'showCreateWishlist'
*/
EventBus.$on('showCreateWishlist', () => {
this.value = '';
this.toggleModal();
});
},
};
</script>

View File

@@ -0,0 +1,57 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Create from './Create';
const props = [
{
name: 'url',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'label',
type: String,
},
{
name: 'productId',
type: Number,
},
{
name: 'placeholder',
type: String,
},
{
name: 'cancelText',
type: String,
},
{
name: 'lengthText',
type: String,
},
{
name: 'createText',
type: String,
},
];
initApp(Create, '.wishlist-create', props);

View File

@@ -0,0 +1,158 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import deleteList from '@graphqlFiles/mutations/deletelist';
import removeFromList from '@graphqlFiles/mutations/removeFromList';
import EventBus from '@components/EventBus';
/**
* This component display a modal where you can delete a wishlist
*/
export default {
name: 'Delete',
props: {
deleteProductUrl: {
type: String,
required: false,
default: '#',
},
deleteListUrl: {
type: String,
required: false,
default: '#',
},
title: {
type: String,
required: true,
default: 'Delete',
},
titleList: {
type: String,
required: true,
default: 'Delete',
},
placeholder: {
type: String,
required: true,
default: 'This action is irreversible',
},
cancelText: {
type: String,
required: true,
default: 'Cancel',
},
deleteText: {
type: String,
required: true,
default: 'Delete',
},
deleteTextList: {
type: String,
required: true,
default: 'Delete',
},
},
data() {
return {
value: '',
isHidden: true,
listId: null,
listName: '',
productId: null,
productAttributeId: null,
};
},
computed: {
confirmMessage() {
return this.placeholder.replace('%nameofthewishlist%', this.listName);
},
modalTitle() {
return this.productId ? this.title : this.titleList;
},
modalDeleteText() {
return this.productId ? this.deleteText : this.deleteTextList;
},
},
methods: {
/**
* Toggle the modal
*/
toggleModal() {
this.isHidden = !this.isHidden;
},
/**
* Launch a deleteList mutation to delete a Wishlist
*/
async deleteWishlist() {
const {data} = await this.$apollo.mutate({
mutation: this.productId ? removeFromList : deleteList,
variables: {
listId: this.listId,
productId: parseInt(this.productId, 10),
productAttributeId: parseInt(this.productAttributeId, 10),
url: this.productId ? this.deleteProductUrl : this.deleteListUrl,
},
});
const response = data.deleteList
? data.deleteList
: data.removeFromList;
/**
* As this is not a real SPA, we need to inform others VueJS apps that they need to refetch the list
*/
EventBus.$emit('refetchList');
EventBus.$emit('showToast', {
detail: {
type: response.success ? 'success' : 'error',
message: response.message,
},
});
/**
* Finally hide the modal after deleting the list
* and reopen the wishlist modal
*/
this.toggleModal();
},
},
mounted() {
/**
* Register to the event showCreateWishlist so others components can toggle this modal
*
* @param {String} 'showDeleteWishlist'
*/
EventBus.$on('showDeleteWishlist', (event) => {
this.value = '';
this.listId = event.detail.listId;
this.listName = event.detail.listName;
this.productId = null;
this.productAttributeId = null;
if (event.detail.productId) {
this.productId = event.detail.productId;
this.productAttributeId = event.detail.productAttributeId;
}
this.toggleModal();
});
},
};
</script>

View File

@@ -0,0 +1,57 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Delete from './Delete';
const props = [
{
name: 'deleteProductUrl',
type: String,
},
{
name: 'deleteListUrl',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'titleList',
type: String,
},
{
name: 'placeholder',
type: String,
},
{
name: 'cancelText',
type: String,
},
{
name: 'deleteText',
type: String,
},
{
name: 'deleteTextList',
type: String,
},
];
initApp(Delete, '.wishlist-delete', props);

View File

@@ -0,0 +1,28 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import Vue from 'vue';
import prestashop from 'prestashop';
const EventBus = new Vue();
window.WishlistEventBus = EventBus;
prestashop.emit('wishlistEventBusInit');
export default EventBus;

View File

@@ -0,0 +1,353 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div class="wishlist-list-container">
<ul
class="wishlist-list"
v-if="items.length > 0 && items"
v-click-outside="emptyPopups"
>
<li
class="wishlist-list-item"
:key="list.id_wishlist"
v-for="list of items"
:class="{ 'wishlist-list-item-default': list.default }"
>
<a
class="wishlist-list-item-link"
@click="redirectToList(list.listUrl)"
>
<p class="wishlist-list-item-title">
{{ list.name }}
<span v-if="list.nbProducts">({{ list.nbProducts }})</span>
<span v-else>(0)</span>
</p>
<div class="wishlist-list-item-right">
<button
class="wishlist-list-item-actions"
@click.stop="togglePopup(list.id_wishlist)"
v-if="!list.default"
>
<i class="material-icons">more_vert</i>
</button>
<button
@click.stop="toggleShare(list.id_wishlist, list.shareUrl)"
v-if="list.default"
>
<i class="material-icons">share</i>
</button>
<div
class="dropdown-menu show"
v-if="activeDropdowns.includes(list.id_wishlist)"
>
<button @click.stop="toggleRename(list.id_wishlist, list.name)">
{{ renameText }}
</button>
<button
@click.stop="toggleShare(list.id_wishlist, list.shareUrl)"
>
{{ shareText }}
</button>
</div>
<button
@click.stop="toggleDelete(list.id_wishlist, list.name)"
v-if="!list.default"
>
<i class="material-icons">delete</i>
</button>
</div>
</a>
</li>
</ul>
<ContentLoader
v-if="loading"
class="wishlist-list-loader"
height="105"
>
<rect
x="0"
y="12"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="36"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="60"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="84"
rx="3"
ry="0"
width="100%"
height="11"
/>
</ContentLoader>
<p
class="wishlist-list-empty"
v-if="items.length <= 0 && !loading"
>
{{ emptyText }}
</p>
</div>
</template>
<script>
import {ContentLoader} from 'vue-content-loader';
import EventBus from '@components/EventBus';
import wishlistUrl from 'wishlistUrl';
import vClickOutside from 'v-click-outside';
/**
* Dumb component to display the list of Wishlist on a page
*/
export default {
name: 'List',
components: {
ContentLoader,
},
data() {
return {
activeDropdowns: [],
listUrl: wishlistUrl,
};
},
props: {
items: {
type: Array,
default: () => [],
},
renameText: {
type: String,
default: 'Rename',
},
emptyText: {
type: String,
default: '',
},
shareText: {
type: String,
default: 'Share',
},
loading: {
type: Boolean,
default: true,
},
},
methods: {
/**
* Toggle a dropdown with some actions
*
* @param {Int} id The ID of the list which contain this dropdown
*/
togglePopup(id) {
if (this.activeDropdowns.includes(id)) {
this.activeDropdowns = this.activeDropdowns.filter((e) => e !== id);
} else {
this.activeDropdowns = [];
this.activeDropdowns.push(id);
}
},
emptyPopups() {
this.activeDropdowns = [];
},
/**
* Toggle the popup to rename a list
*
* @param {Int} id The list ID so the rename popup know which list to rename
* @param {String} The base title so the rename popup can autofill it
*/
toggleRename(id, title) {
EventBus.$emit('showRenameWishlist', {
detail: {listId: id, title},
});
},
/**
* Toggle the popup to rename a list
*
* @param {Int} id The list ID so the rename popup know which list to rename
* @param {String} The base title so the rename popup can autofill it
*/
toggleShare(id, shareUrl) {
EventBus.$emit('showShareWishlist', {
detail: {listId: id, shareUrl},
});
},
/**
* Toggle the popup to rename a list
*
* @param {Int} id The list ID so the rename popup know which list to rename
* @param {String} The base title so the rename popup can autofill it
*/
toggleDelete(id) {
EventBus.$emit('showDeleteWishlist', {
detail: {listId: id, userId: 1},
});
},
/**
* Redirect to the list URI
*
* @param {String} listUrl The list url
*/
redirectToList(listUrl) {
window.location.href = listUrl;
},
},
directives: {
clickOutside: vClickOutside.directive,
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-list {
margin-bottom: 0;
&-empty {
font-size: 1.875rem;
text-align: center;
padding: 1.875rem;
padding-bottom: 1.25rem;
font-weight: bold;
color: #000;
}
&-loader {
padding: 0 1.25rem;
width: 100%;
}
&-item {
&-default {
border-bottom: 1px solid #0000002e;
}
&:hover {
cursor: pointer;
.wishlist-list-item-title {
color: $blue;
}
}
&-link {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 1.25rem;
}
.dropdown-menu {
right: 1.25rem;
left: inherit;
display: flex;
flex-direction: column;
}
&-right {
position: relative;
white-space: nowrap;
> button {
transition: 0.25s ease-out;
&:hover {
opacity: 0.6;
}
i {
color: #7a7a7a;
}
}
.dropdown-menu {
box-sizing: border-box;
border: 1px solid #e5e5e5;
border-radius: 0.25rem;
background-color: #ffffff;
box-shadow: 0.125rem 0.125rem 0.625rem 0 rgba(0, 0, 0, 0.2);
padding: 0;
overflow: hidden;
> button {
padding: 0.625rem 1.25rem;
transition: 0.2s ease-out;
text-align: left;
&:hover {
background-color: #f1f1f1;
}
}
}
}
&-title {
color: #232323;
font-size: 1rem;
font-weight: bold;
letter-spacing: 0;
line-height: 1.375rem;
margin-bottom: 0;
word-break: break-word;
span {
color: #7a7a7a;
font-size: 1rem;
letter-spacing: 0;
line-height: 1.375rem;
font-weight: normal;
margin-left: 0.3125rem;
}
}
button {
cursor: pointer;
border: none;
background: none;
&:focus {
outline: 0;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,67 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import EventBus from '@components/EventBus';
import prestashop from 'prestashop';
/**
* This component display a modal where you can redirect to login page
*/
export default {
name: 'Login',
props: {
cancelText: {
type: String,
required: true,
default: 'Cancel',
},
loginText: {
type: String,
required: true,
default: 'Login',
},
},
data() {
return {
value: '',
isHidden: true,
listId: null,
prestashop,
};
},
methods: {
/**
* Toggle the modal
*/
toggleModal() {
this.isHidden = !this.isHidden;
},
},
mounted() {
/**
* Register to the event showCreateWishlist so others components can toggle this modal
*
* @param {String} 'showDeleteWishlist'
*/
EventBus.$on('showLogin', () => {
this.toggleModal();
});
},
};
</script>

View File

@@ -0,0 +1,33 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Login from './Login';
const props = [
{
name: 'loginText',
type: String,
},
{
name: 'cancelText',
type: String,
},
];
initApp(Login, '.wishlist-login', props);

View File

@@ -0,0 +1,87 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import EventBus from '@components/EventBus';
/**
* Dumb component to display the list of Wishlist on a page
*/
export default {
name: 'Pagination',
data() {
return {
total: null,
minShown: null,
maxShown: null,
pageNumber: 0,
pages: [],
currentPage: null,
display: false,
};
},
methods: {
paginate(page) {
EventBus.$emit('updatePagination', {
page,
});
this.currentPage = page;
},
},
mounted() {
EventBus.$on('paginate', (payload) => {
this.total = payload.detail.total;
this.minShown = payload.detail.minShown;
this.maxShown = payload.detail.maxShown;
this.pageNumber = payload.detail.pageNumber;
this.currentPage = payload.detail.currentPage;
this.pages = payload.detail.pages;
this.display = payload.detail.display;
});
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-pagination {
.previous {
margin-right: 1.875rem;
}
.js-wishlist-search-link {
cursor: pointer;
&:not([href]):not([tabindex]):hover {
color: $blue;
}
&.disabled {
cursor: inherit;
&:hover {
color: $blue;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,24 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Pagination from './Pagination';
const props = [];
initApp(Pagination, '.wishlist-pagination', props);

View File

@@ -0,0 +1,594 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div class="wishlist-product">
<a
class="wishlist-product-link"
:href="product.canonical_url"
>
<div class="wishlist-product-image">
<img
v-if="product.default_image"
:src="product.default_image.large.url"
:alt="product.default_image.legend"
:title="product.default_image.legend"
:class="{
'wishlist-product-unavailable': !product.add_to_cart_url
}"
>
<img
v-else-if="product.cover"
:src="product.cover.large.url"
:alt="product.cover.legend"
:title="product.cover.legend"
:class="{
'wishlist-product-unavailable': !product.add_to_cart_url
}"
>
<img
v-else
:src="prestashop.urls.no_picture_image.bySize.home_default.url"
>
<p
class="wishlist-product-availability"
v-if="product.show_availability"
>
<i
class="material-icons"
v-if="product.availability === 'unavailable'"
>
block
</i>
<i
class="material-icons"
v-if="product.availability === 'last_remaining_items'"
>
warning
</i>
{{ product.availability_message }}
</p>
</div>
<div class="wishlist-product-right">
<p class="wishlist-product-title">{{ product.name }}</p>
<p class="wishlist-product-price">
<span
class="wishlist-product-price-promo"
v-if="product.has_discount"
>
{{ product.regular_price }}
</span>
{{ product.price }}
</p>
<div class="wishlist-product-combinations">
<p class="wishlist-product-combinations-text">
<template v-for="(attribute, key, index) of product.attributes">
{{ attribute.group }} : {{ attribute.name }}
<span
:key="key"
v-if="index <= Object.keys(product.attributes).length - 1"
>
-
</span>
<span
:key="key + 'end'"
v-if="index == Object.keys(product.attributes).length - 1"
>
{{ quantityText }} : {{ product.wishlist_quantity }}
</span>
</template>
<span v-if="Object.keys(product.attributes).length === 0">
{{ quantityText }} : {{ product.wishlist_quantity }}
</span>
</p>
<a
:href="product.canonical_url"
v-if="!isShare"
>
<i class="material-icons">create</i>
</a>
</div>
</div>
</a>
<div class="wishlist-product-bottom">
<button
class="btn wishlist-product-addtocart"
:class="{
'btn-secondary': product.customizable,
'btn-primary': !product.customizable
}"
:disabled="isDisabled || forceDisable"
@click="
product.add_to_cart_url || product.customizable
? addToCartAction()
: null
"
>
<i
class="material-icons shopping-cart"
v-if="!product.customizable"
>
shopping_cart
</i>
{{ product.customizable ? customizeText : addToCart }}
</button>
<button
class="wishlist-button-add"
v-if="!isShare"
@click="removeFromWishlist"
>
<i class="material-icons">delete</i>
</button>
</div>
<p
class="wishlist-product-availability wishlist-product-availability-responsive"
v-if="product.show_availability"
>
<i
class="material-icons"
v-if="product.availability === 'unavailable'"
>
block
</i>
<i
class="material-icons"
v-if="product.availability === 'last_remaining_items'"
>
warning
</i>
{{ product.availability_message }}
</p>
</div>
</template>
<script>
import EventBus from '@components/EventBus';
import headers from '@constants/headers';
import prestashop from 'prestashop';
import wishlistAddProductToCartUrl from 'wishlistAddProductToCartUrl';
export default {
name: 'Product',
props: {
product: {
type: Object,
required: true,
default: null,
},
listId: {
type: Number,
required: true,
default: null,
},
listName: {
type: String,
required: true,
default: '',
},
isShare: {
type: Boolean,
required: false,
default: false,
},
customizeText: {
type: String,
required: true,
default: 'Customize',
},
quantityText: {
type: String,
required: true,
default: 'Quantity',
},
addToCart: {
type: String,
required: true,
},
status: {
type: Number,
required: false,
default: 0,
},
hasControls: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
prestashop,
forceDisable: false,
};
},
computed: {
isDisabled() {
const wishlistQuantity = parseInt(this.product.wishlist_quantity, 10);
const quantityAvailable = parseInt(this.product.quantity_available, 10);
const cartQuantity = parseInt(this.product.cart_quantity, 10);
if (this.product.allow_oosp) {
return false;
}
if (this.product.customizable) {
return false;
}
if (wishlistQuantity > quantityAvailable) {
return true;
}
if (cartQuantity >= quantityAvailable) {
return true;
}
if (cartQuantity
&& cartQuantity + wishlistQuantity > quantityAvailable
) {
return true;
}
return !this.product.add_to_cart_url;
},
},
methods: {
/**
* Remove the product from the wishlist
*/
async removeFromWishlist() {
EventBus.$emit('showDeleteWishlist', {
detail: {
listId: this.listId,
listName: this.listName,
productId: this.product.id,
productAttributeId: this.product.id_product_attribute,
},
});
},
async addToCartAction() {
if (this.product.add_to_cart_url && !this.product.customizable) {
try {
this.forceDisable = true;
const datas = new FormData();
datas.append('qty', this.product.wishlist_quantity);
datas.append('id_product', this.product.id_product);
datas.append('id_customization', this.product.id_customization);
const response = await fetch(
`${this.product.add_to_cart_url}&action=update`,
{
method: 'POST',
headers: headers.addToCart,
body: datas,
},
);
const resp = await response.json();
EventBus.$emit('refetchList');
prestashop.emit('updateCart', {
reason: {
idProduct: this.product.id_product,
idProductAttribute: this.product.id_product_attribute,
idCustomization: this.product.id_customization,
linkAction: 'add-to-cart',
},
resp,
});
$('body').on('hide.bs.modal', '#blockcart-modal', () => {
this.forceDisable = false;
});
/* eslint-disable */
const statResponse = await fetch(
`${wishlistAddProductToCartUrl}&params[idWishlist]=${this.listId}&params[id_product]=${this.product.id_product}&params[id_product_attribute]=${this.product.id_product_attribute}&params[quantity]=${this.product.wishlist_quantity}`,
{
headers: {
'Content-Type':
'application/x-www-form-urlencoded; charset=UTF-8',
Accept: 'application/json, text/javascript, */*; q=0.01'
}
}
);
/* eslint-enable */
await statResponse.json();
} catch (error) {
prestashop.emit('handleError', {
eventType: 'addProductToCart',
resp: error,
});
}
} else {
window.location.href = this.product.canonical_url;
}
},
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-products-item {
margin: 1.5625rem;
}
&-product {
max-width: 15.625rem;
width: 100%;
position: relative;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
&-unavailable {
opacity: 0.5;
}
&-availability {
display: flex;
align-items: flex-start;
margin-bottom: 0;
color: #232323;
font-size: 0.75rem;
font-weight: bold;
letter-spacing: 0;
line-height: 1.0625rem;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 1.0625rem;
z-index: 5;
min-width: 80%;
justify-content: center;
i {
color: #ff4c4c;
margin-right: 0.3125rem;
font-size: 1.125rem;
}
&-responsive {
display: none;
position: inherit;
transform: inherit;
bottom: inherit;
margin-top: 0.625rem;
left: inherit;
}
}
&-link {
&:focus {
text-decoration: none;
}
&:hover {
img {
transform: translate(-50%, -50%) scale(1.1);
}
}
}
&-title {
margin-top: 0.625rem;
margin-bottom: 0.315rem;
color: #737373;
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1.875rem;
}
&-image {
width: 15.625rem;
height: 15.625rem;
position: relative;
overflow: hidden;
img {
position: absolute;
max-width: 100%;
max-height: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition: 0.25s ease-out;
}
}
&-price {
color: #232323;
font-size: 1rem;
font-weight: bold;
letter-spacing: 0;
line-height: 1.375rem;
&-promo {
text-decoration: line-through;
color: #737373;
font-size: 0.875rem;
font-weight: bold;
letter-spacing: 0;
line-height: 1.1875rem;
margin-right: 0.3125rem;
vertical-align: middle;
display: inline-block;
margin-top: -0.1875rem;
}
}
&-combinations {
display: flex;
align-items: flex-start;
justify-content: space-between;
a {
display: block;
color: #7a7a7a;
&:hover {
color: $blue;
}
}
&-text {
color: #7a7a7a;
font-size: 0.8125rem;
letter-spacing: 0;
line-height: 1.25rem;
min-height: 3.125rem;
margin: 0;
}
}
&-addtocart {
width: 100%;
text-transform: inherit;
}
}
&-button {
&-add {
position: absolute;
top: 0.625rem;
right: 0.625rem;
display: flex;
align-items: center;
justify-content: center;
height: 2.5rem;
width: 2.5rem;
min-width: 2.5rem;
padding-top: 0.1875rem;
background-color: #ffffff;
box-shadow: 0.125rem 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
transition: 0.2s ease-out;
border: none;
&:hover {
opacity: 0.7;
}
&:focus {
outline: 0;
}
&:active {
transform: scale(1.2);
}
i {
color: #7a7a7a;
margin-top: -0.125rem;
}
}
}
}
@media screen and (max-width: 768px) {
.wishlist {
&-button-add {
position: inherit;
margin-left: 0.625rem;
}
&-products-item {
width: 100%;
margin: 0;
margin-bottom: 1.875rem;
&:not(:last-child) {
margin-bottom: 1.875rem;
}
}
&-product {
margin: 0;
width: 100%;
max-width: 100%;
&-link {
&:hover {
img {
transform: inherit;
}
}
}
&-bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
&-right {
flex: 1;
}
&-availability {
display: none;
&-responsive {
display: block;
min-width: 100%;
justify-content: flex-start;
}
}
&-image {
width: 100px;
height: 100px;
margin-right: 1.25rem;
position: inherit;
img {
position: inherit;
left: inherit;
top: inherit;
transform: inherit;
}
}
&-link {
display: flex;
align-items: flex-start;
}
&-title {
margin-top: 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,114 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import renameList from '@graphqlFiles/mutations/renamelist';
import EventBus from '@components/EventBus';
/**
* A modal used to rename a list
*/
export default {
name: 'Rename',
props: {
url: {
type: String,
required: true,
default: '#',
},
title: {
type: String,
required: true,
default: 'Rename wishlist',
},
label: {
type: String,
required: true,
default: 'Wishlist name',
},
placeholder: {
type: String,
required: true,
default: 'Rename text',
},
cancelText: {
type: String,
required: true,
default: 'Cancel',
},
renameText: {
type: String,
required: true,
default: 'Rename',
},
},
data() {
return {
value: '',
isHidden: true,
listId: 0,
};
},
methods: {
/**
* Toggle the modal
*/
toggleModal() {
this.isHidden = !this.isHidden;
},
/**
* Launch a renameList mutation, then dispatch an event to everycomponent to refetch the list after renaming it
*
* @param {Int} listId Id of the list to be renamed
*/
async renameWishlist() {
const {data} = await this.$apollo.mutate({
mutation: renameList,
variables: {
name: this.value,
url: this.url,
listId: this.listId,
},
});
const {renameList: response} = data;
EventBus.$emit('refetchList');
EventBus.$emit('showToast', {
detail: {
type: response.success ? 'success' : 'error',
message: response.message,
},
});
this.toggleModal();
},
},
mounted() {
/**
* Register to the showRenameWishlist event so everycomponents can display this modal
*/
EventBus.$on('showRenameWishlist', (event) => {
this.value = event.detail.title;
this.listId = event.detail.listId;
this.toggleModal();
});
},
};
</script>

View File

@@ -0,0 +1,49 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Rename from './Rename';
const props = [
{
name: 'url',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'label',
type: String,
},
{
name: 'placeholder',
type: String,
},
{
name: 'cancelText',
type: String,
},
{
name: 'renameText',
type: String,
},
];
initApp(Rename, '.wishlist-rename', props);

View File

@@ -0,0 +1,113 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<script>
import EventBus from '@components/EventBus';
/**
* This component display a modal where you can create a wishlist
*/
export default {
name: 'Share',
props: {
url: {
type: String,
required: true,
default: '#',
},
title: {
type: String,
required: true,
default: 'Share wishlist',
},
label: {
type: String,
required: true,
default: 'Share link',
},
cancelText: {
type: String,
required: true,
default: 'Cancel',
},
copyText: {
type: String,
required: true,
default: 'Copy text',
},
copiedText: {
type: String,
required: true,
default: 'Copied',
},
},
data() {
return {
value: '',
isHidden: true,
actionText: '',
};
},
methods: {
/**
* Toggle the modal
*/
toggleModal() {
this.isHidden = !this.isHidden;
},
/**
* Copy the link in the input value
*/
copyLink() {
const shareInput = document.querySelector(
'.wishlist-share .form-control',
);
shareInput.select();
shareInput.setSelectionRange(0, 99999);
document.execCommand('copy');
this.actionText = this.copiedText;
this.toggleModal();
EventBus.$emit('showToast', {
detail: {
type: 'success',
message: 'copyText',
},
});
},
},
mounted() {
this.actionText = this.copyText;
/**
* Register to the event showCreateWishlist so others components can toggle this modal
*
* @param {String} 'showCreateWishlist'
*/
EventBus.$on('showShareWishlist', async (event) => {
this.actionText = this.copyText;
this.value = event.detail.shareUrl;
this.toggleModal();
});
},
};
</script>

View File

@@ -0,0 +1,49 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Share from './Share';
const props = [
{
name: 'url',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'label',
type: String,
},
{
name: 'copyText',
type: String,
},
{
name: 'copiedText',
type: String,
},
{
name: 'cancelText',
type: String,
},
];
initApp(Share, '.wishlist-share', props);

View File

@@ -0,0 +1,151 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div
class="wishlist-toast"
:class="[{ isActive: active }, type]"
>
<p class="wishlist-toast-text">
{{ text }}
</p>
</div>
</template>
<script>
import EventBus from '@components/EventBus';
export default {
name: 'Button',
props: {
renameWishlistText: {
type: String,
required: true,
},
addedWishlistText: {
type: String,
required: true,
},
deleteWishlistText: {
type: String,
required: true,
},
createWishlistText: {
type: String,
required: true,
},
deleteProductText: {
type: String,
required: true,
},
copyText: {
type: String,
required: true,
},
},
data() {
return {
text: '',
active: false,
timeout: null,
type: 'basic',
};
},
mounted() {
/**
* Register to an even so every components can show toast
*/
EventBus.$on('showToast', (event) => {
if (event.detail.message) {
if (this[event.detail.message]) {
this.text = this[event.detail.message];
} else {
this.text = event.detail.message;
}
}
this.active = true;
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => {
this.active = false;
this.timeout = null;
}, 2500);
this.type = event.detail.type ? event.detail.type : 'basic';
});
},
};
</script>
<style lang="scss" type="text/scss">
.wishlist {
&-toast {
padding: 0.875rem 1.25rem;
box-sizing: border-box;
width: auto;
border: 1px solid #e5e5e5;
border-radius: 4px;
background-color: #ffffff;
box-shadow: 0.125rem 0.125rem 0.625rem 0 rgba(0, 0, 0, 0.2);
position: fixed;
right: 1.25rem;
z-index: 9999;
top: 4.375rem;
transition: 0.2s ease-out;
transform: translateY(-10px);
pointer-events: none;
opacity: 0;
&.success {
background-color: #69b92d;
border-color: #69b92d;
.wishlist-toast-text {
color: white;
}
}
&.error {
background-color: #b9312d;
border-color: #b9312d;
.wishlist-toast-text {
color: white;
}
}
&.isActive {
transform: translateY(0);
pointer-events: all;
opacity: 1;
}
&-text {
color: #232323;
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1.1875rem;
margin-bottom: 0;
}
}
}
</style>

View File

@@ -0,0 +1,53 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import Toast from './Toast';
const props = [
{
name: 'renameWishlistText',
type: String,
},
{
name: 'createWishlistText',
type: String,
},
{
name: 'addedWishlistText',
type: String,
},
{
name: 'shareText',
type: String,
},
{
name: 'deleteWishlistText',
type: String,
},
{
name: 'deleteProductText',
type: String,
},
{
name: 'copyText',
type: String,
},
];
initApp(Toast, '.wishlist-toast', props);

View File

@@ -0,0 +1,64 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import apolloClient from '@graphqlFiles/client';
/**
* Init a VueJS application to keep monolith features such as hooks or event the use of twig/smarty
*
* @param {Vue} component The component to be init
* @param {String} componentSelector A selector for querySelectorAll
* @param {Array[Object]} props An array containing Object{name, type} to parse int
*/
export default function initApp(component, componentSelector, props) {
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
const componentElements = document.querySelectorAll(componentSelector);
const ComponentRoot = Vue.extend(component);
const propsData = {};
componentElements.forEach((e) => {
/* eslint-disable */
for (const prop of props) {
if (e.dataset[prop.name]) {
if (prop.type === Number) {
propsData[prop.name] = parseInt(e.dataset[prop.name], 10);
} else if (prop.type === Boolean) {
propsData[prop.name] = e.dataset[prop.name] === 'true';
} else {
propsData[prop.name] = e.dataset[prop.name];
}
}
}
/* eslint-enable */
new ComponentRoot({
el: e,
delimiters: ['((', '))'],
apolloProvider,
propsData,
});
});
}

View File

@@ -0,0 +1,29 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
const headers = {
addToCart: {
Accept: 'application/json, text/javascript',
},
products: {
'Content-Type': 'application/json',
Accept: 'application/json, text/javascript, */*; q=0.01',
},
};
export default headers;

View File

@@ -0,0 +1,367 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div class="wishlist-products-container">
<div class="wishlist-products-container-header">
<h1>
{{ title }}
<span
class="wishlist-products-count"
v-if="products.datas && products.datas.products"
>
({{ products.datas.pagination.total_items }})
</span>
</h1>
<div
class="sort-by-row"
v-if="products.datas"
>
<span class="hidden-sm-down col-sm-3 col-md-3 sort-by">{{ filter }}</span>
<div class="col-xs-12 col-sm-9 col-md-9 products-sort-order dropdown">
<button
class="btn-unstyle select-title"
rel="nofollow"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
{{ currentSort }}
<i class="material-icons float-xs-right">arrow_drop_down</i>
</button>
<div class="dropdown-menu">
<a
rel="nofollow"
@click="changeSelectedSort(sort)"
class="select-list"
:key="key"
v-for="(sort, key) in productList"
>
{{ sort.label }}
</a>
</div>
</div>
</div>
</div>
<section
id="content"
class="page-content card card-block"
>
<ul
class="wishlist-products-list"
v-if="products.datas && products.datas.products.length > 0"
>
<li
class="wishlist-products-item"
v-for="(product, key) in products.datas.products"
:key="key"
>
<Product
:product="product"
:add-to-cart="addToCart"
:customize-text="customizeText"
:quantity-text="quantityText"
:list-name="title"
:list-id="
listId ? listId : parseInt(currentWishlist.id_wishlist, 10)
"
:is-share="share"
/>
</li>
</ul>
<ContentLoader
v-if="!products.datas"
class="wishlist-list-loader"
height="105"
>
<rect
x="0"
y="12"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="36"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="60"
rx="3"
ry="0"
width="100%"
height="11"
/>
<rect
x="0"
y="84"
rx="3"
ry="0"
width="100%"
height="11"
/>
</ContentLoader>
<p
class="wishlist-list-empty"
v-if="products.datas && products.datas.products.length <= 0"
>
{{ noProductsMessage }}
</p>
</section>
</div>
</template>
<script>
import Product from '@components/Product/Product';
import getProducts from '@graphqlFiles/queries/getproducts';
import {ContentLoader} from 'vue-content-loader';
import EventBus from '@components/EventBus';
/**
* This component act as a smart component wich will handle every actions of the list one
*/
export default {
name: 'ProductsListContainer',
components: {
Product,
ContentLoader,
},
apollo: {
products: {
query: getProducts,
variables() {
return {
listId: this.listId,
url: this.apiUrl,
};
},
skip() {
return true;
},
fetchPolicy: 'network-only',
},
},
props: {
url: {
type: String,
required: false,
default: '#',
},
title: {
type: String,
required: true,
},
filter: {
type: String,
required: true,
},
noProductsMessage: {
type: String,
required: true,
},
listId: {
type: Number,
required: false,
default: 0,
},
addToCart: {
type: String,
required: true,
},
share: {
type: Boolean,
required: true,
},
customizeText: {
type: String,
required: true,
},
quantityText: {
type: String,
required: true,
},
},
data() {
return {
products: [],
currentWishlist: {},
apiUrl: window.location.href,
selectedSort: '',
};
},
methods: {
/**
* Sort by the select drop down
* @param {String} value The value selected
*/
async changeSelectedSort(value) {
this.selectedSort = value.label;
this.apiUrl = value.url;
},
},
computed: {
productList() {
const productList = this.products.datas.sort_orders.filter(
(sort) => sort.label !== this.products.datas.sort_selected,
);
return productList;
},
currentSort() {
return this.selectedSort !== ''
? this.selectedSort
: this.products.datas.sort_selected;
},
},
mounted() {
if (this.listId) {
this.$apollo.queries.products.skip = false;
}
/**
* Register to the event refetchProducts so if an other component update it, this one can update his list
*
* @param {String} 'refetchProduct' The event I decided to create to communicate between VueJS Apps
*/
EventBus.$on('refetchList', () => {
this.$apollo.queries.products.refetch();
});
EventBus.$on('updatePagination', (payload) => {
this.products = false;
this.apiUrl = payload.page.url;
});
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-list-loader {
padding: 0 1.25rem;
width: 100%;
}
&-list-empty {
font-size: 30;
text-align: center;
padding: 1.875rem;
padding-bottom: 1.25rem;
font-weight: bold;
color: #000;
}
&-products-container {
.sort-by-row {
min-width: 19.6875rem;
display: flex;
align-items: center;
a {
cursor: pointer;
}
.sort-by {
padding: 0;
}
.products-sort-order {
padding: 0;
}
}
&-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1.25rem;
}
@at-root #main & .card.page-content {
padding: 0;
margin-bottom: 0.75rem;
}
}
&-products {
&-list {
display: flex;
flex-wrap: wrap;
margin: -1.5625rem;
padding: 1.25rem 2.8125rem;
margin-top: 0;
}
&-count {
color: #7a7a7a;
font-size: 1.375rem;
font-weight: normal;
line-height: 1.875rem;
}
}
}
@media screen and (max-width: 768px) {
.wishlist {
&-products-container {
&-header {
flex-wrap: wrap;
.products-sort-order {
flex: 1;
}
.filter-button {
width: auto;
padding-right: 0;
}
.sort-by-row {
width: 100%;
min-width: 16.00rem;
}
}
.page-content.card {
box-shadow: 0.125rem 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.2);
background-color: #fff;
margin-top: 1.25rem;
}
.wishlist-products-list {
justify-content: center;
margin: 0;
padding: 0.9375rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,69 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import ProductsListContainer from './ProductsListContainer.vue';
const props = [
{
name: 'url',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'noProductsMessage',
type: String,
},
{
name: 'addToCart',
type: String,
},
{
name: 'customizeText',
type: String,
},
{
name: 'wishlistProducts',
type: String,
},
{
name: 'wishlist',
type: String,
},
{
name: 'share',
type: Boolean,
},
{
name: 'quantityText',
type: String,
},
{
name: 'filter',
type: String,
},
{
name: 'listId',
type: Number,
},
];
initApp(ProductsListContainer, '.wishlist-products-container', props);

View File

@@ -0,0 +1,172 @@
<!--**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*-->
<template>
<div class="wishlist-container">
<div class="wishlist-container-header">
<h1>{{ title }}</h1>
<a
@click="openNewWishlistModal"
class="wishlist-add-to-new text-primary"
>
<i class="material-icons">add_circle_outline</i>
{{ addText }}
</a>
</div>
<section
id="content"
class="page-content card card-block"
>
<list
:items="lists"
:rename-text="renameText"
:share-text="shareText"
:empty-text="emptyText"
:loading="$apollo.queries.lists.loading"
/>
</section>
</div>
</template>
<script>
import List from '@components/List/List';
import getLists from '@graphqlFiles/queries/getlists';
import EventBus from '@components/EventBus';
/**
* This component act as a smart component wich will handle every actions of the list one
*/
export default {
name: 'WishlistContainer',
components: {
List,
},
apollo: {
lists: {
query: getLists,
variables() {
return {
url: this.url,
};
},
},
},
props: {
url: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
addText: {
type: String,
required: true,
},
renameText: {
type: String,
required: true,
},
emptyText: {
type: String,
required: true,
},
shareText: {
type: String,
required: true,
},
},
data() {
return {
lists: [],
};
},
methods: {
/**
* Send an event to opoen the Create Wishlist Modal
*/
openNewWishlistModal() {
EventBus.$emit('showCreateWishlist');
},
},
mounted() {
/**
* Register to the event refetchList so if an other component update it, this one can update his list
*
* @param {String} 'refetchList' The event I decided to create to communicate between VueJS Apps
*/
EventBus.$on('refetchList', () => {
this.$apollo.queries.lists.refetch();
});
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-container {
&-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1.25rem;
}
@at-root #main & .card.page-content {
padding: 0;
margin-bottom: 0.75rem;
}
}
&-add-to-new {
cursor: pointer;
transition: 0.2s ease-out;
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1rem;
&:hover {
opacity: 0.7;
}
i {
margin-right: 0.3125rem;
vertical-align: middle;
margin-top: -0.125rem;
font-size: 1.25rem;
}
}
}
@media screen and (max-width: 768px) {
.wishlist {
&-container {
.page-content.card {
box-shadow: 0.125rem 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.2);
background-color: #fff;
margin-top: 1.25rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,53 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initApp from '@components/init';
import WishlistContainer from './WishlistContainer';
const props = [
{
name: 'url',
type: String,
},
{
name: 'title',
type: String,
},
{
name: 'addText',
type: String,
},
{
name: 'renameText',
type: String,
},
{
name: 'emptyText',
type: String,
},
{
name: 'homeLink',
type: String,
},
{
name: 'shareText',
type: String,
},
];
initApp(WishlistContainer, '.wishlist-container', props);

View File

@@ -0,0 +1,36 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import {ApolloClient} from 'apollo-client';
import {SchemaLink} from 'apollo-link-schema';
import {InMemoryCache} from 'apollo-cache-inmemory';
import link from './link';
/**
* Enabling client side cache
*/
const cache = new InMemoryCache();
/**
* Creating the ApolloClient managing cache and schemas
*/
export default new ApolloClient({
link: new SchemaLink({schema: link}),
cache,
});

View File

@@ -0,0 +1,31 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import {makeExecutableSchema} from 'graphql-tools';
import resolvers from './resolvers';
import typeDefs from './types';
/**
* Generate SchemaLink that ApolloClient needs to understand schemas
* and link resolvers to schemas
*/
export default makeExecutableSchema({
typeDefs,
resolvers,
});

View File

@@ -0,0 +1,35 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation addToList($listId: Int!, $productId: Int!, $quantity: Int!, $productAttributeId: Int!, $url: String!) {
addToList(
listId: $listId
productId: $productId
quantity: $quantity
productAttributeId: $productAttributeId
url: $url
) {
success
message
}
}
`;

View File

@@ -0,0 +1,33 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation createList($name: String!, $url: String!) {
createList(name: $name, url: $url) {
message
datas {
name
id_wishlist
}
success
}
}
`;

View File

@@ -0,0 +1,29 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation deleteList($listId: Int!, $url: String!) {
deleteList(listId: $listId, url: $url) {
success
message
}
}
`;

View File

@@ -0,0 +1,29 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation removeFromList($listId: Int!, $productId: Int!, $productAttributeId: Int!, $url: String!) {
removeFromList(listId: $listId, productId: $productId, productAttributeId: $productAttributeId, url: $url) {
success
message
}
}
`;

View File

@@ -0,0 +1,29 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation renameList($name: String!, $url: String!, $listId: Int!) {
renameList(name: $name, url: $url, listId: $listId) {
message
success
}
}
`;

View File

@@ -0,0 +1,28 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
mutation shareList($listId: Int!, $userId: Int!) {
shareList(listId: $listId, userId: $userId) {
url
}
}
`;

View File

@@ -0,0 +1,33 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
query lists($url: String!) {
lists(url: $url) {
id_wishlist
name
listUrl
shareUrl
nbProducts
default
}
}
`;

View File

@@ -0,0 +1,28 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import gql from 'graphql-tag';
export default gql`
query getProducts($listId: Int!, $url: String!) {
products(listId: $listId, url: $url) {
datas
}
}
`;

View File

@@ -0,0 +1,197 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import EventBus from '@components/EventBus';
import headers from '@constants/headers';
import GraphQLJSON, {GraphQLJSONObject} from 'graphql-type-json';
/**
* Resolvers linked to schemas definitions
*/
export default {
JSON: GraphQLJSON,
JSONObject: GraphQLJSONObject,
Query: {
/**
* Get product from a list
*/
products: async (root, {url}) => {
const response = await fetch(`${url}&from-xhr`, {
headers: headers.products,
});
const datas = await response.json();
EventBus.$emit('paginate', {
detail: {
total: datas.pagination.total_items,
minShown: datas.pagination.items_shown_from,
maxShown: datas.pagination.items_shown_to,
pageNumber: datas.pagination.pages_count,
pages: datas.pagination.pages,
display: datas.pagination.should_be_displayed,
currentPage: datas.pagination.current_page,
},
});
window.history.pushState(datas, document.title, datas.current_url);
window.scrollTo(0, 0);
return {
datas: {
products: datas.products,
pagination: datas.pagination,
current_url: datas.current_url,
sort_orders: datas.sort_orders,
sort_selected: datas.sort_selected,
},
};
},
/**
* Get every lists from User
*/
lists: async (root, {url}) => {
const response = await fetch(url);
const datas = await response.json();
return datas.wishlists;
},
},
Mutation: {
/**
* Create a list based on a name and an userId
*
* @param {String} name The name of the list
* @param {Int} userId The ID of the user you want to create a list on
*/
createList: async (root, {name, url}) => {
const nameEncoded = encodeURIComponent(name);
const response = await fetch(`${url}&params[name]=${nameEncoded}`, {
method: 'POST',
});
const datas = await response.json();
return datas;
},
/**
* Rename a list
*
* @param {String} {name New name of the list
* @param {Int} userId Id of the user
* @param {Int} listId} ID of the list to be renamed
*/
renameList: async (root, {name, listId, url}) => {
const response = await fetch(`${url}&params[name]=${name}&params[idWishList]=${listId}`, {
method: 'POST',
});
const datas = await response.json();
return datas;
},
/**
* Add a product to a list
*
* @param {Int} listId The list id
* @param {Int} userId The user id
* @param {Int} productId The product id to be added to the list id
*
* @returns {JSON} A success or failed response
*/
addToList: async (root, {
listId, url, productId, quantity, productAttributeId,
}) => {
/* eslint-disable */
const response = await fetch(
`${url}&params[id_product]=${productId}&params[idWishList]=${listId}&params[quantity]=${quantity}&params[id_product_attribute]=${productAttributeId}`,
{
method: 'POST'
}
);
/* eslint-enable */
const datas = await response.json();
if (datas.success) {
// eslint-disable-next-line
productsAlreadyTagged.push({
id_product: productId.toString(),
id_wishlist: listId.toString(),
quantity: quantity.toString(),
id_product_attribute: productAttributeId.toString(),
});
}
return datas;
},
/**
* Remove a product from a list
*
* @param {Int} listId The list id
* @param {Int} userId The user id
* @param {Int} productId The product id to be removed from the list id
*
* @returns {JSON} A success or failed response
*/
removeFromList: async (root, {
listId, productId, url, productAttributeId,
}) => {
/* eslint-disable */
const response = await fetch(
`${url}&params[id_product]=${productId}&params[idWishList]=${listId}&params[id_product_attribute]=${productAttributeId}`,
{
method: 'POST'
}
);
/* eslint-enable */
const datas = await response.json();
if (datas.success) {
// eslint-disable-next-line
productsAlreadyTagged = productsAlreadyTagged.filter(
(e) => e.id_product !== productId.toString()
|| (e.id_product_attribute !== productAttributeId.toString() && e.id_product === productId.toString())
|| e.id_wishlist !== listId.toString(),
);
}
return datas;
},
/**
* Remove a list
*
* @param {Int} {listId} The list id
*
* @returns {JSON} a JSON success or failed response
*/
deleteList: async (root, {listId, url}) => {
const response = await fetch(`${url}&params[idWishList]=${listId}`, {
method: 'POST',
});
const datas = await response.json();
return datas;
},
},
};

View File

@@ -0,0 +1,64 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
export default `
scalar JSON
scalar JSONObject
type List {
id_wishlist: Int
name: String
listUrl: String
shareUrl: String
default: Int
nbProducts: Int
}
type ShareUrl {
url: String
}
type CreateResponse {
datas: List
success: Boolean!
message: String!
}
type ProductListResponse {
datas: JSONObject
}
type Response {
success: Boolean!
message: String!
}
type Query {
products(listId: Int!, url: String!): ProductListResponse
lists(url: String!): [List]
}
type Mutation {
createList(name: String!, url: String!): CreateResponse
shareList(listId: String!, userId: Int!): ShareUrl
renameList(name: String!, url: String!, listId: Int!): Response
addToList(listId: Int!, productId: Int!, quantity: Int!, productAttributeId: Int!, url: String!): Response
removeFromList(listId: Int!, productId: Int!, productAttributeId: Int!, url: String!): Response
deleteList(listId: Int!, url: String!): Response
}
`;

View File

@@ -0,0 +1,54 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
import initVueButtons from '@components/Button';
import removeFromWishlistUrl from 'removeFromWishlistUrl';
const initButtons = () => {
const products = document.querySelectorAll('.js-product-miniature');
products.forEach((product) => {
const wishlistButton = document.createElement('div');
wishlistButton.classList.add('wishlist-button');
wishlistButton.dataset.productId = product.dataset.idProduct;
wishlistButton.dataset.url = removeFromWishlistUrl;
wishlistButton.dataset.productAttributeId = product.dataset.idProductAttribute;
wishlistButton.dataset.checked = false;
product.querySelector('.thumbnail-container').append(wishlistButton);
});
};
initButtons();
initVueButtons();
const productList = document.querySelectorAll('#products, .featured-products');
const config = {attributes: false, childList: true};
productList.forEach((e) => {
const callback = function () {
initButtons();
initVueButtons();
};
const observer = new MutationObserver(callback);
observer.observe(e, config);
});

View File

@@ -0,0 +1,41 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist {
&-footer {
&-links {
margin-bottom: 3.125rem;
> a {
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1.1875rem;
&:not(:first-child) {
margin-left: 1.25rem;
}
i {
font-size: 1.25rem;
margin-right: 0.25rem;
vertical-align: middle;
}
}
}
}
}

View File

@@ -0,0 +1,128 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist-modal {
display: none;
opacity: 0;
pointer-events: none;
z-index: 0;
&.show {
display: block;
opacity: 1;
pointer-events: all;
z-index: 1051;
+ .modal-backdrop {
pointer-events: all;
}
}
&.fade .modal-dialog {
max-width: 34.375rem;
transform: translateY(0);
}
.close {
font-weight: 400;
color: #7a7a7a;
opacity: 1;
font-size: 2.25rem;
&:hover {
opacity: 0.6;
}
}
.modal {
&-header {
display: flex;
align-items: center;
justify-content: space-between;
border: none;
h5 {
color: #232323;
font-size: 1.375rem;
font-weight: bold;
letter-spacing: 0;
line-height: 1.875rem;
}
&::after {
content: none;
}
}
&-text {
color: #232323;
font-size: 0.875rem;
letter-spacing: 0;
line-height: 1.875rem;
}
&-body {
padding: 0.9375 1.875rem;
.form-group {
margin-bottom: 0;
.form-control {
border-radius: 0;
background: none;
color: black;
}
}
}
&-content {
width: 100%;
}
&-cancel {
&:hover {
opacity: 0.7;
}
}
&-footer {
border: none;
.btn {
text-transform: none;
margin-bottom: 0.5rem;
}
}
&-backdrop {
pointer-events: none;
&.in {
pointer-events: all;
}
}
}
+ .modal-backdrop {
pointer-events: none;
&.in {
pointer-events: all;
}
}
}

View File

@@ -0,0 +1,30 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.products {
article {
.wishlist {
&-button-add {
position: absolute;
top: 0.635rem;
right: 0.635rem;
z-index: 10;
}
}
}
}

View File

@@ -0,0 +1,66 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.lang-rtl {
.products {
article {
.wishlist {
&-button-add {
right: inherit;
left: 0.635rem;
}
}
}
}
.wishlist {
&-button {
&-product {
margin-left: 0;
margin-right: 1.25rem;
}
}
&-list {
&-item {
.dropdown-menu {
right: inherit;
left: 1.25rem;
}
&-right {
.dropdown-menu {
> button {
text-align: right;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
$blue: #2fb5d2;

View File

@@ -0,0 +1,23 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
@import '_variables';
@import '_modal';
@import '_product';
@import '_footer-links';
@import '_rtl';

View File

@@ -0,0 +1,324 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use PrestaShop\Module\BlockWishList\Database\Install;
use PrestaShop\Module\BlockWishList\Database\Uninstall;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
if (!defined('_PS_VERSION_')) {
exit;
}
$autoloadPath = __DIR__ . '/vendor/autoload.php';
if (file_exists($autoloadPath)) {
require_once $autoloadPath;
}
class BlockWishList extends Module
{
const HOOKS = [
'actionAdminControllerSetMedia',
'actionFrontControllerSetMedia',
'actionAttributeDelete',
'actionProductDelete',
'actionProductAttributeDelete',
'deleteProductAttribute',
'displayProductActions',
'displayCustomerAccount',
'displayFooter',
'displayAdminCustomers',
'displayMyAccountBlock',
];
const MODULE_ADMIN_CONTROLLERS = [
[
'class_name' => 'WishlistConfigurationAdminParentController',
'visible' => false,
'parent_class_name' => 'AdminParentModulesSf',
'name' => 'Wishlist Module',
],
[
'class_name' => 'WishlistConfigurationAdminController',
'visible' => true,
'parent_class_name' => 'WishlistConfigurationAdminParentController',
'name' => 'Configuration',
],
[
'class_name' => 'WishlistStatisticsAdminController',
'visible' => true,
'parent_class_name' => 'WishlistConfigurationAdminParentController',
'name' => 'Statistics',
],
];
public function __construct()
{
$this->name = 'blockwishlist';
$this->tab = 'front_office_features';
$this->version = '3.0.2';
$this->author = 'PrestaShop';
$this->need_instance = 0;
parent::__construct();
$this->displayName = $this->trans('Wishlist', [], 'Modules.Blockwishlist.Admin');
$this->description = $this->trans('Allow customers to create wishlists to save their favorite products for later.', [], 'Modules.Blockwishlist.Admin');
$this->ps_versions_compliancy = [
'min' => '8.0.0',
'max' => _PS_VERSION_,
];
}
/**
* @return bool
*/
public function install()
{
if (false === (new Install($this->getTranslator()))->run()) {
return false;
}
return parent::install()
&& $this->registerHook(static::HOOKS);
}
/**
* @return bool
*/
public function uninstall()
{
return (new Uninstall())->run()
&& parent::uninstall();
}
public function getContent()
{
Tools::redirectAdmin(
SymfonyContainer::getInstance()->get('router')->generate('blockwishlist_configuration')
);
}
/**
* Add asset for Administration
*
* @param array $params
*/
public function hookActionAdminControllerSetMedia(array $params)
{
$this->context->controller->addCss($this->getPathUri() . 'public/backoffice.css');
$this->context->controller->addJs($this->getPathUri() . 'public/vendors.js');
}
/**
* Add asset for Shop Front Office
*
* @see https://devdocs.prestashop.com/1.7/themes/getting-started/asset-management/#without-a-front-controller-module
*
* @param array $params
*/
public function hookActionFrontControllerSetMedia(array $params)
{
$productsTagged = true === $this->context->customer->isLogged()
? WishList::getAllProductByCustomer($this->context->customer->id, $this->context->shop->id)
: false;
Media::addJsDef([
'blockwishlistController' => $this->context->link->getModuleLink(
$this->name,
'action'
),
'removeFromWishlistUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'deleteProductFromWishlist']),
'wishlistUrl' => $this->context->link->getModuleLink('blockwishlist', 'view'),
'wishlistAddProductToCartUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'addProductToCart']),
'productsAlreadyTagged' => $productsTagged ?: [],
]);
$this->context->controller->registerStylesheet(
'blockwishlistController',
'modules/' . $this->name . '/public/wishlist.css',
[
'media' => 'all',
'priority' => 100,
]
);
$this->context->controller->registerJavascript(
'blockwishlistController',
'modules/' . $this->name . '/public/product.bundle.js',
[
'priority' => 100,
]
);
$this->context->controller->registerJavascript(
'blockwishlistGraphql',
'modules/' . $this->name . '/public/graphql.js',
[
'priority' => 190,
]
);
$this->context->controller->registerJavascript(
'blockwishlistVendors',
'modules/' . $this->name . '/public/vendors.js',
[
'priority' => 190,
]
);
}
/**
* This hook allow additional action button, near the add to cart button on the product page
*
* @param array $params
*
* @return string
*/
public function hookDisplayProductActions(array $params)
{
$this->smarty->assign([
'blockwishlist' => $this->displayName,
'url' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'deleteProductFromWishlist']),
]);
return $this->fetch('module:blockwishlist/views/templates/hook/product/add-button.tpl');
}
public function hookActionProductDelete(array $params)
{
if (!isset($params['id_product'])) {
return;
}
WishList::removeProductFromWishlist($params['id_product']);
Statistics::removeProductFromStatistics($params['id_product']);
}
public function hookActionProductAttributeDelete(array $params)
{
if (!isset($params['id_product']) || !isset($params['id_product_attribute'])) {
return;
}
// Remove all attributes from a product
if (!empty($params['deleteAllAttributes'])) {
$this->hookActionProductDelete($params);
return;
}
WishList::removeProductFromWishlist($params['id_product'], $params['id_product_attribute']);
Statistics::removeProductFromStatistics($params['id_product'], $params['id_product_attribute']);
}
public function hookActionAttributeDelete(array $params)
{
if (!isset($params['id_attribute'])) {
return;
}
/*
* Because we don't know which product attributes were related to deleted attribute
* since they are already gone from database, we just remove any leftovers.
*/
WishList::removeNonExistingProductAttributesFromWishlist();
Statistics::removeNonExistingProductAttributesFromStatistics();
}
public function hookDeleteProductAttribute(array $params)
{
$this->hookActionProductAttributeDelete($params);
}
/**
* This hook displays new elements on the customer account page
*
* @param array $params
*
* @return string
*/
public function hookDisplayCustomerAccount(array $params)
{
$this->smarty->assign([
'url' => $this->context->link->getModuleLink('blockwishlist', 'lists'),
'wishlistsTitlePage' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
]);
return $this->fetch('module:blockwishlist/views/templates/hook/displayCustomerAccount.tpl');
}
/**
* This hook displays a new block on the admin customer page
*
* @param array $params
*
* @return string
*/
public function hookDisplayAdminCustomers(array $params)
{
$this->smarty->assign([
'blockwishlist' => $this->displayName,
]);
return $this->fetch('module:blockwishlist/views/templates/hook/displayAdminCustomers.tpl');
}
/**
* Display additional information inside the "my account" block
*
* @param array $params
*
* @return string
*/
public function hookDisplayMyAccountBlock(array $params)
{
$this->smarty->assign([
'blockwishlist' => $this->displayName,
'url' => $this->context->link->getModuleLink('blockwishlist', 'lists'),
'wishlistsTitlePage' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
]);
return $this->fetch('module:blockwishlist/views/templates/hook/account/myaccount-block.tpl');
}
/**
* This hook adds additional elements in the footer section of your pages
*
* @param array $params
*
* @return string
*/
public function hookDisplayFooter(array $params)
{
$this->smarty->assign([
'context' => $this->context->controller->php_self,
'url' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'getAllWishlist']),
'deleteListUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'deleteWishlist']),
'createUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'createNewWishlist']),
'deleteProductUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'deleteProductFromWishlist']),
'addUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'addProductToWishlist']),
'newWishlistCTA' => Configuration::get('blockwishlist_CreateButtonLabel', $this->context->language->id),
'wishlistsTitlePage' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
]);
return $this->fetch('module:blockwishlist/views/templates/hook/displayHeader.tpl');
}
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
class Statistics extends ObjectModel
{
/** @var int ID */
public $id_statistics;
/** @var int id_product */
public $id_product;
/** @var int id_product_attribute */
public $id_product_attribute;
/** @var string date_add */
public $date_add;
/** @var int|null date_add */
public $id_cart;
/** @var int ID */
public $id_shop;
/**
* @see ObjectModel::$definition
*/
public static $definition = [
'table' => 'blockwishlist_statistics',
'primary' => 'id_statistics',
'fields' => [
'id_cart' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => false],
'id_product' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
'id_product_attribute' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
'date_add' => ['type' => self::TYPE_DATE, 'required' => true],
'id_shop' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
],
];
/**
* @param int|null $id_product
* @param int|null $id_product_attribute
*
* @return bool
*/
public static function removeProductFromStatistics($id_product = null, $id_product_attribute = null)
{
if ($id_product === null && $id_product_attribute === null) {
return false;
}
return Db::getInstance()->delete(
'blockwishlist_statistics',
($id_product ? 'id_product = ' . (int) $id_product : '')
. ($id_product && $id_product_attribute ? ' AND ' : '')
. ($id_product_attribute ? ' id_product_attribute = ' . (int) $id_product_attribute : '')
);
}
/**
* @return void
*/
public static function removeNonExistingProductAttributesFromStatistics()
{
$dbQuery = new DbQuery();
$dbQuery->select('bws.id_product_attribute');
$dbQuery->from('blockwishlist_statistics', 'bws');
$dbQuery->leftJoin('product_attribute', 'pa', 'bws.id_product_attribute = pa.id_product_attribute');
$dbQuery->where('pa.id_product_attribute IS NULL');
$productAttributes = Db::getInstance()->executeS($dbQuery);
foreach ($productAttributes as $productAttribute) {
self::removeProductFromStatistics(null, (int) $productAttribute['id_product_attribute']);
}
}
}

View File

@@ -0,0 +1,660 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
class WishList extends ObjectModel
{
/** @var int Wishlist ID */
public $id;
/** @var int Customer ID */
public $id_customer;
/** @var int Token */
public $token;
/** @var string Name */
public $name;
/** @var string Object creation date */
public $date_add;
/** @var string Object last modification date */
public $date_upd;
/** @var int Object last modification date */
public $id_shop;
/** @var int Object last modification date */
public $id_shop_group;
/** @var int default */
public $default;
/**
* @see ObjectModel::$definition
*/
public static $definition = [
'table' => 'wishlist',
'primary' => 'id_wishlist',
'fields' => [
'id_customer' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
'token' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true],
'name' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true],
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
'id_shop' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'],
'id_shop_group' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'],
'default' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'],
],
];
/**
* Get Customers having a wishlist
*
* @return array Results
*/
public static function getCustomers()
{
$cache_id = 'WishList::getCustomers';
if (false === Cache::isStored($cache_id)) {
$result = Db::getInstance((bool) _PS_USE_SQL_SLAVE_)->executeS('
SELECT c.`id_customer`, c.`firstname`, c.`lastname`
FROM `' . _DB_PREFIX_ . 'wishlist` w
INNER JOIN `' . _DB_PREFIX_ . 'customer` c ON c.`id_customer` = w.`id_customer`
ORDER BY c.`firstname` ASC'
);
Cache::store($cache_id, $result);
}
return Cache::retrieve($cache_id);
}
/**
* Return true if wishlist exists else false
*
* @param int $id_wishlist
* @param int $id_customer
*
* @return bool exists
*/
public static function exists($id_wishlist, $id_customer)
{
$result = Db::getInstance()->getRow('
SELECT 1
FROM `' . _DB_PREFIX_ . 'wishlist`
WHERE `id_wishlist` = ' . (int) $id_wishlist . '
AND `id_customer` = ' . (int) $id_customer . '
AND `id_shop` = ' . (int) Context::getContext()->shop->id
);
return (bool) $result;
}
/**
* Set current WishList as default
*
* @return bool
*/
public function setDefault()
{
if ($default = $this->getDefault($this->id_customer)) {
Db::getInstance()->update('wishlist', ['default' => '0'], 'id_wishlist = ' . (int) $default);
}
return Db::getInstance()->update('wishlist', ['default' => '1'], 'id_wishlist = ' . (int) $this->id);
}
/**
* Return if there is a default already set
*
* @param int $id_customer
*
* @return bool
*/
public static function isDefault($id_customer)
{
return (bool) Db::getInstance()->getValue('SELECT 1 FROM `' . _DB_PREFIX_ . 'wishlist` WHERE `id_customer` = ' . (int) $id_customer . ' AND `default` = 1');
}
/**
* @param int $id_customer
*
* @return int
*/
public static function getDefault($id_customer)
{
return (int) Db::getInstance()->getValue('SELECT `id_wishlist` FROM `' . _DB_PREFIX_ . 'wishlist` WHERE `id_customer` = ' . (int) $id_customer . ' AND `default` = 1');
}
/**
* Add product to ID wishlist
*
* @param int $id_wishlist
* @param int $id_customer
* @param int $id_product
* @param int $id_product_attribute
* @param int $quantity
*
* @return bool succeed
*/
public static function addProduct($id_wishlist, $id_customer, $id_product, $id_product_attribute, $quantity)
{
$result = Db::getInstance()->getRow('
SELECT wp.`quantity`
FROM `' . _DB_PREFIX_ . 'wishlist_product` wp
JOIN `' . _DB_PREFIX_ . 'wishlist` w ON (w.`id_wishlist` = wp.`id_wishlist`)
WHERE wp.`id_wishlist` = ' . (int) $id_wishlist . '
AND w.`id_customer` = ' . (int) $id_customer . '
AND wp.`id_product` = ' . (int) $id_product . '
AND wp.`id_product_attribute` = ' . (int) ($id_product_attribute)
);
if (!empty($result)) {
if ((int) $result['quantity'] + (int) $quantity <= 0) {
return WishList::removeProduct($id_wishlist, $id_customer, $id_product, $id_product_attribute);
}
// TODO: use a method for this like updateProduct ?
return Db::getInstance()->update(
'wishlist_product',
[
'quantity' => (int) $quantity + (int) $result['quantity'],
],
'`id_wishlist` = ' . (int) $id_wishlist . ' AND `id_product` = ' . (int) $id_product . ' AND `id_product_attribute` = ' . (int) $id_product_attribute
);
}
return Db::getInstance()->insert(
'wishlist_product',
[
'id_wishlist' => (int) $id_wishlist,
'id_product' => (int) $id_product,
'id_product_attribute' => (int) $id_product_attribute,
'quantity' => (int) $quantity,
'priority' => 1,
]
);
}
/**
* Remove product from wishlist
*
* @param int $id_wishlist
* @param int $id_customer
* @param int $id_product
* @param int $id_product_attribute
*
* @return bool
*/
public static function removeProduct($id_wishlist, $id_customer, $id_product, $id_product_attribute)
{
$result = Db::getInstance()->getRow('
SELECT w.`id_wishlist`, wp.`id_wishlist_product`
FROM `' . _DB_PREFIX_ . 'wishlist` w
LEFT JOIN `' . _DB_PREFIX_ . 'wishlist_product` wp ON (wp.`id_wishlist` = w.`id_wishlist`)
WHERE `id_customer` = ' . (int) $id_customer . '
AND w.`id_wishlist` = ' . (int) $id_wishlist
);
if (empty($result)) {
return false;
}
// Delete product in wishlist_product_cart
Db::getInstance()->delete(
'wishlist_product_cart',
'id_wishlist_product = ' . (int) $result['id_wishlist_product']
);
return Db::getInstance()->delete(
'wishlist_product',
'id_wishlist = ' . (int) $id_wishlist . ' AND id_product = ' . (int) $id_product . ' AND id_product_attribute = ' . (int) $id_product_attribute
);
}
/**
* @param int|null $id_product
* @param int|null $id_product_attribute
*
* @return bool
*/
public static function removeProductFromWishlist($id_product = null, $id_product_attribute = null)
{
if ($id_product === null && $id_product_attribute === null) {
return false;
}
return Db::getInstance()->delete(
'wishlist_product',
($id_product ? 'id_product = ' . (int) $id_product : '')
. ($id_product && $id_product_attribute ? ' AND ' : '')
. ($id_product_attribute ? ' id_product_attribute = ' . (int) $id_product_attribute : '')
);
}
/**
* @return void
*/
public static function removeNonExistingProductAttributesFromWishlist()
{
$dbQuery = new DbQuery();
$dbQuery->select('wp.id_product_attribute');
$dbQuery->from('wishlist_product', 'wp');
$dbQuery->leftJoin('product_attribute', 'pa', 'wp.id_product_attribute = pa.id_product_attribute');
$dbQuery->where('pa.id_product_attribute IS NULL');
$productAttributes = Db::getInstance()->executeS($dbQuery);
foreach ($productAttributes as $productAttribute) {
self::removeProductFromWishlist(null, (int) $productAttribute['id_product_attribute']);
}
}
/**
* Update product to wishlist
*
* @param int $id_wishlist
* @param int $id_product
* @param int $id_product_attribute
* @param int $priority
* @param int $quantity
*
* @return bool succeed
*/
public static function updateProduct($id_wishlist, $id_product, $id_product_attribute, $priority, $quantity)
{
if ($priority < 0 || $priority > 2) {
return false;
}
return Db::getInstance()->update(
'wishlist_product',
[
'priority' => (int) $priority,
'quantity' => (int) $quantity,
],
'id_wishlist = ' . (int) $id_wishlist . 'id_product` = ' . (int) $id_product . 'id_product_attribute` = ' . (int) $id_product_attribute
);
}
/**
* Get all Wishlists by Customer ID
*
* @param int $id_customer
*
* @return array Results
*/
public static function getAllWishlistsByIdCustomer($id_customer)
{
$shop_restriction = '';
if (Shop::getContextShopID()) {
$shop_restriction = 'AND w.id_shop = ' . (int) Shop::getContextShopID();
} elseif (Shop::getContextShopGroupID()) {
$shop_restriction = 'AND w.id_shop_group = ' . (int) Shop::getContextShopGroupID();
}
$sql = sprintf(
'SELECT w.`id_wishlist`, (
SELECT COUNT(wp.id_wishlist_product)
FROM `%1$swishlist_product` wp
INNER JOIN `%1$sproduct` p ON p.`id_product` = wp.`id_product`
%2$s
WHERE wp.id_wishlist = w.id_wishlist
) AS nbProducts, w.`name`, w.`default`, w.`token`
FROM `%1$swishlist` w
WHERE w.`id_customer` = %3$d %4$s
ORDER BY w.`default` DESC, w.`name` ASC',
_DB_PREFIX_,
Shop::addSqlAssociation('product', 'p', true, 'product_shop.active = 1'),
(int) $id_customer,
$shop_restriction
);
return Db::getInstance((bool) _PS_USE_SQL_SLAVE_)->executeS($sql);
}
/**
* Get products by Wishlist
*
* @param int $id_wishlist
*
* @return array|false Results
*/
public static function getProductsByWishlist($id_wishlist)
{
$wishlistProducts = Db::getInstance()->executeS('
SELECT `id_product`, `id_product_attribute`, `quantity`
FROM `' . _DB_PREFIX_ . 'wishlist_product`
WHERE `id_wishlist` = ' . (int) $id_wishlist . '
And quantity > 0'
);
if (!empty($wishlistProducts)) {
return $wishlistProducts;
}
return false;
}
/**
* Get Wishlist products by Customer ID
*
* @param int $id_wishlist
* @param int $id_customer
* @param int $id_lang
* @param int|null $id_product
* @param bool $quantity
*
* @return array Results
*/
public static function getProductByIdCustomer($id_wishlist, $id_customer, $id_lang, $id_product = null, $quantity = false)
{
$products = Db::getInstance()->executeS('
SELECT wp.`id_product`, wp.`quantity` as wishlist_quantity, p.`quantity` AS product_quantity, pl.`name`, wp.`id_product_attribute`, wp.`priority`, pl.link_rewrite, cl.link_rewrite AS category_rewrite
FROM `' . _DB_PREFIX_ . 'wishlist_product` wp
LEFT JOIN `' . _DB_PREFIX_ . 'product` p ON p.`id_product` = wp.`id_product`
' . Shop::addSqlAssociation('product', 'p') . '
LEFT JOIN `' . _DB_PREFIX_ . 'product_lang` pl ON pl.`id_product` = wp.`id_product`' . Shop::addSqlRestrictionOnLang('pl') . '
LEFT JOIN `' . _DB_PREFIX_ . 'wishlist` w ON w.`id_wishlist` = wp.`id_wishlist`
LEFT JOIN `' . _DB_PREFIX_ . 'category_lang` cl ON cl.`id_category` = product_shop.`id_category_default` AND cl.id_lang=' . (int) $id_lang . Shop::addSqlRestrictionOnLang('cl') . '
WHERE w.`id_customer` = ' . (int) $id_customer . '
AND pl.`id_lang` = ' . (int) $id_lang . '
AND wp.`id_wishlist` = ' . (int) $id_wishlist .
(empty($id_product) === false ? ' AND wp.`id_product` = ' . (int) $id_product : '') .
($quantity == true ? ' AND wp.`quantity` != 0' : '') . '
GROUP BY p.id_product, wp.id_product_attribute'
);
if (empty($products)) {
return [];
}
for ($i = 0; $i < sizeof($products); ++$i) {
if (isset($products[$i]['id_product_attribute']) &&
Validate::isUnsignedInt($products[$i]['id_product_attribute'])) {
$result = Db::getInstance()->executeS('
SELECT al.`name` AS attribute_name, pa.`quantity` AS "attribute_quantity"
FROM `' . _DB_PREFIX_ . 'product_attribute_combination` pac
LEFT JOIN `' . _DB_PREFIX_ . 'attribute` a ON (a.`id_attribute` = pac.`id_attribute`)
LEFT JOIN `' . _DB_PREFIX_ . 'attribute_group` ag ON (ag.`id_attribute_group` = a.`id_attribute_group`)
LEFT JOIN `' . _DB_PREFIX_ . 'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = ' . (int) $id_lang . ')
LEFT JOIN `' . _DB_PREFIX_ . 'attribute_group_lang` agl ON (ag.`id_attribute_group` = agl.`id_attribute_group` AND agl.`id_lang` = ' . (int) $id_lang . ')
LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON (pac.`id_product_attribute` = pa.`id_product_attribute`)
' . Shop::addSqlAssociation('product_attribute', 'pa') . '
WHERE pac.`id_product_attribute` = ' . (int) ($products[$i]['id_product_attribute']));
$products[$i]['attributes_small'] = '';
if ($result) {
foreach ($result as $k => $row) {
$products[$i]['attributes_small'] .= $row['attribute_name'] . ', ';
}
}
$products[$i]['attributes_small'] = rtrim($products[$i]['attributes_small'], ', ');
if (isset($result[0])) {
$products[$i]['attribute_quantity'] = $result[0]['attribute_quantity'];
}
} else {
$products[$i]['attribute_quantity'] = $products[$i]['product_quantity'];
}
}
return $products;
}
/**
* Add bought product
*
* @param int $id_wishlist
* @param int $id_product
* @param int $id_product_attribute
* @param int $id_cart
* @param int $quantity
*
* @return bool succeed
*/
public static function addBoughtProduct($id_wishlist, $id_product, $id_product_attribute, $id_cart, $quantity)
{
$result = Db::getInstance()->getRow('
SELECT `quantity`, `id_wishlist_product`
FROM `' . _DB_PREFIX_ . 'wishlist_product` wp
WHERE `id_wishlist` = ' . (int) $id_wishlist . '
AND `id_product` = ' . (int) $id_product . '
AND `id_product_attribute` = ' . (int) $id_product_attribute
);
if (empty($result) ||
($result['quantity'] - $quantity) < 0 ||
$quantity > $result['quantity']) {
return false;
}
Db::getInstance()->executeS('
SELECT *
FROM `' . _DB_PREFIX_ . 'wishlist_product_cart`
WHERE `id_wishlist_product`=' . (int) $result['id_wishlist_product'] . ' AND `id_cart`=' . (int) $id_cart
);
if (Db::getInstance()->NumRows() > 0) {
$result2 = Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'wishlist_product_cart`
SET `quantity`=`quantity` + ' . (int) $quantity . '
WHERE `id_wishlist_product`=' . (int) $result['id_wishlist_product'] . ' AND `id_cart`=' . (int) $id_cart
);
} else {
$result2 = Db::getInstance()->execute('
INSERT INTO `' . _DB_PREFIX_ . 'wishlist_product_cart`
(`id_wishlist_product`, `id_cart`, `quantity`, `date_add`) VALUES(
' . (int) $result['id_wishlist_product'] . ',
' . (int) $id_cart . ',
' . (int) $quantity . ',
\'' . pSQL(date('Y-m-d H:i:s')) . '\')');
}
if ($result2 === false) {
return false;
}
return true;
}
/**
* @param int $id_customer
* @param int $idShop
*
* @return array|false
*/
public static function getAllProductByCustomer($id_customer, $idShop)
{
$result = Db::getInstance()->executeS('
SELECT `id_product`, `id_product_attribute`, w.`id_wishlist`, wp.`quantity`
FROM `' . _DB_PREFIX_ . 'wishlist_product` wp
LEFT JOIN `' . _DB_PREFIX_ . 'wishlist` w ON (w.`id_wishlist` = wp.`id_wishlist`)
WHERE w.`id_customer` = ' . (int) $id_customer . '
AND w.id_shop = ' . (int) $idShop . '
AND wp.`quantity` > 0 ');
if (empty($result)) {
return false;
}
return $result;
}
/**
* Get ID wishlist by Token
*
* @param string $token
*
* @return array Results
*
* @throws PrestaShopException
*/
public static function getByToken($token)
{
if (empty($token) || false === Validate::isMessage($token)) {
throw new PrestaShopException('Invalid token');
}
return Db::getInstance((bool) _PS_USE_SQL_SLAVE_)->getRow('
SELECT w.`id_wishlist`, w.`name`, w.`id_customer`, c.`firstname`, c.`lastname`
FROM `' . _DB_PREFIX_ . 'wishlist` w
INNER JOIN `' . _DB_PREFIX_ . 'customer` c ON c.`id_customer` = w.`id_customer`
WHERE `token` = \'' . pSQL($token) . '\''
);
}
public static function refreshWishList($id_wishlist)
{
$old_carts = Db::getInstance((bool) _PS_USE_SQL_SLAVE_)->executeS('
SELECT wp.id_product, wp.id_product_attribute, wpc.id_cart, UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(wpc.date_add) AS timecart
FROM `' . _DB_PREFIX_ . 'wishlist_product_cart` wpc
JOIN `' . _DB_PREFIX_ . 'wishlist_product` wp ON (wp.id_wishlist_product = wpc.id_wishlist_product)
JOIN `' . _DB_PREFIX_ . 'cart` c ON (c.id_cart = wpc.id_cart)
JOIN `' . _DB_PREFIX_ . 'cart_product` cp ON (wpc.id_cart = cp.id_cart)
LEFT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.id_cart = c.id_cart)
WHERE (wp.id_wishlist=' . (int) $id_wishlist . ' AND o.id_cart IS NULL)
HAVING timecart >= 3600*6');
if (!empty($old_carts)) {
foreach ($old_carts as $old_cart) {
Db::getInstance()->execute('
DELETE FROM `' . _DB_PREFIX_ . 'cart_product`
WHERE id_cart=' . (int) $old_cart['id_cart'] . ' AND id_product=' . (int) $old_cart['id_product'] . ' AND id_product_attribute=' . (int) $old_cart['id_product_attribute']
);
}
}
$freshwish = Db::getInstance()->executeS('
SELECT wpc.id_cart, wpc.id_wishlist_product
FROM `' . _DB_PREFIX_ . 'wishlist_product_cart` wpc
JOIN `' . _DB_PREFIX_ . 'wishlist_product` wp ON (wpc.id_wishlist_product = wp.id_wishlist_product)
JOIN `' . _DB_PREFIX_ . 'cart` c ON (c.id_cart = wpc.id_cart)
LEFT JOIN `' . _DB_PREFIX_ . 'cart_product` cp ON (cp.id_cart = wpc.id_cart AND cp.id_product = wp.id_product AND cp.id_product_attribute = wp.id_product_attribute)
WHERE (wp.id_wishlist = ' . (int) $id_wishlist . ' AND ((cp.id_product IS NULL AND cp.id_product_attribute IS NULL)))
');
$res = Db::getInstance()->executeS('
SELECT wp.id_wishlist_product, cp.quantity AS cart_quantity, wpc.quantity AS wish_quantity, wpc.id_cart
FROM `' . _DB_PREFIX_ . 'wishlist_product_cart` wpc
JOIN `' . _DB_PREFIX_ . 'wishlist_product` wp ON (wp.id_wishlist_product = wpc.id_wishlist_product)
JOIN `' . _DB_PREFIX_ . 'cart` c ON (c.id_cart = wpc.id_cart)
JOIN `' . _DB_PREFIX_ . 'cart_product` cp ON (cp.id_cart = wpc.id_cart AND cp.id_product = wp.id_product AND cp.id_product_attribute = wp.id_product_attribute)
WHERE wp.id_wishlist=' . (int) $id_wishlist
);
if (!empty($res)) {
foreach ($res as $refresh) {
if ($refresh['wish_quantity'] > $refresh['cart_quantity']) {
Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'wishlist_product`
SET `quantity`= `quantity` + ' . ((int) $refresh['wish_quantity'] - (int) $refresh['cart_quantity']) . '
WHERE id_wishlist_product=' . (int) $refresh['id_wishlist_product']
);
Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'wishlist_product_cart`
SET `quantity`=' . (int) $refresh['cart_quantity'] . '
WHERE id_wishlist_product=' . (int) $refresh['id_wishlist_product'] . ' AND id_cart=' . (int) $refresh['id_cart']
);
}
}
}
if (!empty($freshwish)) {
foreach ($freshwish as $prodcustomer) {
Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'wishlist_product` SET `quantity`=`quantity` +
(
SELECT `quantity` FROM `' . _DB_PREFIX_ . 'wishlist_product_cart`
WHERE `id_wishlist_product`=' . (int) $prodcustomer['id_wishlist_product'] . ' AND `id_cart`=' . (int) $prodcustomer['id_cart'] . '
)
WHERE `id_wishlist_product`=' . (int) $prodcustomer['id_wishlist_product'] . ' AND `id_wishlist`=' . (int) $id_wishlist
);
Db::getInstance()->execute('
DELETE FROM `' . _DB_PREFIX_ . 'wishlist_product_cart`
WHERE `id_wishlist_product`=' . (int) $prodcustomer['id_wishlist_product'] . ' AND `id_cart`=' . (int) $prodcustomer['id_cart']
);
}
}
}
/**
* Increment counter
*
* @param int $id_wishlist
*
* @return bool succeed
*/
public static function incCounter($id_wishlist)
{
$counter = WishList::getWishlistCounter((int) $id_wishlist);
++$counter;
return Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'wishlist` SET
`counter` = ' . $counter . '
WHERE `id_wishlist` = ' . (int) $id_wishlist
);
}
/**
* @param int $id_wishlist
*
* @return int
*/
public static function getWishlistCounter($id_wishlist)
{
return (int) Db::getInstance()->getValue('
SELECT `counter`
FROM `' . _DB_PREFIX_ . 'wishlist`
WHERE `id_wishlist` = ' . (int) $id_wishlist
);
}
/**
* Get Wishlists by Customer ID
*
* @param int $id_customer
*
* @return array Results
*/
public static function getByIdCustomer($id_customer)
{
$shop_restriction = '';
if (Shop::getContextShopID()) {
$shop_restriction = 'AND id_shop = ' . (int) Shop::getContextShopID();
} elseif (Shop::getContextShopGroupID()) {
$shop_restriction = 'AND id_shop_group = ' . (int) Shop::getContextShopGroupID();
}
$cache_id = 'WhishList::getByIdCustomer_' . (int) $id_customer . '-' . (int) Shop::getContextShopID() . '-' . (int) Shop::getContextShopGroupID();
if (!Cache::isStored($cache_id)) {
$result = Db::getInstance()->executeS('
SELECT w.`id_wishlist`, w.`name`, w.`token`, w.`date_add`, w.`date_upd`, w.`counter`, w.`default`
FROM `' . _DB_PREFIX_ . 'wishlist` w
WHERE `id_customer` = ' . (int) $id_customer . '
' . $shop_restriction . '
ORDER BY w.`name` ASC'
);
Cache::store($cache_id, $result);
}
return Cache::retrieve($cache_id);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

2423
modules/blockwishlist/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<module>
<name>blockwishlist</name>
<displayName><![CDATA[Wishlist block]]></displayName>
<version><![CDATA[3.0.2]]></version>
<description><![CDATA[Adds a block containing the customer&#039;s wishlists.]]></description>
<author><![CDATA[PrestaShop]]></author>
<tab><![CDATA[front_office_features]]></tab>
<is_configurable>1</is_configurable>
<need_instance>0</need_instance>
<limited_countries></limited_countries>
</module>

View File

@@ -0,0 +1,21 @@
blockwishlist_configuration:
path: blockwishlist/configuration
methods: [GET, POST]
defaults:
_controller: PrestaShop\Module\BlockWishList\Controller\WishlistConfigurationAdminController::configurationAction
_legacy_controller: 'WishlistConfigurationAdminController'
_legacy_link: 'WishlistConfigurationAdminController'
blockwishlist_statistics:
path: blockwishlist/statistics
methods: [GET]
defaults:
_controller: PrestaShop\Module\BlockWishList\Controller\WishlistConfigurationAdminController::statisticsAction
_legacy_controller: 'WishlistStatisticsAdminController'
_legacy_link: 'WishlistStatisticsAdminController'
blockwishlist_statistics_reset:
path: blockwishlist/statistics/reset
methods: [POST]
defaults:
_controller: PrestaShop\Module\BlockWishList\Controller\WishlistConfigurationAdminController::resetStatisticsCacheAction

View File

@@ -0,0 +1,103 @@
services:
# Controller
PrestaShop\Module\BlockWishList\Controller\WishlistConfigurationAdminController:
public: true
class: PrestaShop\Module\BlockWishList\Controller\WishlistConfigurationAdminController
arguments:
- '@doctrine.cache.provider'
- '@=service("prestashop.adapter.shop.context").getContextShopID()'
# Calculator
prestashop.module.blockwishlist.calculator.statistics_calculator:
public: true
class: PrestaShop\Module\BlockWishList\Calculator\StatisticsCalculator
arguments:
- '@prestashop.adapter.legacy.context' #used for product presenter
- '@=service("prestashop.core.localization.locale.repository").getLocale(service("prestashop.adapter.legacy.context").getContext().language.getLocale())' # From PS 1.7.7: "@prestashop.core.localization.locale.context_locale"
# Grid Definition
prestashop.module.blockwishlist.grid.all_time_statistics_grid_definition_factory:
public: true
class: 'PrestaShop\Module\BlockWishList\Grid\Definition\AllTimeStatisticsGridDefinitionFactory'
parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
prestashop.module.blockwishlist.grid.current_year_statistics_grid_definition_factory:
public: true
class: 'PrestaShop\Module\BlockWishList\Grid\Definition\CurrentYearStatisticsGridDefinitionFactory'
parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
prestashop.module.blockwishlist.grid.current_month_statistics_grid_definition_factory:
public: true
class: 'PrestaShop\Module\BlockWishList\Grid\Definition\CurrentMonthStatisticsGridDefinitionFactory'
parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
prestashop.module.blockwishlist.grid.current_day_statistics_grid_definition_factory:
public: true
class: 'PrestaShop\Module\BlockWishList\Grid\Definition\CurrentDayStatisticsGridDefinitionFactory'
parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
# Grid Data Factories
prestashop.module.blockwishlist.grid.all_time_statistics_data_factory:
class: 'PrestaShop\Module\BlockWishList\Grid\Data\AllTimeStatisticsGridDataFactory'
arguments:
- '@doctrine.cache.provider'
- '@prestashop.module.blockwishlist.calculator.statistics_calculator'
- '@=service("prestashop.adapter.shop.context").getContextShopID()'
prestashop.module.blockwishlist.grid.current_year_statistics_data_factory:
class: 'PrestaShop\Module\BlockWishList\Grid\Data\CurrentYearStatisticsGridDataFactory'
arguments:
- '@doctrine.cache.provider'
- '@prestashop.module.blockwishlist.calculator.statistics_calculator'
- '@=service("prestashop.adapter.shop.context").getContextShopID()'
prestashop.module.blockwishlist.grid.current_month_statistics_data_factory:
class: 'PrestaShop\Module\BlockWishList\Grid\Data\CurrentMonthStatisticsGridDataFactory'
arguments:
- '@doctrine.cache.provider'
- '@prestashop.module.blockwishlist.calculator.statistics_calculator'
- '@=service("prestashop.adapter.shop.context").getContextShopID()'
prestashop.module.blockwishlist.grid.current_day_statistics_data_factory:
class: 'PrestaShop\Module\BlockWishList\Grid\Data\CurrentDayStatisticsGridDataFactory'
arguments:
- '@doctrine.cache.provider'
- '@prestashop.module.blockwishlist.calculator.statistics_calculator'
- '@=service("prestashop.adapter.shop.context").getContextShopID()'
# Grid Factories
prestashop.module.blockwishlist.grid.all_time_stastistics_grid_factory:
public: true
class: 'PrestaShop\PrestaShop\Core\Grid\GridFactory'
arguments:
- '@prestashop.module.blockwishlist.grid.all_time_statistics_grid_definition_factory'
- '@prestashop.module.blockwishlist.grid.all_time_statistics_data_factory'
- '@prestashop.core.grid.filter.form_factory'
- '@prestashop.core.hook.dispatcher'
prestashop.module.blockwishlist.grid.current_year_stastistics_grid_factory:
public: true
class: 'PrestaShop\PrestaShop\Core\Grid\GridFactory'
arguments:
- '@prestashop.module.blockwishlist.grid.current_year_statistics_grid_definition_factory'
- '@prestashop.module.blockwishlist.grid.current_year_statistics_data_factory'
- '@prestashop.core.grid.filter.form_factory'
- '@prestashop.core.hook.dispatcher'
prestashop.module.blockwishlist.grid.current_month_stastistics_grid_factory:
public: true
class: 'PrestaShop\PrestaShop\Core\Grid\GridFactory'
arguments:
- '@prestashop.module.blockwishlist.grid.current_month_statistics_grid_definition_factory'
- '@prestashop.module.blockwishlist.grid.current_month_statistics_data_factory'
- '@prestashop.core.grid.filter.form_factory'
- '@prestashop.core.hook.dispatcher'
prestashop.module.blockwishlist.grid.current_day_stastistics_grid_factory:
public: true
class: 'PrestaShop\PrestaShop\Core\Grid\GridFactory'
arguments:
- '@prestashop.module.blockwishlist.grid.current_day_statistics_grid_definition_factory'
- '@prestashop.module.blockwishlist.grid.current_day_statistics_data_factory'
- '@prestashop.core.grid.filter.form_factory'
- '@prestashop.core.hook.dispatcher'

View File

@@ -0,0 +1,461 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use PrestaShop\Module\BlockWishList\Access\CustomerAccess;
class BlockWishListActionModuleFrontController extends ModuleFrontController
{
public function postProcess()
{
if (false === $this->context->customer->isLogged()) {
$this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('You aren\'t logged in', [], 'Modules.Blockwishlist.Shop'),
])
);
exit;
}
$params = Tools::getValue('params');
// Here we call all methods dynamically given by the path
if (method_exists($this, Tools::getValue('action') . 'Action')) {
call_user_func([$this, Tools::getValue('action') . 'Action'], $params);
exit;
}
$this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Unknown action', [], 'Modules.Blockwishlist.Shop'),
])
);
exit;
}
private function addProductToWishListAction($params)
{
$id_product = (int) $params['id_product'];
$product = new Product($id_product);
if (!Validate::isLoadedObject($product)) {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('There was an error adding the product', [], 'Modules.Blockwishlist.Shop'),
])
);
}
$idWishList = (int) $params['idWishList'];
$id_product_attribute = (int) $params['id_product_attribute'];
$quantity = (int) $params['quantity'];
if (0 === $quantity) {
$quantity = $product->minimal_quantity;
}
if (false === $this->assertProductAttributeExists($id_product, $id_product_attribute) && $id_product_attribute !== 0) {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('There was an error while adding the product attributes', [], 'Modules.Blockwishlist.Shop'),
])
);
}
$wishlist = new WishList($idWishList);
// Exit if not owner of the wishlist
$this->assertWriteAccess($wishlist);
$productIsAdded = $wishlist->addProduct(
$idWishList,
$this->context->customer->id,
$id_product,
$id_product_attribute,
$quantity
);
$newStat = new Statistics();
$newStat->id_product = $id_product;
$newStat->id_product_attribute = $id_product_attribute;
$newStat->id_shop = $this->context->shop->id;
$newStat->save();
if (false === $productIsAdded) {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('There was an error adding the product', [], 'Modules.Blockwishlist.Shop'),
])
);
}
Hook::exec('actionWishlistAddProduct', [
'idWishlist' => $idWishList,
'customerId' => $this->context->customer->id,
'idProduct' => $id_product,
'idProductAttribute' => $id_product_attribute,
]);
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('Product added', [], 'Modules.Blockwishlist.Shop'),
])
);
}
private function createNewWishListAction($params)
{
if (isset($params['name'])) {
if (!Validate::isGenericName($params['name'])) {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('The list name is invalid.', [], 'Modules.Blockwishlist.Shop'),
'datas' => [
'name' => $params['name'],
],
])
);
}
$wishlist = new WishList();
$wishlist->name = $params['name'];
$wishlist->id_shop_group = $this->context->shop->id_shop_group;
$wishlist->id_customer = $this->context->customer->id;
$wishlist->id_shop = $this->context->shop->id;
$wishlist->token = $this->generateWishListToken();
if (true === $wishlist->save()) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('The list has been properly created', [], 'Modules.Blockwishlist.Shop'),
'datas' => [
'name' => $wishlist->name,
'id_wishlist' => $wishlist->id,
],
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Error saving the new list', [], 'Modules.Blockwishlist.Shop'),
])
);
} else {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Missing name parameter', [], 'Modules.Blockwishlist.Shop'),
])
);
}
}
private function renameWishListAction($params)
{
if (isset($params['idWishList'], $params['name'])) {
if (!Validate::isGenericName($params['name'])) {
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('The list name is invalid', [], 'Modules.Blockwishlist.Shop'),
'datas' => [
'name' => $params['name'],
'id_whishlist' => $params['idWishList'],
],
])
);
}
$wishlist = new WishList($params['idWishList']);
// Exit if not owner of the wishlist
$this->assertWriteAccess($wishlist);
$wishlist->name = $params['name'];
if (true === $wishlist->save()) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('List has been renamed', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('List could not be renamed', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRenderMissingParams();
}
private function deleteWishListAction($params)
{
if (isset($params['idWishList'])) {
$wishlist = new WishList($params['idWishList']);
// Exit if not owner of the wishlist
$this->assertWriteAccess($wishlist);
if (true === (bool) $wishlist->delete()) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('List has been removed', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('List deletion was unsuccessful', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRenderMissingParams();
}
private function deleteProductFromWishListAction($params)
{
if (
isset($params['idWishList'])
&& isset($params['id_product'])
&& isset($params['id_product_attribute'])
) {
// Exit if not owner of the wishlist
$this->assertWriteAccess(
new WishList($params['idWishList'])
);
$isDeleted = WishList::removeProduct(
$params['idWishList'],
$this->context->customer->id,
$params['id_product'],
$params['id_product_attribute']
);
if (true === $isDeleted) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('Product successfully removed', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Unable to remove product from list', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRenderMissingParams();
}
private function updateProductFromWishListAction($params)
{
if (isset(
$params['idWishList'],
$params['id_product'],
$params['id_product_attribute'],
$params['priority'],
$params['quantity']
)) {
// Exit if not owner of the wishlist
$this->assertWriteAccess(
new WishList($params['idWishList'])
);
$isDeleted = WishList::updateProduct(
$params['idWishList'],
$params['id_product'],
$params['id_product_attribute'],
$params['priority'],
$params['quantity']
);
if (true === $isDeleted) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('Product successfully updated', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Unable to update product from wishlist', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRenderMissingParams();
}
private function getAllWishListAction()
{
$infos = WishList::getAllWishListsByIdCustomer($this->context->customer->id);
if (empty($infos)) {
$wishlist = new WishList();
$wishlist->id_shop = $this->context->shop->id;
$wishlist->id_shop_group = $this->context->shop->id_shop_group;
$wishlist->id_customer = $this->context->customer->id;
$wishlist->name = Configuration::get('blockwishlist_WishlistDefaultTitle', $this->context->language->id);
$wishlist->token = $this->generateWishListToken();
$wishlist->default = 1;
$wishlist->add();
$infos = WishList::getAllWishListsByIdCustomer($this->context->customer->id);
}
foreach ($infos as $key => $wishlist) {
$infos[$key]['shareUrl'] = $this->context->link->getModuleLink('blockwishlist', 'view', ['token' => $wishlist['token']]);
$infos[$key]['listUrl'] = $this->context->link->getModuleLink('blockwishlist', 'view', ['id_wishlist' => $wishlist['id_wishlist']]);
}
if (false === empty($infos)) {
return $this->ajaxRender(
json_encode([
'wishlists' => $infos,
])
);
}
return $this->ajaxRenderMissingParams();
}
private function generateWishListToken()
{
return strtoupper(substr(sha1(uniqid((string) rand(), true) . _COOKIE_KEY_ . $this->context->customer->id), 0, 16));
}
private function ajaxRenderMissingParams()
{
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Request is missing one or multiple parameters', [], 'Modules.Blockwishlist.Shop'),
])
);
}
private function addProductToCartAction($params)
{
$productAdd = WishList::addBoughtProduct(
$params['idWishlist'],
$params['id_product'],
$params['id_product_attribute'],
(int) $this->context->cart->id,
$params['quantity']
);
// Transform an add to favorite
Db::getInstance()->execute('
UPDATE `' . _DB_PREFIX_ . 'blockwishlist_statistics`
SET `id_cart` = ' . (int) $this->context->cart->id . '
WHERE `id_cart` = 0
AND `id_product` = ' . (int) $params['id_product'] . '
AND `id_product_attribute` = ' . (int) $params['id_product_attribute'] . '
AND `id_shop`= ' . $this->context->shop->id
);
if (true === $productAdd) {
return $this->ajaxRender(
json_encode([
'success' => true,
'message' => $this->trans('Product added to cart', [], 'Modules.Blockwishlist.Shop'),
])
);
}
return $this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('Error when adding product to cart', [], 'Modules.Blockwishlist.Shop'),
])
);
}
private function getUrlByIdWishListAction($params)
{
$wishlist = new WishList($params['idWishList']);
return $this->ajaxRender(
json_encode([
'status' => 'true',
'url' => $this->context->link->getModuleLink('blockwishlist', 'view', ['token' => $wishlist->token]),
])
);
}
/**
* Stop the execution if the current customer isd not allowed to alter the wishlist
*
* @param WishList $wishlist
*/
private function assertWriteAccess(WishList $wishlist)
{
if ((new CustomerAccess($this->context->customer))->hasWriteAccessToWishlist($wishlist)) {
return;
}
$this->ajaxRender(
json_encode([
'success' => false,
'message' => $this->trans('You\'re not allowed to manage this list.', [], 'Modules.Blockwishlist.Shop'),
])
);
exit;
}
/**
* Check if product attribute id is related to the product
*
* @param int $id_product
* @param int $id_product_attribute
*
* @return bool
*/
private function assertProductAttributeExists($id_product, $id_product_attribute)
{
return Db::getInstance()->getValue(
'SELECT pas.`id_product_attribute` ' .
'FROM `' . _DB_PREFIX_ . 'product_attribute` pa ' .
'INNER JOIN `' . _DB_PREFIX_ . 'product_attribute_shop` pas ON (pas.id_product_attribute = pa.id_product_attribute) ' .
'WHERE pas.id_shop =' . (int) $this->context->shop->id . ' AND pa.`id_product` = ' . (int) $id_product . ' ' .
'AND pas.id_product_attribute = ' . (int) $id_product_attribute
);
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
class BlockWishlistListsModuleFrontController extends ModuleFrontController
{
/**
* @var bool If set to true, will be redirected to authentication page
*/
public $auth = true;
public function initContent()
{
parent::initContent();
$this->context->smarty->assign(
[
'url' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'getAllWishlist']),
'renameUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'renameWishlist']),
'shareUrl' => $this->context->link->getModuleLink('blockwishlist', 'action', ['action' => 'getUrlByIdWishlist']),
'accountLink' => '#',
'wishlistsTitlePage' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
'newWishlistCTA' => Configuration::get('blockwishlist_CreateButtonLabel', $this->context->language->id),
]
);
$this->context->controller->registerJavascript(
'blockwishlistController',
'modules/blockwishlist/public/wishlistcontainer.bundle.js',
[
'priority' => 200,
]
);
$this->setTemplate('module:blockwishlist/views/templates/pages/lists.tpl');
}
public function getBreadcrumbLinks()
{
$breadcrumb = parent::getBreadcrumbLinks();
$breadcrumb['links'][] = $this->addMyAccountToBreadcrumb();
$breadcrumb['links'][] = [
'title' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
'url' => $this->context->link->getModuleLink('blockwishlist', 'lists'),
];
return $breadcrumb;
}
}

View File

@@ -0,0 +1,315 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
use PrestaShop\Module\BlockWishList\Access\CustomerAccess;
use PrestaShop\Module\BlockWishList\Search\WishListProductSearchProvider;
use PrestaShop\PrestaShop\Core\Product\Search\ProductSearchQuery;
use PrestaShop\PrestaShop\Core\Product\Search\SortOrder;
use PrestaShop\PrestaShop\Core\Product\Search\SortOrdersCollection;
/**
* View the content of a personal wishlist
*/
class BlockWishlistViewModuleFrontController extends ProductListingFrontController
{
/**
* Made public as the core considers this class as an ModuleFrontController
* and other modules expects to find the $module property.
*
* @var BlockWishList
*/
public $module;
/**
* @var WishList
*/
protected $wishlist;
/**
* @var CustomerAccess
*/
private $customerAccess;
public function __construct()
{
/** @var BlockWishList $module */
$module = Module::getInstanceByName('blockwishlist');
$this->module = $module;
if (empty($this->module->active)) {
Tools::redirect('index');
}
parent::__construct();
$this->controller_type = 'modulefront';
$this->customerAccess = new CustomerAccess($this->context->customer);
}
/**
* {@inheritdoc}
*/
public function init()
{
$id_wishlist = $this->getWishlistId();
$this->wishlist = new WishList($id_wishlist);
if (false === Validate::isLoadedObject($this->wishlist)) {
Tools::redirect('index.php?controller=404');
}
parent::init();
if (false === $this->customerAccess->hasReadAccessToWishlist($this->wishlist)) {
$this->errors = [
$this->trans(
'You do not have access to this wishlist.',
[],
'Modules.Blockwishlist.Shop'
),
];
$this->redirectWithNotifications('index.php');
}
$this->context->smarty->assign(
[
'id' => $id_wishlist,
'wishlistName' => $this->wishlist->name,
'isGuest' => !$this->customerAccess->hasWriteAccessToWishlist($this->wishlist),
'url' => Context::getContext()->link->getModuleLink('blockwishlist', 'view', $this->getAccessParams()),
'wishlistsLink' => Context::getContext()->link->getModuleLink('blockwishlist', 'lists'),
'deleteProductUrl' => Context::getContext()->link->getModuleLink('blockwishlist', 'action', ['action' => 'deleteProductFromWishlist']),
]
);
}
/**
* {@inheritdoc}
*/
public function initContent()
{
parent::initContent();
if (false === $this->customerAccess->hasReadAccessToWishlist($this->wishlist)) {
return;
}
$this->context->controller->registerJavascript(
'blockwishlistController',
'modules/blockwishlist/public/productslist.bundle.js',
[
'priority' => 200,
]
);
$this->doProductSearch(
'../../../modules/blockwishlist/views/templates/pages/products-list.tpl',
[
'entity' => 'wishlist_product',
'id_wishlist' => $this->wishlist->id,
]
);
}
/**
* {@inheritdoc}
*/
public function getListingLabel()
{
return $this->trans(
'WishList: %wishlist_name%',
['%wishlist_name%' => $this->wishlist->name],
'Modules.Blockwishlist.Shop'
);
}
/**
* {@inheritdoc}
*/
protected function getProductSearchQuery()
{
$query = new ProductSearchQuery();
$query->setSortOrder(
new SortOrder(
'product',
Tools::getProductsOrder('by'),
Tools::getProductsOrder('way')
)
);
return $query;
}
/**
* {@inheritdoc}
*/
protected function getDefaultProductSearchProvider()
{
return new WishListProductSearchProvider(
Db::getInstance(),
$this->wishlist,
new SortOrdersCollection($this->getTranslator()),
$this->getTranslator()
);
}
/**
* {@inheritdoc}
*/
protected function getAjaxProductSearchVariables()
{
parent::getAjaxProductSearchVariables();
$context = parent::getProductSearchContext();
$query = $this->getProductSearchQuery();
$provider = $this->getDefaultProductSearchProvider();
$resultsPerPage = (int) Tools::getValue('resultsPerPage');
if ($resultsPerPage <= 0) {
$resultsPerPage = Configuration::get('PS_PRODUCTS_PER_PAGE');
}
// we need to set a few parameters from back-end preferences
$query
->setResultsPerPage($resultsPerPage)
->setPage(max((int) Tools::getValue('page'), 1))
;
// set the sort order if provided in the URL
if (($encodedSortOrder = Tools::getValue('order'))) {
$query->setSortOrder(SortOrder::newFromString($encodedSortOrder));
}
// get the parameters containing the encoded facets from the URL
$encodedFacets = Tools::getValue('q');
$query->setEncodedFacets($encodedFacets);
$result = $provider->runQuery($context, $query);
if (!$result->getCurrentSortOrder()) {
$result->setCurrentSortOrder($query->getSortOrder());
}
// prepare the products
$products = $this->prepareMultipleProductsForTemplate($result->getProducts());
// render the facets with the core
$rendered_facets = $this->renderFacets($result);
$rendered_active_filters = $this->renderActiveFilters($result);
$pagination = $this->getTemplateVarPagination($query, $result);
// prepare the sort orders
// note that, again, the product controller is sort-orders agnostic
// a module can easily add specific sort orders that it needs to support (e.g. sort by "energy efficiency")
$sort_orders = $this->getTemplateVarSortOrders(
$result->getAvailableSortOrders(),
$query->getSortOrder()->toString()
);
$sort_selected = false;
$labelDefaultSort = '';
if (!empty($sort_orders)) {
foreach ($sort_orders as $order) {
if ($order['field'] == 'id_wishlist_product') {
$labelDefaultSort = $order['label'];
}
if (isset($order['current']) && true === $order['current']) {
$sort_selected = $order['label'];
break;
}
}
}
$searchVariables = [
'result' => $result,
'label' => $this->getListingLabel(),
'products' => $products,
'sort_orders' => $sort_orders,
'sort_selected' => $sort_selected ? $sort_selected : $labelDefaultSort,
'pagination' => $pagination,
'rendered_facets' => $rendered_facets,
'rendered_active_filters' => $rendered_active_filters,
'js_enabled' => $this->ajax,
'current_url' => $this->updateQueryString([
'q' => $result->getEncodedFacets(),
]),
];
Hook::exec('filterProductSearch', ['searchVariables' => &$searchVariables]);
Hook::exec('actionProductSearchAfter', $searchVariables);
return $searchVariables;
}
/**
* Depending on the parameters sent, checks if the current visitor may reach the page
*
* @return int|false
*/
private function getWishlistId()
{
if (Tools::getIsset('id_wishlist')) {
return (int) Tools::getValue('id_wishlist');
}
if (Tools::getIsset('token')) {
$wishlistData = WishList::getByToken(
Tools::getValue('token')
);
if (!empty($wishlistData['id_wishlist'])) {
return $wishlistData['id_wishlist'];
}
}
return false;
}
/**
* @return array
*/
private function getAccessParams()
{
if (Tools::getIsset('token')) {
return ['token' => Tools::getValue('token')];
}
if (Tools::getIsset('id_wishlist')) {
return ['id_wishlist' => Tools::getValue('id_wishlist')];
}
return [];
}
public function getBreadcrumbLinks()
{
$breadcrumb = parent::getBreadcrumbLinks();
$breadcrumb['links'][] = $this->addMyAccountToBreadcrumb();
$breadcrumb['links'][] = [
'title' => Configuration::get('blockwishlist_WishlistPageName', $this->context->language->id),
'url' => $this->context->link->getModuleLink('blockwishlist', 'lists'),
];
$breadcrumb['links'][] = [
'title' => $this->wishlist->name,
'url' => Context::getContext()->link->getModuleLink('blockwishlist', 'view', $this->getAccessParams()),
];
return $breadcrumb;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,28 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

15768
modules/blockwishlist/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
module.exports = {
plugins: {
'postcss-preset-env': {
browsers: '> .5%, last 2 versions',
},
},
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist-stats .card-text{width:100%;padding:10px 30px}.wishlist-stats .wishlist-stats-topbar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:20px}.wishlist-stats .wishlist-stats-topbar .btn-group{border:1px solid #b7ced3;border-radius:3px}.wishlist-stats .wishlist-stats-topbar .btn-group button{color:#363a41;font-size:14px;letter-spacing:0;line-height:19px;background:none;font-weight:500;-webkit-transition:.25s ease-out;transition:.25s ease-out}.wishlist-stats .wishlist-stats-topbar .btn-group button:not(:last-child){border-right:1px solid #b7ced3}.wishlist-stats .wishlist-stats-topbar .btn-group button:hover,.wishlist-stats .wishlist-stats-topbar .btn-group button.active{background-color:#25b9d7;color:#fff}.wishlist-stats .wishlist-stats-topbar .refresh{color:#6c868e;font-size:14px;font-weight:bold;letter-spacing:0;line-height:19px;border:1px solid #6c868e;border-radius:4px;-webkit-transition:.25s ease-out;transition:.25s ease-out;background:none}.wishlist-stats .wishlist-stats-topbar .refresh:hover{background:#6c868e;color:#fff}.wishlist-stats .wishlist-tab{display:none}.wishlist-stats .wishlist-tab.active{display:block}.wishlist-stats .wishlist-tab .column-image img{max-width:50px}.wishlist-stats .wishlist-tab .column-conversionRate{font-weight:bold}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
window.form=function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=441)}({227:function(e,n,t){},441:function(e,n,t){t(442),e.exports=t(227)},442:function(e,n,t){"use strict";
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/(0,window.$)((function(){window.prestashop.component.initComponents(["TranslatableInput"])}))}});

View File

@@ -0,0 +1,19 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist-stats .card-text{width:100%;padding:10px 30px}.wishlist-stats .wishlist-stats-topbar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:20px}.wishlist-stats .wishlist-stats-topbar .btn-group{border:1px solid #b7ced3;border-radius:3px}.wishlist-stats .wishlist-stats-topbar .btn-group button{color:#363a41;font-size:14px;letter-spacing:0;line-height:19px;background:none;font-weight:500;-webkit-transition:.25s ease-out;transition:.25s ease-out}.wishlist-stats .wishlist-stats-topbar .btn-group button:not(:last-child){border-right:1px solid #b7ced3}.wishlist-stats .wishlist-stats-topbar .btn-group button:hover,.wishlist-stats .wishlist-stats-topbar .btn-group button.active{background-color:#25b9d7;color:#fff}.wishlist-stats .wishlist-stats-topbar .refresh{color:#6c868e;font-size:14px;font-weight:bold;letter-spacing:0;line-height:19px;border:1px solid #6c868e;border-radius:4px;-webkit-transition:.25s ease-out;transition:.25s ease-out;background:none}.wishlist-stats .wishlist-stats-topbar .refresh:hover{background:#6c868e;color:#fff}.wishlist-stats .wishlist-tab{display:none}.wishlist-stats .wishlist-tab.active{display:block}.wishlist-stats .wishlist-tab .column-image img{max-width:50px}.wishlist-stats .wishlist-tab .column-conversionRate{font-weight:bold}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
.wishlist-modal{display:none;opacity:0;pointer-events:none;z-index:0}.wishlist-modal.show{display:block;opacity:1;pointer-events:all;z-index:1051}.wishlist-modal.show+.modal-backdrop{pointer-events:all}.wishlist-modal.fade .modal-dialog{max-width:34.375rem;-webkit-transform:translateY(0);transform:translateY(0)}.wishlist-modal .close{font-weight:400;color:#7a7a7a;opacity:1;font-size:2.25rem}.wishlist-modal .close:hover{opacity:.6}.wishlist-modal .modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;border:none}.wishlist-modal .modal-header h5{color:#232323;font-size:1.375rem;font-weight:bold;letter-spacing:0;line-height:1.875rem}.wishlist-modal .modal-header::after{content:none}.wishlist-modal .modal-text{color:#232323;font-size:.875rem;letter-spacing:0;line-height:1.875rem}.wishlist-modal .modal-body{padding:.9375 1.875rem}.wishlist-modal .modal-body .form-group{margin-bottom:0}.wishlist-modal .modal-body .form-group .form-control{border-radius:0;background:none;color:#000}.wishlist-modal .modal-content{width:100%}.wishlist-modal .modal-cancel:hover{opacity:.7}.wishlist-modal .modal-footer{border:none}.wishlist-modal .modal-footer .btn{text-transform:none;margin-bottom:.5rem}.wishlist-modal .modal-backdrop{pointer-events:none}.wishlist-modal .modal-backdrop.in{pointer-events:all}.wishlist-modal+.modal-backdrop{pointer-events:none}.wishlist-modal+.modal-backdrop.in{pointer-events:all}.products article .wishlist-button-add{position:absolute;top:.635rem;right:.635rem;z-index:10}.wishlist-footer-links{margin-bottom:3.125rem}.wishlist-footer-links>a{font-size:.875rem;letter-spacing:0;line-height:1.1875rem}.wishlist-footer-links>a:not(:first-child){margin-left:1.25rem}.wishlist-footer-links>a i{font-size:1.25rem;margin-right:.25rem;vertical-align:middle}.lang-rtl .products article .wishlist-button-add{right:inherit;left:.635rem}.lang-rtl .wishlist-button-product{margin-left:0;margin-right:1.25rem}.lang-rtl .wishlist-list-item .dropdown-menu{right:inherit;left:1.25rem}.lang-rtl .wishlist-list-item-right .dropdown-menu>button{text-align:right}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,64 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Access;
use Customer;
use Tools;
use Validate;
use WishList;
class CustomerAccess
{
/**
* @var Customer
*/
private $customer;
public function __construct(Customer $customer)
{
$this->customer = $customer;
}
/**
* @return bool
*/
public function hasReadAccessToWishlist(WishList $wishlist)
{
// Wishlist is shared
if (!empty($wishlist->token) && Tools::getIsset('token')) {
return true;
}
return $this->hasWriteAccessToWishlist($wishlist);
}
/**
* @return bool
*/
public function hasWriteAccessToWishlist(WishList $wishlist)
{
if (false === Validate::isLoadedObject($this->customer)) {
return false;
}
return ((int) $wishlist->id_customer) === $this->customer->id;
}
}

View File

@@ -0,0 +1,270 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Calculator;
use Customer;
use DateTime;
use Db;
use DbQuery;
use PrestaShop\PrestaShop\Adapter\Image\ImageRetriever;
use PrestaShop\PrestaShop\Adapter\LegacyContext;
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray;
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductPresenter;
use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter;
use PrestaShop\PrestaShop\Adapter\Product\ProductColorsRetriever;
use PrestaShop\PrestaShop\Core\Localization\Locale;
use ProductAssembler;
use ProductPresenterFactory;
class StatisticsCalculator
{
const ARRAY_KEYS_STATS = [
'allTime',
'currentYear',
'currentMonth',
'currentDay',
];
private $context;
private $productAssembler;
/**
* @var Locale
*/
private $locale;
public function __construct(LegacyContext $context, Locale $locale)
{
$this->context = $context->getContext();
$this->context->customer = new Customer();
$this->productAssembler = new ProductAssembler($this->context);
$this->locale = $locale;
}
/**
* computeStatsFor
*
* @param string|null $statsRange
*
* @return array
*/
public function computeStatsFor($statsRange = null)
{
$query = new DbQuery();
$query->select('id_product');
$query->select('id_product_attribute');
$query->select('date_add');
$query->select('id_statistics');
$query->from('blockwishlist_statistics');
$query->where('id_shop = "' . (int) $this->context->shop->id . '"');
switch ($statsRange) {
case 'currentYear':
$dateStart = (new DateTime('now'))->modify('-1 year')->format('Y-m-d H:i:s');
break;
case 'currentMonth':
$dateStart = (new DateTime('now'))->modify('-1 month')->format('Y-m-d H:i:s');
break;
case 'currentDay':
$dateStart = (new DateTime('now'))->modify('-1 day')->format('Y-m-d H:i:s');
break;
case 'allTime':
default:
$dateStart = null;
break;
}
if (null !== $dateStart) {
$query->where('date_add >= "' . $dateStart . '"');
}
$results = Db::getInstance()->executeS($query);
$stats = [];
foreach ($results as $result) {
$productAttributeKey = $result['id_product'] . '.' . $result['id_product_attribute'];
if (isset($stats[$productAttributeKey])) {
$stats[$productAttributeKey] = $stats[$productAttributeKey] + 1;
} else {
$stats[$productAttributeKey] = 1;
}
}
arsort($stats);
$stats = array_slice($stats, 0, 10);
$this->computeConversionRate($stats, $dateStart);
return $stats;
}
/**
* computeconversionRate
*
* @param array $stats
* @param string|null $dateStart
*
* @return void
*/
public function computeConversionRate(&$stats, $dateStart = null)
{
$position = 0;
foreach ($stats as $idProductAndAttribute => $count) {
// first ID is product, second one is product_attribute
$combination = '';
$ids = explode('.', $idProductAndAttribute);
$id_product = $ids[0];
$id_product_attribute = $ids[1];
$productDetails = $this->productAssembler->assembleProduct([
'id_product' => $id_product,
'id_product_attribute' => $id_product_attribute,
]);
if (!empty($productDetails['attributes'])) {
$combinationArr = [];
foreach ($productDetails['attributes'] as $attribute) {
$combinationArr[] = $attribute['group'] . ' : ' . $attribute['name'];
}
$combination = implode(',', $combinationArr);
}
$presentedProduct = $this->getPresentedProduct($productDetails);
$imgDetails = $this->getProductImage($presentedProduct);
$stats[$idProductAndAttribute] = [
'position' => $position,
'count' => $count,
'id_product' => $id_product,
'id_product_attribute' => $id_product_attribute,
'name' => $productDetails['name'],
'combination' => $combination,
'category_name' => $presentedProduct['category_name'],
'image_small_url' => $imgDetails['small']['url'],
'link' => $presentedProduct['link'],
'reference' => $productDetails['reference'],
'price' => $this->locale->formatPrice($productDetails['price'], $this->context->currency->iso_code),
'quantity' => $productDetails['quantity'],
'conversionRate' => $this->computeConversionByProduct($id_product, $id_product_attribute, $dateStart) . '%',
];
++$position;
}
}
private function getPresentedProduct($productDetails)
{
$presenterFactory = new ProductPresenterFactory($this->context);
$presentationSettings = $presenterFactory->getPresentationSettings();
$imageRetriever = new ImageRetriever($this->context->link);
$presenter = new ProductPresenter(
$imageRetriever,
$this->context->link,
new PriceFormatter(),
new ProductColorsRetriever(),
$this->context->getTranslator()
);
return $presenter->present(
$presentationSettings,
$productDetails,
$this->context->language
);
}
/**
* getProductImage
*
* @param mixed|ProductLazyArray $presentedProduct
*
* @return array
*/
public function getProductImage($presentedProduct)
{
$imgDetails = [];
foreach ($presentedProduct as $key => $value) {
if ($key == 'embedded_attributes') {
$imgDetails = $value['cover'];
}
}
if (!$imgDetails) {
$imageRetriever = new ImageRetriever($this->context->link);
$imgDetails = $imageRetriever->getNoPictureImage($this->context->language);
}
return $imgDetails;
}
/**
* computeConversionByProduct
*
* @param string $id_product
* @param string $id_product_attribute
* @param string $dateStart (Y-m-d H:i:s)
*
* @return float
*/
public function computeConversionByProduct($id_product, $id_product_attribute, $dateStart = null)
{
$nbOrderPaidAndShipped = [];
$queryOrders = '
SELECT count(distinct(o.id_order)) as nb
FROM ' . _DB_PREFIX_ . 'orders o
INNER JOIN ' . _DB_PREFIX_ . 'blockwishlist_statistics bws ON (o.id_cart = bws.id_cart )
LEFT JOIN ' . _DB_PREFIX_ . 'order_history oh ON (o.`id_order` = oh.`id_order`)
LEFT JOIN ' . _DB_PREFIX_ . 'order_state os ON (os.`id_order_state` = oh.`id_order_state` AND os.`paid` = 1 AND os.`shipped` = 1)
LEFT JOIN ' . _DB_PREFIX_ . 'order_detail od ON (od.`id_order` = o.`id_order` AND od.`product_id` = bws.`id_product` AND od.`product_attribute_id` = bws.`id_product_attribute`)
WHERE bws.`id_cart` <> 0 AND bws.`id_product` = ' . (int) $id_product . ' AND bws.`id_product_attribute` = ' . (int) $id_product_attribute . '
AND bws.`id_shop` = ' . (int) $this->context->shop->id . '
';
if (null != $dateStart) {
$queryOrders .= 'AND bws.date_add >= "' . $dateStart . '"';
}
$nbOrderPaidAndShipped = Db::getInstance()->getRow($queryOrders);
if (empty($nbOrderPaidAndShipped['nb'])) {
return 0;
}
$queryCountAll = new DbQuery();
$queryCountAll->select('COUNT(id_statistics)');
$queryCountAll->from('blockwishlist_statistics');
$queryCountAll->where('id_product = ' . $id_product);
$queryCountAll->where('id_product_attribute = ' . $id_product_attribute);
$queryCountAll->where('id_shop = ' . (int) $this->context->shop->id);
if (null != $dateStart) {
$queryCountAll->where('date_add >= "' . $dateStart . '"');
}
$countAddedToWishlist = Db::getInstance()->getValue($queryCountAll);
if (0 != $countAddedToWishlist) {
return round(($nbOrderPaidAndShipped['nb'] / $countAddedToWishlist) * 100, 2);
}
return 0;
}
}

View File

@@ -0,0 +1,176 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Controller;
use Configuration;
use Doctrine\Common\Cache\CacheProvider;
use Language;
use PrestaShop\Module\BlockWishList\Grid\Data\BaseGridDataFactory;
use PrestaShop\Module\BlockWishList\Type\ConfigurationType;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteria;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class WishlistConfigurationAdminController extends FrameworkBundleAdminController
{
/**
* @var CacheProvider
*/
private $cache;
/**
* @var int|null
*/
private $shopId;
public function __construct(CacheProvider $cache, $shopId)
{
$this->cache = $cache;
$this->shopId = $shopId;
}
public function configurationAction(Request $request)
{
$datas = $this->getWishlistConfigurationDatas();
$configurationForm = $this->createForm(ConfigurationType::class, $datas);
$configurationForm->handleRequest($request);
$resultHandleForm = null;
if ($configurationForm->isSubmitted() && $configurationForm->isValid()) {
$resultHandleForm = $this->handleForm($configurationForm->getData());
if ($resultHandleForm) {
return $this->redirectToRoute('blockwishlist_configuration');
}
}
return $this->render('@Modules/blockwishlist/views/templates/admin/home.html.twig', [
'configurationForm' => $configurationForm->createView(),
'resultHandleForm' => $resultHandleForm,
'enableSidebar' => true,
'help_link' => $this->generateSidebarLink('WishlistConfigurationAdminController'),
]);
}
public function statisticsAction()
{
$searchCriteria = new SearchCriteria();
$allTimeStatsGridFactory = $this->get('prestashop.module.blockwishlist.grid.all_time_stastistics_grid_factory');
$currentYearGridFactory = $this->get('prestashop.module.blockwishlist.grid.current_year_stastistics_grid_factory');
$currentMonthGridFactory = $this->get('prestashop.module.blockwishlist.grid.current_month_stastistics_grid_factory');
$currentDayGridFactory = $this->get('prestashop.module.blockwishlist.grid.current_day_stastistics_grid_factory');
$allTimeStatisticsGrid = $allTimeStatsGridFactory->getGrid($searchCriteria);
$currentYearGrid = $currentYearGridFactory->getGrid($searchCriteria);
$currentMonthGrid = $currentMonthGridFactory->getGrid($searchCriteria);
$currentDayGrid = $currentDayGridFactory->getGrid($searchCriteria);
return $this->render('@Modules/blockwishlist/views/templates/admin/statistics.html.twig', [
'allTimeStatisticsGrid' => $this->presentGrid($allTimeStatisticsGrid),
'currentYearStatisticsGrid' => $this->presentGrid($currentYearGrid),
'currentMonthStatisticsGrid' => $this->presentGrid($currentMonthGrid),
'currentDayStatisticsGrid' => $this->presentGrid($currentDayGrid),
'shopId' => $this->shopId,
'enableSidebar' => true,
'help_link' => $this->generateSidebarLink('WishlistConfigurationAdminController'),
]);
}
public function resetStatisticsCacheAction()
{
$result = $this->cache->delete(BaseGridDataFactory::CACHE_KEY_STATS_ALL_TIME . $this->shopId)
&& $this->cache->delete(BaseGridDataFactory::CACHE_KEY_STATS_CURRENT_DAY . $this->shopId)
&& $this->cache->delete(BaseGridDataFactory::CACHE_KEY_STATS_CURRENT_MONTH . $this->shopId)
&& $this->cache->delete(BaseGridDataFactory::CACHE_KEY_STATS_CURRENT_YEAR . $this->shopId);
return new JsonResponse(['success' => $result]);
}
/**
* handleForm
*
* @param array $datas
*
* @return bool
*/
private function handleForm($datas)
{
$result = true;
$defaultLanguageId = (int) Configuration::get('PS_LANG_DEFAULT');
if (isset($datas['WishlistPageName'])) {
foreach ($datas['WishlistPageName'] as $langID => $value) {
if (empty($value) && $langID != $defaultLanguageId) {
$value = $datas['WishlistPageName'][$defaultLanguageId];
}
$result = $result && Configuration::updateValue('blockwishlist_WishlistPageName', [$langID => $value]);
}
}
if (isset($datas['WishlistDefaultTitle'])) {
foreach ($datas['WishlistDefaultTitle'] as $langID => $value) {
if (empty($value) && $langID != $defaultLanguageId) {
$value = $datas['WishlistDefaultTitle'][$defaultLanguageId];
}
$result = $result && Configuration::updateValue('blockwishlist_WishlistDefaultTitle', [$langID => $value]);
}
}
if (isset($datas['CreateButtonLabel'])) {
foreach ($datas['CreateButtonLabel'] as $langID => $value) {
if (empty($value) && $langID != $defaultLanguageId) {
$value = $datas['CreateButtonLabel'][$defaultLanguageId];
}
$result = $result && Configuration::updateValue('blockwishlist_CreateButtonLabel', [$langID => $value]);
}
}
if ($result === true) {
$this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success'));
}
return $result;
}
/**
* getWishlistConfigurationDatas
*
* @return array
*/
private function getWishlistConfigurationDatas()
{
$languages = Language::getLanguages(true);
$wishlistNames = $wishlistDefaultTitles = $wishlistCreateNewButtonsLabel = [];
foreach ($languages as $lang) {
$wishlistNames[$lang['id_lang']] = Configuration::get('blockwishlist_WishlistPageName', $lang['id_lang']);
$wishlistDefaultTitles[$lang['id_lang']] = Configuration::get('blockwishlist_WishlistDefaultTitle', $lang['id_lang']);
$wishlistCreateNewButtonsLabel[$lang['id_lang']] = Configuration::get('blockwishlist_CreateButtonLabel', $lang['id_lang']);
}
$datas = [
'WishlistPageName' => $wishlistNames,
'WishlistDefaultTitle' => $wishlistDefaultTitles,
'CreateButtonLabel' => $wishlistCreateNewButtonsLabel,
];
return $datas;
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Database;
use BlockWishList;
use Configuration;
use Db;
use Language;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tab;
class Install
{
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function run()
{
return $this->installTables()
&& $this->installConfiguration()
&& $this->installTabs();
}
public function installTables()
{
$sql = [];
$sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'wishlist` (
`id_wishlist` int(10) unsigned NOT NULL auto_increment,
`id_customer` int(10) unsigned NOT NULL,
`id_shop` int(10) unsigned default 1,
`id_shop_group` int(10) unsigned default 1,
`token` varchar(64) NOT NULL,
`name` varchar(64) NOT NULL,
`counter` int(10) unsigned NULL,
`date_add` datetime NOT NULL,
`date_upd` datetime NOT NULL,
`default` int(10) unsigned default 0,
PRIMARY KEY (`id_wishlist`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;';
$sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'wishlist_product` (
`id_wishlist_product` int(10) NOT NULL auto_increment,
`id_wishlist` int(10) unsigned NOT NULL,
`id_product` int(10) unsigned NOT NULL,
`id_product_attribute` int(10) unsigned NOT NULL,
`quantity` int(10) unsigned NOT NULL,
`priority` int(10) unsigned NOT NULL,
PRIMARY KEY (`id_wishlist_product`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;';
$sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'wishlist_product_cart` (
`id_wishlist_product` int(10) unsigned NOT NULL,
`id_cart` int(10) unsigned NOT NULL,
`quantity` int(10) unsigned NOT NULL,
`date_add` datetime NOT NULL
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;';
$sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'blockwishlist_statistics` (
`id_statistics` int(10) unsigned NOT NULL auto_increment,
`id_cart` int(10) unsigned default NULL,
`id_product` int(10) unsigned NOT NULL,
`id_product_attribute` int(10) unsigned NOT NULL,
`date_add` datetime NOT NULL,
`id_shop` int(10) unsigned default 1,
PRIMARY KEY (`id_statistics`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8;';
$result = true;
foreach ($sql as $query) {
$result = $result && Db::getInstance()->execute($query);
}
return $result;
}
public function installConfiguration()
{
$pageName = $defaultName = $createButtonLabel = [];
foreach (Language::getLanguages() as $lang) {
$pageName[$lang['id_lang']] = $this->translator->trans('My wishlists', [], 'Modules.Blockwishlist.Admin', $lang['locale']);
$defaultName[$lang['id_lang']] = $this->translator->trans('My wishlist', [], 'Modules.Blockwishlist.Admin', $lang['locale']);
$createButtonLabel[$lang['id_lang']] = $this->translator->trans('Create new list', [], 'Modules.Blockwishlist.Admin', $lang['locale']);
}
return Configuration::updateValue('blockwishlist_WishlistPageName', $pageName)
&& Configuration::updateValue('blockwishlist_WishlistDefaultTitle', $defaultName)
&& Configuration::updateValue('blockwishlist_CreateButtonLabel', $createButtonLabel);
}
public function installTabs()
{
$installTabCompleted = true;
foreach (BlockWishList::MODULE_ADMIN_CONTROLLERS as $controller) {
if (Tab::getIdFromClassName($controller['class_name'])) {
continue;
}
$tab = new Tab();
$tab->class_name = $controller['class_name'];
$tab->active = $controller['visible'];
foreach (Language::getLanguages() as $lang) {
$tab->name[$lang['id_lang']] = $this->translator->trans($controller['name'], [], 'Modules.BlockWishList.Admin', $lang['locale']);
}
$tab->id_parent = Tab::getIdFromClassName($controller['parent_class_name']);
$tab->module = 'blockwishlist';
$installTabCompleted = $installTabCompleted && $tab->add();
}
return $installTabCompleted;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Database;
use BlockWishList;
use Db;
use Tab;
use Validate;
class Uninstall
{
public function run()
{
return $this->dropTables() && $this->uninstallTabs();
}
private function dropTables()
{
$sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'wishlist`';
$sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'wishlist_product`';
$sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'wishlist_product_cart`';
$sql[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'blockwishlist_statistics`';
$result = true;
foreach ($sql as $query) {
$result = $result && Db::getInstance()->execute($query);
}
return $result;
}
private function uninstallTabs()
{
$uninstallTabCompleted = true;
foreach (BlockWishList::MODULE_ADMIN_CONTROLLERS as $controller) {
$id_tab = (int) Tab::getIdFromClassName($controller['class_name']);
$tab = new Tab($id_tab);
if (Validate::isLoadedObject($tab)) {
$uninstallTabCompleted = $uninstallTabCompleted && $tab->delete();
}
}
return $uninstallTabCompleted;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,44 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Data;
use PrestaShop\PrestaShop\Core\Grid\Data\Factory\GridDataFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\GridData;
use PrestaShop\PrestaShop\Core\Grid\Record\RecordCollection;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
class AllTimeStatisticsGridDataFactory extends BaseGridDataFactory implements GridDataFactoryInterface
{
// 1 month
const CACHE_LIFETIME_SECONDS = 2629746;
public function getData(SearchCriteriaInterface $searchCriteria)
{
if ($this->cache->contains(self::CACHE_KEY_STATS_ALL_TIME . $this->shopId)) {
$results = $this->cache->fetch(self::CACHE_KEY_STATS_ALL_TIME . $this->shopId);
} else {
$results = $this->calculator->computeStatsFor('allTime');
$this->cache->save(self::CACHE_KEY_STATS_ALL_TIME . $this->shopId, $results, self::CACHE_LIFETIME_SECONDS);
}
return new GridData(new RecordCollection($results), count($results));
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Data;
use Doctrine\Common\Cache\CacheProvider;
use PrestaShop\Module\BlockWishList\Calculator\StatisticsCalculator;
class BaseGridDataFactory
{
const CACHE_KEY_STATS_CURRENT_DAY = 'blockwishlist.stats.currentDay';
const CACHE_KEY_STATS_CURRENT_MONTH = 'blockwishlist.stats.currentMonth';
const CACHE_KEY_STATS_CURRENT_YEAR = 'blockwishlist.stats.currentYear';
const CACHE_KEY_STATS_ALL_TIME = 'blockwishlist.stats.allTime';
/* @var CacheProvider $cache */
protected $cache;
/* @var StatisticsCalculator $calculator */
protected $calculator;
/**
* @var int|null
*/
protected $shopId;
public function __construct(CacheProvider $cache, StatisticsCalculator $calculator, $shopId)
{
$this->cache = $cache;
$this->calculator = $calculator;
$this->shopId = $shopId;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Data;
use PrestaShop\PrestaShop\Core\Grid\Data\Factory\GridDataFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\GridData;
use PrestaShop\PrestaShop\Core\Grid\Record\RecordCollection;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
class CurrentDayStatisticsGridDataFactory extends BaseGridDataFactory implements GridDataFactoryInterface
{
// 1 day
const CACHE_LIFETIME_SECONDS = 86400;
public function getData(SearchCriteriaInterface $searchCriteria)
{
if ($this->cache->contains(self::CACHE_KEY_STATS_CURRENT_DAY . $this->shopId)) {
$results = $this->cache->fetch(self::CACHE_KEY_STATS_CURRENT_DAY . $this->shopId);
} else {
$results = $this->calculator->computeStatsFor('currentDay');
$this->cache->save(self::CACHE_KEY_STATS_CURRENT_DAY . $this->shopId, $results, self::CACHE_LIFETIME_SECONDS);
}
return new GridData(new RecordCollection($results), count($results));
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Data;
use PrestaShop\PrestaShop\Core\Grid\Data\Factory\GridDataFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\GridData;
use PrestaShop\PrestaShop\Core\Grid\Record\RecordCollection;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
class CurrentMonthStatisticsGridDataFactory extends BaseGridDataFactory implements GridDataFactoryInterface
{
// 1 week
const CACHE_LIFETIME_SECONDS = 604800;
public function getData(SearchCriteriaInterface $searchCriteria)
{
if ($this->cache->contains(self::CACHE_KEY_STATS_CURRENT_MONTH . $this->shopId)) {
$results = $this->cache->fetch(self::CACHE_KEY_STATS_CURRENT_MONTH . $this->shopId);
} else {
$results = $this->calculator->computeStatsFor('currentMonth');
$this->cache->save(self::CACHE_KEY_STATS_CURRENT_MONTH . $this->shopId, $results, self::CACHE_LIFETIME_SECONDS);
}
return new GridData(new RecordCollection($results), count($results));
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Data;
use PrestaShop\PrestaShop\Core\Grid\Data\Factory\GridDataFactoryInterface;
use PrestaShop\PrestaShop\Core\Grid\Data\GridData;
use PrestaShop\PrestaShop\Core\Grid\Record\RecordCollection;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
class CurrentYearStatisticsGridDataFactory extends BaseGridDataFactory implements GridDataFactoryInterface
{
// 1 month
const CACHE_LIFETIME_SECONDS = 2629746;
public function getData(SearchCriteriaInterface $searchCriteria)
{
if ($this->cache->contains(self::CACHE_KEY_STATS_CURRENT_YEAR . $this->shopId)) {
$results = $this->cache->fetch(self::CACHE_KEY_STATS_CURRENT_YEAR . $this->shopId);
} else {
$results = $this->calculator->computeStatsFor('currentYear');
$this->cache->save(self::CACHE_KEY_STATS_CURRENT_YEAR . $this->shopId, $results, self::CACHE_LIFETIME_SECONDS);
}
return new GridData(new RecordCollection($results), count($results));
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Definition;
class AllTimeStatisticsGridDefinitionFactory extends BaseStatisticsGridDefinitionFactory
{
protected function getId()
{
return 'statistics_all_time';
}
protected function getName()
{
return $this->trans('All Time Statistics', [], 'Modules.Blockwishlist.Admin');
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Definition;
use PrestaShop\PrestaShop\Core\Grid\Column\ColumnCollection;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ImageColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\LinkColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\PositionColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\AbstractGridDefinitionFactory;
class BaseStatisticsGridDefinitionFactory extends AbstractGridDefinitionFactory
{
protected function getId()
{
return 'statistics';
}
protected function getName()
{
return $this->trans('Statistics', [], 'Admin.Advparameters.Feature');
}
protected function getColumns()
{
return (new ColumnCollection())
->add((new PositionColumn('position'))
->setName($this->trans('Product', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'id_field' => 'position',
'position_field' => 'position',
'update_route' => '',
])
)
->add((new ImageColumn('image'))
->setOptions([
'src_field' => 'image_small_url',
])
)
->add((new LinkColumn('name'))
->setOptions([
'field' => 'name',
'route' => 'admin_product_form',
'route_param_name' => 'id',
'route_param_field' => 'id_product',
])
)
->add((new DataColumn('reference'))
->setName($this->trans('Reference', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'reference',
])
)
->add((new DataColumn('combination'))
->setName($this->trans('Combination', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'combination',
])
)
->add((new DataColumn('category_name'))
->setName($this->trans('Category', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'category_name',
])
)
->add((new DataColumn('price'))
->setName($this->trans('Price (tax excl.)', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'price',
])
)
->add((new DataColumn('quantity'))
->setName($this->trans('Available Qty', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'quantity',
])
)
->add((new DataColumn('conversionRate'))
->setName($this->trans('Conversion rate', [], 'Modules.Blockwishlist.Admin'))
->setOptions([
'field' => 'conversionRate',
])
)
;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Definition;
class CurrentDayStatisticsGridDefinitionFactory extends BaseStatisticsGridDefinitionFactory
{
protected function getId()
{
return 'statistics_current_day';
}
protected function getName()
{
return $this->trans('Current Day Statistics', [], 'Modules.Blockwishlist.Admin');
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Definition;
class CurrentMonthStatisticsGridDefinitionFactory extends BaseStatisticsGridDefinitionFactory
{
protected function getId()
{
return 'statistics_current_month';
}
protected function getName()
{
return $this->trans('Current Month Statistics', [], 'Modules.Blockwishlist.Admin');
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* 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 Academic Free License version 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/AFL-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.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\BlockWishList\Grid\Definition;
class CurrentYearStatisticsGridDefinitionFactory extends BaseStatisticsGridDefinitionFactory
{
protected function getId()
{
return 'statistics_current_year';
}
protected function getName()
{
return $this->trans('Current Year Statistics', [], 'Modules.Blockwishlist.Admin');
}
}

Some files were not shown because too many files have changed in this diff Show More