ondc-campaign-sdk
Version:
[](https://www.npmjs.com/package/ondc-campaign-sdk) [](LICENSE) [ • 27.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderSleekMinimalTemplate = renderSleekMinimalTemplate;
// Static data that will be replaced by API calls later
async function getBrandsDataMinimal() {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{
id: 1,
name: "Premium",
subtitle: "Luxury Collection",
image: "https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=400&h=300&fit=crop",
redirectUrl: "/brands/premium"
},
{
id: 2,
name: "Modern",
subtitle: "Contemporary Style",
image: "https://images.unsplash.com/photo-1560472354-b33ff0c44a43?w=400&h=300&fit=crop",
redirectUrl: "/brands/modern"
},
{
id: 3,
name: "Classic",
subtitle: "Timeless Design",
image: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=400&h=300&fit=crop",
redirectUrl: "/brands/classic"
},
{
id: 4,
name: "Essential",
subtitle: "Everyday Basics",
image: "https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=400&h=300&fit=crop",
redirectUrl: "/brands/essential"
},
{
id: 5,
name: "Elite",
subtitle: "Exclusive Range",
image: "https://images.unsplash.com/photo-1521737852567-6949f3f9f2b5?w=400&h=300&fit=crop",
redirectUrl: "/brands/elite"
}
]);
}, 100);
});
}
async function getCategoriesDataMinimal() {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{
id: 1,
name: "Electronics",
count: "120+ items",
image: "https://images.unsplash.com/photo-1498049794561-7780e7231661?w=300&h=200&fit=crop",
redirectUrl: "/categories/electronics"
},
{
id: 2,
name: "Fashion",
count: "250+ items",
image: "https://images.unsplash.com/photo-1445205170230-053b83016050?w=300&h=200&fit=crop",
redirectUrl: "/categories/fashion"
},
{
id: 3,
name: "Home",
count: "180+ items",
image: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=300&h=200&fit=crop",
redirectUrl: "/categories/home"
},
{
id: 4,
name: "Beauty",
count: "90+ items",
image: "https://images.unsplash.com/photo-1522335789203-aabd1fc54bc9?w=300&h=200&fit=crop",
redirectUrl: "/categories/beauty"
},
{
id: 5,
name: "Sports",
count: "160+ items",
image: "https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=300&h=200&fit=crop",
redirectUrl: "/categories/sports"
},
{
id: 6,
name: "Books",
count: "300+ items",
image: "https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=300&h=200&fit=crop",
redirectUrl: "/categories/books"
}
]);
}, 100);
});
}
async function renderSleekMinimalTemplate(campaignData, styleConfig = {}, templateConfig = {}) {
if (!campaignData || !campaignData.products || campaignData.products.length === 0) {
return renderNoContentStateMinimal();
}
const defaultStyle = {
primaryColor: "#1a1a1a",
accentColor: "#007aff",
textColor: "#333333",
lightTextColor: "#666666",
backgroundColor: "#ffffff",
cardBackground: "#fafafa",
borderColor: "#e0e0e0"
};
const defaultTemplateConfig = {
compactLayout: false,
showRatings: true,
enableHoverEffects: true,
cardSpacing: 'normal'
};
const mergedStyle = { ...defaultStyle, ...styleConfig };
const mergedConfig = { ...defaultTemplateConfig, ...templateConfig };
// Get static data (will be API calls later)
const brandsData = await getBrandsDataMinimal();
const categoriesData = await getCategoriesDataMinimal();
const featuredProducts = getFeaturedProductsMinimal(campaignData.products, 6);
return `
${generateSleekMinimalCSS(mergedStyle, mergedConfig)}
<div class="sleek-minimal-template" id="sleek-campaign">
${generateMinimalHero(campaignData)}
${generateMinimalBrandsSection(brandsData, mergedConfig)}
${generateMinimalCategoriesSection(categoriesData, mergedConfig)}
${generateMinimalFeaturedSection(featuredProducts, campaignData, mergedConfig)}
</div>
${generateSleekMinimalJavaScript(mergedConfig)}
`;
}
function renderNoContentStateMinimal() {
return `
<div class="minimal-no-content">
<div class="loading-minimal">
<div class="loading-dots">
<span></span>
<span></span>
<span></span>
</div>
<h3>Loading Campaign</h3>
<p>Please wait while we prepare your content</p>
</div>
<style>
.minimal-no-content {
min-height: 300px;
display: flex;
align-items: center;
justify-content: center;
background: #fafafa;
border-radius: 8px;
margin: 2rem 0;
}
.loading-minimal {
text-align: center;
color: #666;
}
.loading-dots {
display: flex;
gap: 4px;
justify-content: center;
margin-bottom: 1rem;
}
.loading-dots span {
width: 8px;
height: 8px;
background: #007aff;
border-radius: 50%;
animation: bounce 1.4s ease-in-out infinite both;
}
.loading-dots span:nth-child(1) { animation-delay: -0.32s; }
.loading-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes bounce {
0%, 80%, 100% { transform: scale(0); }
40% { transform: scale(1); }
}
</style>
</div>
`;
}
function getFeaturedProductsMinimal(products, count) {
return [...products]
.sort((a, b) => (b.discountPercentage || 0) - (a.discountPercentage || 0))
.slice(0, count);
}
function generateMinimalHero(campaignData) {
return `
<section class="minimal-hero">
<div class="hero-content-minimal">
<div class="hero-text-minimal">
<h1 class="hero-title-minimal">${campaignData.campaignName || 'Featured Collection'}</h1>
<p class="hero-subtitle-minimal">${campaignData.description || 'Discover our carefully curated selection of premium products'}</p>
</div>
<div class="hero-image-minimal">
<img src="${campaignData.banner || 'https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=800&h=400&fit=crop'}" alt="Campaign Banner" />
</div>
</div>
</section>
`;
}
function generateMinimalBrandsSection(brandsData, config) {
const brandCards = brandsData.map((brand, index) => `
<div class="brand-minimal-card" onclick="redirectToBrandMinimal('${brand.redirectUrl}')" style="animation-delay: ${index * 0.1}s;">
<div class="brand-image-minimal">
<img src="${brand.image}" alt="${brand.name}" />
<div class="brand-overlay-minimal">
<h3>${brand.name}</h3>
<p>${brand.subtitle}</p>
</div>
</div>
</div>
`).join('');
return `
<section class="brands-minimal-section">
<div class="section-header-minimal">
<h2>Premium Brands</h2>
<p>Explore collections from top brands</p>
</div>
<div class="brands-scroll-minimal">
${brandCards}
</div>
</section>
`;
}
function generateMinimalCategoriesSection(categoriesData, config) {
const categoryCards = categoriesData.map((category, index) => `
<div class="category-minimal-card" onclick="redirectToCategoryMinimal('${category.redirectUrl}')" style="animation-delay: ${index * 0.1}s;">
<div class="category-image-minimal">
<img src="${category.image}" alt="${category.name}" />
</div>
<div class="category-info-minimal">
<h3>${category.name}</h3>
</div>
</div>
`).join('');
return `
<section class="categories-minimal-section">
<div class="section-header-minimal">
<h2>Shop Categories</h2>
<p>Find exactly what you're looking for</p>
</div>
<div class="categories-scroll-minimal">
${categoryCards}
</div>
</section>
`;
}
function generateMinimalFeaturedSection(products, campaignData, config) {
const productCards = products.map((product, index) => generateMinimalProductCard(product, index, config, campaignData)).join('');
return `
<section class="featured-minimal-section">
<div class="section-header-minimal">
<h2>Featured Products</h2>
<p>Our most popular and recommended items</p>
</div>
<div class="products-minimal-grid">
${productCards}
</div>
</section>
`;
}
function generateMinimalProductCard(product, index, config, campaignData) {
const productName = product.productName || '';
const productId = product.productId || '';
const imageUrl = product.imgUrl || (product.galleryImages && product.galleryImages.length > 0 ? product.galleryImages[0].url : '');
const discountPercent = product.discountPercentage || 0;
const regularPrice = product.regularPrice || 0;
const discountedPrice = product.discountedPrice || regularPrice;
const brandName = product.brandName || '';
const rating = product.productRatings || 0;
const formattedRegularPrice = `₹${regularPrice.toLocaleString('en-IN')}`;
const formattedDiscountedPrice = `₹${discountedPrice.toLocaleString('en-IN')}`;
const productNameSlug = productName
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-');
const productUrl = `https://shop.samhita.org/product/${productNameSlug}/${productId}`;
return `
<div class="product-minimal-card ${config.cardSpacing}-spacing" style="animation-delay: ${index * 0.1}s;" data-product-id="${productId}">
<div class="product-image-minimal">
<img src="${imageUrl}" alt="${productName}" loading="lazy" onerror="this.onerror=null;this.src='https://via.placeholder.com/300x300?text=Product&bg=f5f5f5&color=999';" />
${discountPercent > 0 ? `<span class="discount-minimal">-${discountPercent}%</span>` : ''}
</div>
<div class="product-info-minimal">
${brandName ? `<div class="brand-minimal">${brandName}</div>` : ''}
<h3 class="product-title-minimal">${productName}</h3>
${config.showRatings && rating > 0 ? `
<div class="rating-minimal">
<div class="stars-minimal">
${Array(5).fill('').map((_, i) => `<span class="${i < Math.floor(rating) ? 'star-filled' : 'star-empty'}">★</span>`).join('')}
</div>
<span class="rating-text">${rating.toFixed(1)}</span>
</div>
` : ''}
<div class="price-minimal">
${discountedPrice < regularPrice ?
`<span class="current-price-minimal">${formattedDiscountedPrice}</span>
<span class="original-price-minimal">${formattedRegularPrice}</span>` :
`<span class="current-price-minimal">${formattedRegularPrice}</span>`}
</div>
<button class="cta-minimal" onclick="handleProductClickMinimal('${productId}', '${productUrl}', '${campaignData._id || ''}')">
Add to Cart
</button>
</div>
</div>
`;
}
function generateSleekMinimalCSS(style, config) {
const spacingMap = {
tight: '1rem',
normal: '1.5rem',
spacious: '2rem'
};
return `
<style>
:root {
--primary-color: ${style.primaryColor};
--accent-color: ${style.accentColor};
--text-color: ${style.textColor};
--light-text: ${style.lightTextColor};
--bg-color: ${style.backgroundColor};
--card-bg: ${style.cardBackground};
--border-color: ${style.borderColor};
--spacing: ${spacingMap[config.cardSpacing]};
--compact: ${config.compactLayout ? '1' : '0'};
}
.sleek-minimal-template {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
line-height: 1.5;
color: var(--text-color);
background: var(--bg-color);
max-width: 1200px;
margin: 0 auto;
padding: calc(var(--spacing) * 1.5);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Hero Section */
.minimal-hero {
padding: calc(var(--spacing) * 2) 0;
border-bottom: 1px solid var(--border-color);
margin-bottom: calc(var(--spacing) * 2);
}
.hero-content-minimal {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing);
text-align: center;
}
.hero-title-minimal {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 300;
letter-spacing: -0.02em;
margin-bottom: var(--spacing);
color: var(--primary-color);
}
.hero-subtitle-minimal {
font-size: 1.1rem;
color: var(--light-text);
line-height: 1.6;
max-width: 500px;
}
.hero-image-minimal {
width: 100%;
height: 250px;
border-radius: 8px;
overflow: hidden;
}
.hero-image-minimal img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Section Headers */
.section-header-minimal {
margin-bottom: calc(var(--spacing) * 2);
text-align: center;
}
.section-header-minimal h2 {
font-size: 2rem;
font-weight: 500;
margin-bottom: 0.5rem;
color: var(--primary-color);
}
.section-header-minimal p {
color: var(--light-text);
font-size: 1rem;
}
/* Brands Section */
.brands-minimal-section {
margin-bottom: calc(var(--spacing) * 3);
}
.brands-scroll-minimal {
display: flex;
gap: var(--spacing);
overflow-x: auto;
padding: var(--spacing) 0;
scroll-behavior: smooth;
}
.brands-scroll-minimal::-webkit-scrollbar {
height: 4px;
}
.brands-scroll-minimal::-webkit-scrollbar-track {
background: var(--border-color);
}
.brands-scroll-minimal::-webkit-scrollbar-thumb {
background: var(--accent-color);
border-radius: 2px;
}
.brand-minimal-card {
min-width: 300px;
height: 200px;
position: relative;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
animation: slideInLeft 0.6s ease forwards;
opacity: 0;
transform: translateX(-20px);
}
${config.enableHoverEffects ? `
.brand-minimal-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0,0,0,0.1);
}
` : ''}
.brand-image-minimal {
width: 100%;
height: 100%;
position: relative;
}
.brand-image-minimal img {
width: 100%;
height: 100%;
object-fit: cover;
}
.brand-overlay-minimal {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0,0,0,0.7));
color: white;
padding: var(--spacing);
}
.brand-overlay-minimal h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.2rem;
}
.brand-overlay-minimal p {
font-size: 0.9rem;
opacity: 0.9;
}
/* Categories Section */
.categories-minimal-section {
margin-bottom: calc(var(--spacing) * 3);
}
.categories-scroll-minimal {
display: flex;
gap: var(--spacing);
overflow-x: auto;
padding: var(--spacing) 0;
scroll-behavior: smooth;
}
.categories-scroll-minimal::-webkit-scrollbar {
height: 4px;
}
.categories-scroll-minimal::-webkit-scrollbar-track {
background: var(--border-color);
}
.categories-scroll-minimal::-webkit-scrollbar-thumb {
background: var(--accent-color);
border-radius: 2px;
}
.category-minimal-card {
min-width: 300px;
height: 200px;
position: relative;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
animation: slideInUp 0.6s ease forwards;
opacity: 0;
transform: translateY(20px);
background: var(--card-bg);
}
${config.enableHoverEffects ? `
.category-minimal-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0,0,0,0.1);
}
` : ''}
.category-image-minimal {
width: 100%;
height: 150px;
overflow: hidden;
}
.category-image-minimal img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
${config.enableHoverEffects ? `
.category-minimal-card:hover .category-image-minimal img {
transform: scale(1.05);
}
` : ''}
.category-info-minimal {
padding: var(--spacing);
text-align: center;
}
.category-info-minimal h3 {
font-size: 1.1rem;
font-weight: 500;
color: var(--primary-color);
}
.category-count {
font-size: 0.8rem;
color: var(--light-text);
}
/* Products Section */
.featured-minimal-section {
margin-bottom: calc(var(--spacing) * 2);
}
.products-minimal-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--spacing);
}
.product-minimal-card {
background: var(--card-bg);
border-radius: 8px;
overflow: hidden;
transition: all 0.3s ease;
animation: fadeInUp 0.6s ease forwards;
opacity: 0;
transform: translateY(20px);
}
.tight-spacing .product-info-minimal {
padding: calc(var(--spacing) * 0.75);
}
.normal-spacing .product-info-minimal {
padding: var(--spacing);
}
.spacious-spacing .product-info-minimal {
padding: calc(var(--spacing) * 1.25);
}
${config.enableHoverEffects ? `
.product-minimal-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0,0,0,0.1);
}
` : ''}
.product-image-minimal {
width: 100%;
height: 250px;
position: relative;
overflow: hidden;
}
.product-image-minimal img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
${config.enableHoverEffects ? `
.product-minimal-card:hover .product-image-minimal img {
transform: scale(1.02);
}
` : ''}
.discount-minimal {
position: absolute;
top: var(--spacing);
right: var(--spacing);
background: var(--accent-color);
color: white;
padding: 0.3rem 0.6rem;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 500;
}
.product-info-minimal {
padding: var(--spacing);
}
.brand-minimal {
font-size: 0.8rem;
color: var(--light-text);
text-transform: uppercase;
letter-spacing: 0.1em;
margin-bottom: 0.5rem;
}
.product-title-minimal {
font-size: 1.1rem;
font-weight: 500;
margin-bottom: 0.8rem;
line-height: 1.4;
color: var(--primary-color);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.rating-minimal {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.8rem;
}
.stars-minimal {
display: flex;
gap: 1px;
}
.star-filled {
color: #ffa500;
font-size: 0.9rem;
}
.star-empty {
color: var(--border-color);
font-size: 0.9rem;
}
.rating-text {
font-size: 0.8rem;
color: var(--light-text);
}
.price-minimal {
display: flex;
align-items: center;
gap: 0.8rem;
margin-bottom: var(--spacing);
}
.current-price-minimal {
font-size: 1.3rem;
font-weight: 600;
color: var(--accent-color);
}
.original-price-minimal {
font-size: 1rem;
color: var(--light-text);
text-decoration: line-through;
}
.cta-minimal {
width: 100%;
background: var(--primary-color);
color: white;
border: none;
padding: 0.8rem;
border-radius: 4px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.cta-minimal:hover {
background: var(--accent-color);
transform: translateY(-1px);
}
/* Animations */
@keyframes slideInLeft {
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive Design */
@media (max-width: 768px) {
.sleek-minimal-template {
padding: var(--spacing);
}
.hero-content-minimal {
grid-template-columns: 1fr;
gap: var(--spacing);
text-align: center;
}
.brand-minimal-card {
min-width: 250px;
}
.categories-scroll-minimal {
gap: var(--spacing);
}
.products-minimal-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.hero-title-minimal {
font-size: 2rem;
}
.section-header-minimal h2 {
font-size: 1.5rem;
}
.brand-minimal-card {
min-width: 200px;
height: 150px;
}
}
</style>
`;
}
function generateSleekMinimalJavaScript(config) {
return `
<script>
// Brand redirection
function redirectToBrandMinimal(url) {
window.open(url, '_blank');
}
// Category redirection
function redirectToCategoryMinimal(url) {
window.open(url, '_blank');
}
// Product click with transaction API
function handleProductClickMinimal(productId, productUrl, campaignId) {
// Get user ID from localStorage or generate
let userId = localStorage.getItem('ondc_user_id');
if (!userId) {
userId = crypto.randomUUID();
localStorage.setItem('ondc_user_id', userId);
}
// Update transaction status
fetch('https://ondc-sdk.samhita.org/api/transactions/update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
campaign_id: campaignId,
product_id: productId,
status: 'initiated',
user_id: userId
})
})
.then(response => {
if (response.ok) {
window.open(productUrl, '_blank');
} else {
console.error('Failed to update transaction');
window.open(productUrl, '_blank'); // Still redirect even if tracking fails
}
})
.catch(err => {
console.error('Error updating transaction:', err);
window.open(productUrl, '_blank'); // Still redirect even if tracking fails
});
}
// Initialize animations
document.addEventListener('DOMContentLoaded', function() {
// Intersection Observer for staggered animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -30px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.animationPlayState = 'running';
}
});
}, observerOptions);
// Observe all animated elements
document.querySelectorAll('.brand-minimal-card, .category-minimal-card, .product-minimal-card').forEach(el => {
observer.observe(el);
});
// Smooth scroll for brands section
const brandsScroll = document.querySelector('.brands-scroll-minimal');
const categoriesScroll = document.querySelector('.categories-scroll-minimal');
function initAutoScroll(element, speed = 0.5) {
if (!element) return;
let isScrolling = false;
let scrollDirection = 1;
let scrollAmount = 0;
function autoScroll() {
if (!isScrolling) {
scrollAmount += scrollDirection * speed;
element.scrollLeft = scrollAmount;
if (scrollAmount >= element.scrollWidth - element.clientWidth) {
scrollDirection = -1;
} else if (scrollAmount <= 0) {
scrollDirection = 1;
}
}
requestAnimationFrame(autoScroll);
}
element.addEventListener('mouseenter', () => isScrolling = true);
element.addEventListener('mouseleave', () => isScrolling = false);
// Start auto-scroll after a delay
setTimeout(autoScroll, 3000);
}
// Initialize auto-scroll for both sections
initAutoScroll(brandsScroll, 0.5);
initAutoScroll(categoriesScroll, 0.3); // Slower for categories
});
</script>
`;
}