🔔 Notifications

0 unread
📱

Verify with OTP

OTP sent to your WhatsApp & email

Resend OTP in 30s
Home ❯ Notification Settings

🔔 Notifications

Tone

🛒 My Cart

0
📌

No items saved for later.

❤️

Your wishlist is empty.
Click ♡ on any product to add.

Hubooze
♻ India ki Eco Commerce Live

🔄
50K+
Products
90
Din Return
Instant Refund
500+
Rural Jobs
😉
NAYA

Ethnic Festive Collection

Rural artisans ke haath se bane

Sirf ₹299 se
-40%
🎧
Wireless Earbuds
₹799
₹1,499
-47%
Face Glow Serum
₹179
₹349
-49%
🔪
Kitchen Knife Set
₹449
₹899
-50%
👔
Cotton Ethnic Shirt
₹399
₹799
-50%
⚡ FLASH SALE
😉 Kurti — ₹299 | 🎧 Earphones — ₹799 | 🍶 Handicraft — ₹299 | 🔊 Speaker — ₹699 | ✨ Serum — ₹179
Khatam hoga:
04GHANTE
:
27MIN
:
33SEC

Categories

Sab Dekho →
Recrafted
Rural Artisans ka Kaam
Return se bana naya product
Flash Sale
70% tak Discount
Electronics aaj hi
🔄
90 Din Return
FREE Return Pickup
Ghar se uthayenge

🔥 Trending Products

Sab Dekho →

Desi Artisans ka Kaam

Rural kaarigaron ne banaya

🍺 Desi & Handmade

Sab Dekho →

📱 Electronics

Sab Dekho →

Hubooze pe kyun Bharosa?

🔄
90 Din Return

90 puri dinon tak return karo.

💸
Instant Refund

Return approve hote hi turant paisa wapas.

🚚
Free Delivery

₹499 se upar delivery free.

Return = Recycle

Rural artisans se naya product banta hai.

😉 Fashion Picks

Sab Dekho →

Customers kya kehte hain?

PR
★★★★★
Priya Rathore
📍 Indore, MP

"Kurti 3 din mein aa gayi! Return bhi ekdum aasaan raha — ghar se uthaya, turant paisa wapas!"

✓ Verified · Women's Kurti

AK
★★★★★
Amit Kumar
📍 Pithampur, MP

"Desi handmade wall hanging liya — ekdum kamaal! Garv hota hai aisi cheez khareed ke."

✓ Verified · Recrafted Hanging

SM
★★★★★
Seema Malhotra
📍 Bhopal, MP

"90 din return policy ne itna confidence diya! Paisa 5 minute mein wapas. Shukriya Hubooze!"

✓ Verified · Face Care Kit

🧑 Seller Bano

Hubooze pe Bechna Shuru Karo

Apna samaan list karo — bilkul free mein. Pehle 3 mahine zero commission!

HomeCategories

All Categories

Showing all products
HomeReturn Policy
🔄 Hassle-Free Returns

90 Din Easy Return

"Ab khareedari hogi aur bhi mazedaar!"

🔄
90
Din Easy Return
FREE
Pickup
Instant Refund
Any Condition
24/7
Support
90

📅 90 Din Return Policy

Puri 90 din tak return kar sakte hain. Aaram se socho — koi jaldi nahi.

📦 Kisi Bhi Condition Mein

Product use hua ho ya torn ho — koi baat nahi. Return accept hoga.

💸 Instant Refund

Return approve hote hi — fauran paisa wapas! UPI, bank, ya wallet.

🚪

🏠 Ghar Se FREE Pickup

Bahar nahi jaana — team ghar aayegi, bilkul free!

Sampark Karo

📧 Team.Support@hubooze.in
Home ❯ Account

Welcome to Hubooze

Choose your portal to continue

🛒

Customer

Shop, track orders, manage returns & wishlist

📩 Track Orders
🔄 Easy Returns
❤ Wishlist
🏷 Exclusive Deals
Demo: tap to login as customer
🧑

Seller

List products, manage inventory & track payouts

📦 Product Listing
📈 Sales Analytics
💸 Payouts
🔄 Return Management
Demo: tap to login as seller
🔒 Secure login • 🔄 90-day returns • ♻ Eco marketplace
HomeMy Orders

My Orders

Home ❯ Seller Panel

Seller Dashboard

Home⚖ Admin Panel

Admin Dashboard

System Online
HomeCartCheckout
' + '' + '
' + '
₹' + itemTotal.toLocaleString('en-IN') + '
' + (disc > 0 ? '
₹' + origTotal.toLocaleString('en-IN') + '
' : '') + (saving > 0 ? '
Save ₹' + saving.toLocaleString('en-IN') + '
' : '') + '
' + ''; }); list.innerHTML = html; } function renderCartSummary() { var sub = cartSubtotal(); var disc = cartDiscount(); var couponD = couponDiscount(); var deliv = deliveryFee(); var total = cartTotal(); var savings = disc + couponD; // Progress bar var dpBar = document.getElementById('dpBar'); var dpLabel = document.getElementById('dpLabel'); var dpAmt = document.getElementById('dpAmt'); if (dpBar) { var pct = Math.min(100, Math.round(sub / FREE_DELIVERY_MIN * 100)); dpBar.style.width = pct + '%'; } if (dpLabel && dpAmt) { if (deliv === 0) { dpLabel.innerHTML = 'Free delivery unlocked! 🎉'; } else { var needed = FREE_DELIVERY_MIN - sub; dpAmt.innerHTML = '₹' + needed.toLocaleString('en-IN'); } } // Summary values function sv(id, val) { var el=document.getElementById(id); if(el) el.innerHTML=val; } function sd(id, show) { var el=document.getElementById(id); if(el) el.style.display=show?'flex':'none'; } sv('sumSubV', '₹' + sub.toLocaleString('en-IN')); sd('sumDiscRow', disc > 0); sv('sumDiscV', '-₹' + disc.toLocaleString('en-IN')); sd('sumCouponRow', couponD > 0); sv('sumCouponV', '-₹' + couponD.toLocaleString('en-IN')); sv('sumDelivV', deliv === 0 ? 'FREE 🎉' : '₹' + deliv); sv('sumTotalV', total.toLocaleString('en-IN')); var noteEl = document.getElementById('sumSavingNote'); if (noteEl) { if (savings > 0) { noteEl.innerHTML = '🎉 You are saving ₹' + savings.toLocaleString('en-IN') + ' on this order!'; } else { noteEl.textContent = ''; } } } function renderSavedPanel() { var list = document.getElementById('savedList'); if (!list) return; if (!savedItems.length) { list.innerHTML = '
📌

' + (T.savedEmptyP || 'No items saved for later.') + '

'; return; } var h = ''; savedItems.forEach(function(item) { var p = PRODUCTS[item.productId]; if (!p) return; h += '
' + '
' + p.icon + '
' + '
' + '
' + p.name + (item.size ? ' — ' + item.size : '') + '
' + '
₹' + (p.price * item.qty).toLocaleString('en-IN') + '
' + '
' + '
' + '' + '' + '
' + '
'; }); list.innerHTML = h; } function renderWishlistPanel() { var list = document.getElementById('wishList'); if (!list) return; if (!wishlist.length) { list.innerHTML = '
❤️

' + (T.wishEmptyP || 'Your wishlist is empty.') + '

