`;
c.appendChild(d);
}
}
// ── Openings ──
function addOpening(type){
openingCount++;
const id=openingCount;
const isW=type==='Window';
const c=document.getElementById('opening-list');
const d=document.createElement('div'); d.className='opening-item'; d.id='op'+id;
d.innerHTML=`
${isW?'🪟':'🚪'} ${type} ${id}
Remove
Which wall? Wall A Wall B Wall C Wall D
${isW?`
`:`
Door swing Swings left Swings right Pocket door Sliding
`}
${isW?`
`:''}`;
c.appendChild(d);
}
// ── Appliances ──
function togAppl(el){el.classList.toggle('on');}
// ── File uploads ──
function handleFiles(input, previewId, countId){
const files=Array.from(input.files);
const key=previewId.includes('wall')?'wall':previewId.includes('sketch')?'sketch':'extra';
uploadedFiles[key]=uploadedFiles[key].concat(files);
renderPreviews(previewId, countId, uploadedFiles[key]);
}
function renderPreviews(previewId, countId, files){
const c=document.getElementById(previewId); c.innerHTML='';
files.forEach((f,i)=>{
if(!f.type.startsWith('image/'))return;
const reader=new FileReader();
reader.onload=e=>{
const wrap=document.createElement('div'); wrap.className='preview-wrap';
const img=document.createElement('img'); img.src=e.target.result;
const btn=document.createElement('button'); btn.className='preview-del'; btn.textContent='×';
const key=previewId.includes('wall')?'wall':previewId.includes('sketch')?'sketch':'extra';
btn.onclick=()=>{uploadedFiles[key].splice(i,1);renderPreviews(previewId,countId,uploadedFiles[key]);};
wrap.appendChild(img); wrap.appendChild(btn); c.appendChild(wrap);
};
reader.readAsDataURL(f);
});
const countEl=document.getElementById(countId);
countEl.textContent=files.length>0?`${files.length} file${files.length>1?'s':''} selected`:'';
}
function dragOver(e,zoneId){e.preventDefault();document.getElementById(zoneId).classList.add('drag');}
function dragLeave(zoneId){document.getElementById(zoneId).classList.remove('drag');}
function handleDrop(e,inputId){
e.preventDefault();
const zone=e.currentTarget; zone.classList.remove('drag');
const dt=e.dataTransfer; if(!dt)return;
const input=document.getElementById(inputId);
const key=inputId.includes('wall')?'wall':'sketch';
const previewId=key+'-previews', countId=key+'-count';
uploadedFiles[key]=uploadedFiles[key].concat(Array.from(dt.files));
renderPreviews(previewId,countId,uploadedFiles[key]);
}
// ── Canvas sketch ──
function initCanvas(){
const cv=document.getElementById('sketch-cv');
if(!cv) return;
const card=cv.closest('.canvas-card')||cv.parentElement;
cvW=card.offsetWidth||560; cvH=400;
cv.width=cvW; cv.height=cvH;
drawCGrid();
if(!canvasInited){
canvasInited=true;
cv.addEventListener('mousedown',cvDown);
cv.addEventListener('mousemove',cvMove);
cv.addEventListener('mouseup',cvUp);
cv.addEventListener('mouseleave',()=>{if(cDrawing){cDrawing=false;redrawCanvas();}});
cv.addEventListener('touchstart',cvDown,{passive:false});
cv.addEventListener('touchmove',cvMove,{passive:false});
cv.addEventListener('touchend',cvUp);
}
}
function getCtx(){return document.getElementById('sketch-cv').getContext('2d');}
function cvPos(e){
const cv=document.getElementById('sketch-cv');
const r=cv.getBoundingClientRect();
const src=e.touches?e.touches[0]:e.changedTouches?e.changedTouches[0]:e;
return{x:(src.clientX-r.left)*(cvW/r.width),y:(src.clientY-r.top)*(cvH/r.height)};
}
function drawCGrid(){
const ctx=getCtx();
ctx.fillStyle='#f9f8f4'; ctx.fillRect(0,0,cvW,cvH);
ctx.strokeStyle='#ece9e0'; ctx.lineWidth=0.5;
for(let x=0;x<=cvW;x+=20){ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,cvH);ctx.stroke();}
for(let y=0;y<=cvH;y+=20){ctx.beginPath();ctx.moveTo(0,y);ctx.lineTo(cvW,y);ctx.stroke();}
}
function drawArrow(ctx,x1,y1,x2,y2,color){
const dx=x2-x1,dy=y2-y1,len=Math.sqrt(dx*dx+dy*dy);
if(len<4) return;
const ang=Math.atan2(dy,dx);
ctx.save();
ctx.strokeStyle=color; ctx.fillStyle=color; ctx.lineWidth=1.5; ctx.lineCap='round';
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke();
[0,1].forEach(end=>{
const bx=end?x2:x1, by=end?y2:y1, dir=end?1:-1;
ctx.beginPath();
ctx.moveTo(bx,by);
ctx.lineTo(bx-dir*9*Math.cos(ang-0.38),by-dir*9*Math.sin(ang-0.38));
ctx.lineTo(bx-dir*9*Math.cos(ang+0.38),by-dir*9*Math.sin(ang+0.38));
ctx.closePath(); ctx.fill();
});
ctx.restore();
}
function drawDimLabel(ctx,x1,y1,x2,y2,label,color){
const mx=(x1+x2)/2, my=(y1+y2)/2;
const ang=Math.atan2(y2-y1,x2-x1);
const ox=-Math.sin(ang)*16, oy=Math.cos(ang)*16;
ctx.save();
ctx.font='bold 12px DM Sans,sans-serif';
ctx.textAlign='center'; ctx.textBaseline='middle';
const tw=ctx.measureText(label).width+12;
ctx.fillStyle='rgba(255,243,214,0.96)';
ctx.beginPath(); ctx.roundRect(mx+ox-tw/2,my+oy-11,tw,22,5); ctx.fill();
ctx.strokeStyle=color; ctx.lineWidth=1; ctx.stroke();
ctx.fillStyle=color;
ctx.fillText(label,mx+ox,my+oy);
ctx.restore();
}
function redrawCanvas(){
drawCGrid();
const ctx=getCtx();
cStrokes.forEach(s=>{
ctx.save();
if(s.type==='label'){
ctx.font='bold 13px DM Sans,sans-serif';
const tw=ctx.measureText(s.text).width+12;
ctx.fillStyle='rgba(253,246,236,0.96)';
ctx.beginPath(); ctx.roundRect(s.x-6,s.y-12,tw,24,5); ctx.fill();
ctx.strokeStyle=s.color; ctx.lineWidth=1; ctx.stroke();
ctx.fillStyle=s.color; ctx.textAlign='left'; ctx.textBaseline='middle';
ctx.fillText(s.text,s.x,s.y);
} else if(s.type==='dim'){
drawArrow(ctx,s.x1,s.y1,s.x2,s.y2,s.color);
if(s.label) drawDimLabel(ctx,s.x1,s.y1,s.x2,s.y2,s.label,s.color);
} else if(s.type==='wall'){
ctx.strokeStyle=s.color; ctx.lineWidth=4; ctx.lineCap='round';
ctx.beginPath(); ctx.moveTo(s.x1,s.y1); ctx.lineTo(s.x2,s.y2); ctx.stroke();
} else if(s.type==='rect'){
ctx.strokeStyle=s.color; ctx.lineWidth=3; ctx.lineCap='round'; ctx.lineJoin='round';
ctx.strokeRect(s.x,s.y,s.w,s.h);
} else if(s.type==='pen'){
ctx.strokeStyle=s.color; ctx.lineWidth=2; ctx.lineCap='round'; ctx.lineJoin='round';
ctx.beginPath();
s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));
ctx.stroke();
}
ctx.restore();
});
}
let snapData=null;
function setCTool(t,el){
cTool=t;
el.closest('.canvas-toolbar').querySelectorAll('.ctool').forEach(b=>b.classList.remove('on'));
el.classList.add('on');
const bar=document.getElementById('cv-input-bar');
const txtIn=document.getElementById('cv-text-input');
const numIn=document.getElementById('cv-inch-input');
const unit=document.getElementById('cv-inch-unit');
const lbl=document.getElementById('cv-input-label');
const hint=document.getElementById('cv-input-hint');
txtIn.style.display='none'; numIn.style.display='none'; unit.style.display='none';
if(t==='label'){
bar.style.display='block'; txtIn.style.display='block';
lbl.textContent='Label text:'; txtIn.placeholder='e.g. Wall A, Sink, Window, Fridge...';
hint.textContent='Then tap the canvas to place it'; setTimeout(()=>txtIn.focus(),50);
} else if(t==='inch'){
bar.style.display='block'; numIn.style.display='block'; unit.style.display='block';
lbl.textContent='Measurement:'; numIn.placeholder='e.g. 120';
hint.textContent='Then tap the canvas to stamp it'; setTimeout(()=>numIn.focus(),50);
} else if(t==='dim'){
bar.style.display='block'; numIn.style.display='block'; unit.style.display='block';
lbl.textContent='↔ Dimension line:'; numIn.placeholder='Optional: inches';
hint.textContent='Drag to draw an arrow. Number shows on the line.';
} else {
bar.style.display='none';
}
const hints={pen:'Freehand — sketch freely',wall:'Wall — drag to draw a thick wall line',rect:'Room — drag to outline a room or space',dim:'Dimension — drag to draw a measurement arrow with inches',label:'Label — type text above, then tap the canvas to place it',inch:'Inches — type a number above, then tap to stamp it on the sketch'};
document.getElementById('cv-hint').textContent=hints[t]||'';
}
function setCColor(el){
el.closest('.canvas-toolbar').querySelectorAll('.cdot').forEach(d=>d.classList.remove('on'));
el.classList.add('on'); cColor=el.dataset.c;
}
function cvDown(e){
e.preventDefault();
const p=cvPos(e);
if(cTool==='label'){
const txt=document.getElementById('cv-text-input').value.trim();
if(!txt){document.getElementById('cv-text-input').focus();return;}
cStrokes.push({type:'label',text:txt,x:p.x,y:p.y,color:cColor});
redrawCanvas(); return;
}
if(cTool==='inch'){
const val=document.getElementById('cv-inch-input').value.trim();
if(!val){document.getElementById('cv-inch-input').focus();return;}
cStrokes.push({type:'label',text:val+'"',x:p.x,y:p.y,color:'#b08d5b'});
redrawCanvas(); return;
}
cDrawing=true; cSx=p.x; cSy=p.y;
if(cTool==='pen') cStrokes.push({type:'pen',color:cColor,pts:[{x:p.x,y:p.y}]});
else snapData=getCtx().getImageData(0,0,cvW,cvH);
}
function cvMove(e){
e.preventDefault();
if(!cDrawing) return;
const p=cvPos(e);
const ctx=getCtx();
if(cTool==='pen'){
cStrokes[cStrokes.length-1].pts.push({x:p.x,y:p.y}); redrawCanvas();
} else if(cTool==='wall'){
ctx.putImageData(snapData,0,0);
ctx.save(); ctx.strokeStyle=cColor; ctx.lineWidth=4; ctx.lineCap='round';
ctx.beginPath(); ctx.moveTo(cSx,cSy); ctx.lineTo(p.x,p.y); ctx.stroke(); ctx.restore();
} else if(cTool==='dim'){
ctx.putImageData(snapData,0,0);
drawArrow(ctx,cSx,cSy,p.x,p.y,cColor);
const val=document.getElementById('cv-inch-input').value.trim();
if(val) drawDimLabel(ctx,cSx,cSy,p.x,p.y,val+'"',cColor);
} else if(cTool==='rect'){
ctx.putImageData(snapData,0,0);
ctx.save(); ctx.strokeStyle=cColor; ctx.lineWidth=3;
ctx.strokeRect(cSx,cSy,p.x-cSx,p.y-cSy); ctx.restore();
}
}
function cvUp(e){
if(!cDrawing) return; cDrawing=false;
const p=cvPos(e);
if(cTool==='wall') cStrokes.push({type:'wall',color:cColor,x1:cSx,y1:cSy,x2:p.x,y2:p.y});
else if(cTool==='dim'){const val=document.getElementById('cv-inch-input').value.trim();cStrokes.push({type:'dim',color:cColor,x1:cSx,y1:cSy,x2:p.x,y2:p.y,label:val?val+'"':null});}
else if(cTool==='rect') cStrokes.push({type:'rect',color:cColor,x:cSx,y:cSy,w:p.x-cSx,h:p.y-cSy});
redrawCanvas();
}
function cUndo(){if(cStrokes.length){cStrokes.pop();redrawCanvas();}}
function cClear(){cStrokes=[];redrawCanvas();}
function downloadSketch(){
const a=document.createElement('a');
a.download='kitchen-sketch.png';
a.href=document.getElementById('sketch-cv').toDataURL('image/png');
a.click();
}
// ── Summary ──
function gv(id){return(document.getElementById(id)||{}).value||'—';}
function buildSummary(){
document.getElementById('review-step-num').textContent = sketchOnly ? 'Step 8 — Final' : 'Step 8 of 8';
document.getElementById('review-desc').textContent = sketchOnly
? 'Your sketch has been submitted. Check your details and hit submit — we\'ll reach out to discuss measurements.'
: 'Check everything below, then submit. We\'ll review and follow up within 1 business day.';
const walls=['A','B','C','D'].map(l=>{const v=gv('w'+l);return v&&v!=='—'?`
Wall ${l} ${v}"${gv('wn'+l)!=='—'?' — '+gv('wn'+l):''}
`:''}).filter(Boolean).join('');
const appls=Array.from(document.querySelectorAll('.appl.on')).map(a=>a.querySelector('.appl-name').textContent).join(', ')||'—';
const ops=document.querySelectorAll('.opening-item').length;
const wphotos=uploadedFiles.wall.length;
const sphotos=uploadedFiles.sketch.length;
const ephotos=uploadedFiles.extra.length;
const hasSketch=cStrokes.length>0;
document.getElementById('summary-card').innerHTML=`
Contact
Name ${gv('fname')} ${gv('lname')}
Address ${gv('addr')}
Phone ${gv('phone')}
Email ${gv('email')}
Kitchen
Layout ${gv('layout')}
Ceiling height ${gv('ceiling')}"
Walls
${walls||'
None entered
'}
Openings
Windows & doors ${ops} added
Appliances & plumbing
Appliances ${appls}
Sink location ${gv('p_wall')}, drain ${gv('p_pos')}" from left
Soffit ${gv('soffit')==='yes'?gv('sof_ht')+'" from floor, '+gv('sof_d')+'" deep':'None'}
Photos & sketch
Wall photos ${wphotos} uploaded
Sketch uploaded ${sphotos>0?'Yes':'No'}
Digital sketch drawn ${hasSketch?'Yes':'No'}
`;
}
// ── Submit ──
function copyEmail(){
const text=document.getElementById('email-body').textContent;
navigator.clipboard.writeText(text).then(()=>{
const btn=document.querySelector('.copy-btn');
btn.textContent='✅ Copied!';
setTimeout(()=>btn.innerHTML='📋 Copy to clipboard',2000);
});
}
// ── Markup canvas (upload + draw on top) ──
let mkTool='pen', mkColor='#e03030';
let mkStrokes=[], mkDrawing=false, mkSx=0, mkSy=0, mkSnap=null;
let mkW=0, mkH=0, mkBgImage=null, mkSavedDataURL=null;
function loadMarkupImage(input){
const file = input.files[0];
if(!file) return;
const reader = new FileReader();
reader.onload = e => {
const img = new Image();
img.onload = () => {
const wrap = document.getElementById('markup-canvas-wrap');
const cv = document.getElementById('markup-cv');
const maxW = wrap.offsetWidth || 560;
const ratio = img.height / img.width;
mkW = maxW;
mkH = Math.min(Math.round(maxW * ratio), 520);
cv.width = mkW; cv.height = mkH;
cv.style.width = '100%';
mkBgImage = img;
mkStrokes = [];
redrawMk();
document.getElementById('markup-upload-zone').style.display = 'none';
wrap.style.display = 'block';
// Save to uploadedFiles as original
uploadedFiles.sketch = uploadedFiles.sketch.filter(f=>f._markupOriginal !== true);
file._markupOriginal = true;
uploadedFiles.sketch.push(file);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
function handleMarkupDrop(e){
e.preventDefault();
document.getElementById('markup-upload-zone').classList.remove('drag');
const file = e.dataTransfer?.files?.[0];
if(file && file.type.startsWith('image/')){
const dt = new DataTransfer();
dt.items.add(file);
document.getElementById('markup-file-input').files = dt.files;
loadMarkupImage(document.getElementById('markup-file-input'));
}
}
function redrawMk(){
const cv = document.getElementById('markup-cv');
const ctx = cv.getContext('2d');
ctx.clearRect(0,0,mkW,mkH);
if(mkBgImage) ctx.drawImage(mkBgImage, 0, 0, mkW, mkH);
mkStrokes.forEach(s => {
ctx.save();
ctx.strokeStyle = s.color; ctx.fillStyle = s.color;
ctx.lineWidth = s.type==='pen' ? 2.5 : 2.5;
ctx.lineCap = 'round'; ctx.lineJoin = 'round';
if(s.type==='text'){
ctx.font = 'bold 14px DM Sans,sans-serif';
const tw = ctx.measureText(s.text).width;
ctx.fillStyle = 'rgba(255,255,255,0.88)';
ctx.fillRect(s.x-3, s.y-14, tw+6, 20);
ctx.fillStyle = s.color;
ctx.textAlign='left'; ctx.textBaseline='middle';
ctx.fillText(s.text, s.x, s.y);
} else if(s.type==='arrow'){
const dx=s.x2-s.x1, dy=s.y2-s.y1;
const len=Math.sqrt(dx*dx+dy*dy); if(len<2){ctx.restore();return;}
const ang=Math.atan2(dy,dx);
// line
ctx.beginPath(); ctx.moveTo(s.x1,s.y1); ctx.lineTo(s.x2,s.y2); ctx.stroke();
// arrowhead
const hw=10, hlen=16;
ctx.beginPath();
ctx.moveTo(s.x2,s.y2);
ctx.lineTo(s.x2-hlen*Math.cos(ang-0.4), s.y2-hlen*Math.sin(ang-0.4));
ctx.lineTo(s.x2-hlen*Math.cos(ang+0.4), s.y2-hlen*Math.sin(ang+0.4));
ctx.closePath(); ctx.fill();
} else if(s.type==='rect'){
ctx.strokeRect(s.x,s.y,s.w,s.h);
} else if(s.type==='pen'||s.type==='line'){
ctx.beginPath();
s.pts.forEach((p,i)=>i===0?ctx.moveTo(p.x,p.y):ctx.lineTo(p.x,p.y));
ctx.stroke();
}
ctx.restore();
});
}
function getMkPos(e){
const cv=document.getElementById('markup-cv');
const r=cv.getBoundingClientRect();
const src=e.touches?e.touches[0]:e.changedTouches?e.changedTouches[0]:e;
return{x:(src.clientX-r.left)*(mkW/r.width), y:(src.clientY-r.top)*(mkH/r.height)};
}
function mkDown(e){
e.preventDefault();
const p=getMkPos(e);
if(mkTool==='text'){
const lbl=document.getElementById('mk-label-input').value.trim();
if(lbl){mkStrokes.push({type:'text',text:lbl,x:p.x,y:p.y,color:mkColor});redrawMk();}
return;
}
mkDrawing=true; mkSx=p.x; mkSy=p.y;
if(mkTool==='pen'){mkStrokes.push({type:'pen',color:mkColor,pts:[{x:p.x,y:p.y}]});}
else{mkSnap=document.getElementById('markup-cv').getContext('2d').getImageData(0,0,mkW,mkH);}
}
function mkMove(e){
e.preventDefault();
if(!mkDrawing)return;
const p=getMkPos(e);
const ctx=document.getElementById('markup-cv').getContext('2d');
if(mkTool==='pen'){mkStrokes[mkStrokes.length-1].pts.push({x:p.x,y:p.y});redrawMk();}
else if(mkTool==='line'||mkTool==='arrow'||mkTool==='rect'){
ctx.putImageData(mkSnap,0,0);
ctx.save(); ctx.strokeStyle=mkColor; ctx.fillStyle=mkColor; ctx.lineWidth=2.5; ctx.lineCap='round';
if(mkTool==='line'){ctx.beginPath();ctx.moveTo(mkSx,mkSy);ctx.lineTo(p.x,p.y);ctx.stroke();}
else if(mkTool==='arrow'){
const dx=p.x-mkSx,dy=p.y-mkSy,len=Math.sqrt(dx*dx+dy*dy);
if(len>2){
const ang=Math.atan2(dy,dx);
ctx.beginPath();ctx.moveTo(mkSx,mkSy);ctx.lineTo(p.x,p.y);ctx.stroke();
ctx.beginPath();ctx.moveTo(p.x,p.y);ctx.lineTo(p.x-16*Math.cos(ang-0.4),p.y-16*Math.sin(ang-0.4));ctx.lineTo(p.x-16*Math.cos(ang+0.4),p.y-16*Math.sin(ang+0.4));ctx.closePath();ctx.fill();
}
}
else if(mkTool==='rect'){ctx.strokeRect(mkSx,mkSy,p.x-mkSx,p.y-mkSy);}
ctx.restore();
}
}
function mkUp(e){
if(!mkDrawing)return; mkDrawing=false;
const p=getMkPos(e);
if(mkTool==='line'){mkStrokes.push({type:'line',color:mkColor,pts:[{x:mkSx,y:mkSy},{x:p.x,y:p.y}]});}
else if(mkTool==='arrow'){mkStrokes.push({type:'arrow',color:mkColor,x1:mkSx,y1:mkSy,x2:p.x,y2:p.y});}
else if(mkTool==='rect'){mkStrokes.push({type:'rect',color:mkColor,x:mkSx,y:mkSy,w:p.x-mkSx,h:p.y-mkSy});}
redrawMk();
// auto-save marked version to uploadedFiles
saveMkToUploads();
}
function saveMkToUploads(){
const cv=document.getElementById('markup-cv');
if(!cv||!mkBgImage) return;
cv.toBlob(blob=>{
if(!blob)return;
const f=new File([blob],'marked-sketch.png',{type:'image/png'});
f._isMarkup=true;
uploadedFiles.sketch=uploadedFiles.sketch.filter(x=>!x._isMarkup);
uploadedFiles.sketch.push(f);
},'image/png');
}
function saveMkImage(){
const cv=document.getElementById('markup-cv');
const a=document.createElement('a');
a.download='marked-sketch.png'; a.href=cv.toDataURL('image/png');
a.click();
}
function mkUndo(){mkStrokes.pop();redrawMk();saveMkToUploads();}
function mkClearMarkup(){mkStrokes=[];redrawMk();saveMkToUploads();}
function setMkTool(t,el){
mkTool=t;
document.querySelectorAll('[id^="mk-"]').forEach(b=>b.tagName==='BUTTON'&&b.classList.remove('on'));
el.classList.add('on');
document.getElementById('mk-label-bar').style.display=t==='text'?'block':'none';
const hints={pen:'Draw freehand on your sketch',line:'Draw a straight line',arrow:'Draw an arrow pointing to something',rect:'Draw a box to highlight an area',text:'Type a label, then tap where to place it'};
document.getElementById('mk-hint').textContent=hints[t]||'';
}
function setMkColor(el){
el.closest('.canvas-toolbar').querySelectorAll('.cdot').forEach(d=>d.classList.remove('on'));
el.classList.add('on'); mkColor=el.dataset.c;
}
// Attach markup canvas events + init sketch canvas after DOM ready
document.addEventListener('DOMContentLoaded',()=>{
// Markup canvas events
const mkCv=document.getElementById('markup-cv');
if(mkCv){
mkCv.addEventListener('mousedown',mkDown);
mkCv.addEventListener('mousemove',mkMove);
mkCv.addEventListener('mouseup',mkUp);
mkCv.addEventListener('mouseleave',()=>{if(mkDrawing){mkDrawing=false;}});
mkCv.addEventListener('touchstart',mkDown,{passive:false});
mkCv.addEventListener('touchmove',mkMove,{passive:false});
mkCv.addEventListener('touchend',mkUp);
}
// Pre-init sketch canvas size so it's ready when step 2 is shown
setTimeout(()=>{ try{ initCanvas(); }catch(e){} }, 100);
});
// ── CLOUDINARY CONFIG ──
var CLOUD_NAME = 'dhaa8rbtd';
var UPLOAD_PRESET = 'lkn_unsigned';
var SESSION_TOKEN = Date.now().toString(36) + Math.random().toString(36).slice(2,8);
function uploadToCloudinary(blob, filename){
return new Promise(function(resolve, reject){
var fd = new FormData();
fd.append('file', blob instanceof File ? blob : new File([blob], filename, {type:'image/png'}), filename);
fd.append('upload_preset', UPLOAD_PRESET);
fd.append('folder', 'measurements/' + SESSION_TOKEN);
fetch('https://api.cloudinary.com/v1_1/' + CLOUD_NAME + '/image/upload', {
method:'POST', body:fd
})
.then(function(r){
if(!r.ok) throw new Error('HTTP ' + r.status);
return r.json();
})
.then(function(data){
if(data.secure_url) resolve(data.secure_url);
else { console.error('Cloudinary error:', data); reject(new Error(data.error ? data.error.message : 'Upload failed')); }
})
.catch(function(err){ console.error('Upload failed:', err); reject(err); });
});
}
function canvasToBlob(canvas){
return new Promise(function(res){ canvas.toBlob(function(b){ res(b); },'image/png',0.92); });
}
function updateStatus(msg){
var el=document.getElementById('upload-status');
if(el){ el.textContent=msg; el.style.display='block'; }
}
function updateStatus(msg){
var el=document.getElementById('upload-status');
if(el){el.textContent=msg;el.style.display='block';}
}
function submitAndSend(channel){
var btnE=document.getElementById('btn-send-email');
var btnW=document.getElementById('btn-send-wa');
if(btnE)btnE.disabled=true;
if(btnW)btnW.disabled=true;
updateStatus('Uploading\u2026');
// Get sketch as base64
var sketchUrl = null;
var cv = document.getElementById('sketch-cv');
if(cv && cStrokes.length > 0){
try{ sketchUrl = cv.toDataURL('image/png'); }catch(e){}
}
// Upload photos to Cloudinary first, then send
var uploads = [];
if(cv && cStrokes.length > 0){
uploads.push(new Promise(function(res){
cv.toBlob(function(blob){
uploadToCloudinary(blob,'sketch.png')
.then(function(url){res({label:'Sketch',url:url});})
.catch(function(){res(null);});
},'image/png');
}));
}
var allPhotos = [].concat(uploadedFiles.wall, uploadedFiles.sketch, uploadedFiles.extra);
allPhotos.forEach(function(f,i){
uploads.push(
uploadToCloudinary(f, f.name||('photo-'+(i+1)+'.jpg'))
.then(function(url){return {label:'Photo '+(i+1),url:url};})
.catch(function(){return null;})
);
});
var timedOut = false;
var timer = setTimeout(function(){
timedOut = true;
doSend(channel, []);
}, 20000);
Promise.all(uploads).then(function(results){
if(timedOut) return;
clearTimeout(timer);
doSend(channel, results.filter(Boolean));
}).catch(function(){
if(timedOut) return;
clearTimeout(timer);
doSend(channel, []);
});
}
function doSend(channel, fileResults){
updateStatus('Sending\u2026');
var text = buildSubmitText();
var name = (gv('fname')||'') + ' ' + (gv('lname')||'');
var fileSection = fileResults.length > 0
? '\n\nIMAGES ('+fileResults.length+' uploaded)\n'+fileResults.map(function(r){return ' '+r.label+': '+r.url;}).join('\n')
: '';
var fullMsg = text + fileSection;
if(channel === 'wa'){
window.open('https://wa.me/18483664333?text='+encodeURIComponent(fullMsg),'_blank');
updateStatus('\u2713 WhatsApp opened! Your measurements were sent.');
var btnW=document.getElementById('btn-send-wa');
if(btnW){btnW.textContent='\u2713 Sent!';btnW.style.background='#1a8c43';btnW.disabled=false;}
var btnE=document.getElementById('btn-send-email');
if(btnE)btnE.disabled=false;
return;
}
// Send via Web3Forms
fetch('https://api.web3forms.com/submit',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({
access_key:'ae642e25-8c52-4691-b5fd-1e66336cb8a9',
subject:'Kitchen Measurement \u2014 '+(name.trim()||'Customer')+(gv('addr')?' \u2014 '+gv('addr'):''),
from_name: name.trim()||'Customer',
email: gv('email')||'noreply@litekitchensnj.com',
message: fullMsg
})
}).then(function(r){return r.json();}).then(function(d){
if(d.success){
updateStatus('\u2713 Sent! We will follow up within 1 business day.'+(fileResults.length>0?' ('+fileResults.length+' file(s))':''));
var btnE=document.getElementById('btn-send-email');
if(btnE){btnE.textContent='\u2713 Sent!';btnE.style.background='#1a8c43';btnE.disabled=false;}
var btnW=document.getElementById('btn-send-wa');
if(btnW)btnW.disabled=false;
}else{throw new Error(d.message||'Failed');}
}).catch(function(err){
console.error('Send error:',err);
updateStatus('\u26a0 Email failed. Please use WhatsApp below.');
var btnE=document.getElementById('btn-send-email');
if(btnE){btnE.textContent='Retry Email';btnE.disabled=false;}
var btnW=document.getElementById('btn-send-wa');
if(btnW){btnW.disabled=false;btnW.style.background='#1a8c43';}
});
}
function sendViaEmail(){ submitAndSend('email'); }
function sendViaWhatsApp(){ submitAndSend('wa'); }
function showConfirmation(){}
function showSaveFilesPanel(){}
function showPhotoDownloadPanel(){}
function renderSuccessSketch(){
var cv=document.getElementById('sketch-cv');
var prev=document.getElementById('success-sketch-canvas');
var wrap=document.getElementById('success-sketch-wrap');
if(!cv||!prev||cStrokes.length===0){if(wrap)wrap.style.display='none';return;}
if(wrap)wrap.style.display='block';
prev.width=cv.width;prev.height=cv.height;prev.style.width='100%';
prev.getContext('2d').drawImage(cv,0,0);
}
// Expose
// Expose real go() for the shim to use
window._goReal = go;
window.go = go; // Also override shim version
// Replay any queued go() calls made before IIFE loaded
if(window._goQueue && window._goQueue.length){
var last = window._goQueue[window._goQueue.length-1];
go(last); // replay the last queued step
window._goQueue = [];
}
window.addOpening = addOpening;
window.buildWalls = buildWalls;
window._buildWallsReal = buildWalls;
window._addOpeningReal = addOpening;
window._togApplReal = togAppl;
window.cClear = cClear;
window.cUndo = cUndo;
window.downloadSketch = downloadSketch;
window.dragLeave = dragLeave;
window.dragOver = dragOver;
window.handleDrop = handleDrop;
window.handleFiles = handleFiles;
window.setCColor = setCColor;
window.setCTool = setCTool;
window.submitForm = submitForm;
window.addExtraAppliance = addExtraAppliance;
window.togAppl = togAppl;
window.sendViaEmail = sendViaEmail;
window.sendViaWhatsApp = sendViaWhatsApp;
window.submitAndSend = submitAndSend;
window.openMeasureModal = openMeasureModal;
window.closeMeasureModal = closeMeasureModal;
window.renderSuccessSketch = renderSuccessSketch;
window.submitAndSend = submitAndSend;
window.submitForm = submitForm;
// Wire real versions to stubs
window._submitAndSendReal = submitAndSend;
window._addExtraApplianceReal = addExtraAppliance;
window._setCColorReal = setCColor;
window._setCToolReal = setCTool;
window._cClearReal = cClear;
window._cUndoReal = cUndo;
window._downloadSketchReal = downloadSketch;
window._handleFilesReal = handleFiles;
window._handleDropReal = handleDrop;
window._addOpeningReal = addOpening;
window._togApplReal = togAppl;
window._buildWallsReal = buildWalls;
} catch(e) {
console.error('IIFE CRASH:', e.message, e.stack);
// Show visible error so we can debug
var dbg = document.createElement('div');
dbg.style.cssText = 'position:fixed;bottom:0;left:0;right:0;background:#c00;color:#fff;padding:10px;font-family:monospace;font-size:11px;z-index:999999;';
dbg.textContent = 'IIFE Error: ' + e.message;
document.body && document.body.appendChild(dbg);
}
})();
;
window.downloadSketch = downloadSketch;
window.dragLeave = dragLeave;
window.dragOver = dragOver;
window.handleDrop = handleDrop;
window.handleFiles = handleFiles;
window.setCColor = setCColor;
window.setCTool = setCTool;
window.submitForm = submitForm;
window.addExtraAppliance = addExtraAppliance;
window.togAppl = togAppl;
window.sendViaEmail = sendViaEmail;
window.sendViaWhatsApp = sendViaWhatsApp;
window.openMeasureModal = openMeasureModal;
window.closeMeasureModal = closeMeasureModal;
window.renderSuccessSketch = renderSuccessSketch;
})();