Uname:Linux ip-10-0-5-176 6.8.0-1057-aws #60~22.04.1-Ubuntu SMP Wed May 27 08:16:59 UTC 2026 x86_64

403WebShell
403Webshell
Server IP : 3.111.61.48  /  Your IP : 216.73.216.67
Web Server : Apache
System : Linux ip-10-0-5-176 6.8.0-1057-aws #60~22.04.1-Ubuntu SMP Wed May 27 08:16:59 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.2.31
Disable Function : exec,passthru,shell_exec,system
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/vhost/book.gyaniguru.org/js/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhost/book.gyaniguru.org/js/main.js
/* ================================================================
   GYANI GURU - Main JavaScript
   ================================================================ */

// ---- Store State ----
const Store = {
  cart: JSON.parse(localStorage.getItem('gg_cart') || '[]'),
  wishlist: JSON.parse(localStorage.getItem('gg_wishlist') || '[]'),

  saveCart() { localStorage.setItem('gg_cart', JSON.stringify(this.cart)); },
  saveWishlist() { localStorage.setItem('gg_wishlist', JSON.stringify(this.wishlist)); },

  addToCart(book) {
    const existing = this.cart.find(i => i.id === book.id);
    if (existing) {
      existing.qty += 1;
    } else {
      this.cart.push({ ...book, qty: 1 });
    }
    this.saveCart();
    updateCartBadge();
    showToast(`"${book.title}" added to cart! 🛒`, 'cart');
  },

  removeFromCart(id) {
    this.cart = this.cart.filter(i => i.id !== id);
    this.saveCart();
    updateCartBadge();
  },

  updateQty(id, delta) {
    const item = this.cart.find(i => i.id === id);
    if (item) {
      item.qty = Math.max(1, item.qty + delta);
      this.saveCart();
    }
  },

  toggleWishlist(book) {
    const idx = this.wishlist.findIndex(i => i.id === book.id);
    if (idx >= 0) {
      this.wishlist.splice(idx, 1);
      this.saveWishlist();
      updateWishlistBadge();
      showToast(`"${book.title}" removed from wishlist`, 'remove');
      return false;
    } else {
      this.wishlist.push(book);
      this.saveWishlist();
      updateWishlistBadge();
      showToast(`"${book.title}" added to wishlist! ❤️`, 'wish');
      return true;
    }
  },

  isWishlisted(id) { return this.wishlist.some(i => i.id === id); },

  getCartTotal() {
    return this.cart.reduce((sum, i) => sum + (i.price * i.qty), 0);
  },

  getCartCount() {
    return this.cart.reduce((sum, i) => sum + i.qty, 0);
  }
};

// ---- Toast Notification ----
function showToast(message, type = 'cart') {
  let toast = document.getElementById('globalToast');
  if (!toast) {
    toast = document.createElement('div');
    toast.id = 'globalToast';
    toast.className = 'toast-custom';
    toast.innerHTML = `<span class="toast-icon"><i id="toastIcon" class="bi bi-bag-check-fill"></i></span><span class="toast-msg" id="toastMsg"></span>`;
    document.body.appendChild(toast);
  }

  const iconMap = {
    cart: 'bi-bag-check-fill',
    wish: 'bi-heart-fill',
    remove: 'bi-trash3',
    success: 'bi-check-circle-fill',
    info: 'bi-info-circle-fill'
  };

  document.getElementById('toastIcon').className = `bi ${iconMap[type] || 'bi-check-circle-fill'}`;
  document.getElementById('toastMsg').textContent = message;
  toast.classList.add('show');

  setTimeout(() => toast.classList.remove('show'), 3000);
}

// ---- Badge Updates ----
function updateCartBadge() {
  const badges = document.querySelectorAll('.cart-badge');
  const count = Store.getCartCount();
  badges.forEach(b => { b.textContent = count; b.style.display = count > 0 ? 'flex' : 'none'; });
}

function updateWishlistBadge() {
  const badges = document.querySelectorAll('.wish-badge');
  const count = Store.wishlist.length;
  badges.forEach(b => { b.textContent = count; b.style.display = count > 0 ? 'flex' : 'none'; });
}

