diff --git a/.gitignore b/.gitignore index 8d97424..2c3d84f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ coverage .yalc yalc.lock .epilot-docs +node-compile-cache +demo/screenshots/capture.mjs diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..8973371 --- /dev/null +++ b/demo/index.html @@ -0,0 +1,13 @@ + + +
+ + +
+ {highlighted}
+
+ {label}
+{value}
+ {sublabel &&{sublabel}
} +{title}
} ++ Bundle multiple price components into a single product. Each component can have its own pricing model, + recurrence, and quantity. Component quantities multiply with the parent quantity. +
+ +{comp.name}
++ โฌ{comp.unitAmountDecimal} x {comp.quantity} + {parentQty > 1 ? ` x ${parentQty}` : ''} + {comp.type === 'recurring' && ` / ${comp.billingPeriod}`} +
+โฌ{price.toFixed(2)}
+ + {comp.type === 'one_time' ? 'One-time' : comp.billingPeriod} + +By Recurrence:
+ {result.total_details?.breakdown?.recurrences?.map((r: any, i: number) => ( ++ Multi-currency support with locale-aware formatting. Uses Dinero.js for precise decimal arithmetic + and provides utilities for converting between string/integer representations. +
+ +formatAmount({'{'} amount: {intAmount}, currency: '{selectedCurrency}', locale: '{locale}' {'}'})
+{formattedAmount}
+formatAmountFromString({'{'} decimalAmount: '{amount}', currency: '{selectedCurrency}', locale: '{locale}' {'}'})
+{formattedFromString}
+getCurrencySymbol('{selectedCurrency}', '{locale}')
+{symbol}
+toIntegerAmount('{amount}')
+{integerAmount} (cents)
+{intAmount} cents formatted per locale
+{c.name}
+{c.code} ({c.locale})
++ Apply fixed-value, percentage discounts, and cashback coupons. Coupons are prioritized: + cashback > discounts, percentage > fixed, highest value first. +
+ +Before
++ {fmtCents(baseResult.amount_total)} +
+After
++ {fmtCents(discountResult.amount_total)} +
++ Market-based pricing for energy products. Combines a day-ahead market price with a configurable markup. + Supports both automatic (day_ahead_market) and manual modes. +
+ ++ Standard German electricity pricing with Grundpreis (base fee) and Arbeitspreis (work price per kWh). + Supports single-tariff and dual-tariff (HT/NT) meters for peak and off-peak consumption. +
+ ++ Total: {totalConsumption.toLocaleString()} kWh/year +
+Grundpreis
+EUR {parseFloat(basePrice).toFixed(2)}/year
++ {tariffType === 'dual' ? 'Arbeitspreis HT' : 'Arbeitspreis'} +
++ {htRate.toFixed(2)} ct/kWh x {(tariffType === 'dual' ? consumptionHT : totalConsumption).toLocaleString()} kWh +
+Arbeitspreis NT
++ {ntRate.toFixed(2)} ct/kWh x {consumptionNT.toLocaleString()} kWh +
+HT (Peak)
+{htRate.toFixed(2)} ct
+{consumptionHT.toLocaleString()} kWh
+NT (Off-Peak)
+{ntRate.toFixed(2)} ct
+{consumptionNT.toLocaleString()} kWh
++ Savings vs. all-HT: EUR {((htRate - ntRate) * consumptionNT).toFixed(2)}/year +
++ German gas supply pricing with Grundpreis, Arbeitspreis, and gas-specific levies + including CO2 tax and gas storage levy. Typical household consumption: 10,000 - 25,000 kWh/year. +
+ +Grundpreis
+EUR {parseFloat(basePrice).toFixed(2)}/year
+Arbeitspreis + Markup
++ {workRate.toFixed(2)} ct/kWh x {consumption.toLocaleString()} kWh +
+Gas Levies
++ {levyRate.toFixed(3)} ct/kWh x {consumption.toLocaleString()} kWh (CO2 + storage) +
++ German energy operator (GetAG) integration supporting base price + work price models + with tiered markups and additional fees. Used for electricity and gas tariffs. +
+ +{item.label}
+{item.detail}
+GetAG Price
+{workPrice} ct
+Markup
+{markupPerUnit} ct
+Total
++ {(parseFloat(workPrice) + parseFloat(markupPerUnit)).toFixed(2)} ct +
++ Hausanschluss (house connection) pricing for new builds and renovations. + Combines one-time connection fees, distance-based trench work, and recurring meter costs. +
+ +{item.name}
+ + {item.type === 'one_time' ? 'One-time' : `${item.billingPeriod}`} + +Total Trench Cost
+EUR {trenchCost.toFixed(2)}
+By Recurrence:
+ {result.total_details?.breakdown?.recurrences?.map((r: any, i: number) => ( ++ Products and services beyond the energy supply itself โ solar panels, battery storage, + wallboxes, heat pumps, and smart home devices. Combines one-time hardware and installation + costs with recurring service and maintenance contracts. +
+ +{product.name}
+No products selected
+ ) : ( + <> + {/* Stacked bar for one-time costs */} + {oneTimeCosts > 0 && ( +One-time costs
+{cat.icon} {cat.label}
+{cat.count} item(s)
+EUR {cat.oneTime.toFixed(2)}
+ )} + {cat.recurring > 0 && ( ++ EUR {cat.recurring.toFixed(2)}/mo
+ )} +No products selected
+ )} +By Recurrence:
+ {result.total_details?.breakdown?.recurrences?.map((r: any, i: number) => ( +
+ Interactive playground for @epilot/pricing โ a comprehensive
+ pricing calculation engine supporting 6 pricing models, tax handling,
+ discounts, composite pricing, recurring billing, multi-currency formatting, and
+ energy-market integrations. Explore each capability below.
+
{stat.value}
+{stat.label}
+{s.label}
+{s.desc}
++ The simplest model: unit price multiplied by quantity. Supports tax-inclusive and tax-exclusive modes. +
+ ++ Support for one-time and recurring prices with frequency normalization. + Convert prices between billing periods automatically. +
+ ++ Same price expressed in different billing periods using normalizeValueToFrequencyUnit() +
++ Three items: a one-time setup fee, a monthly subscription, and an annual license. + The library groups totals by recurrence type. +
+ +{label}
++ {fmtCents(mixedResult.items?.[i]?.amount_total)} +
+Grouped by Recurrence:
+ {mixedResult.total_details?.breakdown?.recurrences?.map((r: any, i: number) => ( ++ Compare tax-inclusive vs tax-exclusive pricing side by side. The library handles tax calculations + precisely using Dinero.js for decimal arithmetic. +
+ + {/* Controls */} ++ Two items with different tax rates (19% standard, 7% reduced). The library tracks + tax breakdown by rate. +
+Tax Breakdown:
+ {multiTaxResult.total_details?.breakdown?.taxes?.map((t: any, i: number) => { + const rate = t.tax?.rate ?? t.rateValue ?? 0; + const type = t.tax?.type || 'VAT'; + return ( ++ A single fixed fee is charged based on the quantity range. Unlike volume pricing, + the fee does not multiply by quantity. +
+ +| Tier | +Up To | +Flat Fee | +Status | +
|---|---|---|---|
| Tier {idx + 1} | ++ updateTier(idx, 'up_to', e.target.value)} + className="input-field w-20" + /> + | ++ updateTier(idx, 'flat_fee_amount_decimal', e.target.value)} + className="input-field w-28" + /> + | ++ {idx === activeTierIdx && Selected} + | +
+ Units are spread across tiers. Each tier charges its own rate for the units within its range. + This is the "graduated" model used by many SaaS platforms. +
+ +| Tier | +Up To | +Unit Price | +
|---|---|---|
| + + Tier {idx + 1} + | ++ updateTier(idx, 'up_to', e.target.value)} + className="input-field w-20" + /> + | ++ updateTier(idx, 'unit_amount_decimal', e.target.value)} + className="input-field w-24" + /> + | +
+ A single tier is selected based on total quantity. The selected tier's unit price applies to all units. +
+ +| Tier | +Up To | +Unit Price | +Active | +
|---|---|---|---|
| Tier {idx + 1} | ++ updateTier(idx, 'up_to', e.target.value)} + className="input-field w-20" + /> + | ++ updateTier(idx, 'unit_amount_decimal', e.target.value)} + className="input-field w-24" + /> + | ++ {idx === activeTierIdx && Active} + | +