'; return; } var h = ''; wishlist.forEach(function(pid) { var p = PRODUCTS[pid]; if (!p) return; var disc = Math.round((1 - p.price / p.orig) * 100); h += '
' + '
' + p.icon + '
' + '
' + '
' + p.name + '
' + '
₹' + p.price.toLocaleString('en-IN') + (disc > 0 ? ' ' + disc + '% off' : '') + '
' + '
' + '
' + '' + '' + '
' + '
'; }); list.innerHTML = h; } function renderSuggestedProducts() { var list = document.getElementById('suggestList'); if (!list) return; var cartProductIds = cartItems.map(function(i) { return i.productId; }); var suggestions = Object.values(PRODUCTS).filter(function(p) { return cartProductIds.indexOf(p.id) === -1; }).sort(function() { return Math.random() - 0.5; }).slice(0, 6); var h = ''; suggestions.forEach(function(p) { h += '
' + '
' + p.icon + '
' + '
' + p.name + '
' + '
₹' + p.price.toLocaleString('en-IN') + '
' + '' + '
'; }); list.innerHTML = h; } function updateCartBadge(bump) { var count = cartCount(); ['cartCountEl', 'mobCartBadge'].forEach(function(id) { var el = document.getElementById(id); if (!el) return; el.textContent = count; if (id === 'mobCartBadge') el.style.display = count > 0 ? 'flex' : 'none'; if (bump) { el.classList.add('bump'); setTimeout(function() { el.classList.remove('bump'); }, 300); } }); var pill = document.getElementById('cartCountPill'); if (pill) pill.textContent = count; } // ════════════════════════════════════════════════════════════════ // PRODUCT CARDS // ════════════════════════════════════════════════════════════════ function makeCard(p) { var disc = Math.round((1 - p.price / p.orig) * 100); var bcls = {BESTSELLER:'pb-sale',NEW:'pb-new',ECO:'pb-eco',HOT:'pb-hot',POPULAR:'pb-popular',SALE:'pb-sale',FESTIVE:'pb-festive'}[p.badge] || 'pb-new'; var full = Math.floor(p.rating); var stars = ''; for (var i=0;i -1; return '
' + '
' + (p.badge ? '
' + p.badge + '
' : '') + '' + '' + p.icon + '' + '
' + '
' + '
' + p.brand + '
' + '
' + p.name + '
' + '
' + stars + '(' + p.reviews.toLocaleString('en-IN') + ')
' + '
' + '₹' + p.price.toLocaleString('en-IN') + '' + '₹' + p.orig.toLocaleString('en-IN') + '' + '' + disc + '% off' + '
' + (p.eco ? '
♻ Recrafted · Rural Jobs
' : '') + '
' + '' + '' + '
' + '
' + '
'; } function renderGrid(id, arr) { var el = document.getElementById(id); if (!el) return; el.innerHTML = arr.map(makeCard).join(''); } // ════════════════════════════════════════════════════════════════ // HOME CONTENT // ════════════════════════════════════════════════════════════════ var allProducts = Object.values(PRODUCTS); function renderHomeContent() { ss('heroBadgeEl',T.heroBadge,true); ss('heroH1El',T.heroH1,true); ss('heroSubEl',T.heroSub,true); ss('rbTitleEl',T.rbTitle,false); ss('rbDescEl',T.rbDesc,false); ss('hcta1El',T.hcta1,true); ss('hcta2El',T.hcta2,true); ss('hs2El',T.hs2,false); ss('hs3El',T.hs3,false); ss('hcBadgeEl',T.hcBadge,false); ss('hcTitleEl',T.hcTitle,false); ss('hcDescEl',T.hcDesc,false); ss('hcPriceEl',T.hcPrice,true); ss('flashPillEl',T.flashPill,true); ss('timerLblEl',T.timerEnd,false); ss('tlhEl',T.tlh,false); ss('catTitleEl',T.catTitle,true); var cg = document.getElementById('catGridEl'); if (cg) { cg.innerHTML = T.cats.map(function(c) { return '
' + '
' + c.i + '
' + '
' + c.n + '
' + '
' + c.c + '
' + '
'; }).join(''); } ss('b1tEl',T.b1t,false); ss('b1sEl',T.b1s,true); ss('b3tEl',T.b3t,false); ss('trendTitleEl',T.trendTitle,true); ss('ecoHEl',T.ecoH,false); ss('ecoPEl',T.ecoP,false); ss('handTitleEl',T.handTitle,true); ss('elecTitleEl',T.elecTitle,true); ss('trustTitleEl',T.trustTitle,true); ss('t1hEl',T.t1h,false); ss('t1pEl',T.t1p,false); ss('t2hEl',T.t2h,false); ss('t2pEl',T.t2p,false); ss('t3hEl',T.t3h,false); ss('t3pEl',T.t3p,false); ss('t4hEl',T.t4h,false); ss('t4pEl',T.t4p,false); ss('fashTitleEl',T.fashTitle,true); ss('selBadgeEl',T.selBadge,false); ss('selTitleEl',T.selTitle,false); ss('selSubEl',T.selSub,true); ss('selBtnEl',T.selBtn,true); ss('footDescEl',T.footDesc,false); ss('footCopyEl',T.footCopy,true); renderGrid('trendGridEl', allProducts.sort(function(a,b){return b.reviews-a.reviews;}).slice(0,8)); renderGrid('handmadeScrollEl', allProducts.filter(function(p){return p.cat==='handmade';})); renderGrid('electronicsScrollEl', allProducts.filter(function(p){return p.cat==='electronics';})); renderGrid('fashionScrollEl', allProducts.filter(function(p){return p.cat==='fashion';})); ['fc1El','fc2El','fc3El','fc4El'].forEach(function(id,i) { var col = T['fc'+(i+1)]; var el = document.getElementById(id); if (!el||!col) return; el.innerHTML = '
'+col.h+'
' + col.l.map(function(l){return ''+l+'';}).join(''); }); } // ════════════════════════════════════════════════════════════════ // CATEGORIES PAGE // ════════════════════════════════════════════════════════════════ var catTabActive = 'all'; function renderCategoriesPage(cat) { if (cat) catTabActive = cat; ss('catPageTitleEl', T.catPageTitle, false); ss('catPageBcEl', T.catPageTitle, false); ss('filterTitleEl', T.filterTitle, false); ss('ecoChkLblEl', T.ecoChkL, false); var te = document.getElementById('catTabsEl'); if (te) { te.innerHTML = T.catTabs.map(function(tab, i) { var key = T.catTabKeys[i]; return ''; }).join(''); } renderCatProducts(); } function renderCatProducts() { var priceFilter = (document.querySelector('input[name="price"]:checked') || {value:''}).value; var sortVal = (document.getElementById('sortSelectEl') || {value:''}).value; var ecoOnly = (document.getElementById('ecoCheckEl') || {checked:false}).checked; var filtered = allProducts.filter(function(p) { if (catTabActive && catTabActive !== 'all' && p.cat !== catTabActive) return false; if (ecoOnly && !p.eco) return false; if (priceFilter) { var parts = priceFilter.split('-'); var min = parseInt(parts[0]); var max = parts[1] === '+' ? Infinity : parseInt(parts[1]); if (p.price < min || p.price > max) return false; } return true; }); if (sortVal === 'price_asc') filtered.sort(function(a,b){return a.price-b.price;}); else if (sortVal === 'price_desc') filtered.sort(function(a,b){return b.price-a.price;}); else if (sortVal === 'rating') filtered.sort(function(a,b){return b.rating-a.rating;}); else filtered.sort(function(a,b){return b.reviews-a.reviews;}); ss('showingEl', T.showingL, false); ss('prodCountEl', filtered.length + ' products', false); renderGrid('catProductsEl', filtered); } function doSearch() { var q = (document.getElementById('searchInpEl') || {value:''}).value.toLowerCase().trim(); if (!q) return; var results = allProducts.filter(function(p) { return p.name.toLowerCase().includes(q) || p.brand.toLowerCase().includes(q) || p.cat.toLowerCase().includes(q); }); showPage('categories'); catTabActive = 'all'; renderCategoriesPage(); renderGrid('catProductsEl', results); ss('prodCountEl', results.length + ' results for "' + q + '"', false); } // ════════════════════════════════════════════════════════════════ // TONE CONTENT // ════════════════════════════════════════════════════════════════ var V = { topbar:'🔄 90 Din Easy Return — Kisi bhi condition mein FREE!  |  🚀 FREE Delivery above ₹499  |  ⚡ Instant Refund  |  📧 Team.Support@hubooze.in', searchPh:'Kuch bhi dhundhein...', locLbl:'Yahan deliver karo', signIn:'Login', myAcc:'Mera Account', ordLbl:'Orders', retLbl:'& Returns', cartLbl:'Cart', timerEnd:'Khatam hoga:', tlh:'GHANTE', addCartL:'Cart Mein Daalo', buyNowL:'Abhi Kharido', addedMsg:function(n){return '"'+n+'" cart mein add ho gaya! 🛒';}, savedTabLbl:'Save Kiya', wishTabLbl:'Wishlist', saveForLaterLbl:'Baad ke liye save karo', savedEmptyP:'Koi item save nahi kiya.', wishEmptyP:'Wishlist khaali hai. ♡ dabao products pe.', sumSubL:'Subtotal', sumDiscL:'Discount', sumCouponL:'Coupon discount', sumDelivL:'Delivery', retGuaranteeText:'90 Din FREE return — kisi bhi condition mein!', checkoutBtn:'Checkout Karo →', continueBtn:'Shopping Jari Rakho', suggestTitleL:'Aapko yeh bhi pasand aayega', heroBadge:'♻ India ki Eco Commerce', heroH1:'Khareedein Aaram Se.
Return Karen Free Mein.
♻ Recycle Hoga Sab!', heroSub:'Hubooze par 90 din tak return kar sakte hain — kisi bhi condition mein! Instant refund milega.', rbTitle:'90 Din Easy Return — Bilkul FREE!', rbDesc:'Na pasand aaye to 90 din mein wapas bhejo. Pickup free, refund instant!', hcta1:'Abhi Khareedein →', hcta2:'Return Policy Dekho 🔄', hs2:'Din Return', hs3:'Instant Refund', hcBadge:'NAYA COLLECTION', hcTitle:'Ethnic Festive Collection', hcDesc:'Rural artisans ke haath se bane', hcPrice:'Sirf ₹299 se', flashPill:'⚡ FLASH SALE', catTitle:'Category se Khareedein', cats:[{i:'😉',n:'Kapde & Fashion',c:'12,000+',cat:'fashion',hl:true},{i:'🏠',n:'Ghar & Rasoi',c:'8,400+',cat:'home'},{i:'🤜',n:'Roz Ka Saman',c:'6,200+',cat:'daily'},{i:'📱',n:'Electronics',c:'5,700+',cat:'electronics'},{i:'🍺',n:'Desi/Handmade',c:'3,100+',cat:'handmade',hl:true},{i:'🏷',n:'Offers',c:'2,800+',cat:''},{i:'👟',n:'Joote',c:'4,300+',cat:'fashion'},{i:'🮸',n:'Bacchon ka Saman',c:'3,600+',cat:'daily'}], b1t:'Recrafted', b1s:'Return se bana naya product', b3t:'90 Din Return', trendTitle:'🔥 Trending Products', ecoH:'Desi Artisans ka Kaam', ecoP:'Yahan har product ek returned item tha.', handTitle:'🍺 Desi & Handmade', elecTitle:'📱 Electronics & Gadgets', trustTitle:'Hubooze pe kyun Bharosa?', t1h:'90 Din Return', t1p:'90 puri dinon tak return karo.', t2h:'Instant Refund', t2p:'Return approve hote hi turant paisa wapas.', t3h:'Free Delivery', t3p:'₹499 se upar delivery bilkul muft.', t4h:'Return = Recycle', t4p:'Rural artisans se naya product banta hai.', fashTitle:'😉 Fashion Picks', selBadge:'Seller Bano', selTitle:'Hubooze pe Bechna Shuru Karo', selSub:'Apna samaan list karo — bilkul free mein.', selBtn:'Seller Bano →', catPageTitle:'Sab Categories', filterTitle:'FILTER & SORT', catTabs:['Sab','Fashion','Electronics','Ghar','Roz Ka Saman','Desi/Handmade'], catTabKeys:['all','fashion','electronics','home','daily','handmade'], showingL:'Products dikh rahe hain:', ecoChkL:'Sirf Recrafted Dikhao', navItems:[{t:'🔥 Aaj ke Deals',c:'hot',pg:''},{t:'🏠 Home',c:'nactive',pg:'home'},{t:'😉 Fashion',c:'',pg:'categories',cat:'fashion'},{t:'📱 Electronics',c:'',pg:'categories',cat:'electronics'},{t:'♻ Desi/Handmade',c:'special',pg:'categories',cat:'handmade'},{t:'🏷 Offers',c:'',pg:'categories',cat:''},{t:'🧑 Seller Bano',c:'',pg:'seller'},{t:'🔄 Return Policy',c:'',pg:'returns'},{t:'⚖ Admin',c:'',pg:'admin',adminOnly:true}], fc1:{h:'Shopping',l:['Kapde & Fashion','Electronics','Ghar & Rasoi','Roz Ka Saman','Desi/Handmade','Offers']}, fc2:{h:'Customer',l:['Mera Account','Order Track Karo','Return Karo','Wishlist','Help & Support']}, fc3:{h:'Sellers',l:['Seller Bano','Seller Dashboard','Seller Support','Payment Info']}, fc4:{h:'Company',l:['Hamare Baare Mein','Recycle Mission','Rural Jobs','Contact Us']}, footDesc:'India ki pehli return-to-recycle marketplace.', footCopy:'2025 Hubooze. Sab haq surakshit. ♻ Made with love in India.', mnHome:'Home', mnCat:'Category', mnRet:'Return', mnCart:'Cart', mnAcc:'Account', toneToast:'🏡 Village mode on!' }; var N = { topbar:'🔄 90-Day Easy Returns — Any condition, FREE!  |  🚀 Free Delivery above ₹499  |  ⚡ Instant Refund  |  📧 Team.Support@hubooze.in', searchPh:'Search products, brands and more...', locLbl:'Deliver to', signIn:'Sign In', myAcc:'My Account', ordLbl:'Returns', retLbl:'& Orders', cartLbl:'Cart', timerEnd:'Ends in:', tlh:'HRS', addCartL:'Add to Cart', buyNowL:'Buy Now', addedMsg:function(n){return '"'+n+'" added to cart! 🛒';}, savedTabLbl:'Saved', wishTabLbl:'Wishlist', saveForLaterLbl:'Save for later', savedEmptyP:'No items saved for later.', wishEmptyP:'Your wishlist is empty. Click ♡ on any product.', sumSubL:'Subtotal', sumDiscL:'Discount', sumCouponL:'Coupon discount', sumDelivL:'Delivery', retGuaranteeText:'90-Day free returns on all items — any condition!', checkoutBtn:'Proceed to Checkout →', continueBtn:'Continue Shopping', suggestTitleL:'You might also like', heroBadge:"♻ India's Eco-Commerce", heroH1:'Shop Smart.
Return Freely.
♻ Recycle Everything.', heroSub:'Shop with confidence. 90-day returns on everything — any condition. Instant refunds and free pickup.', rbTitle:'90-Day Easy Returns — Always FREE!', rbDesc:'Changed your mind? Return within 90 days. Free pickup, instant refund.', hcta1:'Shop Now →', hcta2:'View Return Policy 🔄', hs2:'Day Returns', hs3:'Instant Refund', hcBadge:'NEW ARRIVAL', hcTitle:'Ethnic Festive Collection', hcDesc:'Handcrafted by rural artisans', hcPrice:'From ₹299', flashPill:'⚡ FLASH DEALS', catTitle:'Shop by Category', cats:[{i:'😉',n:'Fashion',c:'12,000+',cat:'fashion',hl:true},{i:'🏠',n:'Home & Kitchen',c:'8,400+',cat:'home'},{i:'🤜',n:'Daily Use',c:'6,200+',cat:'daily'},{i:'📱',n:'Electronics',c:'5,700+',cat:'electronics'},{i:'🍺',n:'Handmade/Rural',c:'3,100+',cat:'handmade',hl:true},{i:'🏷',n:'Offers',c:'2,800+',cat:''},{i:'👟',n:'Footwear',c:'4,300+',cat:'fashion'},{i:'🮸',n:'Kids & Baby',c:'3,600+',cat:'daily'}], b1t:'Recrafted', b1s:'From returned items → new life', b3t:'90-Day Returns', trendTitle:'🔥 Trending Now', ecoH:'Recrafted by Rural Artisans', ecoP:'Every product here was once a return.', handTitle:'🍺 Handmade & Rural', elecTitle:'📱 Electronics & Accessories', trustTitle:'Why Hubooze?', t1h:'90-Day Returns', t1p:'Return anything within 90 days — any condition.', t2h:'Instant Refund', t2p:'Refund credited immediately upon return approval.', t3h:'Free Delivery', t3p:'Free shipping on all orders above ₹499.', t4h:'Returns → Recycled', t4p:"Rural artisans turn your return into a new product.", fashTitle:'😉 Fashion Picks', selBadge:'Become a Seller', selTitle:'Start Selling on Hubooze Today', selSub:'List your products for free. Zero commission for first 3 months!', selBtn:'Register as Seller →', catPageTitle:'All Categories', filterTitle:'FILTER & SORT', catTabs:['All','Fashion','Electronics','Home','Daily Use','Handmade'], catTabKeys:['all','fashion','electronics','home','daily','handmade'], showingL:'Showing products:', ecoChkL:'Show Recrafted Only', navItems:[{t:"🔥 Today's Deals",c:'hot',pg:''},{t:'🏠 Home',c:'nactive',pg:'home'},{t:'😉 Fashion',c:'',pg:'categories',cat:'fashion'},{t:'📱 Electronics',c:'',pg:'categories',cat:'electronics'},{t:'♻ Handmade/Rural',c:'special',pg:'categories',cat:'handmade'},{t:'🏷 Offers',c:'',pg:'categories',cat:''},{t:'🧑 Sell on Hubooze',c:'',pg:'seller'},{t:'🔄 Return Policy',c:'',pg:'returns'},{t:'⚖ Admin',c:'',pg:'admin',adminOnly:true}], fc1:{h:'Shop',l:['Fashion','Electronics','Home & Kitchen','Daily Use','Handmade/Rural','Offers']}, fc2:{h:'Customer',l:['My Account','Track Order','Return & Refund','Wishlist','Help & Support']}, fc3:{h:'Sellers',l:['Sell on Hubooze','Seller Dashboard','Seller Support','Payout Info']}, fc4:{h:'Company',l:['About Us','Recycle Mission','Rural Jobs Program','Contact Us']}, footDesc:"India's first return-to-recycle marketplace. Shop, return, and support rural artisans.", footCopy:'2025 Hubooze. All rights reserved. ♻ Made with love in India.', mnHome:'Home', mnCat:'Categories', mnRet:'Returns', mnCart:'Cart', mnAcc:'Account', toneToast:'🌆 Normal mode on!' }; var T = V; // ════════════════════════════════════════════════════════════════ // SHARED UTILS // ════════════════════════════════════════════════════════════════ function ss(id, v, html) { var el = document.getElementById(id); if (!el || v === undefined || v === null) return; if (html) el.innerHTML = v; else el.textContent = v; } function showToast(msg, type) { var t = document.getElementById('toastEl'); var icons = {success:'✓', error:'✗', info:'ℹ'}; document.getElementById('toastIcon').innerHTML = icons[type||'success'] || icons.success; document.getElementById('toastMsg').innerHTML = msg; t.className = 'toast ' + (type||'') + ' show'; setTimeout(function(){t.className='toast '+(type||'');}, 3000); } // ════════════════════════════════════════════════════════════════ // TONE SWITCH // ════════════════════════════════════════════════════════════════ function setTone(tone) { T = (tone === 'village') ? V : N; document.body.className = (tone === 'village') ? 'village' : ''; document.getElementById('btnV').className = 'tbtn' + (tone==='village'?' active':''); document.getElementById('btnN').className = 'tbtn' + (tone==='normal'?' active':''); // Header ss('topbarEl', T.topbar, true); ss('locLblEl', T.locLbl, false); ss('hdrSignEl', T.signIn, false); ss('hdrAccEl', T.myAcc, false); ss('hdrOrdEl', T.ordLbl, false); ss('hdrRetEl', T.retLbl, false); ss('hdrCartEl', T.cartLbl, false); var si = document.getElementById('searchInpEl'); if(si) si.placeholder = T.searchPh; // Mob nav ss('mnHomeLbl',T.mnHome,false); ss('mnCatLbl',T.mnCat,false); ss('mnRetLbl',T.mnRet,false); ss('mnCartLbl',T.mnCart,false); ss('mnAccLbl',T.mnAcc,false); // Cart texts ss('cartTitleEl', '🛒 ' + T.cartLbl, true); ss('retGuaranteeText', T.retGuaranteeText, true); ss('checkoutBtn', T.checkoutBtn, true); ss('continueBtn', T.continueBtn, true); ss('sumSubL', T.sumSubL, false); ss('sumDiscL', T.sumDiscL, false); ss('sumCouponL', T.sumCouponL, false); ss('sumDelivL', T.sumDelivL, false); ss('sumTotalL', 'Total', false); ss('suggestTitleEl', T.suggestTitleL, false); ss('cartEmptyH', T.cartLbl + ' Empty', false); ss('cartEmptyP', 'Add products you love.', false); // Nav renderNav(); // Home renderHomeContent(); // Current page specific if (currentPage === 'categories') renderCategoriesPage(); // Tabs var ts = document.getElementById('tab-saved'); var tw = document.getElementById('tab-wishlist'); if (ts) ts.textContent = T.savedTabLbl + ' (' + savedItems.length + ')'; if (tw) tw.textContent = T.wishTabLbl + ' (' + wishlist.length + ')'; var tabItems = document.getElementById('tab-items'); if (tabItems) tabItems.textContent = T.cartLbl; showToast(T.toneToast, 'success'); } // ════════════════════════════════════════════════════════════════ // PAGE NAV // ════════════════════════════════════════════════════════════════ var currentPage = 'home'; function showPage(name, cat) { currentPage = name; ['home','categories','returns','account','orders','seller','admin','checkout','notifications'].forEach(function(p) { var el = document.getElementById('page-'+p); if (el) el.className = 'page' + (p===name?' active':''); }); ['mnHome','mnCat','mnRet','mnAcc'].forEach(function(id, i) { var el = document.getElementById(id); if (el) el.className = 'mob-btn' + (['home','categories','returns','account'][i]===name?' nactive':''); }); renderNav(); if (name === 'categories') { renderCategoriesPage(cat); } if (name === 'orders') { if (typeof renderOrdersPage === 'function') renderOrdersPage(); } if (name === 'seller') { if (typeof renderSellerPage === 'function') renderSellerPage(); } if (name === 'account') { if (typeof renderAccountPage === 'function') renderAccountPage(); } if (name === 'admin') { if (typeof renderAdminPanel === 'function') renderAdminPanel(); } if (name === 'checkout') { if (typeof renderCheckoutPage === 'function') renderCheckoutPage(); } if (name === 'notifications') { if (typeof renderNotificationsPage === 'function') renderNotificationsPage(); } window.scrollTo(0, 0); } function renderNav() { var nav = document.getElementById('mainNavEl'); if (!nav) return; nav.innerHTML = T.navItems.map(function(n) { var cls = 'nav-link ' + n.c + (n.pg === currentPage ? ' nactive' : ''); if (n.adminOnly && (!currentUser || currentUser.role !== 'admin')) return ''; var oc = n.pg ? 'onclick="showPage(\'' + n.pg + '\'' + (n.cat ? ',\'' + n.cat + '\'' : '') + ')"' : ''; return '' + n.t + ''; }).join(''); } // ════════════════════════════════════════════════════════════════ // TIMER // ════════════════════════════════════════════════════════════════ var timerSec = 4*3600 + 27*60 + 33; function tick() { if (timerSec > 0) timerSec--; var h=Math.floor(timerSec/3600), m=Math.floor((timerSec%3600)/60), s=timerSec%60; var th=document.getElementById('timerH'), tm=document.getElementById('timerM'), ts=document.getElementById('timerS'); if(th) th.textContent = String(h).padStart(2,'0'); if(tm) tm.textContent = String(m).padStart(2,'0'); if(ts) ts.textContent = String(s).padStart(2,'0'); } setInterval(tick, 1000); tick(); // ════════════════════════════════════════════════════════════════ // SCROLL ANIMATE // ════════════════════════════════════════════════════════════════ var obs = new IntersectionObserver(function(entries) { entries.forEach(function(e) { if (e.isIntersecting) { e.target.style.opacity = '1'; e.target.style.transform = 'translateY(0)'; e.target.style.transition = 'opacity .55s ease, transform .55s ease'; } }); }, {threshold: 0.06}); document.querySelectorAll('.section').forEach(function(el) { el.style.opacity = '0'; el.style.transform = 'translateY(24px)'; obs.observe(el); }); // ════════════════════════════════════════════════════════════════ // INIT // ════════════════════════════════════════════════════════════════ loadCartState(); setTone('village'); showPage('home'); updateCartBadge(false); // ════════════════════════════════════════════════════════════════ // AUTH / USER SYSTEM // ════════════════════════════════════════════════════════════════ var DEMO_USERS = { 'priya@demo.com': {id:'u1', name:'Priya Sharma', email:'priya@demo.com', phone:'9999999999', city:'Indore', password:'demo123', role:'customer'}, 'amit@demo.com': {id:'u2', name:'Amit Kumar', email:'amit@demo.com', phone:'8888888888', city:'Pithampur', password:'demo123', role:'seller', businessName:'AK Textiles'}, 'admin@hubooze.in':{id:'u3',name:'Admin User', email:'admin@hubooze.in',phone:'7777777777',city:'Indore', password:'admin123', role:'admin'} }; var currentUser = null; var registeredUsers = {}; function loadUsers() { try { registeredUsers = JSON.parse(localStorage.getItem('hb_users') || '{}'); } catch(e) { registeredUsers = {}; } try { var saved = localStorage.getItem('hb_session'); if (saved) { currentUser = JSON.parse(saved); } } catch(e) {} } function saveUsers() { localStorage.setItem('hb_users', JSON.stringify(registeredUsers)); } // ── LOGIN HELPER ───────────────────────────────────────────── function showLoginOverlay(msg) { return {}; } function hideLoginOverlay(timers) {} function callLoginAPI(email, password, role, cb) { fetch('/api/auth/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({email:email, password:password}) }) .then(function(r){ return r.json().then(function(d){ return {ok:r.ok, data:d}; }); }) .then(function(res){ if (!res.ok) { showToast(res.data.error||'Login failed','error'); return; } if (role && res.data.user.role!==role && !(role==='seller' && res.data.user.role==='admin')) { showToast('Wrong portal. This is a '+res.data.user.role+' account.','error'); return; } var user = res.data.user; var token = res.data.token; localStorage.setItem('hb_token', token); localStorage.setItem('token', token); try { localStorage.setItem('hb_session', JSON.stringify(user)); } catch(e) {} currentUser = user; if (window.api) window.api.token = res.data.token; try { updateHeaderAuth(); } catch(e) {} try { renderNav(); } catch(e) {} showToast('Welcome ' + res.data.user.name.split(' ')[0] + '! 🎉', 'success'); setTimeout(function(){ try { if (res.data.user.role==='admin') showPage('admin'); else if (res.data.user.role==='seller') showPage('seller'); else showPage('account'); } catch(e) {} }, 300); if (cb) cb(res.data.user); }) .catch(function(){ showToast('Connection error. Please try again.','error'); }); } function doLogin() { var email = (document.getElementById('loginEmail')||{value:''}).value.trim().toLowerCase(); var pass = (document.getElementById('loginPass') ||{value:''}).value; if (!email || !pass) { showToast('Please enter email and password','error'); return; } var btn = document.querySelector('#cLoginForm .portal-submit'); if (btn) { btn.textContent = 'Please wait...'; btn.disabled = true; } fetch('/api/auth/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({email:email, password:pass}) }) .then(function(r){ return r.json().then(function(d){return{ok:r.ok,data:d};}); }) .then(function(res){ if (btn) { btn.innerHTML='Login →'; btn.disabled=false; } if (!res.ok) { showToast(res.data.error||'Login failed','error'); return; } localStorage.setItem('hb_token', res.data.token); localStorage.setItem('hb_session', JSON.stringify(res.data.user)); localStorage.setItem('hb_after_login', res.data.user.role==='admin'?'admin':(res.data.user.role==='seller'?'seller':'account')); window.location.reload(); }) .catch(function(){ if (btn) { btn.innerHTML='Login →'; btn.disabled=false; } showToast('Cannot reach server. Please try again.','error'); }); } function doRegister() { // Overridden by app.js showToast('Connecting...', 'info'); } function loginSuccess(user) { currentUser = user; try { localStorage.setItem('hb_session', JSON.stringify(user)); } catch(e) {} try { updateHeaderAuth(); } catch(e) {} try { renderNav(); } catch(e) {} } function doLogout() { currentUser = null; localStorage.removeItem('hb_session'); localStorage.removeItem('hb_token'); if (window.api) window.api.token = null; updateHeaderAuth(); renderNav(); showToast('Logged out successfully', 'info'); showPage('account'); } function updateHeaderAuth() { var signEl = document.getElementById('hdrSignEl'); var accEl = document.getElementById('hdrAccEl'); if (currentUser) { if (signEl) signEl.textContent = currentUser.name.split(' ')[0]; if (accEl) accEl.textContent = T.myAcc || 'My Account'; } else { if (signEl) signEl.textContent = T.signIn || 'Login'; if (accEl) accEl.textContent = T.myAcc || 'Account'; } // Always re-render nav so role-specific links (Admin) show/hide correctly if (typeof renderNav === 'function') renderNav(); } function fillDemo(type) { var map = {customer:{e:'priya@demo.com',p:'demo123'}, seller:{e:'amit@demo.com',p:'demo123'}, admin:{e:'admin@hubooze.in',p:'admin123'}}; var d = map[type]; if (!d) return; var ei = document.getElementById('loginEmail'); if(ei) ei.value = d.e; var pi = document.getElementById('loginPass'); if(pi) pi.value = d.p; showToast('Credentials filled — click Login!', 'info'); } function switchAuthTab(tab) { var btnL = document.getElementById('authTabLogin'); var btnR = document.getElementById('authTabReg'); var lf = document.getElementById('loginFormWrap'); var rf = document.getElementById('registerFormWrap'); if (tab === 'login') { if (btnL) btnL.className = 'auth-tab-btn active'; if (btnR) btnR.className = 'auth-tab-btn'; if (lf) lf.style.display = ''; if (rf) rf.style.display = 'none'; } else { if (btnL) btnL.className = 'auth-tab-btn'; if (btnR) btnR.className = 'auth-tab-btn active'; if (lf) lf.style.display = 'none'; if (rf) rf.style.display = ''; } } // ════════════════════════════════════════════════════════════════ // ACCOUNT PAGE // ════════════════════════════════════════════════════════════════ var accSection = 'profile'; // ════════════════════════════════════════════════════════════════ // PORTAL SYSTEM — 3 Separate Login Portals // ════════════════════════════════════════════════════════════════ var activePortal = null; // 'customer' | 'seller' | 'admin' function openPortal(type) { activePortal = type; document.getElementById('portalChoiceScreen').style.display = 'none'; ['customer','seller','admin'].forEach(function(p) { var el = document.getElementById(p + 'Portal'); if (el) el.style.display = (p === type) ? 'block' : 'none'; }); } function closePortal() { activePortal = null; document.getElementById('portalChoiceScreen').style.display = 'block'; ['customer','seller','admin'].forEach(function(p) { var el = document.getElementById(p + 'Portal'); if (el) el.style.display = 'none'; }); } function switchPortalTab(portal, tab) { if (portal === 'customer') { var lf = document.getElementById('cLoginForm'); var rf = document.getElementById('cRegForm'); var bl = document.getElementById('cTabLogin'); var br = document.getElementById('cTabReg'); if (tab === 'login') { if (lf) lf.style.display = ''; if (rf) rf.style.display = 'none'; if (bl) bl.className = 'plt-btn active'; if (br) br.className = 'plt-btn'; } else { if (lf) lf.style.display = 'none'; if (rf) rf.style.display = ''; if (bl) bl.className = 'plt-btn'; if (br) br.className = 'plt-btn active'; } } else if (portal === 'seller') { var sf = document.getElementById('sLoginForm'); var sr = document.getElementById('sRegForm'); var sl = document.getElementById('sTabLogin'); var sg = document.getElementById('sTabReg'); if (tab === 'login') { if (sf) sf.style.display = ''; if (sr) sr.style.display = 'none'; if (sl) sl.className = 'plt-btn active'; if (sg) sg.className = 'plt-btn'; } else { if (sf) sf.style.display = 'none'; if (sr) sr.style.display = ''; if (sl) sl.className = 'plt-btn'; if (sg) sg.className = 'plt-btn active'; } } } // Quick demo login — one click auto-login function quickLogin(type) { var map = { customer:{email:'priya@demo.com',password:'demo123'}, seller:{email:'amit@demo.com',password:'demo123'}, admin:{email:'admin@hubooze.in',password:'admin123'} }; var c = map[type]; if (!c) return; openPortal(type); setTimeout(function(){ var ef = type==='customer'?'loginEmail':(type==='seller'?'sLoginEmail':'aLoginEmail'); var pf = type==='customer'?'loginPass':(type==='seller'?'sLoginPass':'aLoginPass'); var e = document.getElementById(ef); if(e) e.value=c.email; var p = document.getElementById(pf); if(p) p.value=c.password; if(type==='customer') doLogin(); else if(type==='seller') doSellerLogin(); else doAdminLogin(); }, 100); } // Customer login uses loginEmail + loginPass (same as before — app.js overrides doLogin) // Seller login function doSellerLogin() { var email = (document.getElementById('sLoginEmail')||{value:''}).value.trim().toLowerCase(); var pass = (document.getElementById('sLoginPass') ||{value:''}).value; if (!email || !pass) { showToast('Please enter email and password','error'); return; } var btn = document.querySelector('#sLoginForm .portal-submit'); if (btn) { btn.textContent='Please wait...'; btn.disabled=true; } fetch('/api/auth/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({email:email, password:pass}) }) .then(function(r){ return r.json().then(function(d){return{ok:r.ok,data:d};}); }) .then(function(res){ if (btn) { btn.innerHTML='Login to Seller Dashboard →'; btn.disabled=false; } if (!res.ok) { showToast(res.data.error||'Login failed','error'); return; } if (res.data.user.role!=='seller'&&res.data.user.role!=='admin') { showToast('Not a seller account','error'); return; } localStorage.setItem('hb_token', res.data.token); localStorage.setItem('hb_session', JSON.stringify(res.data.user)); localStorage.setItem('hb_after_login', 'seller'); window.location.reload(); }) .catch(function(){ if (btn) { btn.innerHTML='Login to Seller Dashboard →'; btn.disabled=false; } showToast('Cannot reach server. Please try again.','error'); }); } // Seller register function doSellerRegister() { var name = (document.getElementById('sRegName') || {}).value || ''; var phone = (document.getElementById('sRegPhone') || {}).value || ''; var business = (document.getElementById('sRegBusiness') || {}).value || ''; var email = (document.getElementById('sRegEmail') || {}).value || ''; var pass = (document.getElementById('sRegPass') || {}).value || ''; var city = (document.getElementById('sRegCity') || {}).value || ''; if (!name || !email || !pass || !business) { showToast('Name, business name, email and password are required', 'error'); return; } if (pass.length < 6) { showToast('Password must be at least 6 characters', 'error'); return; } // Mirror into the shared register fields var setVal = function(id, v) { var el=document.getElementById(id); if(el) el.value=v; }; setVal('regName', name); setVal('regEmail', email); setVal('regPass', pass); setVal('regPhone', phone); setVal('regCity', city); var isSellerEl = document.getElementById('regIsSeller'); if (isSellerEl) isSellerEl.value = 'true'; // signal seller role // Call doRegister which reads from reg* fields doRegister(); } // Admin login function doAdminLogin() { var email = (document.getElementById('aLoginEmail')||{value:''}).value.trim().toLowerCase(); var pass = (document.getElementById('aLoginPass') ||{value:''}).value; if (!email || !pass) { showToast('Please enter admin credentials','error'); return; } var btn = document.querySelector('#adminPortal .portal-submit'); if (btn) { btn.textContent='Please wait...'; btn.disabled=true; } fetch('/api/auth/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({email:email, password:pass}) }) .then(function(r){ return r.json().then(function(d){return{ok:r.ok,data:d};}); }) .then(function(res){ if (btn) { btn.innerHTML='⚖ Access Admin Panel →'; btn.disabled=false; } if (!res.ok) { showToast(res.data.error||'Login failed','error'); return; } if (res.data.user.role!=='admin') { showToast('Admin access required','error'); return; } localStorage.setItem('hb_token', res.data.token); localStorage.setItem('hb_session', JSON.stringify(res.data.user)); localStorage.setItem('hb_after_login', 'admin'); window.location.reload(); }) .catch(function(){ if (btn) { btn.innerHTML='⚖ Access Admin Panel →'; btn.disabled=false; } showToast('Cannot reach server. Please try again.','error'); }); } // ── renderAccountPage — shows portal choice or logged-in dashboard ── function renderAccountPage() { var loggedOut = document.getElementById('authLoggedOut'); var loggedIn = document.getElementById('authLoggedIn'); if (!loggedOut || !loggedIn) return; if (!currentUser) { loggedOut.style.display = ''; loggedIn.style.display = 'none'; closePortal(); return; } loggedOut.style.display = 'none'; loggedIn.style.display = ''; ss('accNameEl', currentUser.name, false); ss('accEmailEl', currentUser.email, false); var rolePill = document.getElementById('accRolePill'); if (rolePill) { var roleStyles = { customer: 'background:rgba(0,161,255,.2);color:#00a1ff', seller: 'background:rgba(0,255,143,.2);color:#00ff8f', admin: 'background:rgba(255,77,77,.2);color:#ff4d4d' }; rolePill.style.cssText = roleStyles[currentUser.role] || roleStyles.customer; rolePill.textContent = currentUser.role.toUpperCase(); } var avatarEl = document.getElementById('accAvatarEl'); if (avatarEl) { var roleGrads = { customer: 'var(--grad)', seller: 'linear-gradient(135deg,#00a1ff,#9c27b0)', admin: 'linear-gradient(135deg,#ff4d4d,#ff6b35)' }; avatarEl.style.background = roleGrads[currentUser.role] || 'var(--grad)'; } var menuItems = [ {id:'profile', icon:'👤', label:'My Profile'}, {id:'orders', icon:'📦', label:'My Orders', action:'orders'}, {id:'wishlist', icon:'❤', label:'Wishlist'}, {id:'returns', icon:'🔄', label:'My Returns'}, {id:'addresses', icon:'📍', label:'Addresses'}, ]; if (currentUser.role === 'seller' || currentUser.role === 'admin') { menuItems.push({id:'seller_dash', icon:'🧑', label:'Seller Panel', action:'seller'}); } if (currentUser.role === 'admin') { menuItems.push({id:'admin_dash', icon:'⚖', label:'Admin Panel', action:'admin'}); } menuItems.push({id:'logout', icon:'🚪', label:'Logout', danger:true}); var menuEl = document.getElementById('accMenuEl'); if (menuEl) { menuEl.innerHTML = menuItems.map(function(m) { var cls = 'acc-menu-link' + (accSection===m.id?' active':'') + (m.danger?' danger':''); var oc; if (m.danger) oc = 'onclick="doLogout()"'; else if (m.action) oc = 'onclick="showPage(\'' + m.action + '\')"'; else oc = 'onclick="setAccSection(\'' + m.id + '\')"'; return '
' + m.icon + ' ' + m.label + '
'; }).join(''); } renderAccContent(); } function setAccSection(id) { accSection = id; renderAccountPage(); } function renderAccContent() { var el = document.getElementById('accContentEl'); if (!el || !currentUser) return; if (accSection === 'profile') { el.innerHTML = '
' + '

My Profile

' + '
' + '
' + '
' + '
' + '
' + '
' + '' + '
'; } else if (accSection === 'wishlist') { var wProds = wishlist.map(function(pid){return PRODUCTS[pid];}).filter(Boolean); el.innerHTML = '
' + '

❤ My Wishlist (' + wProds.length + ')

' + (wProds.length ? '
' + wProds.map(makeCard).join('') + '
' : '
❤️

Your wishlist is empty. Click ♡ on any product to add.

') + '
'; } else if (accSection === 'returns') { var myReturns = RETURNS_DB.filter(function(r){ return r.userId === currentUser.id; }); el.innerHTML = '
' + '

🔄 My Returns

' + (myReturns.length ? myReturns.map(function(r){ return '
' + '
' + '
' + r.productName + '
' + '
Order #' + r.orderId + ' • ' + r.createdAt + '
' + '
Reason: ' + r.reason + '
' + '
' + r.status.toUpperCase() + '
' + '
₹' + r.refundAmt.toLocaleString('en-IN') + ' refund
' + '
'; }).join('') : '
🔄

No returns initiated yet.

') + '
'; } else if (accSection === 'addresses') { var myAddrs = ADDRESSES_DB.filter(function(a){ return a.userId === currentUser.id; }); el.innerHTML = '
' + '
' + '

📍 Saved Addresses

' + '' + '
' + (myAddrs.length ? myAddrs.map(function(a){ return '
' + (a.isDefault ? 'Default' : '') + '
' + esc(a.name) + ' • ' + esc(a.phone) + '
' + '
' + esc(a.line1) + (a.line2?', '+esc(a.line2):'') + ', ' + esc(a.city) + ' — ' + esc(a.pincode) + '
' + '
'; }).join('') : '
') + (myAddrs.length ? '
' : '') + '
'; } else if (accSection === 'admin_dash') { renderAdminPanel(); } } function saveProfile() { if (!currentUser) return; currentUser.name = (document.getElementById('profName')||{value:currentUser.name}).value.trim() || currentUser.name; currentUser.phone = (document.getElementById('profPhone')||{value:''}).value.trim(); currentUser.city = (document.getElementById('profCity')||{value:''}).value.trim(); localStorage.setItem('hb_session', JSON.stringify(currentUser)); // Also update in registered users if (registeredUsers[currentUser.email]) { registeredUsers[currentUser.email] = {...registeredUsers[currentUser.email], ...currentUser}; saveUsers(); } ss('accNameEl', currentUser.name, false); showToast('Profile updated!', 'success'); } function showAddAddressForm() { var formEl = document.getElementById('addAddrForm'); if (!formEl) return; formEl.innerHTML = '
' + '

Add New Address

' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '' + '
'; } function addAddress() { if (!currentUser) return; var name = (document.getElementById('addrName')||{value:''}).value.trim(); var phone = (document.getElementById('addrPhone')||{value:''}).value.trim(); var line1 = (document.getElementById('addrLine1')||{value:''}).value.trim(); var city = (document.getElementById('addrCity')||{value:''}).value.trim(); var state = (document.getElementById('addrState')||{value:''}).value.trim(); var pin = (document.getElementById('addrPin')||{value:''}).value.trim(); if (!name || !line1 || !city || !pin) { showToast('Please fill all required fields', 'error'); return; } var addr = {id:'addr_'+Date.now(), userId:currentUser.id, name:name, phone:phone, line1:line1, city:city, state:state, pincode:pin, isDefault: !ADDRESSES_DB.some(function(a){return a.userId===currentUser.id;})}; ADDRESSES_DB.push(addr); saveReturnsDB(); showToast('Address saved!', 'success'); setAccSection('addresses'); } function esc(str) { return String(str||'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } // ════════════════════════════════════════════════════════════════ // ORDERS SYSTEM // ════════════════════════════════════════════════════════════════ var ORDERS_DB = [ {id:'ORD2412001', userId:'u1', items:[{productId:'p1',name:'Floral Printed Kurti',icon:'😉',price:299,qty:2,size:'M'}], subtotal:598, discount:0, couponD:0, delivery:0, total:598, status:'delivered', address:'123 MG Road, Indore, MP 452001', payment:'UPI', date:'2024-12-28', deliveredOn:'2025-01-01'}, {id:'ORD2501002', userId:'u1', items:[{productId:'p2',name:'Wireless Earphones Pro',icon:'🎧',price:799,qty:1,size:null}], subtotal:799, discount:700, couponD:0, delivery:0, total:799, status:'shipped', address:'123 MG Road, Indore, MP 452001', payment:'Card', date:'2025-01-02'}, {id:'ORD2501003', userId:'u1', items:[{productId:'p5',name:'Face Glow Serum',icon:'✨',price:179,qty:1,size:'30ml'},{productId:'p6',name:'Handloom Jute Bag',icon:'👜',price:249,qty:1,size:'S'}], subtotal:428, discount:622, couponD:0, delivery:49, total:477, status:'processing', address:'123 MG Road, Indore, MP 452001', payment:'COD', date:'2025-01-05'}, {id:'ORD2412004', userId:'u1', items:[{productId:'p8',name:'Banarasi Saree',icon:'🧽',price:1299,qty:1,size:'Free Size'}], subtotal:1299, discount:1700, couponD:0, delivery:0, total:1299, status:'delivered', address:'123 MG Road, Indore, MP 452001', payment:'UPI', date:'2024-12-15', deliveredOn:'2024-12-20'}, {id:'ORD2412005', userId:'u2', items:[{productId:'p10',name:'Bluetooth Speaker',icon:'🔊',price:699,qty:2,size:null}], subtotal:1398, discount:0, couponD:50, delivery:0, total:1348, status:'delivered', address:'45 Industrial Area, Pithampur, MP', payment:'UPI', date:'2024-12-20', deliveredOn:'2024-12-24'} ]; var ordTabActive = 'all'; function renderOrdersPage() { if (!currentUser) { showPage('account'); return; } ss('ordTitleEl', 'My Orders', false); ss('ordBcEl', 'My Orders', false); var TABS = [ {key:'all',key2:'',label:'All Orders'}, {key:'processing', label:'Processing'}, {key:'shipped', label:'Shipped'}, {key:'delivered', label:'Delivered'}, {key:'cancelled', label:'Cancelled'}, {key:'returned', label:'Returned'} ]; var te = document.getElementById('ordTabsEl'); if (te) { te.innerHTML = TABS.map(function(t) { return ''; }).join(''); } var myOrders = ORDERS_DB.filter(function(o) { if (o.userId !== currentUser.id) return false; if (ordTabActive && ordTabActive !== 'all' && o.status !== ordTabActive) return false; return true; }); var el = document.getElementById('ordListEl'); if (!el) return; if (!myOrders.length) { el.innerHTML = '
' + '
📦
' + '

No orders found

' + '

Start shopping to see your orders here!

' + '' + '
'; return; } el.innerHTML = myOrders.map(function(o) { var disc = o.discount + o.couponD; return '
' // Header + '
' + '
' + '
Order #' + o.id + '
' + '
' + o.date + (o.deliveredOn ? ' • Delivered: ' + o.deliveredOn : '') + ' • ' + o.payment + '
' + '
' + '' + o.status.toUpperCase() + '' + '
' // Items + '
' + o.items.map(function(it) { return '
' + '' + it.icon + '' + '
' + '
' + it.name + '
' + '
Qty: ' + it.qty + (it.size ? ' • ' + it.size : '') + '
' + '
' + '
₹' + (it.price * it.qty).toLocaleString('en-IN') + '
' + '
'; }).join('') + '
' // Summary row + '
' + '
' + '📍 ' + o.address.substring(0, 35) + (o.address.length > 35 ? '...' : '') + (disc > 0 ? '  •  Saved ₹' + disc.toLocaleString('en-IN') + '' : '') + '
' + '
₹' + o.total.toLocaleString('en-IN') + '
' + '
' // Actions + '
' + (o.status === 'delivered' ? '' : '') + (o.status === 'processing' ? '' : '') + '' + '' + '
' + '
'; }).join(''); } function switchOrdTab(key) { ordTabActive = key; renderOrdersPage(); } function cancelOrder(ordId) { var ord = ORDERS_DB.find(function(o){return o.id===ordId;}); if (!ord) return; if (!confirm('Cancel order #' + ordId + '?')) return; ord.status = 'cancelled'; showToast('Order #' + ordId + ' cancelled. Refund in 3-5 days.', 'info'); renderOrdersPage(); } function reorderItems(ordId) { var ord = ORDERS_DB.find(function(o){return o.id===ordId;}); if (!ord) return; ord.items.forEach(function(it) { addToCart(it.productId, it.size); }); openCart(); } // ════════════════════════════════════════════════════════════════ // RETURN SYSTEM // ════════════════════════════════════════════════════════════════ var RETURNS_DB = []; var ADDRESSES_DB = [ {id:'addr1', userId:'u1', name:'Priya Sharma', phone:'9999999999', line1:'123 MG Road', city:'Indore', state:'MP', pincode:'452001', isDefault:true} ]; function saveReturnsDB() { localStorage.setItem('hb_returns', JSON.stringify(RETURNS_DB)); localStorage.setItem('hb_addresses', JSON.stringify(ADDRESSES_DB)); } function loadReturnsDB() { try { RETURNS_DB = JSON.parse(localStorage.getItem('hb_returns') || '[]'); } catch(e){ RETURNS_DB=[]; } try { ADDRESSES_DB = JSON.parse(localStorage.getItem('hb_addresses') || JSON.stringify(ADDRESSES_DB)); } catch(e){} } var returnModal_orderId = null; function openReturnModal(ordId) { returnModal_orderId = ordId; var ord = ORDERS_DB.find(function(o){return o.id===ordId;}); if (!ord) return; var overlay = document.getElementById('returnModalOverlay'); if (!overlay) return; var itemOptions = ord.items.map(function(it, i) { return ''; }).join(''); document.getElementById('returnModalBody').innerHTML = '
' + '' + itemOptions + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '
🔄 90-Day Return Promise
' + '
Free pickup from your door within 24 hours • Instant refund after pickup • Any condition accepted
' + '
' + ''; overlay.className = 'modal-overlay open'; } function submitReturn() { if (!currentUser || !returnModal_orderId) return; var ord = ORDERS_DB.find(function(o){return o.id===returnModal_orderId;}); if (!ord) return; var reason = (document.getElementById('retReason')||{value:'other'}).value; var cond = (document.getElementById('retCondition')||{value:'used'}).value; // Find selected items var checkedEls = document.querySelectorAll('input[name="retItem"]:checked'); var selectedItems = Array.from(checkedEls).map(function(el){ return ord.items[parseInt(el.value)]; }); if (!selectedItems.length) { showToast('Select at least one item to return', 'error'); return; } var refundAmt = selectedItems.reduce(function(s,it){return s + it.price * it.qty;}, 0); var ret = { id: 'RET' + Date.now(), orderId: returnModal_orderId, userId: currentUser.id, productName: selectedItems.map(function(it){return it.name;}).join(', '), reason: {size:'Wrong size',quality:'Quality issue',wrong:'Wrong product',damaged:'Arrived damaged',mind:'Changed mind',other:'Other'}[reason] || reason, condition: cond, refundAmt: refundAmt, status: 'initiated', createdAt: new Date().toLocaleDateString('en-IN'), pickupDate: new Date(Date.now() + 86400000).toLocaleDateString('en-IN') }; RETURNS_DB.push(ret); ord.status = 'returned'; saveReturnsDB(); document.getElementById('returnModalOverlay').className = 'modal-overlay'; showToast('Return initiated! Pickup on ' + ret.pickupDate + '. Refund ₹' + refundAmt.toLocaleString('en-IN'), 'success'); renderOrdersPage(); } function closeReturnModal() { var ov = document.getElementById('returnModalOverlay'); if (ov) ov.className = 'modal-overlay'; } // ════════════════════════════════════════════════════════════════ // CHECKOUT WITH ADDRESS // ════════════════════════════════════════════════════════════════ function proceedToCheckout() { if (!cartItems.length) { showToast('Your cart is empty!', 'error'); return; } if (!currentUser) { showToast('Please login to checkout', 'error'); setTimeout(function(){ closeCart(); showPage('account'); }, 800); return; } openCheckoutModal(); } function getSellerProducts() { if (!currentUser) return []; var base = Object.values(PRODUCTS).filter(function(p){ return p.sellerId === currentUser.id; }); var own = SELLER_OWN_PRODUCTS[currentUser.id] || []; var runtime = SELLER_PRODUCTS_DB[currentUser.id] || []; return base.concat(own).concat(runtime); } function getSellerOrders() { if (!currentUser) return []; var myProds = getSellerProducts(); var myIds = myProds.map(function(p){ return p.id; }); if (currentUser.role === 'admin') return ORDERS_DB; return ORDERS_DB.filter(function(o){ return o.items.some(function(it){ return myIds.indexOf(it.productId) > -1; }); }); } // ── MAIN RENDER ────────────────────────────────────────────────── function renderSellerPage() { var el = document.getElementById('sellerContentEl'); if (!el) return; // ─ Not logged in ─ if (!currentUser) { el.innerHTML = sellerGate( '🧑', 'Login Required', 'Login as a seller to access your dashboard.', 'Login / Register', "showPage('account')" ); return; } // ─ Not a seller ─ if (currentUser.role !== 'seller' && currentUser.role !== 'admin') { el.innerHTML = sellerGate( '🧑', 'Seller Account Required', 'Your account role is ' + currentUser.role + '. Register a new account with "Register as Seller" checked, or use:

amit@demo.com / demo123', 'Switch Account', "showPage('account')" ); return; } var myProds = getSellerProducts(); var myOrders = getSellerOrders(); var myReturns = RETURNS_DB.filter(function(r){ var ids = myProds.map(function(p){return p.id;}); return currentUser.role==='admin' || ids.indexOf(r.productId) > -1; }); var totalRevenue = myOrders.filter(function(o){return o.status!=='cancelled';}).reduce(function(s,o){return s+o.total;},0); var pendingOrders = myOrders.filter(function(o){return o.status==='processing';}).length; var unreadNotifs = SELLER_NOTIFICATIONS.filter(function(n){return !n.read;}).length; // ─ Stats bar ─ var statsHtml = '
' + selStat(myProds.length, 'Products', 'var(--green)', '📦') + selStat(myOrders.length, 'Total Orders', 'var(--blue)', '📩') + selStat(pendingOrders, 'Pending', 'var(--yellow)', '⏳') + selStat('₹'+totalRevenue.toLocaleString('en-IN'), 'Revenue', 'var(--green)', '💰') + selStat('₹'+Math.round(totalRevenue*.9).toLocaleString('en-IN'), 'Net Payout', 'var(--blue)', '💸') + selStat(myReturns.length, 'Returns', 'var(--red)', '🔄') + '
'; // ─ Tab bar ─ var tabs = [ {id:'overview', label:'📈 Overview'}, {id:'products', label:'📦 Products ('+myProds.length+')'}, {id:'orders', label:'📩 Orders ('+myOrders.length+')'}, {id:'returns', label:'🔄 Returns ('+myReturns.length+')'}, {id:'add_product', label:'➕ Add Product'}, {id:'payouts', label:'💸 Payouts'}, {id:'notifications',label:'🔔 Alerts'+(unreadNotifs?' ('+unreadNotifs+')':'')}, ]; if (currentUser.role === 'admin') { tabs.push({id:'admin', label:'⚖ Admin'}); } var tabsHtml = '
' + tabs.map(function(t){ return ''; }).join('') + '
'; el.innerHTML = statsHtml + tabsHtml + '
'; renderSellerTab(myProds, myOrders, myReturns, totalRevenue); } function sellerGate(icon, title, body, btnLabel, btnAction) { return '
' + '
'+icon+'
' + '

'+title+'

' + '

'+body+'

' + '' + '
'; } function selStat(val, label, color, icon) { return '
' + '
'+icon+'
' + '
'+val+'
' + '
'+label+'
' + '
'; } // ── TAB SWITCH ─────────────────────────────────────────────────── function switchSelTab(t) { sellerTabActive = t; renderSellerPage(); } // ── TAB CONTENT ────────────────────────────────────────────────── function renderSellerTab(myProds, myOrders, myReturns, totalRevenue) { var el = document.getElementById('selTabContent'); if (!el) return; var t = sellerTabActive; if (t === 'overview') renderSelOverview(myProds, myOrders, myReturns, totalRevenue, el); else if (t === 'products') renderSelProducts(myProds, el); else if (t === 'orders') renderSelOrders(myOrders, el); else if (t === 'returns') renderSelReturns(myReturns, el); else if (t === 'add_product') renderSelAddProduct(el); else if (t === 'payouts') renderSelPayouts(myOrders, totalRevenue, el); else if (t === 'notifications') renderSelNotifications(el); else if (t === 'admin') renderAdminPanel(el); } // ── OVERVIEW TAB ───────────────────────────────────────────────── function renderSelOverview(myProds, myOrders, myReturns, totalRevenue, el) { var recent = myOrders.slice().reverse().slice(0, 5); var topProds = myProds.slice().sort(function(a,b){return (b.reviews||0)-(a.reviews||0);}).slice(0,5); var pendRets = myReturns.filter(function(r){return r.status==='initiated';}); el.innerHTML = // Revenue chart placeholder + quick metrics '
' // Revenue breakdown card + '
' + '

💰 Revenue Breakdown

' + metricRow('Gross Revenue', '₹'+totalRevenue.toLocaleString('en-IN'), 'var(--text)') + metricRow('Platform Fee (10%)', '-₹'+Math.round(totalRevenue*.1).toLocaleString('en-IN'), 'var(--red)') + metricRow('Net Payout', '₹'+Math.round(totalRevenue*.9).toLocaleString('en-IN'), 'var(--green)') + '
' + metricRow('Avg Order Value', myOrders.length ? '₹'+Math.round(totalRevenue/myOrders.length).toLocaleString('en-IN') : '₹0', 'var(--blue)') + metricRow('Return Rate', myOrders.length ? (myReturns.length/myOrders.length*100).toFixed(1)+'%' : '0%', 'var(--yellow)') + '
' // Quick actions card + '
' + '

⚡ Quick Actions

' + '
' + '' + '' + '' + '' + '
' + '
' // Recent orders + '
' + '
' + '

📩 Recent Orders

' + '' + '
' + (recent.length ? recent.map(function(o){ return orderRowCompact(o); }).join('') : '

No orders yet.

') + '
' // Top products + '
' + '
' + '

🏆 Top Products

' + '' + '
' + (topProds.length ? topProds.map(function(p){ return productRowCompact(p); }).join('') : '

No products listed yet.

') + '
'; } function metricRow(label, val, color) { return '
' + ''+label+'' + ''+val+'' + '
'; } function orderRowCompact(o) { return '
' + '
' + '
#'+o.id+'
' + '
'+o.date+' • '+o.items.length+' item(s)
' + '
' + ''+o.status+'' + '₹'+o.total.toLocaleString('en-IN')+'' + '' + '
'; } function productRowCompact(p) { var disc = Math.round((1-p.price/p.orig)*100); return '
' + ''+p.icon+'' + '
' + '
'+p.name+'
' + '
'+p.brand+' • '+(p.reviews||0)+' reviews
' + '
' + '
' + '
₹'+p.price.toLocaleString('en-IN')+' '+disc+'% off
' + '
Stock: '+(p.stock||'N/A')+'
' + '
' + '
'; } // ── PRODUCTS TAB ───────────────────────────────────────────────── function renderSelProducts(myProds, el) { var listed = myProds.filter(function(p){ return p.listed !== false; }); var unlisted = myProds.filter(function(p){ return p.listed === false; }); el.innerHTML = '
' + '
' + '

📦 My Products ('+listed.length+' active)

' + '' + '
' + (listed.length ? '
' + listed.map(function(p){ return sellerProductRow(p); }).join('') + '
' : '
📦

No products listed yet.

') + '
' + (unlisted.length ? '
' + '

❌ Unlisted Products ('+unlisted.length+')

' + unlisted.map(function(p){ return sellerProductRow(p); }).join('') + '
' : ''); } function sellerProductRow(p) { var disc = Math.round((1-(p.price||0)/(p.orig||1))*100); return '
' + ''+p.icon+'' + '
' + '
'+p.name+'
' + '
'+p.brand+' • '+p.cat+' • Stock: '+(p.stock||'N/A')+'
' + '
' + (p.badge ? ''+p.badge+'' : '') + (p.eco ? '♻ ECO' : '') + '
' + '
' + '
' + '
₹'+p.price.toLocaleString('en-IN')+'
' + '
₹'+p.orig.toLocaleString('en-IN')+'
' + '
'+disc+'% off
' + '
' + '
' + '' + '' + '
' + '
'; } function editSellerProduct(pid) { sellerEditProductId = pid; switchSelTab('add_product'); } function toggleListProduct(pid) { var p = PRODUCTS[pid]; if (!p) { // search in seller own products var uid = currentUser ? currentUser.id : null; var own = SELLER_OWN_PRODUCTS[uid] || []; p = own.find(function(x){return x.id===pid;}); if (!p) { var run = SELLER_PRODUCTS_DB[uid] || []; p = run.find(function(x){return x.id===pid;}); } } if (!p) { showToast('Product not found','error'); return; } p.listed = (p.listed === false) ? true : false; showToast(p.listed === false ? '"'+p.name+'" unlisted' : '"'+p.name+'" listed again', 'info'); renderSellerPage(); } // ── ORDERS TAB ─────────────────────────────────────────────────── function renderSelOrders(myOrders, el) { var statusFilters = ['all','processing','confirmed','shipped','delivered','cancelled']; var selOrdFilter = window._selOrdFilter || 'all'; var filtered = selOrdFilter === 'all' ? myOrders : myOrders.filter(function(o){ return o.status === selOrdFilter; }); el.innerHTML = '
' + '
' + '

📩 Orders ('+filtered.length+')

' + '
' + statusFilters.map(function(s){ var cnt = s==='all' ? myOrders.length : myOrders.filter(function(o){return o.status===s;}).length; return ''; }).join('') + '
' + '
' + (filtered.length ? '
' + filtered.slice().reverse().map(function(o){ return sellerOrderCard(o); }).join('') + '
' : '
📩

No orders in this category.

') + '
'; } function sellerOrderCard(o) { return '
' + '
' + '
' + '
#'+o.id+'
' + '
'+o.date+' • '+o.payment+' • '+o.address.substring(0,35)+'...
' + '
' + '
' + ''+o.status.toUpperCase()+'' + '₹'+o.total.toLocaleString('en-IN')+'' + '
' + '
' + '
' + o.items.map(function(it){ return '
' + ''+it.icon+'' + '
'+it.name+'
' + '
Qty: '+it.qty+(it.size?' • '+it.size:'')+'
' + '
'; }).join('') + '
' + '
' + 'Update Status:' + '' + '' + '
' + '
'; } // ── RETURNS TAB ────────────────────────────────────────────────── function renderSelReturns(myReturns, el) { el.innerHTML = '
' + '

🔄 Return Requests ('+myReturns.length+')

' + (myReturns.length ? '
' + myReturns.map(function(r){ return sellerReturnCard(r); }).join('') + '
' : '
🔄

No return requests. Great job!

') + '
'; } function sellerReturnCard(r) { return '
' + '
' + '
' + '
'+r.productName+'
' + '
Order #'+r.orderId+' • '+r.createdAt+'
' + '
Reason: '+r.reason+' • Condition: '+r.condition+'
' + '
' + '
' + ''+r.status.toUpperCase()+'' + '
₹'+r.refundAmt.toLocaleString('en-IN')+' refund
' + '
' + '
' + (r.status === 'initiated' ? '
' + '' + '' + '' + '
' : '
Resolved on: '+(r.resolvedAt||r.createdAt)+'
') + '
'; } // ── ADD PRODUCT TAB ────────────────────────────────────────────── function renderSelAddProduct(el) { var isEdit = sellerEditProductId !== null; var ep = isEdit ? (PRODUCTS[sellerEditProductId] || (SELLER_OWN_PRODUCTS[currentUser.id]||[]).find(function(p){return p.id===sellerEditProductId;}) || (SELLER_PRODUCTS_DB[currentUser.id]||[]).find(function(p){return p.id===sellerEditProductId;}) ) : null; el.innerHTML = '
' + '
' + '

'+(isEdit?'✎ Edit Product':'➕ List New Product')+'

' + (isEdit ? '' : '') + '
' + '
' // Name + formField('Product Name *', 'text', 'np_name', 'e.g. Handblock Print Dupatta', ep?ep.name:'') // Brand + formField('Brand *', 'text', 'np_brand', 'e.g. AK Textiles', ep?ep.brand:'') // Price + formField('Selling Price (₹) *', 'number', 'np_price', '299', ep?ep.price:'') // MRP + formField('MRP / Original (₹) *', 'number', 'np_orig', '599', ep?ep.orig:'') + '
' + '
' // Category + '
' + '
' // Stock + formField('Stock Qty *', 'number', 'np_stock', '50', ep?ep.stock:'') // Emoji icon + formField('Icon Emoji', 'text', 'np_icon', '😉', ep?ep.icon:'', 'maxlength="4"') + '
' // Description + '
' + '
' // Sizes + '
' + '
' // Badge + Eco row + '
' + '
' + '
' + '
' + '' + '' + '
' + '
' // Submit + '
' + '' + (isEdit ? '' : '') + '
' + '
'; } function formField(label, type, id, placeholder, value, extra) { return '
' + '' + '
'; } function saveSellerProduct() { if (!currentUser) return; var name = (document.getElementById('np_name')||{value:''}).value.trim(); var brand = (document.getElementById('np_brand')||{value:''}).value.trim(); var price = parseInt((document.getElementById('np_price')||{value:'0'}).value)||0; var orig = parseInt((document.getElementById('np_orig')||{value:'0'}).value)||0; var stock = parseInt((document.getElementById('np_stock')||{value:'0'}).value)||0; var cat = (document.getElementById('np_cat')||{value:'fashion'}).value; var icon = (document.getElementById('np_icon')||{value:'📦'}).value || '📦'; var desc = (document.getElementById('np_desc')||{value:''}).value.trim(); var sizesRaw= (document.getElementById('np_sizes')||{value:''}).value; var badge = (document.getElementById('np_badge')||{value:''}).value || null; var eco = (document.getElementById('np_eco')||{checked:false}).checked; var listed = (document.getElementById('np_listed')||{checked:true}).checked; var sizes = sizesRaw.split(',').map(function(s){return s.trim();}).filter(Boolean); if (!name) { showToast('Product name is required','error'); document.getElementById('np_name').classList.add('error'); return; } if (!brand) { showToast('Brand is required','error'); document.getElementById('np_brand').classList.add('error'); return; } if (!price || price <= 0) { showToast('Please enter a valid selling price','error'); return; } if (!orig || orig <= 0) { showToast('Please enter a valid MRP','error'); return; } if (price >= orig) { showToast('Selling price must be less than MRP','error'); return; } if (stock <= 0) { showToast('Please enter valid stock quantity','error'); return; } if (sellerEditProductId) { // Update existing var existing = PRODUCTS[sellerEditProductId] || (SELLER_OWN_PRODUCTS[currentUser.id]||[]).find(function(p){return p.id===sellerEditProductId;}) || (SELLER_PRODUCTS_DB[currentUser.id]||[]).find(function(p){return p.id===sellerEditProductId;}); if (existing) { existing.name = name; existing.brand = brand; existing.price = price; existing.orig = orig; existing.stock = stock; existing.cat = cat; existing.icon = icon; existing.description = desc; existing.sizes = sizes; existing.badge = badge; existing.eco = eco; existing.listed = listed; showToast('✓ "'+name+'" updated successfully!', 'success'); } sellerEditProductId = null; switchSelTab('products'); } else { // Create new var newProd = { id: 'sp_'+Date.now(), name: name, brand: brand, cat: cat, price: price, orig: orig, stock: stock, icon: icon, rating: 0, reviews: 0, eco: eco, badge: badge, sizes: sizes, inStock: true, sellerId: currentUser.id, description: desc, listed: listed }; if (!SELLER_PRODUCTS_DB[currentUser.id]) SELLER_PRODUCTS_DB[currentUser.id] = []; SELLER_PRODUCTS_DB[currentUser.id].push(newProd); if (listed) PRODUCTS[newProd.id] = newProd; // make visible in shop too showToast('🎉 "'+name+'" listed successfully!', 'success'); switchSelTab('products'); } } // ── PAYOUTS TAB ────────────────────────────────────────────────── function renderSelPayouts(myOrders, totalRevenue, el) { var net = Math.round(totalRevenue * .9); var paid = Math.round(net * .6); var pending = net - paid; var history = [ {date:'2025-01-01', amount: Math.round(net*.3), status:'paid', ref:'PAY_2501_001'}, {date:'2024-12-15', amount: Math.round(net*.2), status:'paid', ref:'PAY_2412_002'}, {date:'2024-12-01', amount: Math.round(net*.1), status:'paid', ref:'PAY_2412_001'}, {date:'2025-01-10', amount: pending, status:'pending', ref:'PAY_2501_002'}, ]; el.innerHTML = '
' + '
₹'+net.toLocaleString('en-IN')+'
Total Net Earnings
' + '
₹'+paid.toLocaleString('en-IN')+'
Total Paid Out
' + '
₹'+pending.toLocaleString('en-IN')+'
Pending Payout
' + '
' + '
' + '

Payment Schedule

' + '

Payouts are processed every 7 days on Monday. Platform fee is 10%.

' + '
' + '
Next payout date
' + '
Monday, 13 Jan 2025
' + '
Estimated amount: ₹'+pending.toLocaleString('en-IN')+'
' + '
' + '
' + '

Payout History

' + history.map(function(h){ return '
' + '
' + '
₹'+h.amount.toLocaleString('en-IN')+'
' + '
'+h.date+' • Ref: '+h.ref+'
' + '
' + ''+h.status.toUpperCase()+'' + '
'; }).join('') + '
'; } // ── NOTIFICATIONS TAB ──────────────────────────────────────────── function renderSelNotifications(el) { var icons = {order:'📩', return:'🔄', payout:'💰', system:'🔔'}; el.innerHTML = '
' + '
' + '

🔔 Notifications

' + '' + '
' + '
' + SELLER_NOTIFICATIONS.map(function(n){ return '
' + '
' + (icons[n.type]||'🔔') + '
' + '
' + '
'+n.text+'
' + '
'+n.time+'
' + '
' + (!n.read ? '
' : '') + '
'; }).join('') + '
'; } function markAllRead() { SELLER_NOTIFICATIONS.forEach(function(n){ n.read = true; }); renderSellerPage(); showToast('All notifications marked as read', 'info'); } // ── ADMIN TAB ──────────────────────────────────────────────────── // ════════════════════════════════════════════════════════════════ // ADMIN PANEL — FULL FEATURED // ════════════════════════════════════════════════════════════════ var adminTabActive = 'overview'; var adminUserFilter = 'all'; var adminOrdFilter = 'all'; var adminRetFilter = 'all'; var adminProdFilter = 'all'; // ── ENTRY POINT ────────────────────────────────────────────────── function renderAdminPanel() { var el = document.getElementById('adminContentEl'); if (!el) return; // Guard: admin only if (!currentUser) { el.innerHTML = adminGate('⚖', 'Admin Access Required', 'Please login with an admin account to access this panel.', 'Login', "showPage('account')"); return; } if (currentUser.role !== 'admin') { el.innerHTML = adminGate('🚫', 'Access Denied', 'Your account role is ' + currentUser.role + '.
Admin credentials: admin@hubooze.in / admin123', 'Switch Account', "showPage('account')"); return; } // Compute live stats var stats = computeAdminStats(); // Stat cards var statsHtml = '
' + adminStat('📩', stats.totalOrders, 'Total Orders', 'var(--blue)') + adminStat('₹', stats.totalRevenue.toLocaleString('en-IN'), 'Platform Revenue', 'var(--green)') + adminStat('👤', stats.totalUsers, 'Registered Users', 'var(--yellow)') + adminStat('🔄', stats.totalReturns, 'Return Requests', 'var(--red)') + '
' + '
' + adminStat('🧑', stats.totalSellers, 'Active Sellers', 'var(--orange)') + adminStat('📦', stats.totalProducts, 'Products Listed', 'var(--blue)') + adminStat('♻', stats.ecoProducts, 'Eco Products', 'var(--green)') + adminStat('🎉', stats.deliveredOrders, 'Delivered Orders', 'var(--green)') + '
'; // Tab bar var tabs = [ {id:'overview', label:'📈 Overview'}, {id:'users', label:'👤 Users (' + stats.totalUsers + ')'}, {id:'orders', label:'📩 Orders (' + stats.totalOrders + ')'}, {id:'products', label:'📦 Products (' + stats.totalProducts + ')'}, {id:'returns', label:'🔄 Returns (' + stats.totalReturns + ')'}, {id:'sellers', label:'🧑 Sellers (' + stats.totalSellers + ')'}, {id:'analytics', label:'📊 Analytics'}, {id:'settings', label:'⚙ Settings'}, ]; var tabsHtml = '
' + tabs.map(function(t) { return ''; }).join('') + '
'; el.innerHTML = statsHtml + tabsHtml + '
'; renderAdminTab(stats); } function adminGate(icon, title, body, btn, action) { return '
' + '
' + icon + '
' + '

' + title + '

' + '

' + body + '

' + '' + '
'; } function adminStat(icon, val, label, color) { return '
' + '
' + icon + '
' + '
' + val + '
' + '
' + label + '
' + '
'; } function computeAdminStats() { var allUsers = Object.values(Object.assign({}, DEMO_USERS, registeredUsers)); var allProducts = Object.values(PRODUCTS); var totalRev = ORDERS_DB.filter(function(o) { return o.status !== 'cancelled'; }) .reduce(function(s, o) { return s + o.total; }, 0); return { totalOrders: ORDERS_DB.length, totalRevenue: totalRev, platformFee: Math.round(totalRev * 0.1), totalUsers: allUsers.length, totalSellers: allUsers.filter(function(u) { return u.role === 'seller'; }).length, totalProducts: allProducts.length, ecoProducts: allProducts.filter(function(p) { return p.eco; }).length, totalReturns: RETURNS_DB.length, pendingReturns: RETURNS_DB.filter(function(r) { return r.status === 'initiated'; }).length, deliveredOrders: ORDERS_DB.filter(function(o) { return o.status === 'delivered'; }).length, cancelledOrders: ORDERS_DB.filter(function(o) { return o.status === 'cancelled'; }).length, processingOrders:ORDERS_DB.filter(function(o) { return o.status === 'processing'; }).length, allUsers: allUsers, }; } function switchAdminTab(t) { adminTabActive = t; renderAdminPanel(); } function renderAdminTab(stats) { var el = document.getElementById('adminTabContent'); if (!el) return; var t = adminTabActive; if (t === 'overview') renderAdminOverview(stats, el); else if (t === 'users') renderAdminUsers(stats.allUsers, el); else if (t === 'orders') renderAdminOrders(el); else if (t === 'products') renderAdminProducts(el); else if (t === 'returns') renderAdminReturns(el); else if (t === 'sellers') renderAdminSellers(stats.allUsers, el); else if (t === 'analytics') renderAdminAnalytics(stats, el); else if (t === 'settings') renderAdminSettings(el); } // ── OVERVIEW TAB ───────────────────────────────────────────────── function renderAdminOverview(stats, el) { var recentOrders = ORDERS_DB.slice().reverse().slice(0, 6); var recentReturns = RETURNS_DB.slice().reverse().slice(0, 4); var pendingRets = RETURNS_DB.filter(function(r) { return r.status === 'initiated'; }); el.innerHTML = // Top row: Revenue + Order breakdown '
' // Revenue card + '
' + '

📈 Revenue Summary

' + adminMetricRow('Gross Revenue', '₹' + stats.totalRevenue.toLocaleString('en-IN'), 'var(--text)') + adminMetricRow('Platform Fee (10%)', '₹' + stats.platformFee.toLocaleString('en-IN'), 'var(--green)') + adminMetricRow('Seller Payouts (90%)', '₹' + (stats.totalRevenue - stats.platformFee).toLocaleString('en-IN'), 'var(--blue)') + '
' + adminMetricRow('Avg Order Value', stats.totalOrders ? '₹' + Math.round(stats.totalRevenue / stats.totalOrders).toLocaleString('en-IN') : '₹0', 'var(--yellow)') + adminMetricRow('Return Rate', stats.totalOrders ? (stats.totalReturns / stats.totalOrders * 100).toFixed(1) + '%' : '0%', stats.totalReturns / Math.max(stats.totalOrders, 1) > 0.15 ? 'var(--red)' : 'var(--green)') + '
' // Order status breakdown + '
' + '

📩 Order Status

' + adminStatusBar('Processing', stats.processingOrders, stats.totalOrders, 'var(--yellow)') + adminStatusBar('Delivered', stats.deliveredOrders, stats.totalOrders, 'var(--green)') + adminStatusBar('Cancelled', stats.cancelledOrders, stats.totalOrders, 'var(--red)') + adminStatusBar('Returned', stats.totalReturns, stats.totalOrders, 'var(--blue)') + '
' + '
' // Alerts + (pendingRets.length ? '
' + '
🔌
' + '
' + pendingRets.length + ' Return Request(s) Pending Approval
' + '
Review and approve/reject to process refunds.
' + '' + '
' : '') // Recent orders + '
' + '
' + '

📩 Recent Orders

' + '' + '
' + recentOrders.map(function(o) { return adminOrderRowCompact(o); }).join('') + '
' // Recent returns + '
' + '
' + '

🔄 Recent Returns

' + '' + '
' + (recentReturns.length ? recentReturns.map(function(r) { return adminReturnRowCompact(r); }).join('') : '

No returns yet.

') + '
'; } function adminMetricRow(label, val, color) { return '
' + '' + label + '' + '' + val + '' + '
'; } function adminStatusBar(label, count, total, color) { var pct = total > 0 ? Math.round(count / total * 100) : 0; return '
' + '
' + '' + label + '' + '' + count + ' (' + pct + '%)' + '
' + '
' + '
' + '
'; } function adminOrderRowCompact(o) { return '
' + '
' + '
#' + o.id + '
' + '
' + o.date + ' • ' + o.items.length + ' item(s) • ' + o.payment + '
' + '
' + '' + o.status + '' + '₹' + o.total.toLocaleString('en-IN') + '' + '' + '
'; } function adminReturnRowCompact(r) { return '
' + '
' + '
' + r.productName + '
' + '
Order #' + r.orderId + ' • ' + r.createdAt + ' • ' + r.reason + '
' + '
' + '' + r.status + '' + '₹' + r.refundAmt.toLocaleString('en-IN') + '' + (r.status === 'initiated' ? '
' + '' + '' + '
' : '') + '
'; } // ── USERS TAB ──────────────────────────────────────────────────── function renderAdminUsers(allUsers, el) { var roleFilters = ['all', 'customer', 'seller', 'admin']; var filtered = adminUserFilter === 'all' ? allUsers : allUsers.filter(function(u) { return u.role === adminUserFilter; }); el.innerHTML = '
' + '
' + '

👤 All Users (' + filtered.length + ')

' + '
' + roleFilters.map(function(r) { var cnt = r === 'all' ? allUsers.length : allUsers.filter(function(u) { return u.role === r; }).length; return ''; }).join('') + '
' + '
' // Table header + '
' + 'NameEmailCityRoleActions' + '
' + (filtered.length ? filtered.map(function(u) { return adminUserRow(u); }).join('') : '
No users in this category.
') + '
'; } function adminUserRow(u) { var roleColor = {customer:'var(--blue)', seller:'var(--green)', admin:'var(--red)'}[u.role] || 'var(--text2)'; return '
' + '' + esc(u.name) + '' + '' + esc(u.email) + '' + '' + esc(u.city || 'N/A') + '' + '' + u.role.toUpperCase() + '' + '
' + (u.role !== 'admin' ? '' : 'Admin') + '
' + '
'; } function adminToggleRole(email) { var user = DEMO_USERS[email] || registeredUsers[email]; if (!user) return; var newRole = user.role === 'seller' ? 'customer' : 'seller'; if (!confirm('Change ' + user.name + '\'s role to ' + newRole + '?')) return; user.role = newRole; if (registeredUsers[email]) { registeredUsers[email].role = newRole; saveUsers(); } showToast(user.name + ' is now a ' + newRole, 'success'); renderAdminPanel(); } // ── ORDERS TAB ─────────────────────────────────────────────────── function renderAdminOrders(el) { var statusFilters = ['all', 'processing', 'confirmed', 'shipped', 'delivered', 'cancelled']; var filtered = adminOrdFilter === 'all' ? ORDERS_DB : ORDERS_DB.filter(function(o) { return o.status === adminOrdFilter; }); var sorted = filtered.slice().reverse(); el.innerHTML = '
' + '
' + '

