optumflex-subscription-core
Version:
Core logic and utilities for subscription management, pricing calculations, and data processing - framework agnostic
856 lines (849 loc) • 28.8 kB
JavaScript
import { useState, useEffect, useCallback, useMemo } from 'react';
// Inline constants
const BILLING_CYCLES = ["weekly", "monthly", "quarterly", "halfyearly", "yearly"];
const DEFAULT_BILLING_CYCLE = 'monthly';
const CURRENCY_SYMBOL = '₹';
const DISCOUNT_THRESHOLD = 0;
// Package state management
let isPackageInitialized = false;
let packageValidationError = null;
let packageValidationData = null;
let apiKey = null;
let validationEndpoint = 'https://api.optumflex.com/validate-key';
/**
* Set API key for the package (call this once at app startup)
*/
const setApiKey = (key, endpoint) => {
apiKey = key;
if (endpoint) {
validationEndpoint = endpoint;
}
// Reset initialization state when API key changes
isPackageInitialized = false;
packageValidationError = null;
packageValidationData = null;
};
/**
* Validate API key for the current domain
*/
const validateApiKey = async (apiKey, domain, validationEndpoint) => {
try {
// ✅ Mock response (pretend validation succeeded)
return new Promise((resolve) => setTimeout(() => {
resolve({
isValid: true,
domain,
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hr later
});
}, 500) // simulate latency
);
// ---- real API call would go below, but it's mocked for now ----
/*
const response = await fetch(validationEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-api-key': apiKey,
'X-Domain': domain,
},
body: JSON.stringify({
timestamp: new Date().toISOString(),
}),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return {
isValid: data.valid === true,
error: data.error,
domain: data.domain,
expiresAt: data.expiresAt,
};
*/
}
catch (error) {
console.error('API key validation failed:', error);
return {
isValid: false,
error: error instanceof Error ? error.message : 'Validation failed',
};
}
};
/**
* Get current domain
*/
const getCurrentDomain = () => {
if (typeof window !== 'undefined') {
return window.location.hostname;
}
return 'localhost';
};
/**
* Initialize the package automatically (internal function)
*/
const initializePackage = async () => {
// If already initialized, return success
if (isPackageInitialized) {
return { success: true };
}
// Check if API key is set
if (!apiKey) {
const error = 'API key not set. Call setApiKey() before using the package.';
packageValidationError = error;
return { success: false, error };
}
try {
const domain = getCurrentDomain();
const validation = await validateApiKey(apiKey, domain, validationEndpoint);
if (!validation.isValid) {
packageValidationError = validation.error || 'Invalid API key';
return { success: false, error: packageValidationError };
}
// Package is now initialized and validated
isPackageInitialized = true;
packageValidationData = {
domain: validation.domain,
expiresAt: validation.expiresAt,
};
return { success: true };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
packageValidationError = errorMessage;
return { success: false, error: errorMessage };
}
};
/**
* Ensure package is initialized before executing any function
*/
const ensureInitialized = async () => {
const result = await initializePackage();
if (!result.success) {
throw new Error(result.error || 'Package initialization failed');
}
};
/**
* Get package validation status
*/
const getPackageStatus = () => {
return {
isInitialized: isPackageInitialized,
error: packageValidationError || undefined,
...packageValidationData,
};
};
/**
* Parse features from API response format
*/
const parseFeatures = (featuresArr) => {
return featuresArr
.map((f) => Object.values(f)[0])
.filter((v) => typeof v === 'string' && v.trim() !== '');
};
/**
* Parse a single plan from API response
*/
const parsePlan = (pkg) => ({
id: pkg.package_code_str,
title: pkg.package_name,
description: pkg.description,
prices: pkg.prices,
discounted: pkg.discounted,
features: parseFeatures(pkg.features),
});
/**
* Find the minimum price cycle for a plan
*/
const getMinimumPriceCycle = (prices) => {
const validPrices = Object.entries(prices)
.filter(([_, price]) => price > 0)
.sort(([_, a], [__, b]) => a - b);
return validPrices.length > 0 ? validPrices[0][0] : DEFAULT_BILLING_CYCLE;
};
/**
* Get available billing cycles for a plan
*/
const getAvailableCycles = (prices) => {
return BILLING_CYCLES.filter((cycle) => prices[cycle] > 0);
};
/**
* Calculate discount information for a plan and cycle
*/
const calculateDiscountInfo = (plan, cycle) => {
const originalPrice = plan.prices[cycle];
const discountedPrice = plan.discounted[cycle];
const isDiscounted = discountedPrice > 0 && discountedPrice < originalPrice;
const savings = isDiscounted ? originalPrice - discountedPrice : 0;
const savingsPercentage = isDiscounted && originalPrice > 0 ? Math.round((savings / originalPrice) * 100) : 0;
return {
originalPrice,
discountedPrice: isDiscounted ? discountedPrice : originalPrice,
savings,
savingsPercentage,
isDiscounted,
};
};
/**
* Sort plans based on criteria
*/
const sortPlans = (plans, sortBy, selectedCycles) => {
return [...plans].sort((a, b) => {
if (sortBy === 'price-asc') {
const aCycle = selectedCycles[a.id] || DEFAULT_BILLING_CYCLE;
const bCycle = selectedCycles[b.id] || DEFAULT_BILLING_CYCLE;
const aPrice = a.discounted[aCycle] || a.prices[aCycle];
const bPrice = b.discounted[bCycle] || b.prices[bCycle];
return aPrice - bPrice;
}
else if (sortBy === 'price-desc') {
const aCycle = selectedCycles[a.id] || DEFAULT_BILLING_CYCLE;
const bCycle = selectedCycles[b.id] || DEFAULT_BILLING_CYCLE;
const aPrice = a.discounted[aCycle] || a.prices[aCycle];
const bPrice = b.discounted[bCycle] || b.prices[bCycle];
return bPrice - aPrice;
}
else if (sortBy === 'name') {
const aName = a.title || '';
const bName = b.title || '';
return aName.localeCompare(bName);
}
return 0;
});
};
/**
* Generate checkout URL with cart data
*/
const generateCheckoutUrl = (cart, baseUrl) => {
const base64 = typeof window !== 'undefined'
? btoa(unescape(encodeURIComponent(JSON.stringify(cart))))
: '';
return `${baseUrl}/checkout?cart=${encodeURIComponent(base64)}`;
};
/**
* Handle buy now functionality for a single plan
*/
const handleBuyNow = (plan, cycle, companyInfo) => {
if (!companyInfo?.application) {
console.error('Company application URL not configured');
return;
}
const payload = [{
packageCode: plan.id,
duration: cycle,
}];
const base64 = typeof window !== 'undefined'
? btoa(unescape(encodeURIComponent(JSON.stringify(payload))))
: '';
const checkoutUrl = `${companyInfo.application}/checkout?cart=${encodeURIComponent(base64)}`;
window.open(checkoutUrl, '_blank');
};
/**
* Format price with currency symbol
*/
const formatPrice = (price) => {
return `${CURRENCY_SYMBOL}${price}`;
};
/**
* Calculate total cart value
*/
const calculateCartTotal = (cart) => {
return cart.reduce((total, item) => {
const discountInfo = calculateDiscountInfo(item.plan, item.cycle);
return total + discountInfo.discountedPrice;
}, 0);
};
/**
* Create checkout payload from cart items
*/
const createCheckoutPayload = (cart) => {
return cart.map(item => ({
packageCode: item.plan.id,
duration: item.cycle,
}));
};
/**
* Check if a plan has any discounts
*/
const hasDiscounts = (plan) => {
return BILLING_CYCLES.some(cycle => {
const discountInfo = calculateDiscountInfo(plan, cycle);
return discountInfo.isDiscounted && discountInfo.savings > DISCOUNT_THRESHOLD;
});
};
/**
* Get the best discount percentage for a plan
*/
const getBestDiscountPercentage = (plan) => {
let bestDiscount = 0;
BILLING_CYCLES.forEach(cycle => {
const discountInfo = calculateDiscountInfo(plan, cycle);
if (discountInfo.isDiscounted && discountInfo.originalPrice > 0) {
const percentage = (discountInfo.savings / discountInfo.originalPrice) * 100;
bestDiscount = Math.max(bestDiscount, percentage);
}
});
return Math.round(bestDiscount);
};
/**
* Validate plan data
*/
const validatePlan = (plan) => {
return !!(plan?.package_code_str &&
plan?.package_name &&
plan?.prices &&
plan?.discounted &&
Array.isArray(plan?.features));
};
/**
* Filter plans by search query
*/
const filterPlansBySearch = (plans, searchQuery) => {
if (!searchQuery.trim())
return plans;
const query = searchQuery.toLowerCase();
return plans.filter(plan => plan.title.toLowerCase().includes(query) ||
plan.description.toLowerCase().includes(query) ||
plan.features.some(feature => feature.toLowerCase().includes(query)));
};
/**
* Get period label for display
*/
const getPeriodLabel = (period) => {
const periodMap = {
weekly: 'Weekly',
monthly: 'Monthly',
quarterly: 'Quarterly',
halfyearly: 'Half Yearly',
yearly: 'Yearly'
};
return periodMap[period] || period;
};
/**
* Get icon for plan based on index
*/
const getIcon = (index) => {
const icons = [
'🚀', // Rocket for first plan
'⭐', // Star for second plan
'💎', // Diamond for third plan
'🏆', // Trophy for fourth plan
'🔥', // Fire for fifth plan
'⚡', // Lightning for sixth plan
'🌟', // Sparkle for seventh plan
'🎯', // Target for eighth plan
'💫', // Dizzy for ninth plan
'✨' // Sparkles for tenth plan
];
return icons[index % icons.length];
};
/**
* Get icon color class based on index
*/
const getIconColor = (index) => {
const colors = [
'text-blue-500',
'text-green-500',
'text-purple-500',
'text-orange-500',
'text-red-500',
'text-pink-500',
'text-indigo-500',
'text-teal-500',
'text-yellow-500',
'text-cyan-500'
];
return colors[index % colors.length];
};
/**
* Handle period selection for a plan
*/
const handlePeriodSelect = (planId, period, selectedPeriods, setSelectedPeriods) => {
setSelectedPeriods({
...selectedPeriods,
[planId]: period
});
};
/**
* Get default billing cycles for all plans
*/
const getDefaultCycles = (plans) => {
const defaultCycles = {};
plans.forEach(plan => {
defaultCycles[plan.id] = getMinimumPriceCycle(plan.prices);
});
return defaultCycles;
};
/**
* Format currency with proper symbol and formatting
*/
const formatCurrency = (amount, currency = '₹') => {
return `${currency}${amount.toLocaleString('en-IN')}`;
};
/**
* Calculate savings amount and percentage
*/
const calculateSavings = (originalPrice, discountedPrice) => {
const savings = originalPrice - discountedPrice;
const percentage = originalPrice > 0 ? (savings / originalPrice) * 100 : 0;
return {
amount: savings,
percentage: Math.round(percentage)
};
};
/**
* Process raw API response and convert to subscription data format
*/
const processSubscriptionData = (apiResponse) => {
try {
// Parse features from array of objects
const parseFeatures = (featuresArr) => {
return featuresArr
.map((f) => Object.values(f)[0])
.filter((v) => typeof v === 'string' && v.trim() !== '');
};
const parsePlan = (pkg) => ({
id: pkg.package_code_str,
title: pkg.package_name,
description: pkg.description,
prices: pkg.prices,
discounted: pkg.discounted,
features: parseFeatures(pkg.features),
});
const subscriptionPlans = (apiResponse?.subscriptionPlans || []).map(parsePlan);
const modelPortfolios = (apiResponse?.modelPortfolios || []).map(parsePlan);
return {
subscriptionPlans,
modelPortfolios,
};
}
catch (error) {
console.error('Error processing subscription data:', error);
return {
subscriptionPlans: [],
modelPortfolios: [],
};
}
};
/**
* Get subscription data with default cycles set
*/
const getSubscriptionData = (apiResponse) => {
const { subscriptionPlans, modelPortfolios } = processSubscriptionData(apiResponse);
// Set default selected cycle for each plan based on minimum price
const defaultCycles = {};
[...subscriptionPlans, ...modelPortfolios].forEach(plan => {
defaultCycles[plan.id] = getMinimumPriceCycle(plan.prices);
});
return {
subscriptionPlans,
modelPortfolios,
defaultCycles,
};
};
/**
* Create subscription state from API response
*/
const createSubscriptionState = (apiResponse, options = {}) => {
const { subscriptionPlans, modelPortfolios, defaultCycles } = getSubscriptionData(apiResponse);
return {
subscriptionPlans,
modelPortfolios,
selectedCycles: defaultCycles,
planType: options.initialPlanType || 'subscriptionPlans',
sortBy: options.initialSortBy || 'default',
};
};
/**
* Update selected cycles for plans
*/
const updateSelectedCycles = (currentCycles, planId, cycle) => {
return {
...currentCycles,
[planId]: cycle,
};
};
/**
* Get sorted and filtered plans for display
*/
const getDisplayPlans = (plans, sortBy, selectedCycles, searchQuery) => {
let filteredPlans = plans;
// Apply search filter if provided
if (searchQuery) {
filteredPlans = filterPlansBySearch(plans, searchQuery);
}
// Apply sorting
return sortPlans(filteredPlans, sortBy, selectedCycles);
};
/**
* Generate checkout URL for a single plan
*/
const generateSinglePlanCheckoutUrl = (plan, cycle, companyInfo) => {
const payload = [{
packageCode: plan.id,
duration: cycle,
}];
const base64 = typeof window !== 'undefined'
? btoa(unescape(encodeURIComponent(JSON.stringify(payload))))
: '';
return `${companyInfo.application}/checkout?cart=${encodeURIComponent(base64)}`;
};
/**
* Get plan statistics
*/
const getPlanStatistics = (plans) => {
if (plans.length === 0) {
return {
totalPlans: 0,
plansWithDiscounts: 0,
averagePrice: 0,
priceRange: { min: 0, max: 0 },
};
}
const prices = [];
let plansWithDiscounts = 0;
plans.forEach(plan => {
BILLING_CYCLES.forEach(cycle => {
const price = plan.prices[cycle];
if (price > 0) {
prices.push(price);
}
});
if (hasDiscounts(plan)) {
plansWithDiscounts++;
}
});
const averagePrice = prices.length > 0 ? prices.reduce((a, b) => a + b, 0) / prices.length : 0;
const priceRange = {
min: Math.min(...prices),
max: Math.max(...prices),
};
return {
totalPlans: plans.length,
plansWithDiscounts,
averagePrice: Math.round(averagePrice),
priceRange,
};
};
/**
* Validate API response structure
*/
const validateApiResponse = (response) => {
return !!(response &&
(response.subscriptionPlans || response.modelPortfolios) &&
Array.isArray(response.subscriptionPlans || []) &&
Array.isArray(response.modelPortfolios || []));
};
/**
* Transform API response to component-ready format
*/
const transformApiResponse = (apiResponse) => {
if (!validateApiResponse(apiResponse)) {
return {
isValid: false,
error: 'Invalid API response structure',
};
}
try {
const data = getSubscriptionData(apiResponse);
return {
isValid: true,
data,
};
}
catch (error) {
return {
isValid: false,
error: error instanceof Error ? error.message : 'Failed to process data',
};
}
};
/**
* Check if a billing cycle is selected for a specific plan
*/
const isSelected = (selectedCycles, planId, cycle) => {
return selectedCycles[planId] === cycle;
};
/**
* Get displayed plans with sorting and filtering applied
*/
const getDisplayedPlans = (plans, sortBy, selectedCycles, searchQuery) => {
let filteredPlans = plans;
if (searchQuery) {
filteredPlans = filterPlansBySearch(plans, searchQuery);
}
return sortPlans(filteredPlans, sortBy, selectedCycles);
};
/**
* Scroll to a specific section on the page
*/
const scrollToSection = (sectionId) => {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Optionally focus the first interactive element inside the section
const firstButton = element.querySelector('button, [tabindex]:not([tabindex="-1"])');
if (firstButton)
firstButton.focus();
}
};
/**
* Handle keyboard events for accessibility
*/
const handleKeyDown = (event, action) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
action();
}
};
/**
* Get CSS classes for cycle selection styling
*/
const getCycleSelectionClasses = (isSelected, baseClasses = '') => {
const selectedClasses = 'bg-primary/10 border-primary ring-2 ring-primary/30';
const defaultClasses = 'bg-white border-gray-100 hover:bg-primary/5';
return `${baseClasses} ${isSelected ? selectedClasses : defaultClasses}`;
};
/**
* Generate benefits data structure
*/
const generateBenefitsData = (benefits) => {
return benefits.map((benefit, index) => ({
id: index,
...benefit
}));
};
/**
* Generate FAQ data structure
*/
const generateFAQData = (faqs) => {
return faqs.map((faq, index) => ({
id: index,
...faq
}));
};
const useSubscriptionData = (options = {}) => {
const { initialPlanType = 'subscriptionPlans', initialSortBy = 'default', onError, onSuccess, enableCart = false, appUrl, apiKey } = options;
// State management
const [subscriptionPlans, setSubscriptionPlans] = useState([]);
const [modelPortfolios, setModelPortfolios] = useState([]);
const [selectedCycles, setSelectedCycles] = useState({});
const [planType, setPlanType] = useState(initialPlanType);
const [sortBy, setSortBy] = useState(initialSortBy);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// Cart state (only when enabled)
const [cart, setCart] = useState([]);
const [showCart, setShowCart] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
// Initialize package on first use
useEffect(() => {
const initPackage = async () => {
try {
// Set API key if provided
if (apiKey) {
setApiKey(apiKey);
}
await ensureInitialized();
setIsInitialized(true);
setError(null);
}
catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Package initialization failed';
setError(errorMessage);
onError?.(errorMessage);
}
};
initPackage();
}, [onError, apiKey]);
// Process API response
const processApiResponse = useCallback(async (apiResponse) => {
try {
// Ensure package is initialized before processing
await ensureInitialized();
const result = processSubscriptionData(apiResponse);
setSubscriptionPlans(result.subscriptionPlans);
setModelPortfolios(result.modelPortfolios);
setError(null);
onSuccess?.('Data processed successfully');
}
catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Failed to process data';
setError(errorMessage);
onError?.(errorMessage);
}
}, [onError, onSuccess]);
// Set default cycles when plans are loaded
useEffect(() => {
if (subscriptionPlans.length > 0 || modelPortfolios.length > 0) {
const allPlans = [...subscriptionPlans, ...modelPortfolios];
const defaultCycles = {};
allPlans.forEach(plan => {
// Only set default if not already set
if (!selectedCycles[plan.id]) {
defaultCycles[plan.id] = getMinimumPriceCycle(plan.prices);
}
});
// Only update if we have new defaults to set
if (Object.keys(defaultCycles).length > 0) {
setSelectedCycles(prev => ({
...prev,
...defaultCycles
}));
}
}
}, [subscriptionPlans, modelPortfolios, selectedCycles]);
// Get current plans based on plan type
const getCurrentPlans = useCallback(() => {
return planType === 'subscriptionPlans' ? subscriptionPlans : modelPortfolios;
}, [planType, subscriptionPlans, modelPortfolios]);
// Get displayed plans with sorting and filtering
const getDisplayedPlans = useCallback((searchQuery) => {
const currentPlans = getCurrentPlans();
let filteredPlans = currentPlans;
if (searchQuery) {
filteredPlans = filterPlansBySearch(currentPlans, searchQuery);
}
return sortPlans(filteredPlans, sortBy, selectedCycles);
}, [getCurrentPlans, sortBy, selectedCycles]);
// Set selected cycle for a plan
const setSelectedCycle = useCallback((planId, cycle) => {
setSelectedCycles(prev => ({
...prev,
[planId]: cycle
}));
}, []);
// Get discount info for a plan and cycle
const getDiscountInfo = useCallback((plan, cycle) => {
return calculateDiscountInfo(plan, cycle);
}, []);
// Get available cycles for a plan
const getAvailableCycles$1 = useCallback((plan) => {
return getAvailableCycles(plan.prices);
}, []);
// Get formatted price for a plan and cycle
const getPlanPrice = useCallback((plan, cycle) => {
const discountInfo = calculateDiscountInfo(plan, cycle);
if (discountInfo.isDiscounted) {
return `${formatPrice(discountInfo.discountedPrice)}`;
}
return formatPrice(discountInfo.originalPrice);
}, []);
// Get plan statistics
const getPlanStatistics = useCallback(() => {
const currentPlans = getCurrentPlans();
const totalPlans = currentPlans.length;
const plansWithDiscounts = currentPlans.filter(plan => getAvailableCycles$1(plan).some(cycle => getDiscountInfo(plan, cycle).isDiscounted)).length;
const allPrices = currentPlans.flatMap(plan => getAvailableCycles$1(plan).map(cycle => getDiscountInfo(plan, cycle).discountedPrice));
const averagePrice = allPrices.length > 0 ? allPrices.reduce((a, b) => a + b, 0) / allPrices.length : 0;
const priceRange = {
min: allPrices.length > 0 ? Math.min(...allPrices) : 0,
max: allPrices.length > 0 ? Math.max(...allPrices) : 0,
};
return {
totalPlans,
plansWithDiscounts,
averagePrice: Math.round(averagePrice),
priceRange,
};
}, [getCurrentPlans, getAvailableCycles$1, getDiscountInfo]);
// Cart functions (only when enabled)
const addToCart = useCallback((plan, cycle) => {
if (!enableCart)
return;
// Check if plan already exists in cart
const existingItemIndex = cart.findIndex(item => item.plan.id === plan.id);
if (existingItemIndex !== -1) {
// Update existing item with new cycle
setCart(cart.map((item, index) => index === existingItemIndex
? { plan, cycle }
: item));
}
else {
// Add new item
setCart([...cart, { plan, cycle }]);
}
}, [cart, enableCart]);
const removeFromCart = useCallback((planId, cycle) => {
if (!enableCart)
return;
setCart(cart.filter(item => !(item.plan.id === planId && item.cycle === cycle)));
}, [cart, enableCart]);
const updateCartItemCycle = useCallback((planId, newCycle) => {
if (!enableCart)
return;
setCart(cart.map(item => item.plan.id === planId
? { ...item, cycle: newCycle }
: item));
}, [cart, enableCart]);
const clearCart = useCallback(() => {
if (!enableCart)
return;
setCart([]);
setShowCart(false);
}, [enableCart]);
const cartTotal = useMemo(() => calculateCartTotal(cart), [cart]);
const cartItemCount = useMemo(() => cart.length, [cart]);
// Generate checkout URL for single plan
const generateSinglePlanCheckoutUrl = useCallback((plan, cycle) => {
if (!appUrl)
return '#';
const checkoutPayload = [{
packageCode: plan.id,
duration: cycle,
}];
const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(checkoutPayload))));
return `${appUrl}/checkout?cart=${encodeURIComponent(base64)}`;
}, [appUrl]);
// Handle cart checkout
const handleCheckout = useCallback(() => {
if (!cart || cart.length === 0 || !appUrl)
return;
const checkoutPayload = cart.map(item => ({
packageCode: item.plan.id,
duration: item.cycle,
}));
const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(checkoutPayload))));
const checkoutUrl = `${appUrl}/checkout?cart=${encodeURIComponent(base64)}`;
window.open(checkoutUrl, '_blank');
}, [cart, appUrl]);
const baseReturn = {
subscriptionPlans,
modelPortfolios,
selectedCycles,
planType,
sortBy,
loading,
error,
setSelectedCycle,
setPlanType,
setSortBy,
processApiResponse,
getDisplayedPlans,
getDiscountInfo,
getAvailableCycles: getAvailableCycles$1,
getPlanStatistics,
generateSinglePlanCheckoutUrl,
formatPrice,
getPlanPrice,
};
// Add cart functionality only when enabled
if (enableCart) {
return {
...baseReturn,
cart,
cartItemCount,
cartTotal,
showCart,
addToCart,
removeFromCart,
updateCartItemCycle,
clearCart,
setShowCart,
handleCheckout,
};
}
return baseReturn;
};
export { calculateCartTotal, calculateDiscountInfo, calculateSavings, createCheckoutPayload, createSubscriptionState, ensureInitialized, filterPlansBySearch, formatCurrency, formatPrice, generateBenefitsData, generateCheckoutUrl, generateFAQData, generateSinglePlanCheckoutUrl, getAvailableCycles, getBestDiscountPercentage, getCycleSelectionClasses, getDefaultCycles, getDisplayPlans, getDisplayedPlans, getIcon, getIconColor, getMinimumPriceCycle, getPackageStatus, getPeriodLabel, getPlanStatistics, getSubscriptionData, handleBuyNow, handleKeyDown, handlePeriodSelect, hasDiscounts, isSelected, parseFeatures, parsePlan, processSubscriptionData, scrollToSection, setApiKey, sortPlans, transformApiResponse, updateSelectedCycles, useSubscriptionData, validateApiResponse, validatePlan };
//# sourceMappingURL=index.esm.js.map