UNPKG

ondc-campaign-sdk

Version:

[![npm version](https://img.shields.io/npm/v/ondc-campaign-sdk.svg)](https://www.npmjs.com/package/ondc-campaign-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Made with ❤️](https://img.shields.io/badge/Made%20with-%

911 lines (812 loc) 27.7 kB
"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> `; }