feat(booking): page /book « jamais bloquée » — repli disponibilités libres quand aucun créneau
Step 2/3. Avant : zéro créneau en ligne → cul-de-sac « nous vous contacterons ». Maintenant : le client saisit jusqu'à 3 disponibilités libres (date + Matin/Après-midi/Soir) → soumises en mode:rank → fitBooking tente de placer, sinon enregistre en 'Proposé' pour le répartiteur. Le client n'est jamais coincé. Vérifié : repli (mock empty) rend le formulaire + soumet OK ; aucune régression avec créneaux (8 tuiles + bascule 2 modes) ; 0 erreur console ; live à msg.gigafibre.ca/book (marqueurs présents). Hub redémarré, sain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e7b94947cf
commit
99f44daf31
|
|
@ -946,6 +946,10 @@ h1{font-size:21px;margin:0 0 4px;letter-spacing:-.02em}
|
|||
.ok{background:#e7f9ef;color:#0d6b34;padding:18px;border-radius:12px;text-align:center;font-size:15px}
|
||||
.err{background:#fdecea;color:#b3261e;padding:13px;border-radius:10px;font-size:13.5px}
|
||||
.empty{color:#9aa5a0;font-size:12.5px;font-style:italic;padding:8px 0}
|
||||
.ff-row{display:flex;align-items:center;gap:8px;margin:8px 0}
|
||||
.ff-n{width:22px;height:22px;border-radius:50%;background:var(--g);color:#fff;font-weight:700;font-size:12px;display:grid;place-items:center;flex:none}
|
||||
.ff-date,.ff-per{font:inherit;font-size:14px;padding:9px 10px;border:1px solid var(--line);border-radius:9px;background:var(--card);color:var(--ink)}
|
||||
.ff-date{flex:1;min-width:0}
|
||||
.foot{text-align:center;color:var(--muted);font-size:12px;margin-top:4px}
|
||||
.foot b{color:var(--g-d)}
|
||||
</style></head>
|
||||
|
|
@ -975,7 +979,7 @@ function load(){api('/book/api/options?token='+encodeURIComponent(token)).then(f
|
|||
if(r.job&&r.job.scheduled){info.textContent='';c.innerHTML='<div class=ok>Votre rendez-vous est déjà confirmé :<br><b>'+dayLabel(r.job.scheduled)+'</b>.</div>';return}
|
||||
dur=Number(r.job&&r.job.duration)||1;windows=r.windows||[];
|
||||
info.textContent=(r.job&&r.job.service_type?r.job.service_type+' · ':'')+((r.job&&r.job.location)||'');
|
||||
if(!windows.length){c.innerHTML='<div class=err>Aucune disponibilité pour le moment — nous vous contacterons.</div>';return}
|
||||
if(!windows.length){renderFreeform();return}
|
||||
c.innerHTML='<div class=seg id=seg><button data-m=pick class=on>Choisir un créneau</button><button data-m=propose>Proposer mes dispos</button></div>'
|
||||
+'<div class=modehint id=modehint></div><div id=grid></div>'
|
||||
+'<div class=hold id=hold><span>Réservé pour vous</span><span class=cd id=cd>5:00</span></div>'
|
||||
|
|
@ -984,6 +988,15 @@ function load(){api('/book/api/options?token='+encodeURIComponent(token)).then(f
|
|||
el('go').onclick=function(){mode==='pick'?confirmPick():submitPropose()};
|
||||
setMode('pick')
|
||||
})}
|
||||
function renderFreeform(){var c=el('content');
|
||||
var opt='<option value=09:00>Matin</option><option value=13:00>Après-midi</option><option value=17:00>Soir</option>';
|
||||
var row=function(n){return '<div class=ff-row><span class=ff-n>'+n+'</span><input type=date class=ff-date data-n="'+n+'"><select class=ff-per data-n="'+n+'">'+opt+'</select></div>'};
|
||||
c.innerHTML='<div class=modehint>Nous n\'avons pas de créneau en ligne pour l\'instant. Indiquez jusqu\'à 3 disponibilités qui vous conviennent — un répartiteur vous confirmera rapidement.</div>'+row(1)+row(2)+row(3)+'<button class=btn id=go>Envoyer mes disponibilités</button><div class=hint id=hint></div>';
|
||||
el('go').onclick=submitFreeform}
|
||||
function submitFreeform(){var go=el('go');var prefs=[];[].forEach.call(document.querySelectorAll('.ff-date'),function(d){if(d.value){var per=document.querySelector('.ff-per[data-n="'+d.dataset.n+'"]');prefs.push({date:d.value,start:per?per.value:'09:00'})}});
|
||||
if(!prefs.length){el('hint').textContent='Choisissez au moins une date.';return}
|
||||
go.disabled=true;go.textContent='Envoi…';
|
||||
api('/book/api/submit?token='+encodeURIComponent(token),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({mode:'rank',prefs:prefs})}).then(done)}
|
||||
function setMode(m){mode=m;picks=[];sel=null;stopCd();el('hold').classList.remove('on');
|
||||
Array.prototype.forEach.call(document.querySelectorAll('#seg button'),function(b){b.classList.toggle('on',b.dataset.m===m)});
|
||||
el('modehint').textContent=m==='pick'?'Touchez un créneau — il est réservé pour vous pendant 5 minutes, le temps de confirmer.':'Touchez 1 à 3 créneaux en ordre de préférence. On confirme le 1er possible.';
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user