📩 All Orders (' + filtered.length + ')

' + '
' + statusFilters.map(function(s) { var cnt = s === 'all' ? ORDERS_DB.length : ORDERS_DB.filter(function(o) { return o.status === s; }).length; return ''; }).join('') + '
' + '
' + sorted.map(function(o) { return adminOrderCard(o); }).join('') + '
'; } function adminOrderCard(o) { return '
' + '
' + '
' + '
#' + o.id + '
' + '
' + o.date + ' • ' + o.payment + ' • ' + esc(o.address.substring(0, 40)) + '...
' + '
' + '
' + '' + o.status.toUpperCase() + '' + '₹' + o.total.toLocaleString('en-IN') + '' + '
' + '
' + '
' + o.items.map(function(it) { return '
' + '' + it.icon + '' + '
' + esc(it.name) + '
' + '
x' + it.qty + (it.size ? ' • ' + it.size : '') + '
' + '
'; }).join('') + '
' + '
' + 'Update:' + '' + '' + (o.status === 'delivered' ? '' : '') + '
' + '
'; } // ── PRODUCTS TAB ───────────────────────────────────────────────── function renderAdminProducts(el) { var catFilters = ['all', 'fashion', 'electronics', 'home', 'daily', 'handmade']; var allProds = Object.values(PRODUCTS); var filtered = adminProdFilter === 'all' ? allProds : allProds.filter(function(p) { return p.cat === adminProdFilter; }); el.innerHTML = '
' + '
' + '

