This guide covers building a wishlist page on headless storefronts.
Step 1: Add wrapper functions that call Swym APIs to support the Wishlist Page
Code Overview:
callDeleteProductFromWishlist(): This function calls the update-ctx API and uses the 'd' parameter (for delete) to delete a product from a list.
callFetchPublicListAPI(): This function calls the markPublic API to mark a list 'public' in order to allow sharing it.
callShareEmailAPI(): This function calls the emailList API to share a publicly marked list to a user email from Swym.
getSwymLocalStorage: These component is found in our utilities file shared in the first page of this guide. If you haven't already, click here to view our guide.
callGenrateRegidAPI: This component is found in the store-api.js file shared in the second page of this guide. If you haven't already, click here to view our guide.
SWYM_CONFIG: This file needs to be setup to store API keys, endpoints, etc. If you haven't set it up already, click here.
callFetchWishlistedProductAPI(): This function calls the fetch-list-with-contents API to fetch all lists of a user with their respective products.
import {getSwymLocalStorage} from '../Utils/Utils';
import {callGenrateRegidAPI} from './store-apis';
import {v4 as uuidv4} from 'uuid';
import SWYM_CONFIG from '../swym.config';
const SWYM_PID = SWYM_CONFIG.PID;
/*
@notice: get wishlisted product by regid
@dev: for single list use this to check if product is wishlisted or not.
@author: swym
@return: array of wishlisted products
*/
export const callFetchWishlistedProductAPI = async () => {
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
const swymConfig = getSwymLocalStorage();
if (!swymConfig || !swymConfig.regid) {
await callGenrateRegidAPI({
username: null,
uuid: uuidv4(),
cb: () => callFetchWishlistedProductAPI(),
});
} else {
var urlencoded = new URLSearchParams();
urlencoded.append('regid', swymConfig.regid);
urlencoded.append('sessionid', swymConfig.sessionid);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow',
};
return fetch(
`${
SWYM_CONFIG.ENDPOINT
}api/v3/lists/fetch-list-with-contents?pid=${encodeURIComponent(SWYM_PID)}`,
requestOptions,
)
.then((response) => response.json())
.then((result) => {
return result;
})
.catch((error) => {
console.log('error', error);
return error;
});
}
};
/*
@notice: to remove product from wishlisted items
@dev: delete product from swym wishlisted products
@author: swym
*/
export const callDeleteProductFromWishlist = async (productData) => {
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
const swymConfig = getSwymLocalStorage();
var urlencoded = new URLSearchParams();
urlencoded.append('regid', swymConfig.regid);
urlencoded.append('sessionid', swymConfig.sessionid);
urlencoded.append('lid', productData.lid);
urlencoded.append(
'd',
`[{ "epi":${productData.epi}, "empi": ${productData.empi}, "du":"${productData.du}"}]`,
);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow',
};
return fetch(
`${SWYM_CONFIG.ENDPOINT}api/v3/lists/update-ctx?pid=${encodeURIComponent(
SWYM_PID,
)}`,
requestOptions,
)
.then((response) => response.json())
.then((result) => {
return result;
})
.catch((error) => {
console.log('error', error);
return error;
});
};
/*
@notice: -
@dev: to mark the list id as public for list sharing
@author: swym
@params: lid - list id of the particular wishlist
*/
export const callFetchPublicListAPI = async (lid) => {
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
const swymConfig = getSwymLocalStorage();
if (!swymConfig || !swymConfig.regid) {
await callGenrateRegidAPI({
username: null,
uuid: uuidv4(),
cb: () => callFetchPublicListAPI(lid),
});
} else {
// console.log("here in wishlist page")
var urlencoded = new URLSearchParams();
urlencoded.append('regid', swymConfig.regid);
urlencoded.append('sessionid', swymConfig.sessionid);
urlencoded.append('lid', lid);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow',
};
return fetch(
`${SWYM_CONFIG.ENDPOINT}api/v3/lists/markPublic?pid=${encodeURIComponent(
SWYM_PID,
)}`,
requestOptions,
)
.then((response) => response.json())
.then((result) => {
return result;
})
.catch((error) => {
console.log('error', error);
return error;
});
}
};
/*
@notice: an email is sent to the given email with the selected list products
@dev: share wishlist via email
@author: swym
@params: publicLid - the list id which has been marked public previously
@params: senderName - the name of the sender/username of the person who has logged in
@params: emailValue - recipent's email address
*/
export const callShareEmailAPI = async (publicLid, senderName, emailValue) => {
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
const swymConfig = getSwymLocalStorage();
if (!swymConfig || !swymConfig.regid) {
await callGenrateRegidAPI({
username: null,
uuid: uuidv4(),
cb: () => callShareEmailAPI(publicLid, senderName, emailValue),
});
} else {
var urlencoded = new URLSearchParams();
urlencoded.append('regid', swymConfig.regid);
urlencoded.append('sessionid', swymConfig.sessionid);
urlencoded.append('lid', publicLid);
urlencoded.append('fromname', senderName);
urlencoded.append('toemail', emailValue);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow',
};
return fetch(
`${SWYM_CONFIG.ENDPOINT}api/v3/lists/emailList?pid=${encodeURIComponent(
SWYM_PID,
)}`,
requestOptions,
)
.then((response) => response.json())
.then((result) => {
return result;
})
.catch((error) => {
console.log('error', error);
return error;
});
}
};
/*
@notice: a link is copied to clipboard which can be used to share the wishlist
@dev: share wishlist via copy link
@author: swym
@params: publicLid - the list id which has been marked public previously
@params: the medium through which we are sharing the list(copyLink, email etc)
@params: sharedurl -
@params: shareListSenderName - the name of the sender/username of the person who has logged in
*/
export const callCopyLinkAPI = async (
publicLid,
medium,
sharedurl,
shareListSenderName,
) => {
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded');
const swymConfig = getSwymLocalStorage();
if (!swymConfig || !swymConfig.regid) {
await callGenrateRegidAPI({
username: null,
uuid: uuidv4(),
cb: () =>
callCopyLinkAPI(publicLid, medium, sharedurl, shareListSenderName),
});
} else {
var urlencoded = new URLSearchParams();
urlencoded.append('regid', swymConfig.regid);
urlencoded.append('sessionid', swymConfig.sessionid);
urlencoded.append('lid', publicLid);
urlencoded.append('fromname', shareListSenderName);
urlencoded.append('medium', medium);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow',
};
return fetch(
`${SWYM_CONFIG.ENDPOINT}api/v3/lists/reportShare?pid=${encodeURIComponent(
SWYM_PID,
)}`,
requestOptions,
)
.then((response) => response.json())
.then((result) => {
return result;
})
.catch((error) => {
console.log('error', error);
return error;
});
}
};
Step 2: Add a component to render a wishlist product tile
Code Overview:
wishlistItem(): Main function that renders a wishlisted product tile.
import { AddToCartButton, ProductOptionsProvider } from '@shopify/hydrogen';
import './wishlistItem.css';
export default function wishlistItem({ productId, variantId, product, readOnly = true , onRemoveItem }){
return (
<div className='swym-hl-listitem'>
<div className='swym-hl-wishlist-item-content'>
<a className='' aria-label={product['dt']} href={product.cprops?.ou} >
<img
className="w-full"
alt={product['dt'] || 'Product Image'}
src={product['iu']}
/>
<div className="swym-hl-list-item-title">{product['dt']}</div>
<div className='swym-hl-list-item-vendor'>{product['bt']}</div>
<div className="swym-hl-list-item-price">${product['pr']}</div>
</a>
<ProductOptionsProvider
data={{
id: `gid://shopify/Product/${productId}`,
title: product.dt,
vendor: product.bt,
variants: [
{
id: `gid://shopify/ProductVariant/${variantId}`,
},
],
}}
>
<AddToCartButton className='swym-hl-addtocart-btn swym-hl-bg-color swym-hl-text-color' variantId={`gid://shopify/ProductVariant/${variantId}`} >Add To Cart</AddToCartButton>
</ProductOptionsProvider>
</div>
{!readOnly && (
<div className='swym-hl-listitem-delete-btn' onClick={onRemoveItem}>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
width={12}
height={12}
viewBox="0 0 512 512"
>
<path fill="currentColor" d="M443.6 387.1 312.4 255.4l131.5-130c5.4-5.4 5.4-14.2 0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4-3.7 0-7.2 1.5-9.8 4L256 197.8 124.9 68.3c-2.6-2.6-6.1-4-9.8-4-3.7 0-7.2 1.5-9.8 4L68 105.9c-5.4 5.4-5.4 14.2 0 19.6l131.5 130L68.4 387.1c-2.6 2.6-4.1 6.1-4.1 9.8 0 3.7 1.4 7.2 4.1 9.8l37.4 37.6c2.7 2.7 6.2 4.1 9.8 4.1 3.5 0 7.1-1.3 9.8-4.1L256 313.1l130.7 131.1c2.7 2.7 6.2 4.1 9.8 4.1 3.5 0 7.1-1.3 9.8-4.1l37.4-37.6c2.6-2.6 4.1-6.1 4.1-9.8-.1-3.6-1.6-7.1-4.2-9.7z" />
</svg>
</div>
)}
</div>
)
}
.swym-hl-listitem{
width: 24%;
position: relative;
}
.swym-hl-wishlist-item-content{
display: flex;
overflow: hidden;
flex-direction: column;
flex: 1 1 0%;
justify-content: space-between;
border-radius: 0.25rem;
height: 100%;
padding: 0.5rem;
border-width: 1px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.swym-hl-listitem-delete-btn{
position: absolute;
top: 5px;
right: 5px;
padding: 8px;
cursor: pointer;
color: gray;
background: white;
border-radius: 50%;
box-shadow: 0 0.5px 0.7px 0.5px lightgray;
}
.swym-hl-list-item-title{
font-size: 16px;
margin-top: 5px;
margin-bottom: 5px;
font-weight: bold;
}
.swym-hl-list-item-vendor{
font-size: 14px;
margin-bottom: 10px;
}
.swym-hl-list-item-price{
font-size: 14px;
margin-bottom: 15px;
font-weight: bold;
}
.swym-hl-addtocart-btn{
padding: 1rem;
border-radius: 0.25rem;
width: 100%;
}
@media only screen and (min-width: 600px) and (max-width: 900px) {
.swym-hl-listitem{
width: 32%;
}
}
@media screen and (max-width: 600px) {
.swym-hl-listitem{
width: 48%;
}
}
.swym-hl-listitem:hover{
transform: scale(1.05);
transition: transform 0.1s ease-in-out;
}
Step 3: Component to render the share wishlist modal.
Code Overview:
callMarkListPublicAPI(): Function that calls the markPublic API to mark a list public in order to allow sharing.
callShareViaEmail(): Function to handle sharing via email.
callCopyLink(): Function that creates a copy link to allow wishlist sharing via link.
onChangeEmail(): Function to handle email input change and validation on the share form.
import './shareListPopup.css';
import {useEffect, useState, useContext} from 'react';
import STRINGS from '../../../swym/Utils/strings';
import {
callFetchPublicListAPI,
callShareEmailAPI,
callCopyLinkAPI,
} from '../../../swym/api/wishlistPage-apis';
import {DataContext} from '../wishlist-context';
import {
getFullUserName,
getSharedURL,
validateEmail,
} from '../../../swym/Utils/utilsFunction';
import SwymAlert from '../common/Alert';
import SWYM_CONFIG from '../../../swym/swym.config';
export function classNames(...args) {
return args.filter(Boolean).join(' ');
}
/*
@author: swym
@notice: a modal that pops up when clicking the 'share wishlist' button
@dev: handles wishlist sharing - share wishlist via email and copying link
@param: onPopupToggle fn
@param: lid(list id) string
*/
export function ShareWishlist({onPopupToggle, lid}) {
const [senderName, setSenderName] = useState(''); // State for sender name
const [emailValue, setEmailValue] = useState(''); // State for email input value
const [publicLid, setPublicLid] = useState(''); // State for public list ID
const [showAlertBox, setshowAlertBox] = useState(false); // State for showing alert box
const [alertBox, setalertBox] = useState({ type: 'success', title: '', info: '', image: '' }); // State for alert box content
const [shareListLoading, setShareListLoading] = useState(false); // State for loading status
const [emailError, setEmailError] = useState(false); // State for email error
const [buttonDisabled, setButtonDisabled] = useState(true); // State for disabling button
const {
setShareListSenderName,
setSenderEmail,
shareListSenderName,
senderEmail,
} = useContext(DataContext);
let hostName = window.location.host;
let medium = SWYM_CONFIG.swymSharedMediumCopyLink;
let sharedurl = getSharedURL(hostName, publicLid);
// Effect to call API on component mount or lid change
useEffect(() => {
callMarkListPublicAPI();
}, [lid]);
const callMarkListPublicAPI = () => {
callFetchPublicListAPI(lid).then((response) => {
setPublicLid(response?.lid);
setShareListSenderName(
getFullUserName(response?.userinfo?.fname, response?.userinfo?.lname),
);
setSenderEmail(response?.userinfo?.em);
});
};
const callShareViaEmail = (e) => {
e.preventDefault();
setShareListLoading(true);
callShareEmailAPI(publicLid, senderName, emailValue)
.then((response) => {
if (response?.errors) {
setshowAlertBox(true);
setalertBox({ type:'error', title: 'Error', info: 'Email Not Sent' });
} else {
setshowAlertBox(true);
setalertBox({ type:'success', title: 'Success!', info: 'Email Sent Successfully' });
}
})
.catch((e) => {
setshowAlertBox(true);
setalertBox({ type:'error', title: 'Error', info: 'Email Not Sent' });
})
.finally(() => {
setShareListLoading(false);
});
};
const callCopyLink = (e) => {
e.preventDefault();
callCopyLinkAPI(publicLid, medium, sharedurl, shareListSenderName).then(
(response) => {
let sharedurl = getSharedURL(hostName, response?.lid);
navigator.clipboard
.writeText(sharedurl)
.then(() => {
setshowAlertBox(true);
setalertBox({ type:'success', title: 'Success!', info: 'Link Copied' });
})
.catch(() => {
setshowAlertBox(true);
setalertBox({ type:'error', title: 'Error!', info: 'Link could not be copied' });
});
},
);
};
const onChangeEmail = (e) => {
setEmailValue(e.target.value);
const isInvalid = validateEmail(
e.target.value,
STRINGS.ValidationErrorEmail,
);
setEmailError(isInvalid);
if (isInvalid) {
setButtonDisabled(true);
} else {
setButtonDisabled(false);
}
};
return (
<div>
<div id="swym-hl-share-list-popup" className="modal" onClick={(e)=> { e.preventDefault(); e.stopPropagation(); onPopupToggle(false) }}>
<SwymAlert
open={showAlertBox}
toggleAlertState={setshowAlertBox}
title={alertBox.title}
info={alertBox.info}
type={alertBox.type}
/>
<div className="swym-hl-share-modal-content" onClick={(e)=>{e.preventDefault(); e.stopPropagation();}}>
<span className="swym-hl-share-modal-close-btn" onClick={()=>onPopupToggle(false)}>×</span>
<div className="swym-hl-share-heading">
<h3>Share Wishlist</h3>
</div>
<div className="swym-hl-share-body">
<div className="swym-hl-share-content">
<label className="swym-input-label">
{STRINGS.ShareWishlistSenderName}
</label>
<div className="swym-input-label">
<input
type="text"
placeholder={STRINGS.ShareWishlistNamePlaceholder}
id="swym-name"
value={senderName}
onChange={(e) => setSenderName(e.target.value)}
className="swym-share-wishlist-email swym-input swym-no-zoom-fix swym-input-1"
/>
</div>
<label className="swym-input-label">
{STRINGS.ShareWishlistRecipientsEmail}
</label>
<div className="swym-input-label">
<input
type="text"
placeholder={STRINGS.ShareWishlistEmailPlaceholder}
id="swym-email"
value={emailValue}
onChange={(e) => onChangeEmail(e)}
className="swym-share-wishlist-name swym-input swym-no-zoom-fix swym-input-1"
/>
{emailError && (
<span className="error-msg" role="alert">
{emailError}
</span>
)}
</div>
</div>
<div className='swym-hl-share-modal-action'>
<button className='swym-hl-bg-color swym-hl-share-modal-action-btn swym-hl-text-color' onClick={(e) => callShareViaEmail(e)}>{STRINGS.ShareWishlistEmailCTA} </button>
<button className='swym-hl-bg-outline swym-hl-share-modal-action-btn' onClick={(e) => callCopyLink(e)} >
<span style={{fontSize: '16px'}} > {STRINGS.ShareWishlistAlternateShareLabel}:</span>
{STRINGS.ShareWishlistCopyLinkText}
</button>
</div>
</div>
</div>
</div>
</div>
);
}
#swym-hl-share-list-popup{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: #00000061;
}
.swym-hl-share-modal-content {
margin: auto;
padding: 20px;
border: 1px solid #888;
display: flex;
flex-direction: column;
color: #000000;
background-color: #ffffff;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
width: 600px;
position: relative;
}
.swym-hl-share-modal-close-btn{
padding: 4px;
position: absolute;
top: 5px;
right: 15px;
font-size: 25px;
z-index: 100;
cursor: pointer;
}
.swym-hl-share-heading {
display: flex;
position: relative;
box-sizing: border-box;
border-bottom: 1px solid #828282;
padding-left: 0px;
padding-top: 0px;
padding-bottom: 10px;
}
.swym-hl-share-content {
margin-top: 20px;
}
.swym-hl-share-modal-loader{
display: flex;
justify-content: center;
align-item: center;
margin-right: 5px;
}
.swym-hl-share-modal-action-btn{
cursor: pointer;
padding: 8px 26px;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: center;
min-width: 170px;
}
.swym-hl-share-modal-action {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
@media screen and (max-width: 450px) {
.swym-hl-share-modal-action-btn{
width: 100%;
}
}
.swym-input-label {
font-size: 12px;
line-height: 14px;
letter-spacing: 0.05em;
color: #828282;
margin-bottom: 5px;
}
.swym-share-wishlist-email,
.swym-share-wishlist-name {
font-size: 14px;
letter-spacing: 0.05em;
width: 100%;
}
.swym-input-label{
padding-bottom: 20px;
}
.swym-input-has-error {
border: 1px solid #CC0000 !important;
}
.error-msg {
font-size: 12px;
line-height: 14px;
letter-spacing: 0.05em;
color: #CC0000;
font-style: italic;
padding: 5px;
}
.swym-title-new {
padding-top: 0px;
padding-left: 0px;
}
Step 4: Add components for the Wishlist page
Code Overview:
fetchList, fetchListWithContents, fetchSwymAccessToken: These are wrapper functions that call Swym APIs. They can be added from the 'Prepare Client-side APIs' guide.
callDeleteProductFromWishlist: This component is available in step 1 of this guide.
SwymAlert, WishlistContext: This is a component that triggers a success notification after a product has been added/removed from a list. They are present in the components file shared in the Pre-requisites section of the Prepare Server-side APIs... guide.
ShareWishlist: This component is used to render a share wishlist form. The code for this component is found in step 4 of this guide.
setSwymLocalStorageListData: This component saves wishlisted items in localstorage for quicker loading and is found in the utilils folder shared in the Pre-requisites section of the Prepare Server-side APIs... guide.
WishlistItem: This component is used to render a wishlist product tile. The code for this component is found in step 3 of this guide.
EmptyWishlist(): Function to show an empty wishlist view.
WishlistPage(): Main function that renders the Wishlist page.
getSetListItems(): Function to fetch and set items for the selected list
removeFromList(): Function to remove an item from the list state.
removeItemFromWishlist(): Function to remove an item from the wishlist and show an alert.
onShareWishlistClick(): Function to handle share wishlist click.
getSwymAccessToken(): Function to fetch Swym access token.
handleListValueChange(): Function to handle list value change in dropdown.
toggleMenu(): Function to toggle dropdown menu open/close.
wishlistPage.css: The code for styling can be found at the bottom of this page.
import './wishlistPage.css';
import {useEffect, useState} from 'react';
import {callDeleteProductFromWishlist} from '../../../swym/api/wishlistPage-apis';
import {
fetchList,
fetchListWithContents,
fetchSwymAccessToken,
} from '../../../swym/api/store-apis';
import SwymAlert from '../common/Alert';
import {ShareWishlist} from '../shareListPopup/shareListPopup.client';
import WishlistContext from '../wishlist-context';
import { setSwymLocalStorageListData } from '../../../swym/Utils/Utils';
import WishlistItem from '../wishlistItem/wishlistItem.client';
export function EmptyWishlist(){
return (
<div style={{display: 'block', textAlign: 'center'}}>
<br />
<h3 className="swym-hl-empty-wl-title">Love It? Add To My Wishlist</h3>
<br />
<p>
My Wishlist allows you to keep track of all of your favorites and shopping activity whether you're on your computer, phone, or tablet.
</p>
<p className='mt-4'>
You won't have to waste time searching all over again for that item you loved on your phone the other day - it's all here in one place!
</p>
<br />
<button className='swym-hl-continue-shop-btn swym-hl-bg-color swym-hl-text-color' onClick={()=>{
window.location.href = '/products'
}}>Continue Shopping</button>
</div>
)
}
/*
@author: swym
@notice: Page on which user can see all the wishlisted products
@dev: render withslited products. user can add products to cart or remove products from wishlist
@param: it will use regid stored in localstorage to fetch user related activities
*/
export function WishlistPage() {
const [list, setItems] = useState();
const [showAlertBox, setshowAlertBox] = useState(false);
const [alertBox, setalertBox ] = useState({ type: 'success', title:'', info: '', image: null });
const [selectedListIndex, setselectedListIndex] = useState(0);
const [showLoading, setshowLoading] = useState(true);
const [wishlistCreatedLists, setWishlistCreatedLists] = useState([]);
const [openShareModal, setOpenShareModal] = useState(false);
const [swymAccessToken, setSwymAccessToken] = useState(false);
const [variantDeleted, setVariantDeleted] = useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
useEffect(() => {
getSwymAccessToken();
}, [swymAccessToken]);
useEffect(() => {
fetchList()
.then((response) => {
setWishlistCreatedLists(response);
setSwymLocalStorageListData(response);
setshowLoading(false);
})
.catch((e) => console.log(e));
}, [variantDeleted]);
useEffect(() => {
if (wishlistCreatedLists && wishlistCreatedLists.length > 0) {
getSetListItems();
}
}, [wishlistCreatedLists, selectedListIndex]);
const getSetListItems = () => {
fetchListWithContents(wishlistCreatedLists[selectedListIndex]?.lid)
.then((response) => {
setItems(response?.items);
})
.catch((e) => console.log(e));
};
const removeFromList = (empi, epi) => {
if (list) {
let listArray = list.filter(
(listItem) => empi !== listItem.empi && epi !== listItem.epi,
);
setItems(listArray);
}
};
const removeItemFromWishlist = (productData, showDeleteAlert) => {
callDeleteProductFromWishlist(productData)
.then((response) => {
setVariantDeleted((prev) => !prev);
removeFromList(productData.empi, productData.epi);
if (showDeleteAlert) {
setshowAlertBox(true);
setalertBox({ type:'success', title: 'Success', info: `Product removed from wishlist`, image: productData.iu });
}
})
.catch((e) => {
console.log(e);
setshowAlertBox(true);
setalertBox({ type:'error', title: 'Error', info: `Product not removed from wishlist`, image: productData.iu });
});
};
const onShareWishlistClick = (event) => {
event.preventDefault();
setOpenShareModal(true);
};
const getSwymAccessToken = () => {
fetchSwymAccessToken()
.then((response) => {
if (response && response !== '') {
setSwymAccessToken(true);
} else {
setSwymAccessToken(false);
}
})
.catch((e) => {
console.log(e);
});
};
const handleListValueChange = (e, index) => {
setselectedListIndex(index);
e.preventDefault();
setIsDropdownOpen(false);
};
const toggleMenu = () => {
setIsDropdownOpen(!isDropdownOpen);
};
return (
<div>
<WishlistContext>
<SwymAlert
open={showAlertBox}
toggleAlertState={setshowAlertBox}
title={alertBox.title}
info={alertBox.info}
type={alertBox.type}
image={alertBox.image}
/>
{openShareModal && (
<ShareWishlist
onPopupToggle={setOpenShareModal}
lid={wishlistCreatedLists[selectedListIndex]?.lid}
/>
)}
<div className="swym-hl-wishlist-page">
<div className='swym-hl-wishlist-page-title'>
Wishlist
</div>
<br />
{showLoading && (
<div className='swym-hl-wishlist-loader-container'>
<div className='swym-hl-wishlist-loader' style={{ width: '100%', display: 'flex', justifyContent: 'center', padding: '5rem' }}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="50"><radialGradient id="a12" cx=".66" fx=".66" cy=".3125" fy=".3125" gradientTransform="scale(1.5)"><stop offset="0" stopColor="currentColor"></stop><stop offset=".3" stopColor="currentColor" stopOpacity=".9"></stop><stop offset=".6" stopColor="currentColor" stopOpacity=".6"></stop><stop offset=".8" stopColor="currentColor" stopOpacity=".3"></stop><stop offset="1" stopColor="currentColor" stopOpacity="0"></stop></radialGradient><circle transform-origin="center" fill="none" stroke="url(#a12)" strokeWidth="15" strokeLinecap="round" strokeDasharray="200 1000" strokeDashoffset="0" cx="100" cy="100" r="70"><animateTransform type="rotate" attributeName="transform" calcMode="spline" dur="2" values="360;0" keyTimes="0;1" keySplines="0 0 1 1" repeatCount="indefinite"></animateTransform></circle><circle transform-origin="center" fill="none" opacity=".2" stroke="currentColor" strokeWidth="15" strokeLinecap="round" cx="100" cy="100" r="70"></circle></svg>
</div>
</div>
)}
{!showLoading && (
<>
{( !wishlistCreatedLists || wishlistCreatedLists.length == 0 ) && (
<EmptyWishlist />
)}
<div>
{wishlistCreatedLists && wishlistCreatedLists.length > 1 && (
<div>
<div>
<div className="swym-hl-wl-dropdown-container">
<div>
<button onClick={toggleMenu} className="swym-hl-wl-list-dropdown-btn">
{wishlistCreatedLists &&
wishlistCreatedLists.length > 0 &&
wishlistCreatedLists[selectedListIndex].lname}
{!wishlistCreatedLists ||
(wishlistCreatedLists.length == 0 &&
'No list found')}
<svg
className="swym-hl-dropdown-icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fillRule="evenodd"
d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
clipRule="evenodd"
/>
</svg>
</button>
</div>
{isDropdownOpen && (
<div className="swym-hl-wl-dropdown-list">
{wishlistCreatedLists &&
wishlistCreatedLists.length > 0 &&
wishlistCreatedLists.map(({lname}, index) => (
<a
onClick={(e) =>
handleListValueChange(e, index)
}
key={`menu_${index}`}
value={selectedListIndex}
href="#"
className={`swym-hl-wl-dropdown-list-item ${(selectedListIndex == index)?'swym-hl-dropdown-list-item-active':''}`}
>
{lname}
</a>
))}
</div>
)}
</div>
<br />
<br />
</div>
</div>
)}
<div>
<div className="swym-hl-wl-content-header">
<h2 className="swym-hl-wl-selected-lname">
{wishlistCreatedLists &&
wishlistCreatedLists.length > 0 &&
wishlistCreatedLists[selectedListIndex]?.lname}{' '}
{wishlistCreatedLists &&
wishlistCreatedLists.length > 0 &&
` (${wishlistCreatedLists[selectedListIndex]?.listcontents?.length})`}
</h2>
{wishlistCreatedLists &&
wishlistCreatedLists.length > 0 &&
swymAccessToken && (
<div
className="swym-hl-wishlist-page-share-btn"
onClick={(event) => onShareWishlistClick(event)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
width={15}
height={15}
fill="#035587"
viewBox="0 0 458.624 458.624"
>
<path d="M339.588 314.529a71.683 71.683 0 0 0-38.621 11.239l-112.682-78.67a72.036 72.036 0 0 0 2.798-19.871c0-6.896-.989-13.557-2.798-19.871l109.64-76.547c11.764 8.356 26.133 13.286 41.662 13.286 39.79 0 72.047-32.257 72.047-72.047S379.378 0 339.588 0c-39.79 0-72.047 32.257-72.047 72.047 0 5.255.578 10.373 1.646 15.308l-112.424 78.491c-10.974-6.759-23.892-10.666-37.727-10.666-39.79 0-72.047 32.257-72.047 72.047s32.256 72.047 72.047 72.047c13.834 0 26.753-3.907 37.727-10.666l113.292 79.097a72.108 72.108 0 0 0-2.514 18.872c0 39.79 32.257 72.047 72.047 72.047s72.047-32.257 72.047-72.047-32.257-72.048-72.047-72.048z" />
</svg>
</div>
)}
</div>
<br />
<div className='swym-hl-wishlist-page-list-container'>
{list &&
list.length > 0 &&
list.map((item) => (
<WishlistItem key={item.epi} productId={item.empi} variantId={item.epi} title={item.dt} product={item} readOnly={false} onRemoveItem={()=>removeItemFromWishlist(item, true)} />
))}
</div>
</div>
</div>
</>
)}
</div>
</WishlistContext>
</div>
);
}
.swym-hl-wl-dropdown-container{
display: inline-block;
position: relative;
text-align: left;
}
.swym-hl-wl-list-dropdown-btn{
display: inline-flex;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
justify-content: center;
border-width: 1px;
border-color: #D1D5DB;
width: 100%;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 500;
color: #374151;
background-color: #ffffff;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.swym-hl-dropdown-icon{
margin-left: 0.5rem;
margin-right: -0.25rem;
width: 1.25rem;
height: 1.25rem;
}
.swym-hl-wl-dropdown-list{
position: absolute;
left: 0;
z-index: 10;
margin-top: 0.5rem;
//box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
--ring-color: #000000;
--ring-opacity: 0.05;
width: 14rem;
background-color: #ffffff;
transform-origin: top right;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
border: 1px solid lightgray;
border-radius: 4px;
}
.swym-hl-wl-dropdown-list-item{
display: block;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
font-size: 0.875rem;
line-height: 1.25rem;
color: #374151;
}
.swym-hl-wl-dropdown-list-item.swym-hl-dropdown-list-item-active{
color: #111827;
background-color: #F3F4F6;
}
.swym-hl-wl-dropdown-list-item:hover{
color: #111827;
background-color: #F3F4F6;
}
.swym-hl-wl-list-dropdown-btn:hover{
background-color: #F9FAFB;
}
.swym-hl-wishlist-page-title{
font-size: 20px;
font-weight: bold;
}
.swym-hl-wl-content-header{
display: flex;
}
.swym-hl-wl-selected-lname{
flex: 1 1 0%;
font-size: 1.25rem;
line-height: 1.75rem;
font-weight: 700;
}
.swym-hl-wishlist-page-share-btn{
padding: 10px;
border-radius: 9999px;
border-width: 1px;
cursor: pointer;
}
.swym-hl-wishlist-page-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.swym-list-style {
padding: 10px 20px;
padding-bottom: 0px;
cursor: pointer;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 12px 16px;
z-index: 1;
margin: 10px;
margin-left: 0px
}
.swym-wishlist-style-ul{
margin:20px 0;
list-style:none;
}
.swym-wishlist-style-li{
position:relative;
padding:15px 10px;
border-bottom:1px solid rgba(255,255,255,.1);
overflow:hidden;
margin-right: 40px;
cursor: pointer;
}
.swym-wishlist-style-li:before{
content:'';
position:absolute;
left:-100%;
top:0;
width:100%;
height:100%;
background:#434655;
z-index:-1;
}
.swym-wishlist-style-li:hover:before{
left:0;
border-right:5px solid #434655;
opacity: 0.5;
}
.swym-wishlist-style-li a.active {
background-color: yellow;
}
.swym-wishlist-badge {
width: 30px;
height: 30px;
border-radius: 30px;
display: inline-block;
overflow: hidden;
font-size: 12px;
line-height: 20px;
text-align: center;
text-transform: uppercase;
display: flex;
align-items: center;
justify-content: center;
margin-right: 14px;
flex-shrink: 0;
}
.selected {
background-color:#035587;
font-weight: bold;
font-size: 16px;
}
.add-button{
background-color:#5a31f4;
}
.swym-spinner{
width:40px;
height: 40px;
border: 2px solid black;
border-radius: 25%;
animation: rotator 1.4s linear infinite;
}
@keyframes rotator {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(270deg);
}
}
.grid-item-view:hover{
transform: scale(1.05);
transition: transform 0.1s ease-in-out;
}
.swym-hl-continue-shop-btn{
padding: 0.5rem 1rem;
margin-top: 1rem;
border-radius: 0.25rem;
font-weight: bold;
}
.swym-hl-continue-shop-btn:hover{
transform: scale(1.05);
transition: transform 0.1s ease-in-out;
}
.swym-hl-empty-wl-title{
font-size: 1.25rem;
line-height: 1.75rem;
font-weight: 700;
}