diff --git a/services/targo-hub/lib/roster.js b/services/targo-hub/lib/roster.js index 6a4aa21..a9b215c 100644 --- a/services/targo-hub/lib/roster.js +++ b/services/targo-hub/lib/roster.js @@ -938,6 +938,7 @@ h1{font-size:21px;margin:0 0 4px;letter-spacing:-.02em} .slot.sel{background:#e7f9ef;border-color:var(--g);color:var(--g-d)} .rank{position:absolute;top:-8px;right:-8px;background:var(--g);color:#fff;width:20px;height:20px;border-radius:50%;font-size:12px;font-weight:700;line-height:20px} .btn{background:var(--g);color:#fff;border:0;border-radius:11px;padding:14px 18px;font-size:15px;font-weight:700;font-family:inherit;cursor:pointer;width:100%;margin-top:14px} +.btn2{display:block;text-align:center;text-decoration:none;background:#fff;color:var(--g);border:1.5px solid var(--g);border-radius:11px;padding:12px 18px;font-size:14px;font-weight:700;margin-top:10px} .btn:disabled{background:#b9c7c0;cursor:default} .hint{font-size:12px;color:var(--muted);margin:9px 0 0;text-align:center} .hold{display:none;align-items:center;gap:9px;background:#e7f9ef;border:1px solid #b6ebcd;border-radius:10px;padding:10px 13px;margin-top:12px;font-size:13px;font-weight:600;color:var(--g-d)} @@ -966,7 +967,12 @@ h1{font-size:21px;margin:0 0 4px;letter-spacing:-.02em} var token=new URLSearchParams(location.search).get('token')||''; var FR=['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi']; var MO=['janv.','févr.','mars','avr.','mai','juin','juil.','août','sept.','oct.','nov.','déc.']; -var mode='pick',picks=[],sel=null,windows=[],dur=1,timer=null,deadline=0; +var mode='pick',picks=[],sel=null,windows=[],dur=1,timer=null,deadline=0,loc='',svc=''; +function pad(n){return (n<10?'0':'')+n} +// Lien .ics universel (Apple/Google/Outlook) — heure « flottante » (interprétée dans le fuseau de l'appareil, = Québec). +function icsLink(date,start,durH,tech){var t=start.split(':'),d=date.replace(/-/g,'');var sh=Number(t[0])||9,sm=Number(t[1])||0;var eh=Math.min(23,sh+Math.max(1,Math.round(durH||1)));var dt=function(h,m){return d+'T'+pad(h)+pad(m)+'00'}; + var ics=['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//Gigafibre//RDV//FR','BEGIN:VEVENT','DTSTART:'+dt(sh,sm),'DTEND:'+dt(eh,sm),'SUMMARY:Rendez-vous Gigafibre'+(svc?' - '+svc:''),'DESCRIPTION:'+((tech?'Technicien: '+tech+'. ':'')+'Rendez-vous technique Gigafibre.'),'LOCATION:'+(loc||''),'END:VEVENT','END:VCALENDAR'].join('\r\n'); + return 'data:text/calendar;charset=utf-8,'+encodeURIComponent(ics)} function d2(iso){var a=iso.split('-').map(Number);return new Date(Date.UTC(a[0],a[1]-1,a[2]))} function dayLabel(iso){var dt=d2(iso);return FR[dt.getUTCDay()]+' '+dt.getUTCDate()+' '+MO[dt.getUTCMonth()]} function wkMon(iso){var dt=d2(iso);var off=(dt.getUTCDay()+6)%7;dt.setUTCDate(dt.getUTCDate()-off);return dt.toISOString().slice(0,10)} @@ -977,7 +983,7 @@ function load(){api('/book/api/options?token='+encodeURIComponent(token)).then(f var info=el('jobinfo'),c=el('content'); if(!r.ok){info.textContent='';c.innerHTML='
Lien invalide ou expiré. Contactez-nous.
';return} if(r.job&&r.job.scheduled){info.textContent='';c.innerHTML='
Votre rendez-vous est déjà confirmé :
'+dayLabel(r.job.scheduled)+'.
';return} - dur=Number(r.job&&r.job.duration)||1;windows=r.windows||[]; + dur=Number(r.job&&r.job.duration)||1;windows=r.windows||[];loc=(r.job&&r.job.location)||'';svc=(r.job&&r.job.service_type)||''; info.textContent=(r.job&&r.job.service_type?r.job.service_type+' · ':'')+((r.job&&r.job.location)||''); if(!windows.length){renderFreeform();return} c.innerHTML='
' @@ -1029,7 +1035,7 @@ function confirmPick(){if(!sel)return;var go=el('go');go.disabled=true;go.textCo function submitPropose(){var go=el('go');go.disabled=true;go.textContent='Envoi…';var prefs=picks.map(function(k){return{date:k.split('|')[0],start:k.split('|')[1]}}); api('/book/api/submit?token='+encodeURIComponent(token),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({mode:'rank',prefs:prefs})}).then(done)} function done(r){var c=el('content'); - if(r&&r.ok&&r.confirmed)c.innerHTML='
✅ Rendez-vous confirmé :
'+dayLabel(r.date)+' à '+r.start+''+(r.tech?'
Technicien : '+r.tech+'':'')+'
Merci !
'; + if(r&&r.ok&&r.confirmed)c.innerHTML='
✅ Rendez-vous confirmé :
'+dayLabel(r.date)+' à '+r.start+''+(r.tech?'
Technicien : '+r.tech+'':'')+'
Merci !
📅 Ajouter à mon calendrier'; else if(r&&r.ok)c.innerHTML='
Merci !
'+((r&&r.message)||'Nous vous confirmerons sous peu.')+'
'; else c.innerHTML='
'+((r&&r.message)||(r&&r.error)||'Une erreur est survenue.')+'
'} load();