Show recently viewed product from local storage
use of getLocalStorage action to get recently viewed 10 products
<div class="recently-viewed-section">
<div class="recently-viewed-scroll-wrapper">
<div id="recentlyViewedContainer" class="recently-viewed-scroll"></div>
</div>
</div>/* Recently Viewed Section */
.recently-viewed-section {
padding: 12px 8px;
}
/* Heading (optional) */
.recently-viewed-heading {
font-family: 'Cormorant Garamond', serif;
font-size: 24px;
font-weight: 300;
text-align: center;
color: #202020;
margin: 0;
}
.recently-viewed-heading i {
font-style: italic;
}
/* Scrollable container */
.recently-viewed-scroll-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
scroll-behavior: smooth;
overscroll-behavior-x: contain;
}
.recently-viewed-scroll-wrapper::-webkit-scrollbar {
display: none;
}
.recently-viewed-scroll {
display: flex;
gap: 8px;
}
/* Card */
.recently-viewed-card {
flex: 0 0 54%;
overflow: hidden;
}
.image-wrapper {
position: relative;
width: 100%;
aspect-ratio: 3.8/5;
overflow: hidden;
}
.recently-viewed-img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
transition: transform .2s ease;
}
.recently-viewed-img:active {
transform: scale(.97);
}
/* Content */
.recently-viewed-card-content {
text-align: left;
padding: 8px;
}
/* Title */
.recently-viewed-card-content h3.title {
margin: 1px 0 2px;
font-family: 'Montserrat', sans-serif;
font-size: 14px;
font-weight: 400;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-transform: capitalize;
}
/* Price */
.recently-viewed-card-content h4.price {
font-family: 'Montserrat', sans-serif;
font-weight: 700;
font-size: 12px;
margin-top: 4px;
}
/* Add to Cart Button */
.add-to-cart-btn {
width: 100%;
height: 33px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 0 1px;
border: none;
border-radius: 0;
cursor: pointer;
font-family: 'Montserrat', sans-serif;
font-weight: 700;
font-size: 10px;
color: #000;
background: #e2e2e2;
text-decoration: underline;
text-underline-offset: 2px;
}
.add-to-cart-btn:active {
opacity: .9;
}
.gif-loader {
display: none;
width: 12px;
height: 12px;
margin-left: 6px;
}const RV_KEY = "recentlyViewedProducts";
async function rvGetStoredProducts() {
const raw = await VajroSDK.actions.getLocalStorage(RV_KEY);
try { return raw ? JSON.parse(raw) : []; } catch { return []; }
}
async function rvOpenProduct(handle) {
try { await VajroSDK.actions.openProduct({ productHandle: handle }); }
catch (err) { console.error("openProduct failed:", err); }
}
function rvIsRenderable(p) {
// minimal fields required to render a proper card
const hasTitle = !!p?.title;
const hasHandle = !!p?.handle;
const firstImage = p?.images?.[0];
const imageUrl = typeof firstImage === "string" ? firstImage : firstImage?.url || firstImage?.src;
const firstVariant = p?.variants?.[0];
const hasPrice = Number.isFinite(Number(firstVariant?.price || 0));
return hasTitle && hasHandle && !!imageUrl && hasPrice;
}
function rvGetFirstImageUrl(p) {
const img = p?.images?.[0];
if (!img) return "";
return typeof img === "string" ? img : (img.url || img.src || "");
}
async function rvRender() {
const section = document.querySelector(".recently-viewed-section");
const container = document.getElementById("recentlyViewedContainer");
if (!section || !container) return;
const products = await rvGetStoredProducts();
// Filter to only renderable products
const safeProducts = products.filter(rvIsRenderable);
if (!safeProducts.length) {
section.style.display = "none";
return;
}
container.innerHTML = "";
safeProducts.forEach(product => {
const firstVariant = product?.variants?.[0] || {};
const isSingleVariant = (product?.variants?.length || 0) === 1;
const price = Number(firstVariant?.price || 0);
const compareAt = Number(firstVariant?.compareAtPrice || 0);
const hasDiscount = compareAt > price;
const image = rvGetFirstImageUrl(product);
const card = document.createElement("div");
card.className = "recently-viewed-card";
card.innerHTML = `
<div class="image-wrapper">
<img src="${image}" alt="${product?.title || ""}" class="recently-viewed-img" />
</div>
<outlined-button class="add-to-cart-btn">
<span class="btn-text">${isSingleVariant ? "ADD TO CART" : "Choose Options"}</span>
<img src="https://res.cloudinary.com/dixyq8hvr/image/upload/v1747722131/cupertino_activity_indicator_zze4pb.gif" class="gif-loader" />
</outlined-button>
<div class="recently-viewed-card-content">
<h3 class="title">${product?.title || ""}</h3>
<h4 class="price">
₹${price.toLocaleString("en-IN")}
${hasDiscount ? `<span style="text-decoration:line-through;color:#989898;margin-left:4px;">₹${compareAt.toLocaleString("en-IN")}</span>` : ""}
</h4>
</div>
`;
// Open PDP
card.querySelector(".recently-viewed-img")
?.addEventListener("click", () => rvOpenProduct(product?.handle));
// AddToCart or Choose Options
const button = card.querySelector(".add-to-cart-btn");
const btnText = button.querySelector(".btn-text");
const loader = button.querySelector(".gif-loader");
if (isSingleVariant && firstVariant?.id) {
button.addEventListener("click", async (e) => {
e.stopPropagation();
button.disabled = true;
btnText.style.display = "none";
loader.style.display = "inline-block";
try {
await VajroSDK.actions.addToCart([{ variantId: String(firstVariant.id), quantity: 1 }]);
await VajroSDK.actions.showToast?.({ title: "Added to Cart", message: "Product added successfully" });
} catch (err) {
console.error("⚠️ Add to Cart failed:", err);
} finally {
button.disabled = false;
btnText.style.display = "inline";
loader.style.display = "none";
}
});
} else {
button.addEventListener("click", (e) => {
e.stopPropagation();
rvOpenProduct(product?.handle);
});
}
container.appendChild(card);
});
// If for some reason nothing appended, hide section
if (!container.children.length) {
section.style.display = "none";
return;
}
if (VajroSDK?.actions?.resizeBlock) {
await VajroSDK.actions.resizeBlock();
}
}
document.addEventListener("DOMContentLoaded", rvRender);Updated 3 months ago