(function(){ var STEPS=['Order placed','Cutting material','Sewing','Shipped','In GVA store']; var PW='couture2026'; var API='https://anastasi-couture.ch/save.php'; var orders={};var smsList=[];var loggedIn=false; function saveLocal(){try{localStorage.setItem('ac_orders',JSON.stringify(orders));}catch(e){}try{localStorage.setItem('ac_sms',JSON.stringify(smsList));}catch(e){}} function loadLocal(){try{var o=localStorage.getItem('ac_orders');if(o)orders=JSON.parse(o);}catch(e){}try{var s=localStorage.getItem('ac_sms');if(s)smsList=JSON.parse(s);}catch(e){}} function loadFromServer(cb){ fetch(API).then(function(r){return r.json();}).then(function(d){ if(d.orders){orders=d.orders;saveLocal();} if(cb)cb(); }).catch(function(){if(cb)cb();}); } function saveToSheet(order){ fetch(GSHEET,{method:'POST',body:JSON.stringify({action:'save',order:order})}).catch(function(){}); } function deleteFromSheet(id){ fetch(GSHEET,{method:'POST',body:JSON.stringify({action:'delete',id:id})}).catch(function(){}); } function loadFromServer(callback){ fetch(GSHEET+'?action=getAll') .then(function(r){return r.json();}) .then(function(data){ if(Array.isArray(data)&&data.length>0){ orders={}; data.forEach(function(o){ try{if(typeof o.items==='string')o.items=JSON.parse(o.items);}catch(e){o.items=[];} orders[o.id]=o; }); saveLocal(); } if(callback)callback(); }) .catch(function(){if(callback)callback();}); } function fmtDate(iso){try{return new Date(iso).toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'});}catch(e){return iso;}} function etaAuto(o){ if(o.eta)return fmtDate(o.eta); if(!o.placedIso)return ''; try{var d=new Date(o.placedIso);d.setDate(d.getDate()+15);return d.toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'});}catch(e){return '';} } function showTab(t){ document.getElementById('ac-tab-customer').style.display=t==='customer'?'block':'none'; document.getElementById('ac-tab-admin').style.display=t==='admin'?'block':'none'; document.getElementById('ac-tab-btn-customer').className='ac-tab'+(t==='customer'?' active':''); document.getElementById('ac-tab-btn-admin').className='ac-tab'+(t==='admin'?' active':''); if(t==='admin')renderAdmin(); } window.acShowTab=showTab; function doLogin(){ if(document.getElementById('ac-pw').value===PW){ loggedIn=true;document.getElementById('ac-pw').value=''; document.getElementById('ac-pw-err').innerHTML=''; var box=document.getElementById('ac-admin-lock'); if(box)box.innerHTML='
Chargement des commandes...
'; loadFromServer(function(){renderAdmin();}); }else{document.getElementById('ac-pw-err').innerHTML='
Mot de passe incorrect.
';} } window.acDoLogin=doLogin; window.acDoLogout=function(){loggedIn=false;renderAdmin();}; function renderAdmin(){ document.getElementById('ac-admin-lock').style.display=loggedIn?'none':'block'; document.getElementById('ac-admin-panel').style.display=loggedIn?'block':'none'; if(loggedIn){renderOrders();renderSMS();} } function doTrack(){ var key=document.getElementById('ac-track-input').value.trim().toUpperCase(); var box=document.getElementById('ac-track-result'); box.innerHTML='
Recherche en cours...
'; function showResult(){ var o=orders[key]; if(!o){ fetch(GSHEET+'?action=getOne&id='+key) .then(function(r){return r.json();}) .then(function(data){ if(data&&data.id){ try{if(typeof data.items==='string')data.items=JSON.parse(data.items);}catch(e){data.items=[];} orders[key]=data;saveLocal(); } renderTrackResult(key,box); }) .catch(function(){renderTrackResult(key,box);}); }else{renderTrackResult(key,box);} } showResult(); } window.acDoTrack=doTrack; function renderTrackResult(key,box){ var o=orders[key]; if(!o){box.innerHTML='
Commande introuvable. V\u00e9rifiez votre num\u00e9ro.
';return;} var tl='
'; var steps=o.steps||[]; STEPS.forEach(function(s,i){ var done=i'+ (done?'':'')+ '
'+(i<4?'
':'')+''+ '
'+s+'
'+ (steps[i]&&steps[i].date?'
'+steps[i].date+'
':'')+ (steps[i]&&steps[i].note?'
'+steps[i].note+'
':'')+ '
'; }); tl+=''; var etaF=o.eta?fmtDate(o.eta):null; box.innerHTML='
'+ '
'+ '
'+key+'
'+o.customer+'
'+ ''+STEPS[o.currentStep]+'
'+ (etaF?'
Livraison estim\u00e9e : '+etaF+'
':'')+ tl+'
'; } function smsText(id,o,step){ var name=o.customer.split(' ')[0]; var eta=etaAuto(o); var etaTxt=eta?'\nLivraison pr\u00e9vue le '+eta+'.':''; var nb=(o.items&&o.items.length)||1; var art=nb>1?nb+' articles':((o.items&&o.items[0]&&o.items[0].description)||'votre commande'); var link='\n\nSuivi de votre commande :\nhttps://anastasi-couture.ch/suivi-de-votre-commande?order='+id; var base='Bonjour '+name+',\nN\u00b0 '+id+' \u2014 '+art+'.'+etaTxt; if(step===0)return base+'\nVotre commande a bien \u00e9t\u00e9 enregistr\u00e9e chez Anastasi Couture.'+link; if(step===1||step===2)return base+'\nVotre commande est en production.'+link; if(step===3)return base+'\nVotre commande est en cours de livraison.'+link; return 'Bonjour '+name+',\nN\u00b0 '+id+' \u2014 '+art+'.\nVotre commande est pr\u00eate \u00e0 \u00eatre r\u00e9cup\u00e9r\u00e9e \u00e0 notre atelier.\nAu plaisir de vous accueillir ! \u2014 Anastasi Couture'+link; } window.acSmsText=smsText; function addSMS(id,o,step){ var now=new Date().toLocaleString('fr-FR',{day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'}); smsList.unshift({id:id,customer:o.customer,phone:o.phone||'',text:smsText(id,o,step),time:now}); if(smsList.length>100)smsList.pop(); saveLocal(); } function waUrl(phone,text){ var p=(phone||'').toString().trim().replace(/[\s\-\(\)\.]/g,''); if(p.startsWith('00'))p=p.slice(2); if(p.startsWith('+'))p=p.slice(1); if(p.length===9)p='41'+p; return 'https://wa.me/'+p+'?text='+encodeURIComponent(text); } function renderSMS(){ var box=document.getElementById('ac-sms-list'); var cnt=document.getElementById('ac-sms-count'); if(cnt)cnt.textContent=smsList.length?'('+smsList.length+')':''; if(!box)return; if(!smsList.length){box.innerHTML='
Aucun message.
';return;} box.innerHTML=smsList.map(function(s,i){ return '
'+ '
'+s.customer+(s.phone?' \u00b7 '+s.phone:'')+'
'+ '
'+s.text+'
'+ '
'+s.time+''+ ''+ (s.phone?''+ 'WhatsApp':'')+ '
'; }).join(''); box.querySelectorAll('.ac-copy-btn').forEach(function(btn){ btn.addEventListener('click',function(){ var i=parseInt(btn.getAttribute('data-i')); try{navigator.clipboard.writeText(smsList[i].text);}catch(e){} btn.textContent='Copi\u00e9 !';setTimeout(function(){btn.textContent='Copier';},2000); }); }); } function renderOrders(){ var box=document.getElementById('ac-order-list'); if(!box)return; var keys=Object.keys(orders); if(!keys.length){box.innerHTML='
Aucune commande.
';return;} box.innerHTML=keys.map(function(k){ var o=orders[k]; var nb=(o.items&&o.items.length)||1; var bc=o.currentStep===4?'ac-badge-done':o.currentStep===3?'ac-badge-shipped':'ac-badge-progress'; var wa=o.phone?''+ 'WA':''; return '
'+ '
'+k+'
'+ '
'+o.customer+' \u2014 '+nb+' article'+(nb>1?'s':'')+'
'+ (o.eta?'
ETA: '+fmtDate(o.eta)+'
':'')+ '
'+ ''+STEPS[o.currentStep]+''+wa+ ''+ ''+ '
'; }).join(''); box.querySelectorAll('.ac-prefill-btn').forEach(function(btn){ btn.addEventListener('click',function(){ var id=btn.getAttribute('data-id'); document.getElementById('ac-upd-id').value=id; document.getElementById('ac-upd-status').value=orders[id].currentStep; document.getElementById('ac-upd-note').value=''; document.getElementById('ac-upd-eta').value=orders[id].eta||''; document.getElementById('ac-upd-id').scrollIntoView({behavior:'smooth',block:'center'}); }); }); box.querySelectorAll('.ac-del-btn').forEach(function(btn){ btn.addEventListener('click',function(){ var id=btn.getAttribute('data-id'); if(!confirm('Supprimer la commande '+id+' ?'))return; delete orders[id];saveLocal();deleteFromSheet(id);renderOrders(); }); }); } window.acCreateOrder=function(){ var id=document.getElementById('ac-new-id').value.trim().toUpperCase(); var customer=document.getElementById('ac-new-customer').value.trim(); var item=document.getElementById('ac-new-item').value.trim(); var eta=document.getElementById('ac-new-eta').value; var phone=document.getElementById('ac-new-phone').value.trim(); var msg=document.getElementById('ac-create-msg'); if(!id||!customer||!item){msg.innerHTML='
Remplissez tous les champs.
';return;} if(orders[id]){msg.innerHTML='
Ce num\u00e9ro existe d\u00e9j\u00e0.
';return;} var today=new Date().toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'}); var o={id:id,customer:customer,phone:phone,items:[{ref:id,description:item,fabric:''}],placed:today,placedIso:new Date().toISOString(),eta:eta||null,currentStep:0,steps:[{date:today,note:'Commande cr\u00e9\u00e9e.'},{date:null,note:null},{date:null,note:null},{date:null,note:null},{date:null,note:null}]}; orders[id]=o;addSMS(id,o,0);saveLocal();saveLocal();renderOrders();renderSMS(); msg.innerHTML='
Commande '+id+' cr\u00e9\u00e9e.
'; ['ac-new-id','ac-new-customer','ac-new-item','ac-new-phone'].forEach(function(f){document.getElementById(f).value='';}); document.getElementById('ac-new-eta').value=''; setTimeout(function(){msg.innerHTML='';},3000); }; window.acUpdateOrder=function(){ var id=document.getElementById('ac-upd-id').value.trim().toUpperCase(); var step=parseInt(document.getElementById('ac-upd-status').value); var note=document.getElementById('ac-upd-note').value.trim(); var eta=document.getElementById('ac-upd-eta').value; var msg=document.getElementById('ac-update-msg'); if(!id||!orders[id]){msg.innerHTML='
Commande introuvable.
';return;} orders[id].currentStep=step; if(eta)orders[id].eta=eta; var today=new Date().toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'}); if(!orders[id].steps)orders[id].steps=[{date:today,note:''},{date:null,note:null},{date:null,note:null},{date:null,note:null},{date:null,note:null}]; orders[id].steps[step]={date:today,note:note||null}; addSMS(id,orders[id],step);saveLocal();saveLocal();renderOrders();renderSMS(); msg.innerHTML='
Commande '+id+' mise \u00e0 jour.
'; setTimeout(function(){msg.innerHTML='';},3000); }; function statusToStep(s){ if(!s)return 0;s=s.toLowerCase().trim(); if(s.includes('stock'))return 4; if(s.includes('on deliv')||s.includes('delivery'))return 3; if(s.includes('logist')||s.includes('ship'))return 3; if(s.includes('produc')||s.includes('sew'))return 2; if(s.includes('cut')||s.includes('pattern')||s.includes('measure'))return 1; if(s.includes('arriv')||s.includes('pickup')||s.includes('gva'))return 4; return 0; } window.acHandleFile = handleExcelFile; window.acProcessExcel = function(rows, msgEl){ var today=new Date().toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'}); var byClient={}; rows.forEach(function(r){ var name=(r['Client Name']||r['client name']||'').toString().trim(); if(!name)return; if(!byClient[name])byClient[name]=[]; byClient[name].push(r); }); var imported=0,updated=0,toSave=[]; Object.keys(byClient).forEach(function(name){ var clientRows=byClient[name]; var phone=(clientRows[0]['Phone']||clientRows[0]['phone']||'').toString().trim(); var items=clientRows.map(function(r){return{ref:(r['OrderNO.']||'').toString(),description:(r['Clothing Category']||'').toString(),fabric:(r['Fabric']||'').toString()};}); var maxStep=0; clientRows.forEach(function(r){var s=statusToStep((r['Status']||'').toString());if(s>maxStep)maxStep=s;}); var existingId=null; Object.keys(orders).forEach(function(k){if(orders[k].customer===name)existingId=k;}); if(existingId){ if(phone&&!orders[existingId].phone)orders[existingId].phone=phone; if(maxStep>orders[existingId].currentStep){ orders[existingId].currentStep=maxStep; if(!orders[existingId].steps)orders[existingId].steps=[null,null,null,null,null].map(function(){return{date:null,note:null};}); orders[existingId].steps[maxStep]={date:today,note:'Mis à jour depuis Excel.'}; addSMS(existingId,orders[existingId],maxStep); } toSave.push(orders[existingId]);updated++; }else{ var ini=name.split(' ').map(function(p){return p[0]||'';}).join('').toUpperCase().slice(0,2); var num=String(Math.floor(Math.random()*9000+1000)); var acId='AC-'+ini+num; while(orders[acId]){num=String(parseInt(num)+1);acId='AC-'+ini+num;} var steps=[{date:today,note:'Importé depuis Excel.'},{date:null,note:null},{date:null,note:null},{date:null,note:null},{date:null,note:null}]; if(maxStep>0)steps[maxStep]={date:today,note:"Statut à l'import."}; var o={id:acId,customer:name,phone:phone,items:items,placed:today,placedIso:new Date().toISOString(),eta:null,currentStep:maxStep,steps:steps}; orders[acId]=o;toSave.push(o);imported++; } }); saveLocal(); fetch(GSHEET,{method:'POST',body:JSON.stringify({action:'saveAll',orders:toSave})}).catch(function(){}); renderOrders();renderSMS(); if(msgEl)msgEl.innerHTML='
'+imported+' commande'+(imported>1?'s':'')+' importée'+(imported>1?'s':'')+''+(updated?' — '+updated+' mise'+(updated>1?'s':'')+' à jour':'')+' — Sync Google Sheets...
'; setTimeout(function(){if(msgEl)msgEl.innerHTML='';},6000); }; // Listen for import event from iframe window.addEventListener('ac_import', function(e){ var msgEl=document.getElementById('ac-import-msg'); if(e.detail&&Array.isArray(e.detail))window.acProcessExcel(e.detail,msgEl); }); document.addEventListener('ac_import', function(e){ var msgEl=document.getElementById('ac-import-msg'); if(e.detail&&Array.isArray(e.detail))window.acProcessExcel(e.detail,msgEl); }); function handleExcelFile(file){ var msg=document.getElementById('ac-import-msg'); msg.innerHTML='
Import en cours...
'; var reader=new FileReader(); reader.onload=function(e){ try{ var wb=XLSX.read(e.target.result,{type:'array'}); var orderSheet=wb.SheetNames[0]; wb.SheetNames.forEach(function(sn){if(sn.toLowerCase().includes('order'))orderSheet=sn;}); var rows=XLSX.utils.sheet_to_json(wb.Sheets[orderSheet]); var today=new Date().toLocaleDateString('fr-FR',{day:'numeric',month:'long',year:'numeric'}); var byClient={}; rows.forEach(function(r){ var name=(r['Client Name']||r['client name']||'').toString().trim(); if(!name)return; if(!byClient[name])byClient[name]=[]; byClient[name].push(r); }); var imported=0,updated=0; var toSave=[]; Object.keys(byClient).forEach(function(name){ var clientRows=byClient[name]; var phone=(clientRows[0]['Phone']||clientRows[0]['phone']||'').toString().trim(); var items=clientRows.map(function(r){ return{ref:(r['OrderNO.']||'').toString(),description:(r['Clothing Category']||'').toString(),fabric:(r['Fabric']||'').toString()}; }); var maxStep=0; clientRows.forEach(function(r){var s=statusToStep((r['Status']||'').toString());if(s>maxStep)maxStep=s;}); var existingId=null; Object.keys(orders).forEach(function(k){if(orders[k].customer===name)existingId=k;}); if(existingId){ if(phone&&!orders[existingId].phone)orders[existingId].phone=phone; if(maxStep>orders[existingId].currentStep){ orders[existingId].currentStep=maxStep; if(!orders[existingId].steps)orders[existingId].steps=[null,null,null,null,null].map(function(){return{date:null,note:null};}); orders[existingId].steps[maxStep]={date:today,note:'Mis \u00e0 jour depuis Excel.'}; addSMS(existingId,orders[existingId],maxStep); } toSave.push(orders[existingId]); updated++; }else{ var ini=name.split(' ').map(function(p){return p[0]||'';}).join('').toUpperCase().slice(0,2); var num=String(Math.floor(Math.random()*9000+1000)); var acId='AC-'+ini+num; while(orders[acId]){num=String(parseInt(num)+1);acId='AC-'+ini+num;} var steps=[{date:today,note:'Import\u00e9 depuis Excel.'},{date:null,note:null},{date:null,note:null},{date:null,note:null},{date:null,note:null}]; if(maxStep>0)steps[maxStep]={date:today,note:"Statut \u00e0 l'import."}; var o={id:acId,customer:name,phone:phone,items:items,placed:today,placedIso:new Date().toISOString(),eta:null,currentStep:maxStep,steps:steps}; orders[acId]=o;toSave.push(o);imported++; } }); saveLocal(); fetch(GSHEET,{method:'POST',body:JSON.stringify({action:'saveAll',orders:toSave})}) .then(function(){renderOrders();renderSMS();}) .catch(function(){renderOrders();renderSMS();}); msg.innerHTML='
'+imported+' commande'+(imported>1?'s':'')+' import\u00e9e'+(imported>1?'s':'')+''+(updated?' \u2014 '+updated+' mise'+(updated>1?'s':'')+' \u00e0 jour':'')+' \u2014 Synchronisation Google Sheets en cours...
'; setTimeout(function(){msg.innerHTML='';},6000); }catch(err){msg.innerHTML='
Erreur: '+err.message+'
';} }; reader.readAsArrayBuffer(file); } function initDropzone(){ var btn=document.getElementById('ac-btn-import-pick'); var input=document.getElementById('ac-import-file'); if(!btn||!input)return; btn.addEventListener('click',function(){input.click();}); input.addEventListener('change',function(){ if(input.files[0]){ var fname=document.getElementById('ac-import-filename'); if(fname)fname.textContent=input.files[0].name; handleExcelFile(input.files[0]); } }); } function init(){ if(!document.getElementById('ac-tab-btn-customer')){setTimeout(init,300);return;} document.querySelectorAll('.ac-tab').forEach(function(btn){ btn.addEventListener('click',function(){showTab(btn.getAttribute('data-tab'));}); }); document.getElementById('ac-btn-login').addEventListener('click',doLogin); document.getElementById('ac-btn-logout').addEventListener('click',function(){loggedIn=false;renderAdmin();}); document.getElementById('ac-btn-track').addEventListener('click',doTrack); document.getElementById('ac-btn-create').addEventListener('click',window.acCreateOrder); document.getElementById('ac-btn-update').addEventListener('click',window.acUpdateOrder); document.addEventListener('keydown',function(e){ if(e.key==='Enter'){ if(document.activeElement.id==='ac-track-input')doTrack(); if(document.activeElement.id==='ac-pw')doLogin(); } }); initDropzone(); loadLocal(); try{ var params=new URLSearchParams(window.location.search); var op=params.get('order')||params.get('commande'); if(op){ loadFromServer(function(){ var inp=document.getElementById('ac-track-input'); if(inp){inp.value=op.toUpperCase();doTrack();} }); } }catch(e){} } if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',init);}else{setTimeout(init,100);} })();