ondc-campaign-sdk
Version:
[](https://www.npmjs.com/package/ondc-campaign-sdk) [](LICENSE) [ • 7.44 kB
text/typescript
import { fetchLiveCampaignProducts } from "./api";
export type StyleConfig = Partial<{
primary: string;
primaryDark: string;
accent: string;
text: string;
textLight: string;
bgLight: string;
white: string;
shadow: string;
borderRadius: string;
}>;
export async function fetchLiveCampaignProductsWithHtml(
productCount: number = 10,
style: StyleConfig = {}
): Promise<string> {
const campaign = await fetchLiveCampaignProducts();
const defaultStyle: Required<StyleConfig> = {
primary: "#3d5af1",
primaryDark: "#2a3eb1",
accent: "#ff6b6b",
text: "#333333",
textLight: "#777777",
bgLight: "#f8f9fa",
white: "#ffffff",
shadow: "0 10px 30px rgba(0,0,0,0.08)",
borderRadius: "12px",
};
const mergedStyle = { ...defaultStyle, ...style };
const productCards = campaign.products
.slice(0, productCount)
.map((product: any) => {
const productUrl = product.url_key
? `https://smartsell.samhita.org/${product.url_key}`
: `https://smartsell.samhita.org/${product.name
.toLowerCase()
.replace(/\s+/g, "-")}`;
let discountBadge = "";
if (
product.on_sale &&
product.prices?.regular?.price &&
product.prices?.final?.price
) {
const regularPrice = parseFloat(product.prices.regular.price);
const finalPrice = parseFloat(product.prices.final.price);
if (regularPrice > finalPrice) {
const discountPercent = Math.round(
(1 - finalPrice / regularPrice) * 100
);
discountBadge = `<div class="discount-badge">${discountPercent}% OFF</div>`;
}
}
const newBadge = product.is_new
? '<div class="product-badge new">NEW</div>'
: "";
const featuredBadge = product.is_featured
? '<div class="product-badge featured">FEATURED</div>'
: "";
const saleBadge = product.on_sale
? '<div class="product-badge sale">SALE</div>'
: "";
const badges = newBadge || featuredBadge || saleBadge;
return `
<div class="product-card">
${badges}
<div class="product-image-wrapper">
<img src="${product.base_image.medium_image_url}" alt="${product.name}" />
</div>
<div class="product-info">
<h3 class="product-name">${product.name}</h3>
<div class="price-container">
${product.price_html}
${discountBadge}
</div>
<a class="view-button" href="${productUrl}" target="_blank">View Product</a>
</div>
</div>
`;
})
.join("");
return `
<style>
:root {
--primary: ${mergedStyle.primary};
--primary-dark: ${mergedStyle.primaryDark};
--accent: ${mergedStyle.accent};
--text: ${mergedStyle.text};
--text-light: ${mergedStyle.textLight};
--bg-light: ${mergedStyle.bgLight};
--white: ${mergedStyle.white};
--shadow: ${mergedStyle.shadow};
--border-radius: ${mergedStyle.borderRadius};
}
.campaign-wrapper {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 1.5rem;
color: var(--text);
}
.campaign-banner {
width: 100%;
border-radius: var(--border-radius);
margin-bottom: 1.5rem;
box-shadow: var(--shadow);
}
.campaign-wrapper h2 {
font-size: 2rem;
margin-bottom: 0.5rem;
color: var(--primary);
font-weight: 700;
text-align: center;
}
.campaign-wrapper p {
font-size: 1.1rem;
color: var(--text-light);
margin-bottom: 2rem;
text-align: center;
}
.product-grid {
display: grid;
gap: 2rem;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.product-card {
position: relative;
background-color: var(--white);
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.product-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 35px rgba(0,0,0,0.1);
}
.product-badge {
position: absolute;
top: 1rem;
right: 1rem;
z-index: 1;
padding: 0.4rem 0.8rem;
border-radius: 50px;
font-size: 0.8rem;
font-weight: 600;
color: white;
}
.product-badge.sale {
background-color: var(--accent);
}
.product-badge.new {
background-color: var(--primary);
}
.product-badge.featured {
background-color: #ffc107;
color: #333;
}
.product-image-wrapper {
position: relative;
overflow: hidden;
height: 220px;
}
.product-card img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.product-card:hover img {
transform: scale(1.05);
}
.product-info {
padding: 1.5rem;
}
.product-name {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--text);
}
.price-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.price-container p {
margin: 0;
}
.discount-badge {
background-color: #e8f3ff;
color: var(--primary);
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 600;
}
.view-button {
background: var(--primary);
color: white;
padding: 0.8rem 1.5rem;
text-decoration: none;
border-radius: 50px;
font-weight: 600;
text-align: center;
transition: background 0.3s ease;
display: block;
}
.view-button:hover {
background: var(--primary-dark);
}
.font-medium {
font-weight: 500;
}
.text-zinc-500 {
color: var(--text-light);
}
.line-through {
text-decoration: line-through;
}
.font-semibold {
font-weight: 600;
color: var(--primary);
font-size: 1.2rem;
}
@media (max-width: 768px) {
.campaign-wrapper h2 {
font-size: 1.5rem;
}
.campaign-wrapper p {
font-size: 1rem;
}
}
@media (max-width: 576px) {
.product-grid {
grid-template-columns: 1fr;
}
}
</style>
<div class="campaign-wrapper">
<img class="campaign-banner" src="${campaign.banner}" alt="${campaign.campaignName}" />
<h2>${campaign.campaignName}</h2>
<p>${campaign.description}</p>
<div class="product-grid">
${productCards}
</div>
</div>
`;
}
export async function renderLiveCampaignProducts(
productCount: number = 10,
style: StyleConfig = {}
): Promise<void> {
const html = await fetchLiveCampaignProductsWithHtml(productCount, style);
document.body.innerHTML = html;
}