5S Smart Order

Đăng nhập quản lý nhà phân phối
Mỗi tài khoản chỉ mở dữ liệu của nhà phân phối tương ứng.

Tài khoản bản thử nghiệm: ngoctrai hoặc minhlong
Mật khẩu: 123456

5S
ĐIỆN MÁY 5SUy tín tạo niềm tin
`; } function printOrder(id){let o=orders.find(x=>x.id===id);if(!o)return;let w=window.open('','_blank');if(!w)return toast('Trình duyệt đang chặn cửa sổ in');w.document.open();w.document.write(invoiceHTML(o));w.document.close();setTimeout(()=>{w.focus();w.print()},450)} function exportOrders(){ if(!orders.length){toast('Chưa có đơn hàng để xuất');return} let content=``+ `

5S SMART ORDER - HÓA ĐƠN BÁN HÀNG

`+ orders.map(o=>invoiceHTML(o,true).replace(/|<\/?html[^>]*>|[\s\S]*?<\/head>|<\/?body[^>]*>/gi,'')).join('
')+ ``; let a=document.createElement('a');a.href=URL.createObjectURL(new Blob(['\ufeff'+content],{type:'application/vnd.ms-excel'}));a.download='hoa-don-ban-hang-5s.xls';document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(a.href),1000) } function fillCat(sel=''){const filter=$('productCatFilter'),currentFilter=filter?(filter.value||'all'):'all';$('pCategory').innerHTML=categories.map(c=>``).join('');if(filter){filter.innerHTML=''+categories.map(c=>``).join('');filter.value=[...filter.options].some(o=>o.value===currentFilter)?currentFilter:'all'}}function renderProducts(){fillCat();let q=($('productSearch').value||'').trim().toLowerCase(),f=$('productCatFilter').value||'all';$('productRows').innerHTML=products.filter(p=>(f==='all'||p.category===f)&&(p.name.toLowerCase().includes(q)||p.code.toLowerCase().includes(q))).map(p=>`${p.code}${p.image?``:'📦'}${p.name}${p.description?`
${p.description}`:''}${p.colors?.length?`
${p.colors.map(c=>`${c.name}`).join('')}
`:''}${catName(p.category)}${money(p.retail)}${money(p.wholesale)}${money(p.vip)}${p.active?'Đang bán':'Đã ẩn'}`).join('')}function openProductModal(){editP=null;tmpP='';$('productModalTitle').textContent='Thêm sản phẩm';['pCode','pName','pDescription','pRetail','pWholesale','pVip','pColors'].forEach(i=>$(i).value='');fillCat();$('pImagePreview').innerHTML='Chưa chọn hình';renderProductColorEditor();$('productModal').style.display='flex'}function editProduct(c){let p=products.find(x=>x.code===c);editP=c;tmpP=p.image;$('productModalTitle').textContent='Sửa sản phẩm';$('pCode').value=p.code;$('pName').value=p.name;$('pDescription').value=p.description||'';$('pRetail').value=p.retail;$('pWholesale').value=p.wholesale;$('pVip').value=p.vip;$('pColors').value=colorArrayToText(p.colors);fillCat(p.category);$('pImagePreview').innerHTML=p.image?``:'Chưa có hình';renderProductColorEditor();$('productModal').style.display='flex'}function previewP(e){let f=e.target.files[0];if(!f)return;let r=new FileReader();r.onload=()=>{tmpP=r.result;$('pImagePreview').innerHTML=``};r.readAsDataURL(f)}function saveProduct(){let o={code:$('pCode').value.trim(),name:$('pName').value.trim(),description:$('pDescription').value.trim(),category:$('pCategory').value,retail:+$('pRetail').value,wholesale:+$('pWholesale').value,vip:+$('pVip').value,colors:colorTextToArray($('pColors').value),image:tmpP,active:true};if(!o.code||!o.name)return toast('Nhập mã và tên sản phẩm');if(editP){let i=products.findIndex(x=>x.code===editP);o.active=products[i].active;products[i]=o}else if(products.some(p=>p.code===o.code))return toast('Mã sản phẩm đã tồn tại');else products.push(o);persist();closeM('productModal');renderAdmin();renderCustomer();renderHero()}function toggleProduct(c){let p=products.find(x=>x.code===c);p.active=!p.active;persist();renderAdmin();renderCustomer()}function deleteProduct(c){if(confirm('Xóa sản phẩm?')){products=products.filter(x=>x.code!==c);promotions=promotions.filter(x=>x.productCode!==c);persist();renderAdmin();renderCustomer()}} function renderCategories(){$('categoryRows').innerHTML=categories.map(c=>`${c.image?``:'🏷'}${c.name}${products.filter(p=>p.category===c.id).length}`).join('')}function openCategoryModal(){editC=null;tmpC='';$('categoryModalTitle').textContent='Thêm nhóm hàng';$('catName').value='';$('catImagePreview').innerHTML='Chưa chọn hình';$('categoryModal').style.display='flex'}function editCategory(id){let c=categories.find(x=>x.id===id);editC=id;tmpC=c.image;$('categoryModalTitle').textContent='Sửa nhóm hàng';$('catName').value=c.name;$('catImagePreview').innerHTML=c.image?``:'Chưa có hình';$('categoryModal').style.display='flex'}function previewC(e){let f=e.target.files[0];if(!f)return;let r=new FileReader();r.onload=()=>{tmpC=r.result;$('catImagePreview').innerHTML=``};r.readAsDataURL(f)}function saveCategory(){let n=$('catName').value.trim();if(!n)return toast('Nhập tên nhóm');if(editC)Object.assign(categories.find(x=>x.id===editC),{name:n,image:tmpC});else categories.push({id:'C'+Date.now(),name:n,image:tmpC});persist();closeM('categoryModal');renderAdmin();renderCustomer()}function deleteCategory(id){if(products.some(p=>p.category===id))return toast('Nhóm đang có sản phẩm');categories=categories.filter(c=>c.id!==id);persist();renderAdmin();renderCustomer()} function renderPromos(){$('promoRows').innerHTML=promotions.map(k=>`${k.name}${products.find(p=>p.code===k.productCode)?.name||'Đã xóa'}${k.percent}%${k.poster?'Có':'Không'}
${k.active?'Đang chạy':'Tạm dừng'} ▼
`).join('')||'Chưa có chương trình khuyến mãi'}function openPromoModal(){editK=null;$('promoModalTitle').textContent='Tạo chương trình khuyến mãi';$('promoName').value='';$('promoProduct').innerHTML=products.map(p=>``).join('');$('promoPercent').value=10;$('promoPoster').value='true';$('promoActive').value='true';$('promoModal').style.display='flex'}function editPromo(id){let k=promotions.find(x=>x.id===id);editK=id;$('promoModalTitle').textContent='Sửa chương trình';$('promoName').value=k.name;$('promoProduct').innerHTML=products.map(p=>``).join('');$('promoPercent').value=k.percent;$('promoPoster').value=String(k.poster);$('promoActive').value=String(k.active);$('promoModal').style.display='flex'}function savePromo(){let o={id:editK||'KM'+Date.now(),name:$('promoName').value.trim(),productCode:$('promoProduct').value,percent:+$('promoPercent').value,poster:$('promoPoster').value==='true',active:$('promoActive').value==='true'};if(!o.name)return toast('Nhập tên chương trình');if(editK)promotions[promotions.findIndex(x=>x.id===editK)]=o;else promotions.push(o);persist();closeM('promoModal');renderAdmin();renderCustomer();renderHero()}function setPromoStatus(id,active){let k=promotions.find(x=>x.id===id);if(!k)return;k.active=active;persist();renderAdmin();renderCustomer();toast(active?'Đã bật chương trình':'Đã tạm dừng chương trình')}function togglePromo(id){let k=promotions.find(x=>x.id===id);if(!k)return;setPromoStatus(id,!k.active)}function deletePromo(id){promotions=promotions.filter(x=>x.id!==id);persist();renderAdmin();renderCustomer()} function sales(id){return orders.filter(o=>o.customerId===id).reduce((s,o)=>s+o.total,0)} function appStatusOf(c){let signedPhone=localStorage.getItem('s5phone');if(signedPhone&&c.phone===signedPhone)return'has';return c.appStatus|| (c.addedByNpp?'no':'has')} function appStatusName(c){let st=appStatusOf(c);return st==='has'?'Có App':st==='wait'?'Chờ App':'Chưa App'} function sendAppLink(id){let c=customers.find(x=>x.id===id);if(!c)return;c.appStatus='wait';persist();renderCustomers();toast('Đã chuyển sang Chờ App – sẵn sàng gửi link cho '+(c.store||c.buyer))} function renderCustomers(){let f=$('customerTierFilter').value,sf=$('customerStatusFilter')?.value||'all',q=($('customerSearch').value||'').toLowerCase();let list=customers.filter(c=>c.status!=='pending'&&(f==='all'||c.tier===f)&&(sf==='all'||(sf==='visible'?c.active!==false:c.active===false))&&((c.buyer||'').toLowerCase().includes(q)||(c.phone||'').includes(q)||(c.contactPhone||'').includes(q)||(c.store||'').toLowerCase().includes(q)));$('customerRows').innerHTML=list.map(c=>`${c.buyer}
${c.receiver}${c.phone}
${c.contactPhone?'Liên hệ: '+c.contactPhone:'Chưa có số liên hệ mới'}${c.address}${c.store||'-'}${appStatusName(c)}${money(sales(c.id))}
${c.active===false?'Ẩn':'Hiện'} ▼
`).join('')||'Không tìm thấy khách hàng phù hợp'} function changeTier(id,t){let c=customers.find(x=>x.id===id);if(!c)return;c.tier=t;c.status='approved';if(curCustomer?.id===id)curCustomer=c;persist();renderAdmin();renderCustomer()} function setCustomerVisibility(id,visible){let c=customers.find(x=>x.id===id);if(!c)return;c.active=visible;let phone=String(c.phone||'').trim(),appPhone=String(localStorage.getItem('s5phone')||'').trim();persist();if(phone&&phone===appPhone){syncLinkedNppsForPhone(phone,activeNppId);if(linkedNpps.length)loadNppData(activeNppId);else{curCustomer=null;cart={};cartDetails={}}renderCustomer()}renderAdmin();toast(visible?'Đã hiện khách hàng trên ứng dụng':'Đã ẩn khách hàng và ẩn NPP khỏi ứng dụng')} function toggleCustomer(id){let c=customers.find(x=>x.id===id);if(!c)return;setCustomerVisibility(id,c.active===false)} function openEditCustomer(id){let c=customers.find(x=>x.id===id);if(!c)return;$('editCustomerId').value=c.id;$('editCustomerBuyer').value=c.buyer||'';$('editCustomerPhone').value=c.phone||'';$('editCustomerContactPhone').value=c.contactPhone||'';$('editCustomerReceiver').value=c.receiver||c.buyer||'';$('editCustomerAddress').value=c.address||'';$('editCustomerStore').value=c.store||'';$('editCustomerTier').value=c.tier||'retail';$('editCustomerModal').style.display='flex'} function saveEditedCustomer(){let id=$('editCustomerId').value,c=customers.find(x=>x.id===id);if(!c)return;let buyer=$('editCustomerBuyer').value.trim(),contactPhone=$('editCustomerContactPhone').value.trim(),receiver=$('editCustomerReceiver').value.trim(),address=$('editCustomerAddress').value.trim(),store=$('editCustomerStore').value.trim(),tier=$('editCustomerTier').value,phone=c.phone;if(!buyer||!phone||!receiver||!address)return toast('Vui lòng nhập đủ thông tin bắt buộc');if(contactPhone===phone)contactPhone='';let duplicated=contactPhone&&customers.some(x=>x.id!==id&&(x.phone===contactPhone||x.contactPhone===contactPhone));if(duplicated)return toast('Số điện thoại liên hệ đã thuộc khách hàng khác');Object.assign(c,{buyer,contactPhone,receiver,address,store,tier,status:'approved',active:true});if(curCustomer?.id===id)curCustomer=c;persist();closeM('editCustomerModal');renderAdmin();renderCustomer();toast('Đã cập nhật thông tin; số định danh vẫn được giữ nguyên')} function deleteCustomer(id){let c=customers.find(x=>x.id===id);if(!c)return;let count=orders.filter(o=>o.customerId===id).length,msg=count?`Khách hàng này có ${count} đơn cũ. Xóa khách nhưng vẫn giữ lịch sử đơn và báo cáo. Tiếp tục?`:'Xóa khách hàng này?';if(!confirm(msg))return;customers=customers.filter(x=>x.id!==id);if(curCustomer?.id===id){curCustomer=null;localStorage.removeItem('s5phone')}persist();renderAdmin();toast('Đã xóa khách hàng')} function openAddCustomerModal(){['addCustomerStore','addCustomerBuyer','addCustomerPhone','addCustomerAddress'].forEach(id=>$(id).value='');$('addCustomerModal').style.display='flex'} function saveAddedCustomer(){ let store=$('addCustomerStore').value.trim(), buyer=$('addCustomerBuyer').value.trim(), phone=$('addCustomerPhone').value.trim(), address=$('addCustomerAddress').value.trim(); if(!buyer||!phone||!address)return toast('Vui lòng nhập đủ tên, số điện thoại và địa chỉ'); let c=customers.find(x=>String(x.phone||'').trim()===phone); let identity=null; if(!c){ for(const id of Object.keys(NPP_META)){ if(id===activeNppId)continue; identity=(nppHub[id]?.customers||[]).find(x=>String(x.phone||'').trim()===phone); if(identity)break } } if(c){ Object.assign(c,{ store,buyer,phone,address, receiver:c.receiver||identity?.receiver||buyer, contactPhone:c.contactPhone||identity?.contactPhone||'', tier:'retail',status:'pending',active:true, addedByNpp:true,appStatus:c.appStatus||'no', ownerNppId:activeNppId }) }else{ customers.push({ id:'KH'+Date.now()+'_'+activeNppId, store,buyer,phone,address, receiver:identity?.receiver||buyer, contactPhone:identity?.contactPhone||'', tier:'retail',status:'pending',active:true, addedByNpp:true,appStatus:'no', ownerNppId:activeNppId }) } persist(); closeM('addCustomerModal'); renderAdmin(); go('pending'); toast('Đã tạo khách riêng cho '+settings.distributor+' và chuyển vào danh sách chờ duyệt') } function renderPending(){$('pendingRows').innerHTML=customers.filter(c=>c.status==='pending').map(c=>`${c.buyer}${c.addedByNpp?'
NPP đã thêm':''}${c.phone}${c.contactPhone?'
Liên hệ: '+c.contactPhone+'':''}${c.receiver||c.buyer}${c.address}${c.store||'-'}`).join('')||'Không có khách chờ duyệt'} function approve(id,t){ let c=customers.find(x=>x.id===id);if(!c)return; c.tier=t;c.status='approved';c.linkRequest=false;c.active=true;c.ownerNppId=activeNppId; let phone=localStorage.getItem('s5phone'); if(phone&&String(c.phone||'').trim()===String(phone).trim())c.appStatus='has'; persist(); if(phone&&String(c.phone||'').trim()===String(phone).trim()){ syncLinkedNppsForPhone(phone,activeNppId); loadNppData(activeNppId) } renderAdmin();renderCustomer(); toast('Đã duyệt '+tierName(t)+' cho '+settings.distributor) } function resetQRDemo(){ /* Giữ đúng NPP đang tạo QR trước khi xóa phiên khách cũ. */ const qrNppId=NPP_META[activeNppId]?activeNppId: (NPP_META[requestedNppFromUrl]?requestedNppFromUrl:'npp1'); localStorage.removeItem('s5phone'); localStorage.removeItem(NPP_LINKED_KEY); localStorage.removeItem(NPP_ACTIVE_KEY); linkedNpps=[qrNppId]; activeNppId=qrNppId; S(NPP_LINKED_KEY,linkedNpps); localStorage.setItem(NPP_ACTIVE_KEY,activeNppId); loadNppData(activeNppId); curCustomer=null; cart={}; cartDetails={}; ['regBuyer','regPhone','regContactPhone','regReceiver','regAddress','regStore'] .forEach(id=>{if($(id))$(id).value=''}); renderCustomer(); showView('customer'); prepareRegisterModal('new'); $('registerModal').style.display='flex'; toast('Đã mở đăng ký khách mới của '+settings.distributor); } let deferredInstallPrompt=null;window.addEventListener('beforeinstallprompt',e=>{e.preventDefault();deferredInstallPrompt=e});function currentOrderLink(){ let u=new URL('order.html',location.href); u.hash=''; u.search=''; u.searchParams.set('npp',activeNppId); return u.href }function drawQR(){let link=currentOrderLink();$('retailLink').textContent=link;$('qrRetailImg').src='https://api.qrserver.com/v1/create-qr-code/?size=500x500&margin=12&data='+encodeURIComponent(link)}async function downloadQR(){try{let r=await fetch($('qrRetailImg').src),b=await r.blob(),u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download='QR-'+(NPP_META[activeNppId]?.short||'5S-Smart-Order').replace(/\s+/g,'-')+'.png';a.click();setTimeout(()=>URL.revokeObjectURL(u),1000)}catch(e){window.open($('qrRetailImg').src,'_blank')}}async function copyLink(){let link=currentOrderLink();try{await navigator.clipboard.writeText(link);toast('Đã sao chép link đặt hàng của '+settings.distributor)}catch(e){prompt('Sao chép đường link này:',link)}}async function shareLink(){let link=currentOrderLink();try{if(navigator.share)await navigator.share({title:'5S Smart Order - '+settings.distributor,text:'Mời bạn mở link để đặt hàng',url:link});else await copyLink()}catch(e){if(e.name!=='AbortError')copyLink()}}function installApp(){let ios=/iphone|ipad|ipod/i.test(navigator.userAgent),standalone=window.matchMedia('(display-mode: standalone)').matches||navigator.standalone;if(standalone)return toast('Ứng dụng đã được cài trên màn hình');$('installNowBtn').style.display=deferredInstallPrompt?'inline-block':'none';$('installContent').innerHTML=deferredInstallPrompt?'Bấm Cài ngay để thêm 5S Smart Order lên màn hình điện thoại.':ios?'Trên iPhone: bấm nút Chia sẻ của Safari, sau đó chọn Thêm vào Màn hình chính và bấm Thêm.':'Trên Android: mở menu trình duyệt Chrome rồi chọn Thêm vào màn hình chính hoặc Cài đặt ứng dụng.';$('installModal').style.display='flex'}async function confirmInstall(){if(!deferredInstallPrompt)return installApp();deferredInstallPrompt.prompt();await deferredInstallPrompt.userChoice;deferredInstallPrompt=null;closeM('installModal')} function periodOrders(){let p=$('reportPeriod').value,now=new Date();return orders.filter(o=>{let d=new Date(o.date+'T00:00:00');return p==='day'?o.date===today():p==='month'?d.getMonth()===now.getMonth()&&d.getFullYear()===now.getFullYear():d.getFullYear()===now.getFullYear()})}function renderReports(){let l=periodOrders(),rev=l.reduce((s,o)=>s+o.total,0),ids=[...new Set(l.map(o=>o.customerId))];$('reportRevenue').textContent=money(rev);$('reportOrders').textContent=l.length;$('reportCustomers').textContent=ids.length;let m={};l.forEach(o=>{if(!m[o.customerId])m[o.customerId]={orders:0,total:0};m[o.customerId].orders++;m[o.customerId].total+=o.total});$('topCustomerRows').innerHTML=Object.entries(m).sort((a,b)=>b[1].total-a[1].total).slice(0,10).map(([id,v],i)=>{let c=customers.find(x=>x.id===id)||{buyer:'Khách',phone:'-',tier:'retail'};return `${i+1}${c.buyer}${c.contactPhone||c.phone}${tierName(c.tier)}${v.orders}${money(v.total)}`}).join('')||'Chưa có dữ liệu'}function exportReport(){let r=[['Kỳ','Mã đơn','Ngày','Khách hàng','SĐT','Tổng đơn']];periodOrders().forEach(o=>r.push([$('reportPeriod').value,o.id,o.created,o.buyer,o.phone,o.total]));csv('bao-cao-5s.csv',r)}let pendingDistributorLogo=null;function previewDistributorLogo(event){let file=event.target.files&&event.target.files[0];if(!file)return;if(!file.type.startsWith('image/')){toast('Vui lòng chọn file hình ảnh');return}let reader=new FileReader();reader.onload=e=>{pendingDistributorLogo=e.target.result;renderDistributorLogoPreview(pendingDistributorLogo)};reader.readAsDataURL(file)}function removeDistributorLogo(){pendingDistributorLogo='';let input=$('distributorLogoFile');if(input)input.value='';renderDistributorLogoPreview('')}function renderDistributorLogoPreview(src){let box=$('distributorLogoPreview');if(!box)return;box.innerHTML=src?'Logo nhà phân phối':'Chưa có logo'}function renderDistributorLogo(){let src=settings.logo||'',customerImg=$('customerLogoImg'),fallback=$('customerLogoFallback'),sideImg=$('sidebarLogoImg'),sidebar=$('adminSidebar');if(customerImg&&fallback){customerImg.src=src||'';customerImg.classList.toggle('hidden',!src);fallback.classList.toggle('hidden',!!src)}if(sideImg&&sidebar){sideImg.src=src||'';sidebar.classList.toggle('hasCustomLogo',!!src)}renderDistributorLogoPreview(pendingDistributorLogo!==null?pendingDistributorLogo:src)}function saveSettings(){settings.distributor=$('distributorName').value.trim()||'ĐIỆN MÁY 5S';settings.administrator=$('administratorName').value.trim()||'Nguyễn Văn A';if(pendingDistributorLogo!==null)settings.logo=pendingDistributorLogo;pendingDistributorLogo=null;persist();renderCustomer();renderAdminIdentity();renderDistributorLogo();toast('Đã lưu cài đặt và logo')}function renderAdminIdentity(){let name=settings.administrator||'Nguyễn Văn A',display=$('adminNameDisplay'),avatar=$('adminAvatar');if(display)display.textContent=name;if(avatar){let initials=name.trim().split(/\s+/).filter(Boolean).slice(-2).map(x=>x[0]).join('').toUpperCase();avatar.textContent=initials||'QT'}} function setCount(id,n){let e=$(id);if(!e)return;e.textContent=n;e.classList.toggle('zero',n===0)}function renderAdmin(){renderOverview();renderOrders();renderProducts();renderCategories();renderPromos();renderCustomers();renderPending();drawQR();renderReports();$('distributorName').value=settings.distributor;$('administratorName').value=settings.administrator||'Nguyễn Văn A';pendingDistributorLogo=null;renderAdminIdentity();renderAdminNppSwitch();renderDistributorLogo();let newCount=orders.filter(o=>o.status==='new').length,pendingCount=customers.filter(c=>c.status==='pending').length;setCount('navOrderCount',newCount);setCount('navPendingCount',pendingCount);setCount('mobileOrderCount',newCount);setCount('mobilePendingCount',pendingCount);setCount('topNotifyCount',newCount+pendingCount)} function autoLinkRetailQrForPhone(phone,targetId){ phone=String(phone||'').trim(); if(!phone||!NPP_META[targetId])return false; let source=null; for(const id of Object.keys(NPP_META)){ source=(nppHub[id]?.customers||[]).find(c=>String(c.phone||'').trim()===phone); if(source)break } const target=nppHub[targetId]||(nppHub[targetId]=targetId==='npp2'?buildSecondNppDemo():buildFirstNppDemo()); target.customers=target.customers||[]; let c=target.customers.find(x=>String(x.phone||'').trim()===phone); const isRetail=!source?.store&&(!source?.tier||source.tier==='retail'); const info={ buyer:source?.buyer||'Khách hàng',phone, receiver:source?.receiver||source?.buyer||'Khách hàng', address:source?.address||'Chưa cập nhật',store:source?.store||'', tier:'retail',status:isRetail?'approved':'pending',active:true, appStatus:'has',linkRequest:!isRetail,linkedByQr:true,ownerNppId:targetId }; if(c)Object.assign(c,info);else target.customers.push(Object.assign({id:'KH'+Date.now()},info)); S(NPP_HUB_KEY,nppHub); /* Quét QR NPP nào thì thêm đúng NPP đó. Khách lẻ được vào xem và đặt ngay. */ linkedNpps=approvedNppsForPhone(phone); if(isRetail&&!linkedNpps.includes(targetId))linkedNpps.push(targetId); activeNppId=isRetail?targetId:(linkedNpps[0]||targetId); S(NPP_LINKED_KEY,linkedNpps);localStorage.setItem(NPP_ACTIVE_KEY,activeNppId); return isRetail } function normalizeCustomerPhones(){Object.values(nppHub||{}).forEach(h=>(h.customers||[]).forEach(c=>{if(c.contactPhone===undefined)c.contactPhone=''}));customers.forEach(c=>{if(c.contactPhone===undefined)c.contactPhone=''})} normalizeCustomerPhones(); window.addEventListener('storage',e=>{if(e.key===NPP_HUB_KEY){nppHub=L(NPP_HUB_KEY,nppHub);loadNppData(activeNppId);renderCustomer();renderAdmin()}});persist();const startupPhone=localStorage.getItem('s5phone');if(startupPhone){if(requestedNppFromUrl&&NPP_META[requestedNppFromUrl])autoLinkRetailQrForPhone(startupPhone,requestedNppFromUrl);else syncLinkedNppsForPhone(startupPhone,activeNppId);loadNppData(activeNppId)}renderCustomer();renderAdmin();drawQR();if(new URLSearchParams(location.search).get('view')==='customer')showView('customer'); initHistoryCalendar();