// ---- Wishlist Button State ----
function syncWishlistButtons() {
  document.querySelectorAll('[data-book-id][data-action="wishlist"]').forEach(btn => {
    const id = parseInt(btn.dataset.bookId);
    if (Store.isWishlisted(id)) {
      btn.classList.add('active');
      btn.querySelector('i').className = 'bi bi-heart-fill';
    } else {
      btn.classList.remove('active');
      btn.querySelector('i').className = 'bi bi-heart';
    }
  });
}

// ---- Navbar Scroll Effect ----
function initNavbarScroll() {
  const navbar = document.querySelector('.navbar');
  if (!navbar) return;
  window.addEventListener('scroll', () => {
    navbar.classList.toggle('scrolled', window.scrollY > 50);
  });
}

// ---- Fade In Animation ----
function initFadeIn() {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry, i) => {
      if (entry.isIntersecting) {
        setTimeout(() => entry.target.classList.add('visible'), i * 100);
      }
    });
  }, { threshold: 0.1 });

  document.querySelectorAll('.fade-in-up').forEach(el => observer.observe(el));
}

// ---- Floating Particles ----
function initParticles() {
  const container = document.querySelector('.hero-particles');
  if (!container) return;
  for (let i = 0; i < 25; i++) {
    const p = document.createElement('div');
    p.className = 'particle';
    p.style.cssText = `
      left: ${Math.random() * 100}%;
      width: ${Math.random() * 4 + 2}px;
      height: ${Math.random() * 4 + 2}px;
      animation-duration: ${Math.random() * 15 + 8}s;
      animation-delay: ${Math.random() * 10}s;
      opacity: ${Math.random() * 0.5 + 0.2};
    `;
    container.appendChild(p);
  }
}

// ---- Price Range Slider ----
function initPriceRange() {
  const slider = document.getElementById('priceRange');
  const display = document.getElementById('priceDisplay');
  if (!slider || !display) return;
  slider.addEventListener('input', () => {
    display.textContent = `₹0 - ₹${slider.value}`;
    const pct = ((slider.value - slider.min) / (slider.max - slider.min)) * 100;
    slider.style.background = `linear-gradient(to right, var(--gerua) 0%, var(--gerua) ${pct}%, #ddd ${pct}%)`;
  });
}

// ---- Search Filter ----
function initSearch() {
  const searchInput = document.getElementById('shopSearch');
  if (!searchInput) return;
  searchInput.addEventListener('input', debounce((e) => {
    const q = e.target.value.toLowerCase();
    document.querySelectorAll('.shop-book-card').forEach(card => {
      const title = card.dataset.title?.toLowerCase() || '';
      const cat = card.dataset.category?.toLowerCase() || '';
      card.closest('.col-book').style.display = (title.includes(q) || cat.includes(q)) ? '' : 'none';
    });
  }, 300));
}

// ---- Category Filter ----
function initCategoryFilter() {
  document.querySelectorAll('.filter-cat-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      document.querySelectorAll('.filter-cat-btn').forEach(b => b.classList.remove('active'));
      btn.classList.add('active');
      const cat = btn.dataset.cat;
      document.querySelectorAll('.shop-book-card').forEach(card => {
        const cardCat = card.dataset.category?.toLowerCase();
        card.closest('.col-book').style.display = (cat === 'all' || cardCat === cat.toLowerCase()) ? '' : 'none';
      });
    });
  });
}

// ---- Sort ----
function initSort() {
  const sortSel = document.getElementById('sortSelect');
  if (!sortSel) return;
  sortSel.addEventListener('change', (e) => {
    const val = e.target.value;
    const grid = document.getElementById('booksGrid');
    if (!grid) return;
    const cols = [...grid.querySelectorAll('.col-book')];
    cols.sort((a, b) => {
      const pa = parseFloat(a.querySelector('.price-current')?.textContent.replace('₹', '') || 0);
      const pb = parseFloat(b.querySelector('.price-current')?.textContent.replace('₹', '') || 0);
      const ra = parseFloat(a.querySelector('.rating-val')?.textContent || 0);
      const rb = parseFloat(b.querySelector('.rating-val')?.textContent || 0);
      if (val === 'price-asc') return pa - pb;
      if (val === 'price-desc') return pb - pa;
      if (val === 'rating') return rb - ra;
      return 0;
    });
    cols.forEach(col => grid.appendChild(col));
  });
}

