Live AI Pricing: fetch from P&L manager, auto-update tier cards + form selector, add AI Pricing badge

This commit is contained in:
root
2026-06-20 19:29:28 +00:00
parent 7f77de4cde
commit 66186168c7
+73 -1
View File
@@ -92,7 +92,8 @@
.tier-specs li:last-child{border-bottom:none}
.tier-specs li .check{color:var(--green)}
.tier-specs li .x{color:var(--red)}
.tier-card .btn{width:100%;justify-content:center}
.tier-card .btn{width:100%;justify-content:center;font-size:.82rem;white-space:nowrap}
#aiPricingBadge.loaded{opacity:1!important}
.why-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:1.5rem}
.why-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:2rem}
.why-card .icon{font-size:1.8rem;margin-bottom:1rem}
@@ -224,6 +225,16 @@
<h2 class="section-title"><span class="en-only">Pick a tier. Get a server.</span><span class="fr-only">Choisissez une offre. Recevez un serveur.</span></h2>
<p class="section-sub en-only">Four options, from entry-level to redundant storage. All include hardware, on-site installation, and a working server before we leave.</p>
<p class="section-sub fr-only">Quatre options, de l'entrée de gamme au stockage redondant. Chaque offre inclut le matériel, l'installation sur place et un serveur opérationnel avant notre départ.</p>
<div style="display:flex;align-items:center;gap:.75rem;margin-bottom:2rem;flex-wrap:wrap">
<span id="aiPricingBadge" style="display:inline-flex;align-items:center;gap:.35rem;font-size:.72rem;padding:.2rem .6rem;border-radius:100px;background:rgba(59,130,246,.1);border:1px solid var(--accent);color:var(--accent);font-weight:500;opacity:.6;transition:opacity .3s">
<span style="width:6px;height:6px;border-radius:50%;background:var(--accent);animation:pulse 2s infinite;display:inline-block"></span>
<span class="en-only">AI Pricing — live from P&amp;L</span><span class="fr-only">Prix AI — en direct du P&amp;L</span>
</span>
<span style="font-size:.75rem;color:var(--text-muted)">
<span class="en-only">Prices auto-update when you change costs in the P&amp;L manager</span>
<span class="fr-only">Les prix se mettent à jour automatiquement depuis le gestionnaire P&amp;L</span>
</span>
</div>
<div class="tiers-grid">
<div class="tier-card">
<div class="tier-name">Rif</div>
@@ -503,6 +514,67 @@
<script>
(function(){
const API_URL = 'http://192.168.1.126:8581';
// ── Live AI Pricing: fetch from P&L manager via API proxy ──
const TIER_PRICE_MAP = {rif: 'Rif', rifplus: 'Rif+', atlas: 'Atlas', atlasplus: 'Atlas+'};
let livePrices = {};
let pricingLoaded = false;
async function fetchPricing() {
try {
const resp = await fetch(API_URL + '/api/public/pricing');
if (!resp.ok) return;
const data = await resp.json();
for (const svc of data.pricing) {
livePrices[svc.name] = svc;
}
pricingLoaded = true;
// Update tier card prices
document.querySelectorAll('.tier-card .amount').forEach(el => {
const card = el.closest('.tier-card');
if (!card) return;
const name = card.querySelector('.tier-name')?.textContent?.trim().replace('⁺', '+') || '';
const price = livePrices[name];
if (price) {
const isFr = document.documentElement.classList.contains('lang-fr');
el.textContent = price.sell_price.toLocaleString() + ' MAD';
// Update the "From" label to show monthly
const priceLine = el.closest('.tier-price');
if (priceLine) {
const prefix = priceLine.querySelector('.en-only');
const prefixFr = priceLine.querySelector('.fr-only');
if (prefix) prefix.textContent = 'From';
if (prefixFr) prefixFr.textContent = 'À partir de';
}
// Change button text to show price
const btn = card.querySelector('.btn');
if (btn) {
btn.textContent = price.sell_price.toLocaleString() + ' MAD/mois';
}
}
});
// Update tier-selector pricing labels
document.querySelectorAll('.tier-option').forEach(el => {
const tierKey = el.dataset.tier;
const name = TIER_PRICE_MAP[tierKey];
const price = livePrices[name];
if (price) {
let tag = el.querySelector('.t-tag');
if (tag) {
tag.textContent = price.sell_price.toLocaleString() + ' MAD/mois';
}
}
});
// Show AI Pricing badge
document.getElementById('aiPricingBadge')?.classList.add('loaded');
} catch (e) {
console.log('Pricing API unavailable — using defaults');
}
}
// Fetch pricing immediately and every 60 seconds
fetchPricing();
setInterval(fetchPricing, 60000);
const totalSteps = 4;
let currentStep = 1;
let selectedTier = '';