📦 All Products (' + filtered.length + ')

' + '
' + catFilters.map(function(c) { var cnt = c === 'all' ? allProds.length : allProds.filter(function(p) { return p.cat === c; }).length; return ''; }).join('') + '
' + '
' // Table header + '
' + 'IconProductCategoryPriceRatingReviewsActions' + '
' + filtered.map(function(p) { return adminProductRow(p); }).join('') + '
'; } function adminProductRow(p) { var disc = Math.round((1 - p.price / p.orig) * 100); return '
' + '' + p.icon + '' + '
' + '
' + esc(p.name) + '
' + '
' + esc(p.brand) + (p.eco ? ' • ♻ Eco' : '') + '
' + '
' + '' + p.cat + '' + '
₹' + p.price.toLocaleString('en-IN') + '
' + '
' + disc + '% off
' + '' + (p.rating || 0) + ' ★' + '' + (p.reviews || 0).toLocaleString('en-IN') + '' + '
' + '' + '
' + '
'; } function adminToggleProduct(pid) { var p = PRODUCTS[pid]; if (!p) return; p.active = (p.active === false) ? true : false; showToast('"' + p.name + '" ' + (p.active === false ? 'deactivated' : 'activated'), 'info'); renderAdminPanel(); } // ── RETURNS TAB ────────────────────────────────────────────────── function renderAdminReturns(el) { var retFilters = ['all', 'initiated', 'approved', 'rejected']; var filtered = adminRetFilter === 'all' ? RETURNS_DB : RETURNS_DB.filter(function(r) { return r.status === adminRetFilter; }); el.innerHTML = '
' + '
' + '