// ---- View Toggle ----
function initViewToggle() {
  const gridBtn = document.getElementById('viewGrid');
  const listBtn = document.getElementById('viewList');
  const grid = document.getElementById('booksGrid');
  if (!gridBtn || !listBtn || !grid) return;

  gridBtn.addEventListener('click', () => {
    gridBtn.classList.add('active'); listBtn.classList.remove('active');
    grid.classList.remove('list-view');
    grid.querySelectorAll('.col-book').forEach(c => {
      c.className = 'col-book col-sm-6 col-lg-4 mb-4';
    });
  });

  listBtn.addEventListener('click', () => {
    listBtn.classList.add('active'); gridBtn.classList.remove('active');
    grid.classList.add('list-view');
    grid.querySelectorAll('.col-book').forEach(c => {
      c.className = 'col-book col-12 mb-3';
    });
  });
}

// ---- Cart Page Functions ----
function renderCart() {
  const cartBody = document.getElementById('cartBody');
  const wishlistBody = document.getElementById('wishlistBody');
  if (!cartBody) return;

  if (Store.cart.length === 0) {
    cartBody.innerHTML = `
      <tr><td colspan="6">
        <div class="cart-empty">
          <i class="bi bi-cart3"></i>
          <h4>Your cart is empty</h4>
          <p>Choose a book and add it to your cart</p>
          <a href="shop.html" class="btn-saffron mt-3" style="text-decoration:none">Browse Books 🕉️</a>
        </div>
      </td></tr>`;
  } else {
    cartBody.innerHTML = Store.cart.map(item => `
      <tr>
        <td>
          <div style="display:flex;align-items:center;gap:12px;">
            <img src="${item.image || 'images/book1.png'}" class="cart-item-img" alt="${item.title}" onerror="this.src='images/book1.png'">
            <div>
              <div class="cart-item-title">${item.title}</div>
              <div class="cart-item-author">by ${item.author}</div>
            </div>
          </div>
        </td>
        <td><span class="book-category">${item.category}</span></td>
        <td><strong style="color:var(--gerua-dark)">₹${item.price}</strong></td>
        <td>
          <div class="qty-control">
            <button class="qty-btn" onclick="changeQty(${item.id}, -1)">−</button>
            <input type="number" class="qty-input" value="${item.qty}" min="1" onchange="setQty(${item.id}, this.value)">
            <button class="qty-btn" onclick="changeQty(${item.id}, 1)">+</button>
          </div>
        </td>
        <td><strong style="color:var(--text-dark)">₹${(item.price * item.qty).toLocaleString('en-IN')}</strong></td>
        <td>
          <button class="cart-remove" onclick="removeCartItem(${item.id})" title="Remove">
            <i class="bi bi-trash3"></i>
          </button>
        </td>
      </tr>`).join('');
  }

  if (wishlistBody) {
    if (Store.wishlist.length === 0) {
      wishlistBody.innerHTML = `
        <div class="wishlist-empty">
          <i class="bi bi-heart"></i>
          <h4>Your wishlist is empty</h4>
          <p>Save your favourite books to your wishlist</p>
          <a href="shop.html" class="btn-saffron mt-3" style="text-decoration:none">Browse Books 🕉️</a>
        </div>`;
    } else {
      wishlistBody.innerHTML = `<div class="row g-4">${Store.wishlist.map(item => `
        <div class="col-sm-6 col-lg-4">
          <div class="book-card">
            <button class="wishlist-btn-card active" onclick="removeWishItem(${item.id})" title="Remove from wishlist">
              <i class="bi bi-heart-fill"></i>
            </button>
            <div class="book-image-wrap">
              <img src="${item.image || 'images/book1.png'}" alt="${item.title}" onerror="this.src='images/book1.png'">
            </div>
            <div class="book-card-body">
              <div class="book-category">${item.category}</div>
              <div class="book-title">${item.title}</div>
              <div class="book-price"><span class="price-current">₹${item.price}</span></div>
              <div class="book-actions">
                <button class="btn-cart" onclick='Store.addToCart(${JSON.stringify(item).replace(/'/g, "\\'")}); renderCart();'>
                  <i class="bi bi-bag-plus"></i> Add to Cart
                </button>
              </div>
            </div>
          </div>
        </div>`).join('')}</div>`;
    }
  }

  updateOrderSummary();
}

function removeCartItem(id) {
  Store.removeFromCart(id);
  renderCart();
}

