ProductView.js

13.92 KB
08/11/2024 16:55
JS
ProductView.js
/**
 * ระบบแสดงผลสินค้า
 * รับผิดชอบการแสดงผล จัดการ และกรองสินค้าในหน้าร้าน
 */
const ProductView = {
  /**
   * อิลิเมนต์ที่ใช้ในการแสดงผล
   */
  elements: {
    productGrid: null,      // ตารางแสดงสินค้า
    categoryFilters: null,  // ตัวกรองหมวดหมู่
    searchInput: null       // ช่องค้นหา
  },

  /**
   * เริ่มต้นระบบแสดงผลสินค้า
   * @param {Object} config - ค่าตั้งต้นของระบบ
   */
  init(config = {}) {
    // กำหนดอิลิเมนต์ที่ใช้งาน
    this.elements = {
      productGrid: config.productGrid || document.getElementById('productGrid'),
      categoryFilters: config.categoryFilters || document.getElementById('categoryFilters'),
      searchInput: config.searchInput || document.getElementById('searchInput')
    };

    // ตรวจสอบอิลิเมนต์หลัก
    if (!this.elements.productGrid) {
      console.error('ไม่พบอิลิเมนต์สำหรับแสดงสินค้า');
      return;
    }

    this.setupEventListeners();
  },

  /**
   * ตั้งค่าตัวรับฟังเหตุการณ์
   */
  setupEventListeners() {
    // จัดการการค้นหา
    this.elements.searchInput?.addEventListener('input',
      Utils.debounce((e) => {
        const searchTerm = e.target.value.trim();
        this.filterProducts({
          search: searchTerm,
          category: this.currentCategory
        });
      }, 300)
    );

    // จัดการการกรองหมวดหมู่
    this.elements.categoryFilters?.addEventListener('click', (e) => {
      const button = e.target.closest('.category-filter');
      if (!button) return;

      // อัพเดทการแสดงผลปุ่ม
      this.elements.categoryFilters
        .querySelectorAll('.category-filter')
        .forEach(btn => btn.classList.remove('active'));
      button.classList.add('active');

      // กรองสินค้าตามหมวดหมู่
      this.currentCategory = button.dataset.category;
      this.filterProducts({
        category: this.currentCategory,
        search: this.elements.searchInput?.value.trim()
      });
    });

    // จัดการการเพิ่มสินค้าลงตะกร้า
    this.elements.productGrid?.addEventListener('click', (e) => {
      const button = e.target.closest('.add-to-cart-btn');
      if (!button || button.disabled) return;
      this.handleAddToCart(button);
    });
  },

  /**
   * จัดการการเพิ่มสินค้าลงตะกร้า
   * @param {HTMLElement} button - ปุ่มเพิ่มลงตะกร้า
   */
  handleAddToCart(button) {
    const productId = button.dataset.productId;
    const product = State.products.find(p => p.id === productId);
    if (product) {
      CartManager.addToCart(product);
    }
  },

  /**
   * แสดงสถานะกำลังโหลด
   */
  showLoading() {
    this.elements.productGrid.innerHTML = `
      <div class="loading-state">
        <div class="spinner"></div>
        <p>กำลังโหลดสินค้า...</p>
      </div>
    `;
  },

  /**
   * แสดงข้อผิดพลาด
   */
  showError(message) {
    this.elements.productGrid.innerHTML = `
      <div class="error-state">
        <i class="icon-alert-circle"></i>
        <h3>${message}</h3>
        <button onclick="location.reload()" class="btn btn-primary">
          ลองใหม่อีกครั้ง
        </button>
      </div>
    `;
  },

  /**
   * แสดงสถานะไม่มีสินค้า
   */
  showEmpty(message = 'ไม่พบสินค้า') {
    this.elements.productGrid.innerHTML = `
      <div class="empty-state">
        <i class="icon-package"></i>
        <h3>${message}</h3>
      </div>
    `;
  },

  /**
   * แสดงรายการสินค้า
   * @param {Array} products - รายการสินค้าที่ต้องการแสดง
   */
  renderProducts(products) {
    if (!products || products.length === 0) {
      this.showEmpty();
      return;
    }

    this.elements.productGrid.innerHTML = '';

    products.forEach(product => {
      const element = TemplateManager.create('product-card-template', {
        id: product.id,
        name: product.name,
        description: product.description,
        image: product.image,
        formattedPrice: Utils.formatCurrency(product.price),
        hasNutrition: !!product.nutrition,
        nutrition: product.nutrition,
        ingredients: product.ingredients,
        ingredientsList: product.ingredients?.join(', '),
        allergens: product.allergens,
        allergensList: product.allergens?.join(', '),
        available: product.available && product.stock > 0,
        stockClass: this.getStockClass(product),
        stockText: this.getStockText(product),
        buttonClass: this.getButtonClass(product),
        buttonText: this.getButtonText(product),
        tags: this.gettags(product)
      });

      // จัดการปุ่มเพิ่มลงตะกร้า
      const addToCartBtn = element.querySelector('.add-to-cart-btn');
      if (addToCartBtn) {
        addToCartBtn.classList.add(this.getButtonClass(product));
        if (!product.available || product.stock <= 0) {
          addToCartBtn.disabled = true;
        }
      }

      // เพิ่มแท็กสินค้า
      if (product.tags) {
        const tagsContainer = element.querySelector('.product-tags');
        if (tagsContainer) {
          tagsContainer.innerHTML = '';
          product.tags.forEach(tagId => {
            const tagInfo = State.tags[tagId];
            if (tagInfo) {
              const Tag = TemplateManager.create('product-tags-template', {
                name: tagInfo.name,
                icon: `fas ${tagInfo.icon}`,
                style: `background-color: ${tagInfo.color}`
              });
              tagsContainer.appendChild(Tag);
            }
          });
        }
      }

      this.elements.productGrid.appendChild(element);
    });
  },

  /**
   * สร้างคลาสแสดงสถานะสต็อก
   */
  getStockClass(product) {
    if (!product.available) return 'out-of-stock';
    if (product.stock <= 5) return 'low-stock';
    if (product.stock <= 20) return 'medium-stock';
    return 'in-stock';
  },

  /**
   * สร้างข้อความแสดงสถานะสต็อก
   */
  getStockText(product) {
    if (!product.available) return 'สินค้าหมด';
    if (product.stock <= 5) return `เหลือ ${product.stock} ชิ้นสุดท้าย`;
    if (product.stock <= 20) return `เหลือ ${product.stock} ชิ้น`;
    return 'มีสินค้า';
  },

  /**
   * สร้างคลาสสำหรับปุ่มเพิ่มลงตะกร้า
   */
  getButtonClass(product) {
    if (!product.available || product.stock <= 0) return 'btn btn-disabled';
    if (product.stock <= 5) return 'btn btn-warning';
    return 'add-to-cart-btn';
  },

  /**
   * สร้างข้อความสำหรับปุ่มเพิ่มลงตะกร้า
   */
  getButtonText(product) {
    if (!product.available) return 'สินค้าหมด';
    if (product.stock <= 0) return 'สินค้าหมด';
    if (product.stock <= 5) return 'สั่งซื้อด่วน';
    return 'เพิ่มลงตะกร้า';
  },

  /**
   * สร้างแท็กสำหรับสินค้า
   */
  gettags(product) {
    const tags = [];

    if (product.category) {
      const category = State.categories.find(c => c.id === product.category);
      if (category) {
        tags.push({
          name: category.name,
          icon: category.icon,
          style: 'category-Tag'
        });
      }
    }

    if (product.tags) {
      product.tags.forEach(tagId => {
        const tag = State.tags[tagId];
        if (tag) {
          tags.push({
            name: tag.name,
            icon: tag.icon,
            style: `background-color: ${tag.color}`
          });
        }
      });
    }

    return tags;
  },

  /**
   * แสดงรายการหมวดหมู่
   */
  renderCategories(categories) {
    if (!this.elements.categoryFilters) return;

    // เพิ่มหมวดหมู่ "ทั้งหมด"
    const allCategory = TemplateManager.create('category-filter-template', {
      category: 'all',
      name: 'ทั้งหมด',
      icon: 'fas fa-th-large'
    });
    allCategory.querySelector('.category-filter').classList.add('active');
    this.elements.categoryFilters.appendChild(allCategory);

    // เรียงและแสดงหมวดหมู่
    const sortedCategories = [...categories].sort((a, b) => a.order - b.order);
    sortedCategories.forEach(category => {
      const element = TemplateManager.create('category-filter-template', {
        category: category.id,
        name: category.name,
        icon: `fas ${category.icon}`
      });
      this.elements.categoryFilters.appendChild(element);
    });
  },

  /**
   * ตั้งค่าการโหลดรูปภาพแบบ lazy
   */
  setupLazyLoading() {
    const images = this.elements.productGrid.querySelectorAll('img[loading="lazy"]');
    const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          img.classList.add('loaded');
          observer.unobserve(img);
        }
      });
    });
    images.forEach(img => imageObserver.observe(img));
  },

  /**
   * แสดงรายละเอียดสินค้าแบบด่วน
   */
  showQuickView(productId) {
    const product = State.products.find(p => p.id === productId);
    if (!product) return;

    TemplateManager.showModal('product-quick-view-template', {
      id: product.id,
      name: product.name,
      description: product.description,
      image: product.image,
      formattedPrice: Utils.formatCurrency(product.price),
      stock: product.stock,
      hasNutrition: !!product.nutrition,
      ...product.nutrition,
      inStock: product.stock > 0
    });
  },

  /**
   * กรองสินค้าตามเงื่อนไข
   */
  filterProducts(filters = {}) {
    let filtered = [...State.products];

    if (filters.category && filters.category !== 'all') {
      filtered = filtered.filter(product =>
        product.category === filters.category
      );
    }

    if (filters.search) {
      const search = filters.search.toLowerCase();
      filtered = filtered.filter(product =>
        product.name.toLowerCase().includes(search) ||
        product.description.toLowerCase().includes(search) ||
        product.tags.some(tag =>
          State.tags[tag].name.toLowerCase().includes(search)
        )
      );
    }

    this.renderProducts(filtered);
  },

  /**
   * เรียงลำดับสินค้า
   */
  sortProducts(products, sortBy = 'name', order = 'asc') {
    return [...products].sort((a, b) => {
      let compareA = a[sortBy];
      let compareB = b[sortBy];

      if (sortBy === 'price') {
        compareA = parseFloat(compareA);
        compareB = parseFloat(compareB);
      }

      if (order === 'asc') {
        return compareA > compareB ? 1 : -1;
      } else {
        return compareA < compareB ? 1 : -1;
      }
    });
  },

  /**
   * อัพเดทสถานะการมีสินค้า
   */
  updateProductAvailability(productId, available, stock = 0) {
    const productElement = this.elements.productGrid
      .querySelector(`[data-id="${productId}"]`);

    if (productElement) {
      const button = productElement.querySelector('.add-to-cart-btn');
      if (button) {
        button.disabled = !available;
        button.textContent = available ? 'เพิ่มลงตะกร้า' : 'สินค้าหมด';
      }

      const stockElement = productElement.querySelector('.product-stock');
      if (stockElement) {
        stockElement.textContent = `เหลือ ${stock} ชิ้น`;
        stockElement.classList.toggle('low-stock', stock < 5);
      }
    }
  },

  /**
   * รีเฟรชข้อมูลสินค้าเฉพาะรายการ
   */
  refreshProduct(productId) {
    const product = State.products.find(p => p.id === productId);
    if (!product) return;

    const productElement = this.elements.productGrid
      .querySelector(`[data-id="${productId}"]`);
    if (productElement) {
      const newElement = TemplateManager.create('product-card-template', {
        id: product.id,
        name: product.name,
        image: product.image,
        formattedPrice: Utils.formatCurrency(product.price),
        hasNutrition: !!product.nutrition,
        ...product.nutrition,
        inStock: product.stock > 0
      });

      productElement.replaceWith(newElement);
    }
  },

  /**
   * สร้างสไตล์สำหรับแท็ก
   * @param {string} tag - ชื่อแท็ก
   * @returns {string} สไตล์ CSS สำหรับแท็ก
   */
  getTagStyle(tag) {
    const tagStyles = {
      'new': 'background-color: var(--tag-new)',
      'sale': 'background-color: var(--tag-sale)',
      'best-seller': 'background-color: var(--tag-best-seller)',
      'recommended': 'background-color: var(--tag-recommended)',
      'promotion': 'background-color: var(--tag-promotion)'
    };
    return tagStyles[tag] || '';
  }
};