🔄 Return Requests (' + filtered.length + ')

' + '
' + retFilters.map(function(r) { var cnt = r === 'all' ? RETURNS_DB.length : RETURNS_DB.filter(function(x) { return x.status === r; }).length; return ''; }).join('') + '
' + '
' + (filtered.length ? filtered.slice().reverse().map(function(r) { return adminReturnCard(r); }).join('') : '
🔄

No returns in this category.

') + '
'; } function adminReturnCard(r) { return '
' + '
' + '
' + '
' + esc(r.productName) + '
' + '
Return ID: ' + r.id + ' • Order: #' + r.orderId + '
' + '
Initiated: ' + r.createdAt + ' • Reason: ' + esc(r.reason) + ' • Condition: ' + esc(r.condition) + '
' + (r.pickupDate ? '
🚚 Pickup scheduled: ' + r.pickupDate + '
' : '') + '
' + '
' + '' + r.status.toUpperCase() + '' + '
₹' + r.refundAmt.toLocaleString('en-IN') + '
' + '
Refund amount
' + '
' + '
' + (r.status === 'initiated' ? '
' + '' + '' + '' + '
' : '
Resolved: ' + (r.resolvedAt || 'N/A') + '
') + '
'; } // ── SELLERS TAB ────────────────────────────────────────────────── function renderAdminSellers(allUsers, el) { var sellers = allUsers.filter(function(u) { return u.role === 'seller'; }); el.innerHTML = '
' + '
' + '

🧑 Seller Accounts (' + sellers.length + ')

' + '
' + (sellers.length ? sellers.map(function(u) { return adminSellerCard(u); }).join('') : '
🧑

No seller accounts yet. Users can register as sellers from the Account page.

') + '
'; } function adminSellerCard(u) { var myProds = Object.values(PRODUCTS).filter(function(p) { return p.sellerId === u.id; }); var myOrds = ORDERS_DB.filter(function(o) { var pIds = myProds.map(function(p) { return p.id; }); return o.items.some(function(it) { return pIds.indexOf(it.productId) > -1; }); }); var rev = myOrds.filter(function(o) { return o.status !== 'cancelled'; }).reduce(function(s, o) { return s + o.total; }, 0); return '
' + '
' + '
' + (u.name.charAt(0).toUpperCase()) + '
' + '
' + '
' + esc(u.name) + '
' + '
' + esc(u.email) + ' • ' + esc(u.city || 'N/A') + '
' + (u.businessName ? '
Business: ' + esc(u.businessName) + '
' : '') + '
' + '
' + myProds.length + '
Products
' + '
' + myOrds.length + '
Orders
' + '
₹' + rev.toLocaleString('en-IN') + '
Revenue
' + '
' + '
' + '
' + '' + '' + '
' + '
' + '
'; } function adminDemoteSeller(email) { if (!confirm('Demote ' + email + ' to customer?')) return; adminToggleRole(email); } // ── ANALYTICS TAB ──────────────────────────────────────────────── function renderAdminAnalytics(stats, el) { var allProds = Object.values(PRODUCTS); var catBreakdown = {}; allProds.forEach(function(p) { if (!catBreakdown[p.cat]) catBreakdown[p.cat] = {count: 0, revenue: 0}; catBreakdown[p.cat].count++; }); ORDERS_DB.filter(function(o) { return o.status !== 'cancelled'; }).forEach(function(o) { o.items.forEach(function(it) { var p = PRODUCTS[it.productId]; if (p) { if (!catBreakdown[p.cat]) catBreakdown[p.cat] = {count: 0, revenue: 0}; catBreakdown[p.cat].revenue += it.price * it.qty; } }); }); var maxRev = Math.max.apply(null, Object.values(catBreakdown).map(function(c) { return c.revenue; })) || 1; var catColors = {fashion:'var(--green)', electronics:'var(--blue)', home:'var(--yellow)', daily:'var(--orange)', handmade:'#a78bfa'}; el.innerHTML = '
' // Category revenue bar chart + '
' + '

📊 Revenue by Category

' + Object.entries(catBreakdown).map(function(entry) { var cat = entry[0], data = entry[1]; var pct = Math.round(data.revenue / maxRev * 100); var color = catColors[cat] || 'var(--text2)'; return '
' + '
' + '' + cat + '' + '₹' + data.revenue.toLocaleString('en-IN') + '' + '
' + '
' + '
' + '
' + '
' + data.count + ' products
' + '
'; }).join('') + '
' // Key metrics + '
' + '
' + '

🏆 Top Products

' + allProds.sort(function(a, b) { return (b.reviews || 0) - (a.reviews || 0); }).slice(0, 5).map(function(p, i) { return '
' + '' + (i + 1) + '' + '' + p.icon + '' + '
' + p.name + '
' + '
' + (p.reviews || 0).toLocaleString('en-IN') + ' reviews • ' + (p.rating || 0) + '★
' + '₹' + p.price.toLocaleString('en-IN') + '' + '
'; }).join('') + '
' + '
' + '

📊 Platform Health

' + adminMetricRow('Eco Products Ratio', Math.round(stats.ecoProducts / Math.max(stats.totalProducts, 1) * 100) + '%', 'var(--green)') + adminMetricRow('Order Success Rate', stats.totalOrders ? Math.round((stats.totalOrders - stats.cancelledOrders) / stats.totalOrders * 100) + '%' : 'N/A', 'var(--blue)') + adminMetricRow('Return Approval Rate', RETURNS_DB.length ? Math.round(RETURNS_DB.filter(function(r) { return r.status === 'approved'; }).length / RETURNS_DB.length * 100) + '%' : 'N/A', 'var(--green)') + adminMetricRow('Avg Product Rating', (allProds.reduce(function(s, p) { return s + (p.rating || 0); }, 0) / Math.max(allProds.length, 1)).toFixed(1) + ' / 5.0', 'var(--yellow)') + '
' + '
' + '
' // Order timeline (monthly simulation) + '
' + '