function removeWishItem(id) {
  Store.wishlist = Store.wishlist.filter(i => i.id !== id);
  Store.saveWishlist();
  updateWishlistBadge();
  renderCart();
}

function changeQty(id, delta) {
  Store.updateQty(id, delta);
  renderCart();
}

function setQty(id, val) {
  const item = Store.cart.find(i => i.id === id);
  if (item) { item.qty = Math.max(1, parseInt(val) || 1); Store.saveCart(); }
  renderCart();
}

function updateOrderSummary() {
  const subtotal = Store.getCartTotal();
  const shipping = subtotal >= 999 ? 0 : 80;
  const discount = 0;
  const total = subtotal + shipping - discount;

  const el = (id) => document.getElementById(id);
  if (el('summarySubtotal')) el('summarySubtotal').textContent = `₹${subtotal.toLocaleString('en-IN')}`;
  const shipEl = el('summaryShipping');
  if (shipEl) {
    if (shipping === 0) {
      shipEl.textContent = 'FREE';
      shipEl.style.color = '#27ae60';
    } else {
      shipEl.textContent = `₹${shipping}`;
      shipEl.style.color = 'var(--text-medium)';
    }
  }
  if (el('summaryTotal')) el('summaryTotal').textContent = `₹${total.toLocaleString('en-IN')}`;
  if (el('summaryItems')) el('summaryItems').textContent = Store.getCartCount();
}

// ---- Newsletter ----
function initNewsletter() {
  const form = document.getElementById('newsletterForm');
  if (!form) return;
  form.addEventListener('submit', (e) => {
    e.preventDefault();
    const email = form.querySelector('input').value;
    if (!email) return;
    showToast('Thank you! You have been subscribed 🙏', 'success');
    form.reset();
  });
}

// ---- Checkout ----
function initCheckout() {
  const btn = document.getElementById('checkoutBtn');
  if (!btn) return;
  btn.addEventListener('click', () => {
    if (Store.cart.length === 0) { showToast('Your cart is empty!', 'info'); return; }
    showToast('Initiating checkout process...', 'success');
    setTimeout(() => alert('Payment gateway will be integrated here! Currently in demo mode. 🙏'), 500);
  });
}

// ---- Back To Top ----
function initBackToTop() {
  const btn = document.getElementById('backToTop');
  if (!btn) return;
  window.addEventListener('scroll', () => {
    btn.style.opacity = window.scrollY > 400 ? '1' : '0';
    btn.style.pointerEvents = window.scrollY > 400 ? 'auto' : 'none';
  });
  btn.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }));
}

// ---- Utility ----
function debounce(fn, delay) {
  let timer;
  return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); };
}

// ---- Init ----
document.addEventListener('DOMContentLoaded', () => {
  initNavbarScroll();
  initFadeIn();
  initParticles();
  initPriceRange();
  initSearch();
  initCategoryFilter();
  initSort();
  initViewToggle();
  renderCart();
  initNewsletter();
  initCheckout();
  initBackToTop();
  updateCartBadge();
  updateWishlistBadge();
  syncWishlistButtons();

  // Wishlist toggle (delegated)
  document.addEventListener('click', (e) => {
    const wishBtn = e.target.closest('[data-action="wishlist"]');
    if (!wishBtn) return;
    const bookData = JSON.parse(wishBtn.dataset.book || '{}');
    const added = Store.toggleWishlist(bookData);
    wishBtn.classList.toggle('active', added);
    const icon = wishBtn.querySelector('i');
    if (icon) icon.className = added ? 'bi bi-heart-fill' : 'bi bi-heart';
  });

  // Add to cart (delegated)
  document.addEventListener('click', (e) => {
    const cartBtn = e.target.closest('[data-action="add-cart"]');
    if (!cartBtn) return;
    const bookData = JSON.parse(cartBtn.dataset.book || '{}');
    Store.addToCart(bookData);
    cartBtn.innerHTML = '<i class="bi bi-check-lg"></i> Added!';
    cartBtn.style.background = 'linear-gradient(135deg, #27ae60, #2ecc71)';
    setTimeout(() => {
      cartBtn.innerHTML = `<i class="bi bi-bag-plus"></i> Add to Cart`;
      cartBtn.style.background = '';
    }, 1800);
  });
});

Youez - 2016 - github.com/yon3zu
LinuXploit