Files
integration/website/public/widgets/dist/feedback.js
Sylvain Zimmer 720ee9f4f0 (widgets) import widgets code from Messages and setup Docker workflow (#33)
This adds Gaufre v2 with source, documentation, examples and built artefacts.
Also includes the feedback widget from Messages.
2025-11-19 15:18:21 +01:00

2 lines
6.0 KiB
JavaScript

(function(){"use strict";const P="#wrapper{position:fixed;z-index:1000;width:350px;height:400px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;display:flex;flex-direction:column}#header{background:#000091;color:#fff;display:flex;align-items:center;justify-content:space-between;border-radius:12px 12px 0 0}h6{padding:16px;font-weight:600;font-size:16px;margin:0}#close{background:none;border:none;color:#fff;cursor:pointer;font-size:18px;margin-right:12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:8px}#content{display:flex;flex:1;flex-direction:column}form{flex:1;padding:16px;display:flex;flex-direction:column;gap:12px}#email{border:1px solid #e0e0e0;border-radius:8px;padding:12px;font-family:inherit;font-size:14px}#feedback-text{flex:1;border:1px solid #e0e0e0;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;resize:none}#submit{background:#000091;color:#fff;border:2px solid #000091;border-radius:8px;padding:12px;font-weight:600;cursor:pointer;transition:background .2s}#submit:hover,#close:hover{background:#1212ff}#feedback-text:focus,#email:focus,#submit:focus{outline:2px solid #0a76f6;border-color:#fff}#close:focus{outline:2px solid white}#status{font-size:14px;font-weight:500;text-align:center}#success{display:none;flex:1;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;text-align:center}#success i{background:#27a658;color:#fff;width:60px;height:60px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;margin-bottom:20px;font-style:normal}#success p{color:#0f4e27;margin:0 0 30px;font-size:16px;font-weight:500}#error{color:#dc3545;margin-bottom:12px}#error:empty{margin:0}@media (max-width: 420px){#wrapper{width:100%;right:0!important;border-radius:0}}";function j(e,t,o){const n=`lasuite-widget-${e}-shadow`,s=document.getElementById(n);s&&s.remove();const i=document.createElement("div");i.id=n;const c=i.attachShadow({mode:"open"}),d=document.createElement("style");d.textContent=o;const f=document.createElement("div");return f.innerHTML=t,c.appendChild(d),c.appendChild(f),i}const T="lasuite-widget",u=(e,t,o,n)=>document.dispatchEvent(new CustomEvent(`${T}-${e}-${t}`,o?{detail:o}:void 0)),_=(e,t,o,n,s)=>{const i=d=>s(d.detail),c=`${T}-${e}-${t}`;return document.addEventListener(c,i,void 0),()=>document.removeEventListener(c,i,void 0)},b=2,L=e=>window._lasuite_widget?._loaded?.[e],F=(e,t)=>{window._lasuite_widget?._loaded&&(window._lasuite_widget._loaded[e]=t)},I=e=>{window._lasuite_widget||(window._lasuite_widget=[]);const t=window._lasuite_widget;if(t._loaded||(t._loaded={}),L(e)!==b){t.push=(...o)=>{for(const n of o)L(n[0])===b?u(n[0],n[1],n[2]):t[t.length]=n;return t.length},F(e,b);for(const o of t.splice(0,t.length))t.push(o)}u(e,"loaded")},q=e=>e.offsetWidth>0&&e.offsetHeight>0,O=(e,t,o)=>{const n=s=>{if(s.key!=="Tab")return;const i=Array.from(t.querySelectorAll(o)).filter(f=>q(f));if(i.length===0)return;const c=i[0],d=i[i.length-1];s.shiftKey&&e.activeElement===c?(s.preventDefault(),d.focus()):!s.shiftKey&&e.activeElement===d&&(s.preventDefault(),c.focus())};return t.addEventListener("keydown",n),()=>{t.removeEventListener("keydown",n)}},U=e=>{const t=o=>{o.key==="Escape"&&(o.preventDefault(),e())};return document.addEventListener("keydown",t),()=>{document.removeEventListener("keydown",t)}},a="feedback";_(a,"init",null,!1,async e=>{if(!e.api||!e.channel){console.error("Feedback widget requires an API URL and a channel ID");return}let t;try{const l=await(await fetch(`${e.api}config/`,{headers:{"X-Channel-ID":e.channel}})).json();if(!l.success)throw new Error(l.detail||"Unknown error");if(l.captcha)throw new Error("Captcha is not supported yet");t=l.config}catch(h){console.error("Error fetching config",h),u(a,"closed");return}const o=e.title||t?.title||"Feedback",n=e.placeholder||t?.placeholder||"Share your feedback...",s=e.emailPlaceholder||t?.emailPlaceholder||"Your email...",i=e.submitText||t?.submitText||"Send Feedback",c=e.successText||t?.successText||"Thank you for your feedback!",d=e.successText2||t?.successText2||"",f=e.closeLabel||t?.closeLabel||"Close the feedback widget",D=j(a,'<div id="wrapper"><div id="header"><h6 id="title"></h6><button id="close">&times;</button></div><div id="content"><form><textarea id="feedback-text" autocomplete="off" required></textarea><input type="email" id="email" autocomplete="email" required><button type="submit" id="submit"></button></form><div id="error" aria-live="polite" role="status"></div><div aria-live="polite" role="status" id="success"><i aria-hidden="true">✔</i><p id="success-text"></p><p id="success-text2"></p></div></div></div>',P),p=D.shadowRoot,r=p.querySelector.bind(p),g=r("#wrapper"),W=r("#title"),B=r("#submit"),m=r("#feedback-text"),v=r("#error"),S=r("#close"),x=r("#email"),$=r("form"),K=r("#success"),M=r("#success-text"),H=r("#success-text2");g.style.bottom=20+(e.bottomOffset||0)+"px",g.style.right=20+(e.rightOffset||0)+"px",W.textContent=o,m.placeholder=n,x.placeholder=s,B.textContent=i,S.setAttribute("aria-label",f),e.email&&x.remove(),$.addEventListener("submit",async h=>{h.preventDefault(),v.textContent="";const l=m.value.trim(),A=e.email||x.value.trim();try{if(!l)throw m.focus(),new Error("Missing value");if(!A)throw x.focus(),new Error("Missing value");const w=await fetch(t?.submitUrl||`${e.api}deliver/`,{method:"POST",headers:{"Content-Type":"application/json","X-Channel-ID":e.channel},body:JSON.stringify({textBody:l,email:A})});let C;try{C=await w.json()}catch{throw new Error("Invalid response from server")}if(!C.success)throw new Error(C.detail||"Unknown error");$.remove(),K.style.display="flex",requestAnimationFrame(()=>{M.textContent=c,H.textContent=d})}catch(w){v.style.display="block",v.textContent="⚠ "+(w instanceof Error?w.message:"Unknown error")}});let y=null,E=null,k=()=>{};const z=()=>{p.host.remove(),y&&y(),E&&E(),k&&k(),u(a,"closed")};S.addEventListener("click",z),k=_(a,"close",null,!1,z),document.body.appendChild(D),m.focus(),y=O(p,g,"textarea,input,button"),E=U(()=>{u(a,"close")}),u(a,"opened")}),I(a)})();