📅 Order Volume (Last 7 days)

' + '
' + [42, 58, 35, 71, 89, 63, ORDERS_DB.length * 12].map(function(v, i) { var days = ['Mon','Tue','Wed','Thu','Fri','Sat','Today']; var maxV = 120; var pct = Math.round(v / maxV * 100); return '
' + '' + v + '' + '
' + '' + days[i] + '' + '
'; }).join('') + '
' + '
'; } // ── SETTINGS TAB ───────────────────────────────────────────────── function renderAdminSettings(el) { el.innerHTML = '
' // Platform settings + '
' + '

⚙ Platform Settings

' + settingRow('Platform Fee (%)', ' ') + settingRow('Free Delivery Above (₹)', ' ') + settingRow('Return Window (days)', ' ') + settingRow('Payout Cycle', '') + settingRow('New Seller Auto-approve', '') + settingRow('Maintenance Mode', '') + '
' // Notification settings + '
' + '
' + '

🔔 Notification Settings

' + '
' + notifToggle('New order alerts', true) + notifToggle('Return requests', true) + notifToggle('New seller registrations', true) + notifToggle('Low stock alerts', false) + notifToggle('Weekly revenue report', true) + '
' + '
' + '
' + '

⚒ Danger Zone

' + '
' + '' + '' + '' + '
' + '
' + '
' + '
'; } function settingRow(label, control) { return '
' + '' + label + '' + '
' + control + '
' + '
'; } function notifToggle(label, on) { return '
' + '' + label + '' + '' + '
'; } // ── ADMIN ACTION HELPERS ────────────────────────────────────────── function adminUpdateOrderStatus(ordId, status) { var ord = ORDERS_DB.find(function(o) { return o.id === ordId; }); if (!ord) return; ord.status = status; showToast('Order #' + ordId + ' → ' + status, 'success'); renderAdminPanel(); } function adminApproveReturn(retId) { var ret = RETURNS_DB.find(function(r) { return r.id === retId; }); if (!ret) return; ret.status = 'approved'; ret.resolvedAt = new Date().toLocaleDateString('en-IN'); saveReturnsDB(); showToast('✓ Return approved. ₹' + ret.refundAmt.toLocaleString('en-IN') + ' refund processed!', 'success'); renderAdminPanel(); } function adminRejectReturn(retId) { var ret = RETURNS_DB.find(function(r) { return r.id === retId; }); if (!ret) return; if (!confirm('Reject this return request for "' + ret.productName + '"?')) return; ret.status = 'rejected'; ret.resolvedAt = new Date().toLocaleDateString('en-IN'); saveReturnsDB(); showToast('Return rejected for ' + ret.productName, 'info'); renderAdminPanel(); } function adminClearOrders() { if (!confirm('Clear ALL orders? This cannot be undone.')) return; ORDERS_DB.splice(0, ORDERS_DB.length); showToast('All orders cleared', 'info'); renderAdminPanel(); } function adminResetReturns() { if (!confirm('Reset ALL return requests? This cannot be undone.')) return; RETURNS_DB.splice(0, RETURNS_DB.length); saveReturnsDB(); showToast('All returns cleared', 'info'); renderAdminPanel(); } function adminClearUsers() { if (!confirm('Clear all registered users? Demo accounts will remain.')) return; registeredUsers = {}; saveUsers(); if (currentUser && !DEMO_USERS[currentUser.email]) { doLogout(); } showToast('Registered users cleared', 'info'); renderAdminPanel(); } // ════════════════════════════════════════════════════════════════ // INIT EXTENSION // ════════════════════════════════════════════════════════════════ loadUsers(); loadReturnsDB(); updateHeaderAuth(); // ════════════════════════════════════════════════════════════════ // CHECKOUT FLOW — FULL MULTI-STEP // ════════════════════════════════════════════════════════════════ var checkoutStep = 1; // 1=address 2=payment 3=review var checkoutAddrId = null; var checkoutPayment = 'UPI'; var checkoutPayRef = ''; // UPI id / card last4 etc var checkoutGiftWrap = false; var checkoutNote = ''; var lastPlacedOrder = null; // UPI apps shown on payment step var UPI_APPS = [ {id:'gpay', label:'Google Pay', icon:'📱', color:'#4285f4'}, {id:'phonepe',label:'PhonePe', icon:'📱', color:'#6739b7'}, {id:'paytm', label:'Paytm', icon:'📱', color:'#00baf2'}, {id:'bhim', label:'BHIM UPI', icon:'📱', color:'#00a651'}, ]; // ── ENTRY POINT ────────────────────────────────────────────────── function proceedToCheckout() { if (!cartItems.length) { showToast('Your cart is empty!', 'error'); return; } if (!currentUser) { showToast('Please login to checkout', 'error'); setTimeout(function() { closeCart(); showPage('account'); }, 700); return; } checkoutStep = 1; checkoutAddrId = null; lastPlacedOrder = null; // Auto-select default address var def = ADDRESSES_DB.find(function(a) { return a.userId === currentUser.id && a.isDefault; }); if (def) checkoutAddrId = def.id; closeCart(); showPage('checkout'); } // ── RENDER CHECKOUT PAGE ───────────────────────────────────────── function renderCheckoutPage() { // If order was just placed show confirmation if (lastPlacedOrder) { renderOrderConfirmation(lastPlacedOrder); return; } renderCheckoutSteps(); renderCheckoutSummary(); if (checkoutStep === 1) renderAddressStep(); else if (checkoutStep === 2) renderPaymentStep(); else if (checkoutStep === 3) renderReviewStep(); } // ── STEP INDICATOR ─────────────────────────────────────────────── function renderCheckoutSteps() { var el = document.getElementById('checkoutStepsEl'); if (!el) return; var steps = [ {n:1, label:'Address'}, {n:2, label:'Payment'}, {n:3, label:'Review'}, ]; el.innerHTML = steps.map(function(s, i) { var done = checkoutStep > s.n; var active = checkoutStep === s.n; var color = done ? 'var(--green)' : active ? 'var(--green)' : 'var(--border2)'; var txtClr = done || active ? '#000' : 'var(--text3)'; var bgClr = done || active ? 'var(--green)' : 'var(--bg4)'; return (i > 0 ? '
' : '') + '
' + '
' + (done ? '✓' : s.n) + '
' + '' + s.label + '' + '
'; }).join(''); } function goToStep(n) { if (n < checkoutStep) { checkoutStep = n; renderCheckoutPage(); } } // ── ORDER SUMMARY SIDEBAR ──────────────────────────────────────── function renderCheckoutSummary() { var el = document.getElementById('checkoutSummaryEl'); if (!el) return; var sub = cartSubtotal(); var disc = cartDiscount(); var couponD = couponDiscount(); var deliv = deliveryFee(); var total = cartTotal(); var savings = disc + couponD; el.innerHTML = '
' // Header + '
' + '

Order Summary

' + '' + cartCount() + ' item(s)' + '
' // Items + '
' + cartItems.map(function(ci) { var p = PRODUCTS[ci.productId]; if (!p) return ''; var disc_pct = Math.round((1 - p.price / p.orig) * 100); return '
' + '
' + p.icon + '
' + '
' + '
' + p.name + '
' + '
' + (ci.size ? ci.size + ' • ' : '') + 'Qty: ' + ci.qty + '
' + '
' + '
' + '
₹' + (p.price * ci.qty).toLocaleString('en-IN') + '
' + (disc_pct > 0 ? '
' + disc_pct + '% off
' : '') + '
' + '
'; }).join('') + '
' // Price breakdown + '
' + sumRow('Subtotal', '₹' + sub.toLocaleString('en-IN'), 'var(--text)') + (disc > 0 ? sumRow('Product Discount', '-₹' + disc.toLocaleString('en-IN'), 'var(--green)') : '') + (couponD > 0 ? sumRow('Coupon (' + (appliedCoupon ? appliedCoupon.code : '') + ')', '-₹' + couponD.toLocaleString('en-IN'), 'var(--green)') : '') + sumRow('Delivery', deliv === 0 ? 'FREE 🎉' : '₹' + deliv, deliv === 0 ? 'var(--green)' : 'var(--text)') + (checkoutGiftWrap ? sumRow('Gift Wrap', '₹49', 'var(--text)') : '') + '
' + '
' + 'Total' + '₹' + (total + (checkoutGiftWrap ? 49 : 0)).toLocaleString('en-IN') + '' + '
' + (savings > 0 ? '
You save ₹' + savings.toLocaleString('en-IN') + '! 🎉
' : '') + '
' + '🔄 90-Day free returns on all items' + '
' + '
' + '
'; } function sumRow(label, val, color) { return '
' + '' + label + '' + '' + val + '' + '
'; } // ════════════════════════════════════════════════════════════════ // STEP 1 — ADDRESS // ════════════════════════════════════════════════════════════════ var showAddNewAddr = false; function renderAddressStep() { var el = document.getElementById('checkoutStepContent'); if (!el) return; var myAddrs = ADDRESSES_DB.filter(function(a) { return a.userId === currentUser.id; }); var addrsHtml = myAddrs.length ? myAddrs.map(function(a) { var selected = checkoutAddrId === a.id; return '
' + '
' + '
' + (selected ? '' : '') + '
' + '
' + '
' + '' + esc(a.name) + '' + '' + esc(a.phone) + '' + (a.isDefault ? 'DEFAULT' : '') + '
' + '
' + esc(a.line1) + (a.line2 ? ', ' + esc(a.line2) : '') + '
' + '
' + esc(a.city) + ', ' + esc(a.state || '') + ' — ' + esc(a.pincode) + '
' + '
' + '
' + '
'; }).join('') : '
' + '
📍
' + '

No saved addresses

' + '

Add a delivery address to continue

' + '
'; el.innerHTML = '
' + '

📍 Delivery Address

' + addrsHtml // Add new address toggle + '' // Inline add-new form (hidden by default) + '
' + '
' + '

New Address

' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '
' // Delivery options + '
' + '

Delivery Option

' + '
' + deliveryOption('std', '🚚 Standard Delivery', '3-5 business days', deliveryFee() === 0 ? 'FREE' : '₹49', true) + deliveryOption('exp', '⚡ Express Delivery', '1-2 business days', '₹99', false) + deliveryOption('same', '💢 Same Day Delivery', 'Order before 12 PM', '₹149', false) + '
' + '
' // Gift wrap + '
' + '
' + '🎁' + '
Gift Wrap
Beautiful eco-friendly packaging (+₹49)
' + '
' + '' + '
' // Order note + '
' + '' + '' + '
' + '' + '
'; } function deliveryOption(id, label, sub, price, checked) { return ''; } function toggleAddNewAddr() { showAddNewAddr = !showAddNewAddr; var el = document.getElementById('newAddrFormEl'); if (el) el.style.display = showAddNewAddr ? 'block' : 'none'; } function selectAddr(id) { checkoutAddrId = id; renderAddressStep(); renderCheckoutSummary(); } function saveNewAddrAndContinue() { var name = (document.getElementById('ckAddrName') || {value:''}).value.trim(); var phone = (document.getElementById('ckAddrPhone') || {value:''}).value.trim(); var line1 = (document.getElementById('ckAddrLine1') || {value:''}).value.trim(); var line2 = (document.getElementById('ckAddrLine2') || {value:''}).value.trim(); var city = (document.getElementById('ckAddrCity') || {value:''}).value.trim(); var state = (document.getElementById('ckAddrState') || {value:''}).value.trim(); var pin = (document.getElementById('ckAddrPin') || {value:''}).value.trim(); var isDef = (document.getElementById('ckAddrDefault')|| {checked:false}).checked; if (!name || !phone || !line1 || !city || !pin) { showToast('Please fill all required fields *', 'error'); return; } if (!/^\d{6}$/.test(pin)) { showToast('Enter a valid 6-digit pincode', 'error'); return; } if (isDef) ADDRESSES_DB.forEach(function(a) { if (a.userId === currentUser.id) a.isDefault = false; }); var newAddr = { id: 'addr_' + Date.now(), userId: currentUser.id, name: name, phone: phone, line1: line1, line2: line2, city: city, state: state, pincode: pin, isDefault: isDef }; ADDRESSES_DB.push(newAddr); saveReturnsDB(); checkoutAddrId = newAddr.id; showAddNewAddr = false; showToast('Address saved!', 'success'); goToPayment(); } function goToPayment() { checkoutNote = (document.getElementById('orderNoteCk') || {value:''}).value; if (!checkoutAddrId) { showToast('Please select a delivery address', 'error'); return; } checkoutStep = 2; renderCheckoutPage(); window.scrollTo(0, 0); } // ════════════════════════════════════════════════════════════════ // STEP 2 — PAYMENT // ════════════════════════════════════════════════════════════════ var activePayMethod = 'UPI'; var selectedUpiApp = 'gpay'; function renderPaymentStep() { var el = document.getElementById('checkoutStepContent'); if (!el) return; el.innerHTML = '
' + '

💸 Payment Method

' // Payment method tabs + '
' + payMethodBtn('UPI', '📱', 'UPI') + payMethodBtn('Card', '💳', 'Card') + payMethodBtn('NB', '🏠', 'Net Banking') + payMethodBtn('COD', '💰', 'Cash on Delivery') + '
' // UPI panel + '
' + '

Select UPI App

' + '
' + UPI_APPS.map(function(app) { var sel = selectedUpiApp === app.id; return '
' + '
' + app.icon + '
' + '
' + app.label + '
' + '
'; }).join('') + '
' + '
' + '' + '
We will send a payment request to this UPI ID
' + '
' + '
' // Card panel + '
' + '
' + '' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '🔒 Your card info is encrypted & secure' + '
' + '
' // Net banking panel + '
' + '

Select Bank

' + '
' + ['SBI','HDFC','ICICI','Axis','Kotak','BOB','PNB','Yes Bank'].map(function(b) { return '
' + b + '
'; }).join('') + '
' + '

You will be redirected to your bank\'s website to complete payment.

' + '
' // COD panel + '
' + '
' + '
💰
' + '

Cash on Delivery

' + '
Pay in cash when your order arrives at your doorstep.
' + 'Please keep exact change ready. Our delivery partner will accept cash only.
' + '
' + '⚠ COD available on orders up to ₹5,000 only' + '
' + '
' + '
' // Offers / saved cards section + '
' + '

🏷 Available Offers

' + '
' + offerChip('💳 Get 5% cashback on HDFC Credit Card', 'Max ₹250') + offerChip('📱 Extra ₹50 off with GPay or PhonePe', 'Min order ₹499') + offerChip('📚 No-cost EMI on orders above ₹999', 'Select cards only') + '
' + '
' // Nav buttons + '
' + '' + '' + '
' + '
'; } function payMethodBtn(id, icon, label) { var active = activePayMethod === id; return '
' + '
' + icon + '
' + '
' + label + '
' + '
'; } function offerChip(title, sub) { return '
' + '' + title + '' + '' + sub + '' + '
'; } function switchPayMethod(id) { activePayMethod = id; checkoutPayment = id; ['UPI','Card','NB','COD'].forEach(function(m) { var panel = document.getElementById('payPanel_' + m); if (panel) panel.style.display = m === id ? 'block' : 'none'; }); // Update tab styles document.querySelectorAll('[onclick^="switchPayMethod"]').forEach(function(btn) { var m = btn.getAttribute('onclick').match(/'(\w+)'/)[1]; var active = m === id; btn.style.background = active ? 'rgba(0,255,143,.1)' : 'var(--bg4)'; btn.style.borderColor = active ? 'var(--green)' : 'var(--border)'; btn.querySelector('div:last-child').style.color = active ? 'var(--green)' : 'var(--text2)'; }); } function formatCardNum(inp) { var v = inp.value.replace(/\D/g,'').substring(0,16); inp.value = v.replace(/(.{4})/g,'$1 ').trim(); } function formatExpiry(inp) { var v = inp.value.replace(/\D/g,'').substring(0,4); if (v.length >= 2) v = v.substring(0,2) + '/' + v.substring(2); inp.value = v; } function goToReview() { // Collect payment ref if (activePayMethod === 'UPI') { checkoutPayRef = (document.getElementById('upiIdInput')||{value:''}).value.trim(); if (!checkoutPayRef) { showToast('Please enter your UPI ID', 'error'); return; } } else if (activePayMethod === 'Card') { var cn = (document.getElementById('cardNum')||{value:''}).value.replace(/\s/g,''); if (cn.length < 16) { showToast('Please enter a valid card number', 'error'); return; } checkoutPayRef = '****' + cn.slice(-4); } checkoutPayment = activePayMethod; checkoutStep = 3; renderCheckoutPage(); window.scrollTo(0, 0); } // ════════════════════════════════════════════════════════════════ // STEP 3 — REVIEW & CONFIRM // ════════════════════════════════════════════════════════════════ function renderReviewStep() { var el = document.getElementById('checkoutStepContent'); if (!el) return; var addr = ADDRESSES_DB.find(function(a) { return a.id === checkoutAddrId; }); var sub = cartSubtotal(); var disc = cartDiscount(); var couponD = couponDiscount(); var deliv = deliveryFee(); var total = cartTotal() + (checkoutGiftWrap ? 49 : 0); var payLabel = { UPI: '📱 UPI — ' + (checkoutPayRef || 'Selected app'), Card: '💳 Card — ' + (checkoutPayRef || 'Saved card'), NB: '🏠 Net Banking — ' + (checkoutPayRef || 'Selected bank'), COD: '💰 Cash on Delivery' }[checkoutPayment] || checkoutPayment; el.innerHTML = // Delivery address review '
' + '
' + '

📍 DELIVER TO

' + '' + '
' + (addr ? '
' + esc(addr.name) + '   ' + esc(addr.phone) + '
' + '
' + esc(addr.line1) + (addr.line2 ? ', ' + esc(addr.line2) : '') + '
' + '
' + esc(addr.city) + ', ' + esc(addr.state || '') + ' — ' + esc(addr.pincode) + '
' : '
No address selected
') + '
' // Payment review + '
' + '
' + '

💸 PAYMENT

' + '' + '
' + '
' + payLabel + '
' + '
' // Items review + '
' + '

📦 ORDER ITEMS (' + cartCount() + ')

' + cartItems.map(function(ci) { var p = PRODUCTS[ci.productId]; if (!p) return ''; return '
' + '
' + p.icon + '
' + '
' + '
' + esc(p.name) + '
' + '
' + esc(p.brand) + (ci.size ? ' • ' + ci.size : '') + ' • Qty: ' + ci.qty + '
' + '
' + '
' + '
₹' + (p.price * ci.qty).toLocaleString('en-IN') + '
' + '
₹' + (p.orig * ci.qty).toLocaleString('en-IN') + '
' + '
' + '
'; }).join('') + '
' // Price breakdown + '
' + '

💰 PRICE DETAILS

