{"id":13987,"date":"2026-09-23T13:24:01","date_gmt":"2026-09-23T17:24:01","guid":{"rendered":"https:\/\/nettoyagethermopompegatineau.ca\/?page_id=13987"},"modified":"2026-10-19T16:51:23","modified_gmt":"2026-10-19T20:51:23","slug":"vip-program","status":"publish","type":"page","link":"https:\/\/nettoyagethermopompegatineau.ca\/en\/programmevip\/","title":{"rendered":"VIP Program"},"content":{"rendered":"<section class=\"bde-section-13987-100 bde-section\">\n  \n  \n\t\n\n\n\n<div class=\"section-container\"><div class=\"bde-code-block-13987-101 bde-code-block\">\n\n  <div class=\"afp-vip\">\n  <style>\n    .afp-vip{\n      --afp-bg:#F5F7F6; --afp-surface:#FFFFFF; --afp-ink:#14201E; --afp-ink-soft:#55645F;\n      --afp-line:#DDE4E1; --afp-teal:#0C8479; --afp-teal-dark:#095F58; --afp-teal-tint:#E3F3F1;\n      --afp-amber:#B8791A; --afp-amber-tint:#FBF0DE;\n      --afp-radius:14px;\n      --afp-font-display:'Fraunces', serif; --afp-font-body:'Inter', system-ui, sans-serif;\n      --afp-font-mono:'IBM Plex Mono', ui-monospace, monospace;\n      display:block; width:100%;\n      font-family:var(--afp-font-body); color:var(--afp-ink); background:var(--afp-bg);\n      padding:28px 0 60px; -webkit-font-smoothing:antialiased;\n    }\n    .afp-vip, .afp-vip *{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }\n    .afp-vip h1, .afp-vip h2{ font-family:var(--afp-font-display); font-weight:600; margin:0; }\n    .afp-vip .afp-wrap{ max-width:480px; margin:0 auto; padding:0 16px; display:flex; flex-direction:column; gap:16px; }\n    .afp-vip .afp-brand{ font-family:var(--afp-font-display); font-size:17px; font-weight:600; color:var(--afp-teal-dark); text-align:center; margin-bottom:6px; }\n    .afp-vip .afp-card{ background:var(--afp-surface); border:1.5px solid var(--afp-line); border-radius:var(--afp-radius); padding:24px 20px; }\n    .afp-vip .afp-card h1{ font-size:21px; margin-bottom:8px; text-align:center; }\n    .afp-vip .afp-card h2{ font-size:18px; margin-bottom:6px; }\n    .afp-vip .afp-intro{ font-size:14px; color:var(--afp-ink-soft); line-height:1.55; text-align:center; margin:0 0 6px; }\n    .afp-vip .afp-texte{ font-size:14px; color:var(--afp-ink-soft); line-height:1.55; margin:0; }\n    .afp-vip .afp-badge-vip{ background:var(--afp-amber-tint); color:var(--afp-amber); font-size:12px; font-weight:600; padding:4px 12px; border-radius:999px; margin:0 auto 14px; display:block; width:fit-content; }\n    .afp-vip .afp-badge-ok{ background:var(--afp-teal-tint); color:var(--afp-teal-dark); }\n    .afp-vip .afp-note-info{ background:var(--afp-teal-tint); color:var(--afp-teal-dark); border-radius:10px; padding:10px 12px; font-size:13px; margin:16px 0; line-height:1.5; }\n    .afp-vip .afp-note-warn{ background:var(--afp-amber-tint); color:var(--afp-amber); border-radius:10px; padding:10px 12px; font-size:13px; margin:16px 0; line-height:1.5; }\n    .afp-vip .afp-section-label{ font-size:12px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--afp-ink-soft); margin:20px 0 10px; }\n    .afp-vip .afp-annees-choix{ display:grid; grid-template-columns:repeat(4,1fr); gap:8px; }\n    .afp-vip .afp-annee-btn{ padding:12px 6px; border-radius:10px; border:1.5px solid var(--afp-line); background:var(--afp-surface); font-family:var(--afp-font-mono); font-size:15px; font-weight:600; color:var(--afp-ink-soft); cursor:pointer; text-align:center; }\n    .afp-vip .afp-annee-btn.afp-selected{ border-color:var(--afp-teal); background:var(--afp-teal-tint); color:var(--afp-teal-dark); }\n    .afp-vip .afp-check-row{ display:flex; align-items:center; gap:10px; padding:11px 0; border-bottom:1px solid var(--afp-line); font-size:14.5px; }\n    .afp-vip .afp-check-row:last-of-type{ border-bottom:none; }\n    .afp-vip .afp-check-row input{ width:19px; height:19px; accent-color:var(--afp-teal); cursor:pointer; }\n    .afp-vip .afp-check-row label{ cursor:pointer; }\n    .afp-vip .afp-btn{ display:block; width:100%; margin-top:22px; background:var(--afp-teal); color:#fff; border:none; border-radius:11px; padding:15px; font-family:var(--afp-font-body); font-size:15px; font-weight:600; cursor:pointer; }\n    .afp-vip .afp-btn:disabled{ opacity:.6; cursor:default; }\n    .afp-vip .afp-empty-note{ text-align:center; color:var(--afp-ink-soft); font-size:14px; margin:0; }\n    .afp-vip .afp-succes-icone{ font-size:40px; text-align:center; margin-bottom:8px; }\n\n    \/* ---- Mon compte : solde + code de parrainage ---- *\/\n    .afp-vip .afp-solde{ text-align:center; padding:6px 0 4px; }\n    .afp-vip .afp-solde-label{ font-size:12px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--afp-ink-soft); }\n    .afp-vip .afp-solde-montant{ font-family:var(--afp-font-display); font-size:44px; font-weight:600; color:var(--afp-teal-dark); line-height:1.1; margin-top:4px; }\n    .afp-vip .afp-solde-attente{ display:inline-block; margin-top:8px; background:var(--afp-amber-tint); color:var(--afp-amber); font-size:13px; font-weight:600; padding:4px 12px; border-radius:999px; }\n    .afp-vip .afp-solde-aide{ font-size:13px; color:var(--afp-ink-soft); margin-top:10px; line-height:1.5; }\n    .afp-vip .afp-code-box{ margin-top:18px; border:1.5px dashed var(--afp-teal); background:var(--afp-teal-tint); border-radius:12px; padding:16px; text-align:center; }\n    .afp-vip .afp-code-label{ font-size:12px; color:var(--afp-teal-dark); font-weight:600; letter-spacing:.06em; text-transform:uppercase; }\n    .afp-vip .afp-code{ font-family:var(--afp-font-mono); font-size:28px; font-weight:600; letter-spacing:.08em; color:var(--afp-ink); margin:6px 0 12px; word-break:break-all; }\n    .afp-vip .afp-code-actions{ display:flex; gap:8px; }\n    .afp-vip .afp-code-actions button{ flex:1; padding:12px 8px; border-radius:10px; font-family:var(--afp-font-body); font-size:14px; font-weight:600; cursor:pointer; border:1.5px solid var(--afp-teal); }\n    .afp-vip .afp-btn-copier{ background:var(--afp-surface); color:var(--afp-teal-dark); }\n    .afp-vip .afp-btn-partager{ background:var(--afp-teal); color:#fff; }\n    .afp-vip .afp-etapes{ list-style:none; padding:0; margin:16px 0 0; display:flex; flex-direction:column; gap:10px; }\n    .afp-vip .afp-etapes li{ display:flex; gap:10px; font-size:14px; line-height:1.5; color:var(--afp-ink); }\n    .afp-vip .afp-etape-num{ flex:0 0 24px; height:24px; border-radius:50%; background:var(--afp-teal-tint); color:var(--afp-teal-dark); font-weight:700; font-size:13px; display:flex; align-items:center; justify-content:center; }\n    .afp-vip .afp-histo{ list-style:none; padding:0; margin:0; }\n    .afp-vip .afp-histo li{ display:flex; justify-content:space-between; align-items:flex-start; gap:12px; padding:10px 0; border-bottom:1px solid var(--afp-line); font-size:14px; }\n    .afp-vip .afp-histo li:last-child{ border-bottom:none; }\n    .afp-vip .afp-histo-desc{ color:var(--afp-ink); }\n    .afp-vip .afp-histo-date{ display:block; font-size:12px; color:var(--afp-ink-soft); margin-top:2px; }\n    .afp-vip .afp-histo-montant{ font-family:var(--afp-font-mono); font-weight:600; white-space:nowrap; }\n    .afp-vip .afp-m-dispo{ color:var(--afp-teal-dark); }\n    .afp-vip .afp-m-attente{ color:var(--afp-amber); }\n    .afp-vip .afp-m-utilise{ color:var(--afp-ink-soft); text-decoration:line-through; }\n    .afp-vip .afp-toast{ font-size:12px; color:var(--afp-teal-dark); margin-top:8px; min-height:16px; }\n  <\/style>\n\n  <div class=\"afp-wrap\">\n    <div class=\"afp-brand\">Air-FP<\/div>\n    <div class=\"afp-card\" id=\"afpCompte\" style=\"display:none\"><\/div>\n    <div class=\"afp-card\" id=\"afpVipContenu\"><p class=\"afp-empty-note\">Chargement de votre dossier\u2026<\/p><\/div>\n  <\/div>\n\n  <script>\n  (function(){\n    const SUPABASE_URL = 'https:\/\/hlcvuhwqlqytmnleqgqw.supabase.co';\n    const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhsY3Z1aHdxbHF5dG1ubGVxZ3F3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODQ3NDA3NjAsImV4cCI6MjEwMDMxNjc2MH0.vli-DqA-nNXdRos3fr9jQINoPvlcE4Ca0dJoV_oUQO4';\n\n    async function afpVipAppelerTechApp(payload){\n      const res = await fetch(`${SUPABASE_URL}\/functions\/v1\/tech_app`, {\n        method:'POST',\n        headers:{ apikey: SUPABASE_ANON_KEY, Authorization:`Bearer ${SUPABASE_ANON_KEY}`, 'Content-Type':'application\/json' },\n        body: JSON.stringify(payload)\n      });\n      const data = await res.json();\n      if(!res.ok) throw new Error(data.erreur || 'Erreur serveur');\n      return data;\n    }\n\n    const afpVipParams = new URLSearchParams(window.location.search);\n    const afpVipClientId = afpVipParams.get('client');\n    const afpVipJobId = afpVipParams.get('job');\n    let afpVipAnneeChoisie = 3;\n\n    const esc = (s) => String(s ?? '').replace(\/[&<>\"']\/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]));\n    const dollars = (n) => `${Number(n || 0).toLocaleString('fr-CA', { maximumFractionDigits: 2 })} $`;\n    const dateCourte = (d) => d ? new Date(String(d).length === 10 ? d + 'T12:00:00' : d).toLocaleDateString('fr-CA', { day:'numeric', month:'long', year:'numeric' }) : '';\n\n    \/\/ ---------- Mon compte : solde, code de parrainage, historique ----------\n    function afpRenderCompte(data){\n      if(!data.code_reference) return;\n      const compte = document.getElementById('afpCompte');\n      const prenom = (data.client_nom || '').split(' ')[0];\n      const ami = dollars(data.reference_rabais_ami);\n      const parrain = dollars(data.reference_credit_parrain);\n      const seuil = dollars(data.reference_seuil);\n\n      const lignes = (data.credits_historique || []).map(c => {\n        let desc;\n        if (c.type === 'cadeau') desc = c.note || 'Cadeau de remerciement Air-FP';\n        else if (c.filleul) desc = `Parrainage \u2014 ${esc(c.filleul)}`;\n        else desc = c.note || 'Cr\u00e9dit de parrainage';\n        let etat, cls;\n        if (c.statut === 'en_attente') { etat = 'en attente du service de votre ami'; cls = 'afp-m-attente'; }\n        else if (c.statut === 'utilise') { etat = 'utilis\u00e9 sur un rendez-vous'; cls = 'afp-m-utilise'; }\n        else { etat = 'disponible'; cls = 'afp-m-dispo'; }\n        return `<li><span><span class=\"afp-histo-desc\">${esc(desc)}<\/span><span class=\"afp-histo-date\">${dateCourte(c.date)} \u00b7 ${etat}<\/span><\/span><span class=\"afp-histo-montant ${cls}\">${c.statut === 'utilise' ? '' : '+'}${dollars(c.montant)}<\/span><\/li>`;\n      }).join('');\n\n      compte.innerHTML = `\n        <span class=\"afp-badge-vip afp-badge-ok\">Mon compte Air-FP<\/span>\n        <h1>${prenom ? 'Bonjour ' + esc(prenom) + '!' : 'Votre compte'}<\/h1>\n        <div class=\"afp-solde\">\n          <div class=\"afp-solde-label\">Cr\u00e9dit disponible<\/div>\n          <div class=\"afp-solde-montant\">${dollars(data.credit_disponible)}<\/div>\n          ${data.credit_en_attente > 0 ? `<div class=\"afp-solde-attente\">+ ${dollars(data.credit_en_attente)} en attente<\/div>` : ''}\n          <div class=\"afp-solde-aide\">Votre cr\u00e9dit est valide \u00e0 vie et s'applique automatiquement \u00e0 votre prochain rendez-vous.<\/div>\n        <\/div>\n\n        <div class=\"afp-code-box\">\n          <div class=\"afp-code-label\">Votre code de parrainage<\/div>\n          <div class=\"afp-code\" id=\"afpCode\">${esc(data.code_reference)}<\/div>\n          <div class=\"afp-code-actions\">\n            <button type=\"button\" class=\"afp-btn-copier\" id=\"afpBtnCopier\">Copier<\/button>\n            <button type=\"button\" class=\"afp-btn-partager\" id=\"afpBtnPartager\">Partager<\/button>\n          <\/div>\n          <div class=\"afp-toast\" id=\"afpToast\"><\/div>\n        <\/div>\n\n        <div class=\"afp-section-label\">Comment \u00e7a marche<\/div>\n        <ul class=\"afp-etapes\">\n          <li><span class=\"afp-etape-num\">1<\/span><span>Donnez votre code \u00e0 vos proches.<\/span><\/li>\n          <li><span class=\"afp-etape-num\">2<\/span><span>Ils obtiennent <strong>${ami} de rabais<\/strong> sur leur premier service (${seuil} et plus), en ligne ou par t\u00e9l\u00e9phone.<\/span><\/li>\n          <li><span class=\"afp-etape-num\">3<\/span><span>D\u00e8s que leur service est compl\u00e9t\u00e9, vous recevez <strong>${parrain} de cr\u00e9dit<\/strong>. Aucune limite : les cr\u00e9dits s'accumulent!<\/span><\/li>\n        <\/ul>\n\n        ${lignes ? `<div class=\"afp-section-label\">Historique<\/div><ul class=\"afp-histo\">${lignes}<\/ul>` : ''}\n      `;\n      compte.style.display = '';\n\n      const message = `Je fais affaire avec Air-FP pour le nettoyage de thermopompe et de ventilation. Avec mon code ${data.code_reference}, tu as ${ami} de rabais sur ton premier service : https:\/\/nettoyagethermopompegatineau.ca`;\n      const toast = (t) => { const el = document.getElementById('afpToast'); el.textContent = t; setTimeout(() => { el.textContent = ''; }, 2500); };\n      document.getElementById('afpBtnCopier').addEventListener('click', async () => {\n        try { await navigator.clipboard.writeText(data.code_reference); toast('Code copi\u00e9!'); }\n        catch { toast('Code : ' + data.code_reference); }\n      });\n      document.getElementById('afpBtnPartager').addEventListener('click', async () => {\n        if (navigator.share) {\n          try { await navigator.share({ title: 'Air-FP', text: message }); } catch {}\n        } else {\n          try { await navigator.clipboard.writeText(message); toast('Message copi\u00e9 \u2014 collez-le dans un texto ou un courriel.'); }\n          catch { toast(message); }\n        }\n      });\n    }\n\n    \/\/ ---------- Programme VIP (rappels d'entretien) ----------\n    function afpVipRenderFormulaire(data){\n      afpVipAnneeChoisie = Math.min(data.annees_recommandees || 3, 4);\n      const contenu = document.getElementById('afpVipContenu');\n      const prenom = data.client_nom ? data.client_nom.split(' ')[0] : '';\n\n      const noteInscrit = data.deja_inscrit\n        ? `<div class=\"afp-note-info\">Vous \u00eates d\u00e9j\u00e0 membre VIP. Vous pouvez mettre \u00e0 jour vos pr\u00e9f\u00e9rences ci-dessous.<\/div>`\n        : '';\n      const noteDesinscrit = data.desinscrit\n        ? `<div class=\"afp-note-warn\">Vous vous \u00e9tiez d\u00e9sinscrit(e) de nos communications \u2014 vous inscrire ici r\u00e9active les rappels automatiques.<\/div>`\n        : '';\n\n      contenu.innerHTML = `\n        <span class=\"afp-badge-vip\">Programme VIP<\/span>\n        <h1>${data.deja_inscrit ? 'Vos pr\u00e9f\u00e9rences VIP' : 'Devenez membre VIP' + (prenom && !data.code_reference ? ', ' + esc(prenom) : '')}<\/h1>\n        <p class=\"afp-intro\">Gratuit. Profitez de prix avantageux r\u00e9serv\u00e9s aux membres sur vos prochains services, et on s'occupe de vous rappeler automatiquement quand votre prochain entretien approche.<\/p>\n        ${noteInscrit}\n        ${noteDesinscrit}\n        <div class=\"afp-section-label\">Me rappeler mon entretien aux<\/div>\n        <div class=\"afp-annees-choix\">\n          ${[1,2,3,4].map(n => `<button type=\"button\" class=\"afp-annee-btn${n === afpVipAnneeChoisie ? ' afp-selected' : ''}\" data-annee=\"${n}\">${n} an${n > 1 ? 's' : ''}<\/button>`).join('')}\n        <\/div>\n        <div class=\"afp-section-label\">Comment souhaitez-vous \u00eatre averti(e)?<\/div>\n        <div class=\"afp-check-row\">\n          <input type=\"checkbox\" id=\"afpVipChkCourriel\" ${data.rappel_courriel !== false ? 'checked' : ''}>\n          <label for=\"afpVipChkCourriel\">Par courriel<\/label>\n        <\/div>\n        <div class=\"afp-check-row\">\n          <input type=\"checkbox\" id=\"afpVipChkTexto\" ${data.rappel_texto !== false ? 'checked' : ''}>\n          <label for=\"afpVipChkTexto\">Par texto<\/label>\n        <\/div>\n        <button class=\"afp-btn\" id=\"afpVipBtnInscrire\">${data.deja_inscrit ? 'Mettre \u00e0 jour mes pr\u00e9f\u00e9rences' : \"Je m'inscris au programme VIP\"}<\/button>\n      `;\n\n      contenu.querySelectorAll('.afp-annee-btn').forEach(b => {\n        b.addEventListener('click', () => {\n          afpVipAnneeChoisie = Number(b.dataset.annee);\n          contenu.querySelectorAll('.afp-annee-btn').forEach(x => x.classList.toggle('afp-selected', x === b));\n        });\n      });\n      document.getElementById('afpVipBtnInscrire').addEventListener('click', () => afpVipInscrire(!!data.deja_inscrit));\n    }\n\n    async function afpVipInscrire(dejaInscrit){\n      const btn = document.getElementById('afpVipBtnInscrire');\n      const texto = document.getElementById('afpVipChkTexto').checked;\n      const courriel = document.getElementById('afpVipChkCourriel').checked;\n      btn.disabled = true;\n      btn.textContent = 'Un instant\u2026';\n      try{\n        await afpVipAppelerTechApp({\n          action:'rappelvip_inscrire',\n          client_id: afpVipClientId,\n          job_id: afpVipJobId,\n          annees: afpVipAnneeChoisie,\n          texto,\n          courriel,\n        });\n        const canal = (texto && courriel) ? ' par texto et courriel' : (texto ? ' par texto' : (courriel ? ' par courriel' : ''));\n        document.getElementById('afpVipContenu').innerHTML = `\n          <div class=\"afp-succes-icone\">\u2705<\/div>\n          <h1>C'est confirm\u00e9!<\/h1>\n          <p class=\"afp-intro\" style=\"margin-top:10px;\">Merci de votre confiance. On vous contactera automatiquement aux ${afpVipAnneeChoisie} an${afpVipAnneeChoisie > 1 ? 's' : ''} pour votre prochain entretien${canal}.<\/p>\n        `;\n      }catch(err){\n        btn.disabled = false;\n        btn.textContent = dejaInscrit ? 'Mettre \u00e0 jour mes pr\u00e9f\u00e9rences' : \"Je m'inscris au programme VIP\";\n        alert(`Erreur: ${err.message}`);\n      }\n    }\n\n    async function afpVipCharger(){\n      const contenu = document.getElementById('afpVipContenu');\n      if(!afpVipClientId){\n        contenu.innerHTML = '<p class=\"afp-empty-note\">Lien invalide \u2014 il manque votre r\u00e9f\u00e9rence client.<\/p>';\n        return;\n      }\n      try{\n        const data = await afpVipAppelerTechApp({ action:'rappelvip_infos', client_id: afpVipClientId, job_id: afpVipJobId });\n        afpRenderCompte(data);\n        afpVipRenderFormulaire(data);\n      }catch(err){\n        contenu.innerHTML = `<p class=\"afp-empty-note\">Impossible de charger votre dossier (${esc(err.message)}).<\/p>`;\n      }\n    }\n\n    afpVipCharger();\n  })();\n  <\/script>\n<\/div>\n\n\n<\/div><\/div>\n<\/section>","protected":false},"excerpt":{"rendered":"<p>Air-FP Chargement de votre dossier\u2026<\/p>","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_breakdance_hide_in_design_set":false,"_breakdance_tags":"","footnotes":""},"class_list":["post-13987","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13987","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/comments?post=13987"}],"version-history":[{"count":5,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13987\/revisions"}],"predecessor-version":[{"id":14367,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13987\/revisions\/14367"}],"wp:attachment":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/media?parent=13987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}