{"id":13994,"date":"2026-09-23T13:42:44","date_gmt":"2026-09-23T17:42:44","guid":{"rendered":"https:\/\/nettoyagethermopompegatineau.ca\/?page_id=13994"},"modified":"2026-09-30T14:05:21","modified_gmt":"2026-09-30T18:05:21","slug":"customer-report-2","status":"publish","type":"page","link":"https:\/\/nettoyagethermopompegatineau.ca\/en\/rapportclient\/","title":{"rendered":"Client Report"},"content":{"rendered":"<section class=\"bde-section-13994-100 bde-section\">\n  \n  \n\t\n\n\n\n<div class=\"section-container\"><div class=\"bde-code-block-13994-101 bde-code-block\">\n\n  <!--\n  Air-FP \u2014 Rapport de service client\n  \u00c0 coller tel quel dans un \u00e9l\u00e9ment \"Code\" (HTML) de Breakdance sur la page \"Rapportclient\".\n  Tout est encapsul\u00e9 sous .afp-rapport pour ne rien affecter ailleurs sur le site.\n\n  2026-10: ajout de la note du technicien (jobs.note_client), qui manquait\n  enti\u00e8rement \u2014 le code n'affichait aucun champ \"note\" avant ce changement.\n-->\n<div class=\"afp-rapport\">\n  <style>\n    .afp-rapport{\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-radius:14px;\n      --afp-font-display:'Fraunces', serif; --afp-font-body:'Inter', system-ui, sans-serif;\n      display:block;\n      width:100%;\n      font-family:var(--afp-font-body);\n      color:var(--afp-ink);\n      background:var(--afp-bg);\n      padding:28px 0 60px;\n      -webkit-font-smoothing:antialiased;\n    }\n    .afp-rapport, .afp-rapport *{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }\n    .afp-rapport h1, .afp-rapport h2{ font-family:var(--afp-font-display); font-weight:600; margin:0; }\n    .afp-rapport .afp-wrap{ max-width:560px; margin:0 auto; padding:0 16px; }\n    .afp-rapport .afp-brand{ font-family:var(--afp-font-display); font-size:17px; font-weight:600; color:var(--afp-teal-dark); text-align:center; margin-bottom:22px; }\n    .afp-rapport .afp-card{ background:var(--afp-surface); border:1.5px solid var(--afp-line); border-radius:var(--afp-radius); padding:22px 20px; margin-bottom:16px; }\n    .afp-rapport .afp-card h1{ font-size:21px; margin-bottom:4px; }\n    .afp-rapport .afp-card .afp-sub{ color:var(--afp-ink-soft); font-size:13.5px; margin-bottom:2px; }\n    .afp-rapport .afp-row{ display:flex; justify-content:space-between; gap:12px; padding:10px 0; border-bottom:1px solid var(--afp-line); font-size:14.5px; }\n    .afp-rapport .afp-row:last-child{ border-bottom:none; }\n    .afp-rapport .afp-row span:first-child{ color:var(--afp-ink-soft); flex-shrink:0; }\n    .afp-rapport .afp-row span:last-child{ text-align:right; }\n    .afp-rapport .afp-note{ margin-top:14px; padding:14px 16px; background:var(--afp-teal-tint); border-radius:10px; }\n    .afp-rapport .afp-note-label{ font-size:11.5px; font-weight:600; text-transform:uppercase; letter-spacing:.03em; color:var(--afp-teal-dark); margin-bottom:6px; }\n    .afp-rapport .afp-note-texte{ font-size:14px; color:var(--afp-ink); line-height:1.55; white-space:pre-line; }\n    .afp-rapport .afp-photos{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; margin-top:14px; }\n    .afp-rapport .afp-photos img{ width:100%; aspect-ratio:1; object-fit:cover; border-radius:9px; border:1px solid var(--afp-line); cursor:pointer; }\n    .afp-rapport .afp-vip-cta{ background:var(--afp-teal-tint); border-radius:var(--afp-radius); padding:20px; text-align:center; }\n    .afp-rapport .afp-vip-cta h2{ font-size:17px; color:var(--afp-teal-dark); margin-bottom:6px; }\n    .afp-rapport .afp-vip-cta p{ font-size:13.5px; color:var(--afp-ink-soft); margin:0 0 14px; line-height:1.5; }\n    .afp-rapport .afp-vip-cta a{ display:inline-block; background:var(--afp-teal); color:#fff; text-decoration:none; padding:12px 26px; border-radius:10px; font-size:14px; font-weight:600; }\n    .afp-rapport .afp-empty-note{ color:var(--afp-ink-soft); font-size:14px; text-align:center; padding:30px 10px; }\n    .afp-rapport .afp-lightbox{ position:fixed; inset:0; background:rgba(20,32,30,.85); display:none; align-items:center; justify-content:center; z-index:99999; padding:20px; }\n    .afp-rapport .afp-lightbox.afp-show{ display:flex; }\n    .afp-rapport .afp-lightbox img{ max-width:100%; max-height:100%; border-radius:10px; }\n  <\/style>\n\n  <div class=\"afp-wrap\">\n    <div class=\"afp-brand\">Air-FP<\/div>\n    <div id=\"afpRcContenu\">\n      <div class=\"afp-card\"><p class=\"afp-empty-note\">Chargement du rapport\u2026<\/p><\/div>\n    <\/div>\n  <\/div>\n  <div class=\"afp-lightbox\" id=\"afpRcLightbox\"><img decoding=\"async\" id=\"afpRcLightboxImg\" src=\"\"><\/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 afpRcAppelerTechApp(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    function afpRcFmtDate(iso){\n      if(!iso) return '';\n      const [an,mo,jr] = iso.split('-').map(Number);\n      const d = new Date(an, mo-1, jr);\n      return d.toLocaleDateString('fr-CA', { weekday:'long', day:'numeric', month:'long', year:'numeric' });\n    }\n\n    \/\/ \u00c9chappe le texte de la note (saisie libre par le technicien) avant de\n    \/\/ l'ins\u00e9rer dans le HTML, pour \u00e9viter qu'un caract\u00e8re comme < ou &\n    \/\/ casse l'affichage \u2014 les autres champs ne le font pas car ils viennent\n    \/\/ du catalogue\/de la fiche client, jamais d'un texte libre tap\u00e9 sur le\n    \/\/ terrain.\n    function afpRcEchapper(txt){\n      const div = document.createElement('div');\n      div.textContent = txt;\n      return div.innerHTML;\n    }\n\n    function afpRcOuvrirLightbox(url){\n      const img = document.getElementById('afpRcLightboxImg');\n      const box = document.getElementById('afpRcLightbox');\n      if(img) img.src = url;\n      if(box) box.classList.add('afp-show');\n    }\n    window.afpRcOuvrirLightbox = afpRcOuvrirLightbox;\n\n    async function afpRcCharger(){\n      const params = new URLSearchParams(window.location.search);\n      const jobId = params.get('job');\n      const contenu = document.getElementById('afpRcContenu');\n      if(!contenu) return;\n\n      if(!jobId){\n        contenu.innerHTML = '<div class=\"afp-card\"><p class=\"afp-empty-note\">Lien invalide \u2014 il manque la r\u00e9f\u00e9rence du rendez-vous.<\/p><\/div>';\n        return;\n      }\n\n      try{\n        const data = await afpRcAppelerTechApp({ action:'rapport_client', job_id: jobId });\n\n        const photosHtml = (data.photos||[]).length\n          ? `<div class=\"afp-photos\">${data.photos.map(url=>`<img decoding=\"async\" src=\"${url}\" onclick=\"afpRcOuvrirLightbox('${url}')\">`).join('')}<\/div>`\n          : '';\n\n        const rappelHtml = data.annees_recommandees\n          ? `<div class=\"afp-row\"><span>Recommandation<\/span><span>Entretien aux ${data.annees_recommandees} an(s)<\/span><\/div>`\n          : '';\n\n        const noteHtml = data.note_client\n          ? `<div class=\"afp-note\">\n               <div class=\"afp-note-label\">Note du technicien<\/div>\n               <div class=\"afp-note-texte\">${afpRcEchapper(data.note_client)}<\/div>\n             <\/div>`\n          : '';\n\n        contenu.innerHTML = `\n          <div class=\"afp-card\">\n            <h1>Votre rapport de service<\/h1>\n            <div class=\"afp-sub\">${data.client_nom||''} \u00b7 ${afpRcFmtDate(data.date)}<\/div>\n            <div style=\"margin-top:14px;\">\n              <div class=\"afp-row\"><span>Services<\/span><span>${(data.services||[]).join(', ')||'\u2014'}<\/span><\/div>\n              ${rappelHtml}\n            <\/div>\n            ${noteHtml}\n            ${photosHtml}\n          <\/div>\n          <div class=\"afp-vip-cta\">\n            <h2>Programme fid\u00e9lisation VIP<\/h2>\n            <p>Inscrivez-vous pour profiter de prix avantageux r\u00e9serv\u00e9s aux membres VIP et recevoir automatiquement un rappel quand votre prochain entretien approche.<\/p>\n            <a href=\"\/programmevip\/?client=${data.client_id}&job=${data.job_id}\">Je m'inscris<\/a>\n          <\/div>\n        `;\n      }catch(err){\n        contenu.innerHTML = `<div class=\"afp-card\"><p class=\"afp-empty-note\">Impossible de charger ce rapport (${err.message}).<\/p><\/div>`;\n      }\n    }\n\n    function afpRcInit(){\n      try{\n        const lightbox = document.getElementById('afpRcLightbox');\n        if(lightbox){\n          lightbox.addEventListener('click', ()=>{ lightbox.classList.remove('afp-show'); });\n        }\n        afpRcCharger();\n      }catch(e){\n        const contenu = document.getElementById('afpRcContenu');\n        if(contenu){\n          contenu.innerHTML = '<div class=\"afp-card\"><p class=\"afp-empty-note\">Erreur technique (' + (e && e.message ? e.message : e) + ').<\/p><\/div>';\n        }\n      }\n    }\n\n    if(document.readyState === 'loading'){\n      document.addEventListener('DOMContentLoaded', afpRcInit);\n    }else{\n      afpRcInit();\n    }\n  })();\n  <\/script>\n<\/div>\n\n\n\n<\/div><\/div>\n<\/section>","protected":false},"excerpt":{"rendered":"<p>Air-FP Loading report\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-13994","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13994","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=13994"}],"version-history":[{"count":5,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13994\/revisions"}],"predecessor-version":[{"id":14229,"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/pages\/13994\/revisions\/14229"}],"wp:attachment":[{"href":"https:\/\/nettoyagethermopompegatineau.ca\/en\/wp-json\/wp\/v2\/media?parent=13994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}