' + sumRow('Price (' + cartCount() + ' items)', '₹' + sub.toLocaleString('en-IN'), 'var(--text)') + sumRow('Product Discount', '-₹' + disc.toLocaleString('en-IN'), 'var(--green)') + (couponD > 0 ? sumRow('Coupon Discount', '-₹' + couponD.toLocaleString('en-IN'), 'var(--green)') : '') + sumRow('Delivery Charges', deliv === 0 ? 'FREE' : '₹' + deliv, 'var(--text)') + (checkoutGiftWrap ? sumRow('Gift Wrap', '₹49', 'var(--text)') : '') + '
' + '
' + 'Total Amount' + '₹' + total.toLocaleString('en-IN') + '' + '
' + '
🎉 You will save ₹' + (disc + couponD).toLocaleString('en-IN') + ' on this order
' + '
' // T&C + place order + '
' + '' + '' + '
' + '
' + '' + '' + '
'; } // ════════════════════════════════════════════════════════════════ // PLACE ORDER // ════════════════════════════════════════════════════════════════ function placeOrderFinal() { if (!currentUser) return; if (!checkoutAddrId) { showToast('Please select a delivery address', 'error'); goToStep(1); return; } var tc = document.getElementById('tcCheck'); if (tc && !tc.checked) { showToast('Please accept the Terms & Conditions', 'error'); return; } var btn = document.getElementById('placeOrderBtn'); if (btn) { btn.disabled = true; btn.innerHTML = '⏳ Placing Order...'; btn.style.opacity = '0.7'; } var addr = ADDRESSES_DB.find(function(a) { return a.id === checkoutAddrId; }); var sub = cartSubtotal(); var disc = cartDiscount(); var couponD = couponDiscount(); var deliv = deliveryFee(); var total = cartTotal() + (checkoutGiftWrap ? 49 : 0); // Simulate network delay setTimeout(function() { var orderId = 'ORD' + Date.now(); var order = { id: orderId, userId: currentUser.id, items: cartItems.map(function(ci) { var p = PRODUCTS[ci.productId]; return { productId: ci.productId, name: p ? p.name : 'Unknown', icon: p ? p.icon : '📦', price: p ? p.price : 0, qty: ci.qty, size: ci.size || null }; }), subtotal: sub, discount: disc, couponD: couponD, giftWrap: checkoutGiftWrap ? 49 : 0, delivery: deliv, total: total, status: 'processing', address: addr ? (addr.line1 + ', ' + addr.city + ' - ' + addr.pincode) : '', addrFull: addr || {}, payment: checkoutPayment, payRef: checkoutPayRef, note: checkoutNote, couponCode:appliedCoupon ? appliedCoupon.code : null, date: new Date().toLocaleDateString('en-IN'), estimatedDelivery: getEstimatedDelivery() }; ORDERS_DB.unshift(order); lastPlacedOrder = order; // Clear cart cartItems = []; appliedCoupon = null; saveCartState(); updateCartBadge(false); checkoutGiftWrap = false; checkoutNote = ''; renderOrderConfirmation(order); window.scrollTo(0, 0); }, 1800); } function getEstimatedDelivery() { var d = new Date(); d.setDate(d.getDate() + 4); return d.toLocaleDateString('en-IN', {weekday:'long', day:'numeric', month:'long'}); } // ════════════════════════════════════════════════════════════════ // ORDER CONFIRMATION SCREEN // ════════════════════════════════════════════════════════════════ function renderOrderConfirmation(order) { // Hide the step layout, show confirmation full width var layout = document.getElementById('checkoutLayout'); var confirm = document.getElementById('orderConfirmationEl'); var steps = document.getElementById('checkoutStepsEl'); if (layout) layout.style.display = 'none'; if (steps) steps.style.display = 'none'; if (!confirm) return; confirm.style.display = 'block'; var totalSaved = (order.discount || 0) + (order.couponD || 0); confirm.innerHTML = // Success animation block '
' + '
' + '

Order Placed!

' + '

Thank you for shopping with Hubooze! 🏭

' + '
' + 'Order ID: #' + order.id + '' + '
' + '
' // Info cards row + '
' + confirmInfoCard('🚚', 'Estimated Delivery', order.estimatedDelivery, 'var(--green)') + confirmInfoCard('💸', 'Payment', ({UPI:'UPI Payment',Card:'Card Payment',NB:'Net Banking',COD:'Cash on Delivery'}[order.payment]||order.payment), 'var(--blue)') + confirmInfoCard('🔄', 'Return Policy', '90-day free returns', 'var(--green)') + '
' // Delivery address + '
' + '
' + '

Delivering to

' + (order.addrFull && order.addrFull.name ? '
' + esc(order.addrFull.name) + '
' + '
' + esc(order.addrFull.line1 || '') + '
' + '
' + esc(order.addrFull.city || '') + ' — ' + esc(order.addrFull.pincode || '') + '
' + '
Phone: ' + esc(order.addrFull.phone || '') + '
' : '
' + esc(order.address || '') + '
') + '
' + '
' + '

Price Paid

' + '
' + '
Subtotal₹' + order.subtotal.toLocaleString('en-IN') + '
' + (order.discount > 0 ? '
Discount-₹' + order.discount.toLocaleString('en-IN') + '
' : '') + (order.couponD > 0 ? '
Coupon-₹' + order.couponD.toLocaleString('en-IN') + '
' : '') + '
Delivery' + (order.delivery === 0 ? 'FREE' : '₹' + order.delivery) + '
' + '
' + '
Total₹' + order.total.toLocaleString('en-IN') + '
' + (totalSaved > 0 ? '
Saved ₹' + totalSaved.toLocaleString('en-IN') + '!
' : '') + '
' + '
' + '
' // Items + '
' + '

Items Ordered

' + order.items.map(function(it) { return '
' + '
' + it.icon + '
' + '
' + '
' + esc(it.name) + '
' + '
' + (it.size ? it.size + ' • ' : '') + 'Qty: ' + it.qty + '
' + '
' + '
₹' + (it.price * it.qty).toLocaleString('en-IN') + '
' + '
'; }).join('') + (order.note ? '
📝 Note: ' + esc(order.note) + '
' : '') + '
' // Tracking timeline + '
' + '

Order Timeline

' + '
' + timelineStep('✓', 'Order Placed', new Date().toLocaleDateString('en-IN'), true, false) + timelineStep('●', 'Processing', 'Being prepared', false, false) + timelineStep('●', 'Shipped', 'In transit', false, false) + timelineStep('🏠', 'Out for Delivery', 'Almost there!', false, false) + timelineStep('🎉', 'Delivered', order.estimatedDelivery, false, true) + '
' + '
' // Action buttons + '
' + '' + '' + '' + '
'; // confetti-style animation startConfetti(); } function confirmInfoCard(icon, label, val, color) { return '
' + '
' + icon + '
' + '
' + label + '
' + '
' + val + '
' + '
'; } function timelineStep(icon, label, sub, active, last) { return '
' + '
' + '
' + icon + '
' + (!last ? '
' : '') + '
' + '
' + '
' + label + '
' + '
' + sub + '
' + '
' + '
'; } function continueAfterOrder() { lastPlacedOrder = null; checkoutStep = 1; showPage('home'); } // ── Simple confetti ────────────────────────────────────────────── function startConfetti() { var colors = ['#00ff8f','#00a1ff','#ffc107','#ff4d4d','#ff6b35']; for (var i = 0; i < 60; i++) { (function(i) { setTimeout(function() { var d = document.createElement('div'); d.style.cssText = 'position:fixed;top:-10px;left:' + Math.random() * 100 + 'vw;' + 'width:' + (6 + Math.random() * 8) + 'px;height:' + (6 + Math.random() * 8) + 'px;' + 'background:' + colors[Math.floor(Math.random() * colors.length)] + ';' + 'border-radius:' + (Math.random() > .5 ? '50%' : '2px') + ';' + 'z-index:99999;pointer-events:none;' + 'animation:confettiFall ' + (1.5 + Math.random() * 2) + 's linear forwards'; document.body.appendChild(d); setTimeout(function() { d.remove(); }, 4000); }, i * 50); })(i); } } // ── Patch showPage to handle checkout ─────────────────────────── // showPage is fully defined above // ── Patch openCheckoutModal to redirect to full page ──────────── function openCheckoutModal() { proceedToCheckout(); } function closeCheckoutModal() { } // no-op (we use full page now) function placeOrder() { placeOrderFinal(); } // backward compat alias // ════════════════════════════════════════════════════════════════ // NOTIFICATION SYSTEM — Full Featured // WhatsApp simulator · Email previewer · OTP login · Bell panel // ════════════════════════════════════════════════════════════════ // ── DATA STORE ─────────────────────────────────────────────────── var NOTIFS_DB = []; // all notifications for current user var notifTabActive = 'all'; // ── NOTIFICATION PREFERENCES (default all on) ──────────────────── var NOTIF_PREFS = { order_placed_wa: true, order_placed_email: true, order_shipped_wa: true, order_shipped_email:false, order_delivered_wa: true, order_delivered_email:true, return_initiated_wa:true, return_initiated_email:true, return_approved_wa: true, return_approved_email:true, promo_wa: false, promo_email: true, otp_wa: true, otp_sms: true, login_alert_email: true, }; function loadNotifPrefs() { try { var saved = localStorage.getItem('hb_notif_prefs'); if (saved) NOTIF_PREFS = Object.assign({}, NOTIF_PREFS, JSON.parse(saved)); var savedNotifs = localStorage.getItem('hb_notifs'); if (savedNotifs) NOTIFS_DB = JSON.parse(savedNotifs); } catch(e) {} } function saveNotifPrefs() { localStorage.setItem('hb_notif_prefs', JSON.stringify(NOTIF_PREFS)); localStorage.setItem('hb_notifs', JSON.stringify(NOTIFS_DB.slice(0, 100))); } // ── CORE: ADD NOTIFICATION ──────────────────────────────────────── function addNotification(type, title, body, channels, data) { var notif = { id: 'n_' + Date.now() + '_' + Math.random().toString(36).slice(2,6), type: type, // order|return|promo|system|otp title: title, body: body, channels: channels || ['push'], // wa|email|sms|push data: data || {}, read: false, time: new Date().toLocaleTimeString('en-IN', {hour:'2-digit', minute:'2-digit'}), date: new Date().toLocaleDateString('en-IN'), ts: Date.now() }; NOTIFS_DB.unshift(notif); saveNotifPrefs(); // Update bell badge updateNotifBadge(); // Show channels channels.forEach(function(ch) { if (ch === 'wa' && (data.waMsg || body)) sendWaNotification(notif); if (ch === 'email' && (data.emailHtml|| body)) queueEmailNotification(notif); if (ch === 'push') showPushToast(notif); }); return notif; } // ── BELL + PANEL ───────────────────────────────────────────────── function updateNotifBadge() { var unread = NOTIFS_DB.filter(function(n) { return !n.read; }).length; var badge = document.getElementById('notifBadge'); var bellEl = document.getElementById('notifBellEl'); if (badge) { badge.textContent = unread > 9 ? '9+' : unread; badge.style.display= unread > 0 ? 'flex' : 'none'; } if (bellEl && unread > 0) { bellEl.classList.add('bell-shake'); setTimeout(function() { bellEl.classList.remove('bell-shake'); }, 600); } var label = document.getElementById('notifCountLabel'); if (label) label.textContent = unread + ' unread'; } function openNotifPanel() { renderNotifList(); document.getElementById('notifOverlay').className = 'cart-overlay open'; document.getElementById('notifPanel').className = 'notif-panel open'; } function closeNotifPanel() { document.getElementById('notifOverlay').className = 'cart-overlay'; document.getElementById('notifPanel').className = 'notif-panel'; } function switchNotifTab(tab) { notifTabActive = tab; ['all','order','return','promo'].forEach(function(t) { var el = document.getElementById('ntab-' + t); if (el) el.className = 'cart-tab' + (t === tab ? ' active' : ''); }); renderNotifList(); } function renderNotifList() { var el = document.getElementById('notifList'); if (!el) return; var list = notifTabActive === 'all' ? NOTIFS_DB : NOTIFS_DB.filter(function(n) { return n.type === notifTabActive; }); if (!list.length) { el.innerHTML = '
' + '
🔔
' + '

No notifications yet

