This commit is contained in:
2025-04-01 00:38:54 +02:00
parent d4d4c0c09d
commit 87da06293a
22351 changed files with 5168854 additions and 7538 deletions

View 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';
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 (event.detail.productAttributeId) {
this.productAttributeId = event.detail.productAttributeId;
}
if (event.detail.quantity) {
this.quantity = event.detail.quantity;
}
});
},
};
</script>
<style lang="scss" type="text/scss" scoped>
@import '@scss/_variables';
.wishlist {
&-add-to-new {
cursor: pointer;
transition: 0.2s ease-out;
height: 16px;
width: 79px;
font-size: 14px;
letter-spacing: 0;
line-height: 16px;
&:not([href]):not([tabindex]) {
color: $blue;
}
&:hover {
opacity: 0.7;
}
i {
margin-right: 5px;
vertical-align: middle;
color: $blue;
margin-top: -2px;
font-size: 20px;
}
}
&-add-to {
.modal {
&-body {
padding: 0;
}
&-footer {
text-align: left;
padding: 12px 20px;
}
}
}
}
</style>

View File

@@ -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);

View File

@@ -0,0 +1,230 @@
<!--**
* 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) {
this.isChecked = true;
this.idList = event.detail.listId;
}
});
// eslint-disable-next-line
const items = productsAlreadyTagged.filter(
(e) => e.id_product === this.productId.toString()
&& e.id_product_attribute === this.productAttributeId.toString(),
);
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 = args.id_product_attribute;
// eslint-disable-next-line
const itemsFiltered = productsAlreadyTagged.filter(
(e) => e.id_product === this.productId.toString()
&& e.quantity === quantity.value
&& e.id_product_attribute === this.productAttributeId.toString(),
);
if (itemsFiltered.length > 0) {
this.isChecked = true;
this.idList = parseInt(items[0].id_wishlist, 10);
} else {
this.isChecked = false;
}
});
}
},
};
</script>
<style lang="scss" type="text/scss">
.wishlist {
&-button {
&-product {
margin-left: 20px;
}
&-add {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
min-width: 40px;
padding-top: 3px;
background-color: #ffffff;
box-shadow: 2px 2px 4px 0 rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
transition: 0.2s ease-out;
border: none;
&:hover {
opacity: 0.7;
}
&:focus {
outline: 0;
}
&:active {
transform: scale(1.2);
}
i {
color: #7a7a7a;
}
}
}
}
</style>

View File

