first commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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;
|
||||
padding: 0.75rem 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
import initApp from '@components/init';
|
||||
import AddToWishlist from './AddToWishlist';
|
||||
|
||||
const props = [
|
||||
{
|
||||
name: 'url',
|
||||
type: String,
|
||||
},
|
||||
];
|
||||
|
||||
initApp(AddToWishlist, '.wishlist-add-to', props);
|
||||
233
modules/blockwishlist/_dev/front/js/components/Button/Button.vue
Normal file
233
modules/blockwishlist/_dev/front/js/components/Button/Button.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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,
|
||||
};
|
||||
},
|
||||
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.productAttributeId, 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.productAttributeId,
|
||||
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.productAttributeId
|
||||
) {
|
||||
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.productAttributeId,
|
||||
);
|
||||
|
||||
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.productAttributeId = 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.productAttributeId,
|
||||
);
|
||||
|
||||
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>
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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;
|
||||
@@ -0,0 +1,239 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
159
modules/blockwishlist/_dev/front/js/components/Create/Create.vue
Normal file
159
modules/blockwishlist/_dev/front/js/components/Create/Create.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
|
||||
<style lang="scss" type="text/scss">
|
||||
.wishlist {
|
||||
&-create {
|
||||
.wishlist-modal {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
z-index: 1053;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
177
modules/blockwishlist/_dev/front/js/components/Delete/Delete.vue
Normal file
177
modules/blockwishlist/_dev/front/js/components/Delete/Delete.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
|
||||
<style lang="scss" type="text/scss">
|
||||
.wishlist {
|
||||
&-delete {
|
||||
.wishlist-modal {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
z-index: 1053;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
import Vue from 'vue';
|
||||
import prestashop from 'prestashop';
|
||||
|
||||
const EventBus = new Vue();
|
||||
|
||||
window.WishlistEventBus = EventBus;
|
||||
|
||||
prestashop.emit('wishlistEventBusInit');
|
||||
|
||||
export default EventBus;
|
||||
351
modules/blockwishlist/_dev/front/js/components/List/List.vue
Normal file
351
modules/blockwishlist/_dev/front/js/components/List/List.vue
Normal file
@@ -0,0 +1,351 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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;
|
||||
|
||||
> 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;
|
||||
|
||||
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>
|
||||
@@ -0,0 +1,81 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
|
||||
<style lang="scss" type="text/scss">
|
||||
.wishlist {
|
||||
&-login {
|
||||
.wishlist-modal {
|
||||
z-index: 0;
|
||||
|
||||
&.show {
|
||||
z-index: 1053;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
import initApp from '@components/init';
|
||||
import Login from './Login';
|
||||
|
||||
const props = [
|
||||
{
|
||||
name: 'loginText',
|
||||
type: String,
|
||||
},
|
||||
{
|
||||
name: 'cancelText',
|
||||
type: String,
|
||||
},
|
||||
];
|
||||
|
||||
initApp(Login, '.wishlist-login', props);
|
||||
@@ -0,0 +1,87 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
import initApp from '@components/init';
|
||||
import Pagination from './Pagination';
|
||||
|
||||
const props = [];
|
||||
|
||||
initApp(Pagination, '.wishlist-pagination', props);
|
||||
@@ -0,0 +1,608 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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 === '1',
|
||||
'btn-primary': product.customizable === '0'
|
||||
}"
|
||||
:disabled="isDisabled || forceDisable"
|
||||
@click="
|
||||
product.add_to_cart_url || product.customizable === '1'
|
||||
? addToCartAction()
|
||||
: null
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="material-icons shopping-cart"
|
||||
v-if="product.customizable === '0'"
|
||||
>
|
||||
shopping_cart
|
||||
</i>
|
||||
{{ product.customizable === '1' ? 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 === '1') {
|
||||
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 !== '1') {
|
||||
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}¶ms[idWishlist]=${this.listId}¶ms[id_product]=${this.product.id_product}¶ms[id_product_attribute]=${this.product.id_product_attribute}¶ms[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;
|
||||
padding-left: 0.625rem;
|
||||
|
||||
&.btn-secondary {
|
||||
background-color: #dddddd;
|
||||
|
||||
&:hover {
|
||||
background-color: #dddddd;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
margin-top: -0.1875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-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>
|
||||
133
modules/blockwishlist/_dev/front/js/components/Rename/Rename.vue
Normal file
133
modules/blockwishlist/_dev/front/js/components/Rename/Rename.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
|
||||
<style lang="scss" type="text/scss" scoped>
|
||||
.wishlist {
|
||||
&-rename {
|
||||
.wishlist-modal {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
z-index: 1051;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
132
modules/blockwishlist/_dev/front/js/components/Share/Share.vue
Normal file
132
modules/blockwishlist/_dev/front/js/components/Share/Share.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
|
||||
<style lang="scss" type="text/scss">
|
||||
.wishlist {
|
||||
&-share {
|
||||
.wishlist-modal {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
z-index: 1053;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
151
modules/blockwishlist/_dev/front/js/components/Toast/Toast.vue
Normal file
151
modules/blockwishlist/_dev/front/js/components/Toast/Toast.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
64
modules/blockwishlist/_dev/front/js/components/init.js
Normal file
64
modules/blockwishlist/_dev/front/js/components/init.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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,
|
||||
});
|
||||
});
|
||||
}
|
||||
11
modules/blockwishlist/_dev/front/js/constants/headers.js
Normal file
11
modules/blockwishlist/_dev/front/js/constants/headers.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const headers = {
|
||||
addToCart: {
|
||||
Accept: 'application/json, text/javascript',
|
||||
},
|
||||
products: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json, text/javascript, */*; q=0.01',
|
||||
},
|
||||
};
|
||||
|
||||
export default headers;
|
||||
@@ -0,0 +1,366 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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="col-sm-3 col-md-3 hidden-sm-down sort-by">{{ filter }}</span>
|
||||
<div class="col-sm-9 col-xs-8 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%;
|
||||
}
|
||||
}
|
||||
|
||||
.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>
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
@@ -0,0 +1,172 @@
|
||||
<!--**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*-->
|
||||
<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>
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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);
|
||||
36
modules/blockwishlist/_dev/front/js/graphql/client.js
Normal file
36
modules/blockwishlist/_dev/front/js/graphql/client.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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,
|
||||
});
|
||||
31
modules/blockwishlist/_dev/front/js/graphql/link.js
Normal file
31
modules/blockwishlist/_dev/front/js/graphql/link.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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,
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export default gql`
|
||||
mutation deleteList($listId: Int!, $url: String!) {
|
||||
deleteList(listId: $listId, url: $url) {
|
||||
success
|
||||
message
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export default gql`
|
||||
mutation shareList($listId: Int!, $userId: Int!) {
|
||||
shareList(listId: $listId, userId: $userId) {
|
||||
url
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export default gql`
|
||||
query lists($url: String!) {
|
||||
lists(url: $url) {
|
||||
id_wishlist
|
||||
name
|
||||
listUrl
|
||||
shareUrl
|
||||
nbProducts
|
||||
default
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export default gql`
|
||||
query getProducts($listId: Int!, $url: String!) {
|
||||
products(listId: $listId, url: $url) {
|
||||
datas
|
||||
}
|
||||
}
|
||||
`;
|
||||
197
modules/blockwishlist/_dev/front/js/graphql/resolvers.js
Normal file
197
modules/blockwishlist/_dev/front/js/graphql/resolvers.js
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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}¶ms[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}¶ms[name]=${name}¶ms[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}¶ms[id_product]=${productId}¶ms[idWishList]=${listId}¶ms[quantity]=${quantity}¶ms[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}¶ms[id_product]=${productId}¶ms[idWishList]=${listId}¶ms[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}¶ms[idWishList]=${listId}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
const datas = await response.json();
|
||||
|
||||
return datas;
|
||||
},
|
||||
},
|
||||
};
|
||||
64
modules/blockwishlist/_dev/front/js/graphql/types.js
Normal file
64
modules/blockwishlist/_dev/front/js/graphql/types.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
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
|
||||
}
|
||||
`;
|
||||
54
modules/blockwishlist/_dev/front/js/pages/list/index.js
Normal file
54
modules/blockwishlist/_dev/front/js/pages/list/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 2007-2020 PrestaShop and Contributors
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* 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 <contact@prestashop.com>
|
||||
* @copyright 2007-2020 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user