'; return; } var typeIcons = {order:'📩', return:'🔄', promo:'🏷', system:'⚙', otp:'📱'}; var typeBgs = {order:'rgba(0,161,255,.12)', return:'rgba(0,255,143,.12)', promo:'rgba(255,107,53,.12)', system:'rgba(170,170,170,.12)', otp:'rgba(156,39,176,.12)'}; var typeColors= {order:'var(--blue)', return:'var(--green)', promo:'var(--orange)', system:'var(--text2)', otp:'#9c27b0'}; var chLabels = {wa:'WhatsApp', email:'Email', sms:'SMS', push:'Push'}; el.innerHTML = list.map(function(n) { return '
' + '
' + '
' + (typeIcons[n.type] || '🔔') + '
' + '
' + '
' + n.title + '
' + '
' + n.body + '
' + '
' + '
' + n.date + ' ' + n.time + '
' + n.channels.filter(function(c){return c!=='push';}).map(function(c){ return '' + (chLabels[c]||c) + ''; }).join('') + '
' + '
' + (!n.read ? '
' : '') + '
' + '
'; }).join(''); } function readNotif(id, data) { var n = NOTIFS_DB.find(function(x) { return x.id === id; }); if (n) { n.read = true; saveNotifPrefs(); } updateNotifBadge(); renderNotifList(); // Navigate based on type if (data && data.orderId) { closeNotifPanel(); showPage('orders'); } if (data && data.retId) { closeNotifPanel(); showPage('orders'); } } function markAllNotifsRead() { NOTIFS_DB.forEach(function(n) { n.read = true; }); saveNotifPrefs(); updateNotifBadge(); renderNotifList(); showToast('All notifications marked as read', 'info'); } // ── PUSH TOAST (in-app banner) ──────────────────────────────────── function showPushToast(notif) { // Use a slightly different style from the main toast showToast(notif.title + ' — ' + notif.body.substring(0,60) + (notif.body.length > 60 ? '...' : ''), 'info'); } // ════════════════════════════════════════════════════════════════ // WHATSAPP SIMULATOR // ════════════════════════════════════════════════════════════════ var WA_MSGS = []; var waChatOpen = false; var WA_BOT_REPLIES = { 'hi': 'Hello! Welcome to Hubooze Support 😊 How can I help you today?', 'hello': 'Hi there! 🎉 How can we help you?', 'order': 'I can help with your order! Please share your Order ID (e.g. ORD2501003) and I\'ll look it up.', 'return': 'For returns, you have 90 days from purchase. I\'ll initiate a free pickup for you. Which order would you like to return?', 'refund': 'Refunds are processed instantly once pickup is done. Credited to your original payment method within 24 hours.', 'delivery': 'Standard delivery takes 3-5 business days. Express (1-2 days) and Same-day options are also available at checkout.', 'cancel': 'To cancel an order, go to My Orders and click Cancel. Orders can be cancelled until they are shipped.', 'track': 'You can track your order at Hubooze.in > My Orders. Live tracking will be available once shipped.', 'help': 'I can help with: orders, returns, refunds, delivery, cancellations, payments. What do you need?', 'payment': 'We accept UPI, Credit/Debit Cards, Net Banking, EMI and Cash on Delivery. All payments are secure.', 'default': 'Thank you for reaching out! Our team will respond within 1 hour. For urgent help, call 1800-XXX-XXXX (toll free).' }; function sendWaNotification(notif) { if (!NOTIF_PREFS.order_placed_wa && notif.type === 'order') return; WA_MSGS.push({ from: 'hub', text: notif.data.waMsg || formatWaMsg(notif), time: notif.time }); // If chat is open, refresh if (waChatOpen) renderWaMsgs(); } function formatWaMsg(notif) { return '*Hubooze* 🛒\n' + notif.title + '\n\n' + notif.body + (notif.data.orderId ? '\n\n📩 Order: #' + notif.data.orderId : '') + '\n\n_Reply HELP for support_'; } function openWaChat() { waChatOpen = true; document.getElementById('waChatOverlay').className = 'wa-chat-overlay open'; if (!WA_MSGS.length) { WA_MSGS.push({ from: 'hub', text: 'Hello ' + (currentUser ? currentUser.name.split(' ')[0] : '') + '! 👋\nWelcome to Hubooze WhatsApp Support.\n\nReply with:\n📩 *ORDER* — Track order\n🔄 *RETURN* — Initiate return\n💰 *REFUND* — Refund status\n❓ *HELP* — All options', time: new Date().toLocaleTimeString('en-IN', {hour:'2-digit', minute:'2-digit'}) }); } renderWaMsgs(); } function closeWaChat() { waChatOpen = false; document.getElementById('waChatOverlay').className = 'wa-chat-overlay'; } function renderWaMsgs() { var el = document.getElementById('waMsgs'); if (!el) return; el.innerHTML = WA_MSGS.map(function(m) { return '
' + m.text.replace(/\*(.*?)\*/g, '$1').replace(/\n/g, '
') + '' + '
'; }).join(''); // Scroll to bottom el.scrollTop = el.scrollHeight; } function sendWaMsg() { var inp = document.getElementById('waInput'); if (!inp || !inp.value.trim()) return; var text = inp.value.trim(); var time = new Date().toLocaleTimeString('en-IN', {hour:'2-digit', minute:'2-digit'}); WA_MSGS.push({from:'user', text:text, time:time}); inp.value = ''; renderWaMsgs(); // Show typing indicator then bot reply var el = document.getElementById('waMsgs'); if (el) { var typing = document.createElement('div'); typing.className = 'wa-typing'; typing.innerHTML = ''; el.appendChild(typing); el.scrollTop = el.scrollHeight; } setTimeout(function() { var lower = text.toLowerCase(); var reply = WA_BOT_REPLIES.default; Object.keys(WA_BOT_REPLIES).forEach(function(key) { if (lower.includes(key)) reply = WA_BOT_REPLIES[key]; }); // Remove typing indicator var t = document.querySelector('.wa-typing'); if (t) t.remove(); WA_MSGS.push({ from: 'hub', text: reply, time: new Date().toLocaleTimeString('en-IN', {hour:'2-digit', minute:'2-digit'}) }); renderWaMsgs(); }, 1200 + Math.random() * 800); } // ════════════════════════════════════════════════════════════════ // EMAIL SIMULATOR // ════════════════════════════════════════════════════════════════ function queueEmailNotification(notif) { // Store for viewing — show preview badge var el = document.getElementById('emailPreviewBadge'); if (el) { el.style.display = 'flex'; el.textContent = '1'; } } function showEmail(notif) { var overlay = document.getElementById('emailOverlay'); if (!overlay) return; var templates = { order: buildOrderEmail(notif), return: buildReturnEmail(notif), promo: buildPromoEmail(notif), system: buildSystemEmail(notif), }; var html = templates[notif.type] || templates.system; document.getElementById('emailContent').innerHTML = '
' + '' + '' + '' + '' + '
' + '
' + html + '
'; overlay.className = 'email-overlay open'; } function closeEmail() { document.getElementById('emailOverlay').className = 'email-overlay'; } function buildOrderEmail(notif) { var o = notif.data.order || {}; return '
' + '' + '
Hubooze — Shop. Return. Recycle.
' + '
' + '
' + '

🎉 Order Confirmed!

' + '

Hi ' + (currentUser ? currentUser.name.split(' ')[0] : 'there') + ', your order has been placed successfully!

' + '
' + '
Order ID
' + '
#' + (o.id || notif.data.orderId || 'ORD' + Date.now()) + '
' + '
' + (o.items ? '
' + o.items.map(function(it){return '
' + it.icon + '
' + it.name + '
Qty: ' + it.qty + '
₹' + (it.price * it.qty).toLocaleString('en-IN') + '
';}).join('') + '
' : '') + '
' + '
' + '
🔄 90-Day Free Returns
' + '
Not satisfied? Return in any condition — free pickup, instant refund.
' + '
' + '' + '
'; } function buildReturnEmail(notif) { return '
' + '
Hubooze
' + '
Return & Refund Update
' + '
' + '
' + '

🔄 ' + notif.title + '

' + '

' + notif.body + '

' + '
' + '
What happens next?
' + '
1. Our pickup partner will contact you within 24 hours
2. Free pickup from your doorstep
3. Refund processed instantly after pickup
' + '
' + '
' + '' + '
'; } function buildPromoEmail(notif) { return '
' + '
Hubooze
' + '
' + notif.title + '
' + '
' + '
' + '
' + (notif.data.emoji || '🏷') + '
' + '

' + notif.title + '

' + '

' + notif.body + '

' + (notif.data.coupon ? '
USE COUPON CODE
' + notif.data.coupon + '
' : '') + '
' + '' + '
'; } function buildSystemEmail(notif) { return '
' + '
Hubooze
' + '
' + '
' + '

' + notif.title + '

' + '

' + notif.body + '

' + '' + '
'; } // ════════════════════════════════════════════════════════════════ // OTP LOGIN // ════════════════════════════════════════════════════════════════ var otpValue = ''; var otpGenerated = ''; var otpTimerInt = null; var otpContact = ''; var otpCallback = null; function sendOTP(contact, callback) { otpContact = contact; otpCallback = callback; // Generate 6-digit OTP otpGenerated = String(Math.floor(100000 + Math.random() * 900000)); // Show notification addNotification('otp', 'Your OTP is Ready', 'OTP: ' + otpGenerated + ' — valid for 5 minutes. Do not share.', ['wa','push'], {waMsg:'*Hubooze OTP*\n\nYour one-time password is: *' + otpGenerated + '*\n\nValid for 5 minutes.\n_Do not share this OTP with anyone._'}); // Render modal var overlay = document.getElementById('otpOverlay'); var subtitle= document.getElementById('otpSubtitle'); if (subtitle) subtitle.textContent = 'OTP sent to ' + contact + ' via WhatsApp & SMS'; // Build 6 digit inputs var inputsEl = document.getElementById('otpInputs'); if (inputsEl) { inputsEl.innerHTML = ''; for (var i = 0; i < 6; i++) { var inp = document.createElement('input'); inp.type = 'tel'; inp.maxLength = 1; inp.className = 'otp-digit'; inp.id = 'otp_' + i; inp.setAttribute('inputmode', 'numeric'); inp.setAttribute('pattern', '[0-9]'); (function(idx) { inp.addEventListener('input', function(e) { this.value = this.value.replace(/\D/g,'').slice(-1); if (this.value) { this.classList.add('filled'); var next = document.getElementById('otp_' + (idx + 1)); if (next) next.focus(); } else { this.classList.remove('filled'); } }); inp.addEventListener('keydown', function(e) { if (e.key === 'Backspace' && !this.value) { var prev = document.getElementById('otp_' + (idx - 1)); if (prev) { prev.value = ''; prev.classList.remove('filled'); prev.focus(); } } }); })(i); inputsEl.appendChild(inp); } } // Start timer startOTPTimer(); if (overlay) overlay.className = 'otp-overlay open'; // Auto-hint: show OTP in WA chat setTimeout(function() { openWaChat(); }, 500); } function startOTPTimer() { if (otpTimerInt) clearInterval(otpTimerInt); var secs = 30; var cntEl = document.getElementById('otpCountdown'); var timerEl = document.getElementById('otpTimerEl'); otpTimerInt = setInterval(function() { secs--; if (cntEl) cntEl.textContent = secs; if (secs <= 0) { clearInterval(otpTimerInt); if (timerEl) timerEl.innerHTML = ''; } }, 1000); } function resendOTP() { otpGenerated = String(Math.floor(100000 + Math.random() * 900000)); addNotification('otp', 'New OTP Sent', 'New OTP: ' + otpGenerated + ' — valid for 5 minutes.', ['wa','push'], {waMsg:'*Hubooze — New OTP*\n\nYour new OTP is: *' + otpGenerated + '*\n\nValid for 5 minutes.'}); // Clear inputs for (var i = 0; i < 6; i++) { var inp = document.getElementById('otp_' + i); if (inp) { inp.value = ''; inp.classList.remove('filled'); } } document.getElementById('otp_0').focus(); var timerEl = document.getElementById('otpTimerEl'); if (timerEl) timerEl.innerHTML = 'Resend OTP in 30s'; startOTPTimer(); showToast('New OTP sent to ' + otpContact, 'success'); } function verifyOTP() { var entered = ''; for (var i = 0; i < 6; i++) { var inp = document.getElementById('otp_' + i); entered += inp ? (inp.value || '') : ''; } if (entered.length < 6) { showToast('Please enter the complete 6-digit OTP', 'error'); return; } if (entered === otpGenerated) { closeOTPModal(); showToast('✓ OTP verified successfully!', 'success'); if (typeof otpCallback === 'function') otpCallback(); } else { showToast('Incorrect OTP. Please try again.', 'error'); // Shake inputs var inputsEl = document.getElementById('otpInputs'); if (inputsEl) { inputsEl.style.animation = 'none'; inputsEl.style.transform = 'translateX(10px)'; setTimeout(function() { inputsEl.style.transform = 'translateX(-10px)'; }, 80); setTimeout(function() { inputsEl.style.transform = 'translateX(0)'; }, 160); } } } function closeOTPModal() { if (otpTimerInt) clearInterval(otpTimerInt); var overlay = document.getElementById('otpOverlay'); if (overlay) overlay.className = 'otp-overlay'; } // ════════════════════════════════════════════════════════════════ // NOTIFICATION SETTINGS PAGE // ════════════════════════════════════════════════════════════════ function renderNotificationsPage() { var el = document.getElementById('notifSettingsContent'); if (!el) return; var sections = [ { title: '📩 Order Notifications', prefs: [ {key:'order_placed_wa', label:'Order Confirmed', sub:'Get WhatsApp message when order is placed', ch:'WhatsApp'}, {key:'order_placed_email', label:'Order Confirmed', sub:'Get email confirmation when order is placed', ch:'Email'}, {key:'order_shipped_wa', label:'Order Shipped', sub:'WhatsApp alert when your order is out for delivery', ch:'WhatsApp'}, {key:'order_shipped_email',label:'Order Shipped', sub:'Email when your order ships', ch:'Email'}, {key:'order_delivered_wa', label:'Order Delivered', sub:'WhatsApp when order reaches you', ch:'WhatsApp'}, {key:'order_delivered_email',label:'Order Delivered', sub:'Email delivery confirmation', ch:'Email'}, ] }, { title: '🔄 Return & Refund Notifications', prefs: [ {key:'return_initiated_wa', label:'Return Initiated', sub:'WhatsApp when return is initiated', ch:'WhatsApp'}, {key:'return_initiated_email',label:'Return Initiated', sub:'Email confirmation of return request', ch:'Email'}, {key:'return_approved_wa', label:'Refund Processed', sub:'WhatsApp when refund is credited', ch:'WhatsApp'}, {key:'return_approved_email', label:'Refund Processed', sub:'Email when refund is credited to account', ch:'Email'}, ] }, { title: '🏷 Promotions & Offers', prefs: [ {key:'promo_wa', label:'Deals & Offers', sub:'WhatsApp alerts for flash sales and coupons', ch:'WhatsApp'}, {key:'promo_email', label:'Newsletter', sub:'Weekly email digest of best deals', ch:'Email'}, ] }, { title: '🔒 Security', prefs: [ {key:'otp_wa', label:'OTP via WhatsApp', sub:'Receive login OTPs on WhatsApp', ch:'WhatsApp'}, {key:'otp_sms', label:'OTP via SMS', sub:'Receive login OTPs via SMS', ch:'SMS'}, {key:'login_alert_email',label:'Login Alert', sub:'Email when a new device logs in', ch:'Email'}, ] } ]; // Notification history section var histHtml = '
' + '
' + '

📋 Recent Notifications

' + '' + '
' + (NOTIFS_DB.length ? NOTIFS_DB.slice(0,8).map(function(n) { var typeIcons = {order:'📩',return:'🔄',promo:'🏷',system:'⚙',otp:'📱'}; return '
' + '
' + (typeIcons[n.type]||'🔔') + '
' + '
' + '
' + n.title + '
' + '
' + n.body.substring(0,80) + (n.body.length>80?'...':'') + '
' + '
' + n.date + ' ' + n.time + '
' + '
' + (n.channels.includes('email') ? '' : '') + '
'; }).join('') : '
No notifications yet
') + '
'; // Test section var testHtml = '
' + '

⚡ Test Notifications

' + '
' + '' + '' + '' + '' + '
' + '
'; var prefsHtml = sections.map(function(section) { return '
' + '

' + section.title + '

' + section.prefs.map(function(p) { var isOn = NOTIF_PREFS[p.key] !== false; return '
' + '
' + '
' + p.label + ' ' + p.ch + '
' + '

' + p.sub + '

' + '
' + '' + '
'; }).join('') + '
'; }).join(''); el.innerHTML = histHtml + testHtml + prefsHtml; } // ── TEST TRIGGERS ───────────────────────────────────────────────── function triggerTestNotif(type) { var templates = { order: { title: 'Order Confirmed! 🎉', body: 'Your order #ORD_TEST has been placed. Estimated delivery: ' + getEstimatedDelivery() + '.', channels: ['wa','email','push'], data: {orderId:'ORD_TEST', waMsg:'*Hubooze* 🛒\n\n*Order Confirmed!* 🎉\n\nOrder #ORD_TEST placed successfully.\nEstimated delivery: ' + getEstimatedDelivery() + '\n\n_Reply TRACK to track your order_', emailHtml: true} }, return: { title: 'Return Initiated 🔄', body: 'Your return for "Test Product" has been initiated. Free pickup scheduled within 24 hours.', channels: ['wa','email','push'], data: {retId:'RET_TEST', waMsg:'*Hubooze* 🔄\n\n*Return Initiated*\n\nFree pickup scheduled for tomorrow.\nRefund ₹299 will be credited after pickup.\n\n_Reply RETURN for help_', emailHtml: true} }, promo: { title: '⚡ Flash Sale — 70% OFF!', body: 'Limited time! Use code HUBOOZE for ₹100 off on orders above ₹499.', channels: ['email','push'], data: {coupon:'HUBOOZE', emoji:'⚡', emailHtml: true} } }; var t = templates[type]; if (!t) return; var notif = addNotification(type, t.title, t.body, t.channels, t.data); if (t.channels.includes('email')) setTimeout(function() { showEmail(notif); }, 300); } function triggerTestOTP() { var contact = currentUser ? (currentUser.phone || currentUser.email) : '+91 9999999999'; sendOTP(contact, function() { showToast('OTP verified! Login successful.', 'success'); }); } // ════════════════════════════════════════════════════════════════ // HOOKS INTO EXISTING EVENTS // ════════════════════════════════════════════════════════════════ // ── After login ────────────────────────────────────────────────── var _origLoginSuccess = loginSuccess; function loginSuccess(user) { _origLoginSuccess(user); // Login alert email if (NOTIF_PREFS.login_alert_email) { addNotification('system', 'New Login Detected', 'Someone logged into your Hubooze account at ' + new Date().toLocaleString('en-IN') + '. If this was you, no action needed.', ['email'], {emailHtml: true} ); } // Welcome push addNotification('system', 'Welcome back, ' + user.name.split(' ')[0] + '! 👋', 'You have ' + ORDERS_DB.filter(function(o){return o.userId===user.id;}).length + ' orders. Check your order status anytime.', ['push'], {} ); // Load saved notifications loadNotifPrefs(); updateNotifBadge(); } // ── After order placed ──────────────────────────────────────────── var _origPlaceOrderFinal = placeOrderFinal; function placeOrderFinal() { _origPlaceOrderFinal(); // Hook fires after order is added — watch for lastPlacedOrder setTimeout(function() { if (lastPlacedOrder) { var o = lastPlacedOrder; var channels = []; if (NOTIF_PREFS.order_placed_wa) channels.push('wa'); if (NOTIF_PREFS.order_placed_email) channels.push('email'); channels.push('push'); addNotification('order', 'Order Confirmed! 🎉', 'Your order #' + o.id + ' for ₹' + o.total.toLocaleString('en-IN') + ' is confirmed. Delivery by ' + (o.estimatedDelivery || '3-5 days') + '.', channels, { orderId: o.id, order: o, waMsg: '*Hubooze* 🛒\n\n*Order Confirmed!* 🎉\n\nOrder ID: *#' + o.id + '*\nAmount: ₹' + o.total.toLocaleString('en-IN') + '\nDelivery by: ' + (o.estimatedDelivery || '3-5 days') + '\n\n_Reply ORDER for tracking_', emailHtml: true } ); } }, 2000); } // ── After return submitted ──────────────────────────────────────── var _origSubmitReturn = submitReturn; function submitReturn() { _origSubmitReturn(); setTimeout(function() { var latest = RETURNS_DB[RETURNS_DB.length - 1]; if (latest && (Date.now() - latest.ts < 3000 || !latest.ts)) { var channels = []; if (NOTIF_PREFS.return_initiated_wa) channels.push('wa'); if (NOTIF_PREFS.return_initiated_email) channels.push('email'); channels.push('push'); addNotification('return', 'Return Initiated 🔄', 'Return for "' + latest.productName + '" initiated. Free pickup within 24 hours. Refund ₹' + latest.refundAmt.toLocaleString('en-IN') + ' after pickup.', channels, { retId: latest.id, waMsg: '*Hubooze* 🔄\n\n*Return Initiated*\n\nProduct: ' + latest.productName + '\nRefund: ₹' + latest.refundAmt.toLocaleString('en-IN') + '\nPickup: Within 24 hours\n\n_Reply RETURN to track_', emailHtml: true } ); } }, 500); } // ── After return approved (admin/seller) ────────────────────────── var _origAdminApproveReturn = adminApproveReturn; function adminApproveReturn(retId) { _origAdminApproveReturn(retId); var ret = RETURNS_DB.find(function(r){ return r.id === retId; }); if (ret) { var channels = []; if (NOTIF_PREFS.return_approved_wa) channels.push('wa'); if (NOTIF_PREFS.return_approved_email) channels.push('email'); channels.push('push'); addNotification('return', 'Refund Processed! 💸', 'Your return for "' + ret.productName + '" is approved. ₹' + ret.refundAmt.toLocaleString('en-IN') + ' refund has been initiated to your account.', channels, { retId: retId, waMsg: '*Hubooze* 💸\n\n*Refund Processed!*\n\nReturn approved for: ' + ret.productName + '\nRefund: ₹' + ret.refundAmt.toLocaleString('en-IN') + '\nCredited to: original payment method\nTimeline: Within 24 hours\n\n🎉 Thank you for shopping with Hubooze!', emailHtml: true } ); } } // ── Promo notification (daily/weekly simulation) ────────────────── function sendPromoNotification() { if (!NOTIF_PREFS.promo_email && !NOTIF_PREFS.promo_wa) return; var promos = [ {title:'Flash Sale — 70% OFF! ⚡', body:'Limited time! Electronics, fashion & more.', coupon:'SAVE10', emoji:'⚡'}, {title:'Exclusive for You 🏷', body:'Use code HUBOOZE for ₹100 off on ₹499+', coupon:'HUBOOZE', emoji:'🏷'}, {title:'Weekend Special 😊', body:'Eco products at 20% extra off. Support rural artisans!', coupon:'ECO20', emoji:'🍺'}, ]; var p = promos[Math.floor(Math.random() * promos.length)]; var channels = []; if (NOTIF_PREFS.promo_wa) channels.push('wa'); if (NOTIF_PREFS.promo_email) channels.push('email'); channels.push('push'); addNotification('promo', p.title, p.body, channels, {coupon: p.coupon, emoji: p.emoji, emailHtml: true}); } // ════════════════════════════════════════════════════════════════ // HEADER BELL INJECTION // ════════════════════════════════════════════════════════════════ function injectNotifBell() { var hdrRight = document.querySelector('.hdr-right'); if (!hdrRight || document.getElementById('notifBellEl')) return; var bell = document.createElement('button'); bell.className = 'hdr-btn notif-bell'; bell.id = 'notifBellEl'; bell.onclick = openNotifPanel; bell.innerHTML = '🔔' + ''; // Insert before cart button var cartBtn = hdrRight.querySelector('.cart-hbtn'); if (cartBtn) hdrRight.insertBefore(bell, cartBtn); else hdrRight.appendChild(bell); } // ── WA FAB → open chat ──────────────────────────────────────────── document.addEventListener('DOMContentLoaded', function() { var waFab = document.querySelector('.wa-fab'); if (waFab) waFab.onclick = openWaChat; }); // ════════════════════════════════════════════════════════════════ // PAGE: NOTIFICATIONS (settings) // ════════════════════════════════════════════════════════════════ // showPage notification dispatch handled in main showPage function // ════════════════════════════════════════════════════════════════ // INIT // ════════════════════════════════════════════════════════════════ function initNotifications() { loadNotifPrefs(); injectNotifBell(); updateNotifBadge(); // Seed a welcome notification for demo if (NOTIFS_DB.length === 0) { addNotification('promo', 'Welcome to Hubooze! 🎉', 'Get 15% off your first order with code FIRST. Shop 50,000+ products with 90-day returns.', ['push','email'], {coupon:'FIRST', emoji:'🎉', emailHtml:true} ); setTimeout(function() { addNotification('promo', '⚡ Flash Sale — Today Only!', 'Electronics at 70% off. Use code SAVE10 for an extra 10% off.', ['push'], {coupon:'SAVE10', emoji:'⚡'} ); }, 2000); } // Send a promo every 90 seconds (demo only) setInterval(sendPromoNotification, 90000); } // ── Pre-wake server on page load ──────────────────────────────── (function() { setTimeout(function() { fetch('/api/health').catch(function(){}); }, 1000); })(); // ── Secret Admin Access ─────────────────────────────────────────── var _adminClickCount = 0; var _adminClickTimer = null; function secretAdminReveal() { _adminClickCount++; clearTimeout(_adminClickTimer); _adminClickTimer = setTimeout(function() { _adminClickCount = 0; }, 800); if (_adminClickCount >= 5) { _adminClickCount = 0; var card = document.getElementById('adminPortalCard'); if (card) { card.style.display = 'flex'; card.style.flexDirection = 'column'; showToast('Admin portal unlocked', 'info'); } } } initNotifications(); // ── Restore session from API token ──────────────────────────────── (function() { var savedSession = localStorage.getItem('hb_session'); var token = localStorage.getItem('hb_token') || localStorage.getItem('token'); if (savedSession && !currentUser) { try { var u = JSON.parse(savedSession); if (u && u.id) { currentUser = u; } } catch(_) {} } // If token exists but no session, restore from API if (token && !currentUser) { fetch('/api/auth/me', {headers:{'Authorization':'Bearer '+token}}) .then(function(r){ return r.json(); }) .then(function(d){ if (d.user) { currentUser = d.user; localStorage.setItem('hb_session', JSON.stringify(d.user)); try { updateHeaderAuth(); } catch(e) {} try { renderNav(); } catch(e) {} } }).catch(function(){}); } if (token && window.api) { window.api.token = token; } // Navigate to target page after login redirect var afterLogin = localStorage.getItem('hb_after_login'); if (afterLogin) { localStorage.removeItem('hb_after_login'); // Wait for session restore to complete before navigating var navAttempts = 0; var navInterval = setInterval(function() { navAttempts++; if (currentUser || navAttempts > 20) { clearInterval(navInterval); if (currentUser) { try { showPage(afterLogin); } catch(e) {} } } }, 100); } })(); // Service Worker disabled — prevents caching issues // SW disabled // SW disabled // SW disabled // SW disabled