PageSourceSearch

https://refect.app/static/dist-v/1790357571/components/pricingControls.js

js refect.app collected 2026-09-28 06:16:02 UTC 5,100 bytes, 90 lines download raw bytes

1import { hasAuthenticatedSession } from '../auth/sessionState.js';
2import { navigate } from '../front.js';
3import { getAppSpaRedirectUrl } from '../runtime/appChannel.js';
4import { computeAnnualSavings, formatAnnualSavingsHint, formatAnnualSavingsLabel } from './pricingSavings.js';
5export const goToJoinOrDashboard = (event) => {
6    event.preventDefault();
7    if (hasAuthenticatedSession()) {
8        navigate("/dashboard-extract", event);
9    }
10    else {
11        window.location.href = getAppSpaRedirectUrl('/register-business') ?? "https://app.refect.app/register-business";
12    }
13};
14function formatMarketingPrice(amount) {
15    return `${amount}€`;
16}
17export function initPricingToggle() {
18    const pill = document.getElementById('pricingTogglePill');
19    const monthlyBtn = document.getElementById('pricingMonthlyBtn');
20    const yearlyBtn = document.getElementById('pricingYearlyBtn');
21    if (!pill || !monthlyBtn || !yearlyBtn)
22        return;
23    const starterPriceEl = document.getElementById('pricingStarterPrice');
24    const starterDiscountEl = document.getElementById('pricingStarterDiscount');
25    const proPriceEl = document.getElementById('pricingProPrice');
26    const proDiscountEl = document.getElementById('pricingProDiscount');
27    const autoPriceEl = document.getElementById('pricingAutoPrice');
28    const autoDiscountEl = document.getElementById('pricingAutoDiscount');
29    const locale = document.documentElement.lang || 'fr';
30    const monthlySuffix = locale.startsWith('en') ? '/month' : '/mois';
31    window.__pricingCurrency = 'eur';
32    function positionPill(isMonthly) {
33        const activeBtn = isMonthly ? monthlyBtn : yearlyBtn;
34        pill.style.left = `${activeBtn.offsetLeft}px`;
35        pill.style.width = `${activeBtn.offsetWidth}px`;
36    }
37    function setToggle(isMonthly) {
38        positionPill(isMonthly);
39        monthlyBtn.className = 'relative z-10 px-4 py-1.5 text-sm font-medium rounded-full cursor-pointer transition-colors duration-300 ' + (isMonthly ? 'text-white' : 'text-gray-700');
40        yearlyBtn.className = 'relative z-10 px-4 py-1.5 text-sm font-medium rounded-full cursor-pointer transition-colors duration-300 ' + (isMonthly ? 'text-gray-700' : 'text-white');
41        const starterMonthly = 69;
42        const starterYearlyTotal = 708;
43        const proMonthly = 219;
44        const proYearlyTotal = 2148;
45        const autoMonthly = 539;
46        const autoYearlyTotal = 5388;
47        function renderPlan(priceEl, discountEl, monthly, yearlyTotal) {
48            const effectiveMonthly = Math.round(yearlyTotal / 12);
49            const savings = formatMarketingPrice(computeAnnualSavings(monthly, yearlyTotal));
50            if (priceEl) {
51                priceEl.innerHTML = isMonthly
52                    ? `${formatMarketingPrice(monthly)}<span class="text-base font-normal text-gray-600">${monthlySuffix}</span>`
53                    : `${formatMarketingPrice(effectiveMonthly)}<span class="text-base font-normal text-gray-600">${monthlySuffix}</span>`;
54            }
55            if (discountEl) {
56                discountEl.innerHTML = isMonthly
57                    ? `<span class="text-fuchsia-800 font-semibold">${formatAnnualSavingsHint(savings)}</span>`
58                    : `<span class="text-fuchsia-800 font-semibold">${formatAnnualSavingsLabel(savings)}</span>`;
59                discountEl.classList.remove('invisible');
60            }
61        }
62        renderPlan(starterPriceEl, starterDiscountEl, starterMonthly, starterYearlyTotal);
63        renderPlan(proPriceEl, proDiscountEl, proMonthly, proYearlyTotal);
64        renderPlan(autoPriceEl, autoDiscountEl, autoMonthly, autoYearlyTotal);
65    }
66    let isMonthlySelected = false;
67    setToggle(false);
68    monthlyBtn.addEventListener('click', () => { isMonthlySelected = true; setToggle(true); });
69    yearlyBtn.addEventListener('click', () => { isMonthlySelected = false; setToggle(false); });
70    window.addEventListener('resize', () => positionPill(isMonthlySelected));
71    // Les libellés d'économie viennent de l'i18n : re-rendu si les traductions arrivent après.
72    document.addEventListener('nearby:localeChanged', () => setToggle(isMonthlySelected));
73}
74export function bindLandingPricingBlocks() {
75    document.getElementById("joinLandingPricing")?.addEventListener("click", goToJoinOrDashboard);
76    document.getElementById("joinLandingStarter")?.addEventListener("click", goToJoinOrDashboard);
77    document.getElementById("joinLandingMensuel")?.addEventListener("click", goToJoinOrDashboard);
78    document.getElementById("joinLandingAnnuel")?.addEventListener("click", goToJoinOrDashboard);
79    document.getElementById("joinLandingAuto")?.addEventListener("click", goToJoinOrDashboard);
80    document.getElementById("contactLandingCTA")?.addEventListener("click", (e) => {
81        e.preventDefault();
82        navigate("/contact", e);
83    });
84    document.querySelectorAll(".nav-to-features").forEach(el => {
85        el.addEventListener("click", (e) => {
86            e.preventDefault();
87            navigate("/features/claude-connector", e);
88        });
89    });
90}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.