@@ -0,0 +1,51 @@
/**
* 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;

View File

@@ -0,0 +1,234 @@
<!--**
* 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},
});
},
},
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: scroll;
border-top: 1px solid #e5e5e5;
border-bottom: 1px solid #e5e5e5;
margin: 0;
&-empty {
font-size: 30;
text-align: center;
padding: 30px;
padding-bottom: 20px;
font-weight: bold;
color: #000;
}
&-item {
padding: 14px 0;
transition: 0.25s ease-out;
cursor: pointer;
&:hover {
background: lighten($blue, 45%);
}
p {
font-size: 14px;
letter-spacing: 0;
color: #232323;
margin-bottom: 0;
line-height: 16px;
padding: 0 40px;
}
}
}
}
</style>

View File

@@ -0,0 +1,160 @@
<!--**
* 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" scoped>
.wishlist {
&-create {
.wishlist-modal {
display: block;
opacity: 0;
pointer-events: none;
z-index: 0;
&.show {
opacity: 1;
pointer-events: all;
z-index: 1053;
}
}
}
}
</style>

View File

@@ -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);

View 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" scoped>
.wishlist {
&-delete {
.wishlist-modal {
display: block;
opacity: 0;
pointer-events: none;
z-index: 0;
&.show {
opacity: 1;
pointer-events: all;
z-index: 1053;
}
}
}
}
</style>

View File

@@ -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);

View File

@@ -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;

View 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: 30;
text-align: center;
padding: 30px;
padding-bottom: 20px;
font-weight: bold;
color: #000;
}
&-loader {
padding: 0 20px;
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: 24px 20px;
}
.dropdown-menu {
right: 20px;
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: 4px;
background-color: #ffffff;
box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.2);
padding: 0;
overflow: hidden;
> button {
padding: 10px 20px;
transition: 0.2s ease-out;
text-align: left;
&:hover {
background-color: #f1f1f1;
}
}
}
}
&-title {
color: #232323;
font-size: 16px;
font-weight: bold;
letter-spacing: 0;
line-height: 22px;
margin-bottom: 0;
span {
color: #7a7a7a;
font-size: 16px;
letter-spacing: 0;
line-height: 22px;
font-weight: normal;
margin-left: 5px;
}
}
button {
cursor: pointer;
border: none;
background: none;
&:focus {
outline: 0;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,86 @@
<!--**
* 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" scoped>
.wishlist {
&-login {
.wishlist-modal {
display: block;
opacity: 0;
pointer-events: none;
z-index: 0;
&.show {
opacity: 1;
pointer-events: all;
z-index: 1053;
}
}
}
}
</style>

View File

@@ -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);

View File

@@ -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: 30px;
}
.js-search-link {
cursor: pointer;
&:not([href]):not([tabindex]):hover {
color: $blue;
}
&.disabled {
cursor: inherit;
&:hover {
color: $blue;
}
}
}
}
}
</style>

View File

@@ -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);

View File

@@ -0,0 +1,578 @@
<!--**
* 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"
@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,
};
},
computed: {
isDisabled() {
if (this.product.customizable === '1') {
return false;
}
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 {
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();
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,
});
/* eslint-disable */
const statResponse = await fetch(
`${wishlistAddProductToCartUrl}&params[idWishlist]=${this.listId}&params[id_product]=${this.product.id_product}&params[id_product_attribute]=${this.product.id_product_attribute}&params[quantity]=${this.product.wishlist_quantity}`,
{
headers: {
'Content-Type':
'application/x-www-form-urlencoded; charset=UTF-8',
Accept: 'application/json, text/javascript, */*; q=0.01'
}
}
);
/* eslint-enable */
await statResponse.json();
} catch (error) {
prestashop.emit('handleError', {
eventType: 'addProductToCart',
resp: error,
});
}
} else {
window.location.href = this.product.canonical_url;
}
},
},
};
</script>
<style lang="scss" type="text/scss">
@import '@scss/_variables';
.wishlist {
&-products-item {
margin: 25px;
}
&-product {
max-width: 250px;
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: 12px;
font-weight: bold;
letter-spacing: 0;
line-height: 17px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 17px;
z-index: 5;
min-width: 80%;
justify-content: center;
i {
color: #ff4c4c;
margin-right: 5px;
font-size: 18px;
}
&-responsive {
display: none;
position: inherit;
transform: inherit;
bottom: inherit;
margin-top: 10px;
left: inherit;
}
}
&-link {
&:focus {
text-decoration: none;
}
&:hover {
img {
transform: translate(-50%, -50%) scale(1.1);
}
}
}
&-title {
margin-top: 10px;
margin-bottom: 5px;
color: #737373;
font-size: 14px;
letter-spacing: 0;
line-height: 19px;
}
&-image {
width: 250px;
height: 250px;
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: 16px;
font-weight: bold;
letter-spacing: 0;
line-height: 22px;
&-promo {
text-decoration: line-through;
color: #737373;
font-size: 14px;
font-weight: bold;
letter-spacing: 0;
line-height: 19px;
margin-right: 5px;
vertical-align: middle;
display: inline-block;
margin-top: -3px;
}
}
&-combinations {
display: flex;
align-items: flex-start;
justify-content: space-between;
a {
display: block;
color: #7a7a7a;
&:hover {
color: $blue;
}
}
&-text {
color: #7a7a7a;
font-size: 13px;
letter-spacing: 0;
line-height: 20px;
min-height: 50px;
margin: 0;
}
}
&-addtocart {
width: 100%;
text-transform: inherit;
padding-left: 10px;
&.btn-secondary {
background-color: #dddddd;
&:hover {
background-color: #dddddd;
opacity: 0.7;
}
}
i {
margin-top: -3px;
}
}
}
&-button {
&-add {
position: absolute;
top: 10px;
right: 10px;
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
min-width: 40px;
padding-top: 3px;
background-color: #ffffff;
box-shadow: 2px 2px 4px 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: -2px;
}
}
}
}
@media screen and (max-width: 768px) {
.wishlist {
&-button-add {
position: inherit;
margin-left: 10px;
}
&-products-item {
width: 100%;
margin: 0;
margin-bottom: 30px;
&:not(:last-child) {
margin-bottom: 30px;
}
}
&-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: 20px;
position: inherit;
img {
position: inherit;
left: inherit;
top: inherit;
transform: inherit;
}
}
&-link {
display: flex;
align-items: flex-start;
}
&-title {
margin-top: 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,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>

View File

@@ -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);

View 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" scoped>
.wishlist {
&-create {
.wishlist-modal {
display: block;
opacity: 0;
pointer-events: none;
z-index: 0;
&.show {
opacity: 1;
pointer-events: all;
z-index: 1053;
}
}
}
}
</style>

View File

@@ -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);

View File

@@ -0,0 +1,150 @@
<!--**
* 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: 14px 20px;
box-sizing: border-box;
border: 1px solid #e5e5e5;
border-radius: 4px;
background-color: #ffffff;
box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.2);
position: fixed;
right: 20px;
z-index: 9999;
top: 70px;
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: 14px;
letter-spacing: 0;
line-height: 19px;
margin-bottom: 0;
}
}
}
</style>

View File

@@ -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);

View 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,
});
});
}