shubraVeil/js/search.js
2024-12-25 13:05:50 +02:00

484 lines
16 KiB
JavaScript

// متغيرات عامة
let selectedProducts = [];
const maxCompareItems = 3;
// تهيئة صفحة البحث
document.addEventListener('DOMContentLoaded', () => {
initializeSearch();
initializeComparison();
});
// تهيئة نظام البحث
function initializeSearch() {
const searchForm = document.getElementById('advanced-search');
const filters = document.querySelectorAll('select, input');
// معالجة نموذج البحث
searchForm.addEventListener('submit', async (e) => {
e.preventDefault();
await performSearch();
});
// تحديث النتائج عند تغيير الفلاتر
filters.forEach(filter => {
filter.addEventListener('change', debounce(performSearch, 500));
});
}
// تنفيذ البحث
async function performSearch() {
const searchQuery = document.getElementById('search-query').value;
const productType = document.getElementById('product-type').value;
const minPrice = document.getElementById('min-price').value;
const maxPrice = document.getElementById('max-price').value;
const sortBy = document.getElementById('sort-by').value;
try {
const response = await fetch('/api/search.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: searchQuery,
type: productType,
minPrice,
maxPrice,
sortBy
})
});
if (!response.ok) throw new Error('فشل البحث');
const results = await response.json();
displayResults(results);
} catch (error) {
console.error('Search error:', error);
showError('حدث خطأ أثناء البحث. يرجى المحاولة مرة أخرى.');
}
}
// عرض نتائج البحث
function displayResults(results) {
const resultsContainer = document.getElementById('search-results');
if (!results.length) {
resultsContainer.innerHTML = '<div class="no-results">لم يتم العثور على نتائج</div>';
return;
}
resultsContainer.innerHTML = results.map(product => `
<div class="product-card" data-id="${product.id}">
<div class="product-image">
<img src="${product.image}" alt="${product.name}">
${product.badge ? `<span class="badge">${product.badge}</span>` : ''}
</div>
<div class="product-info">
<h3>${product.name}</h3>
<p>${product.description}</p>
<div class="product-price">${product.price} جنيه</div>
<div class="product-actions">
<button class="btn add-to-cart">أضف للسلة</button>
<button class="btn-secondary add-to-compare" onclick="toggleCompare(${product.id})">
<i class="fas fa-exchange-alt"></i>
</button>
</div>
</div>
</div>
`).join('');
}
// نظام المقارنة
function initializeComparison() {
document.getElementById('compare-btn').addEventListener('click', () => {
if (selectedProducts.length > 1) {
window.location.href = `/compare.html?products=${selectedProducts.join(',')}`;
}
});
}
// إضافة/إزالة منتج من المقارنة
function toggleCompare(productId) {
const index = selectedProducts.indexOf(productId);
if (index === -1) {
if (selectedProducts.length >= maxCompareItems) {
alert(`يمكنك مقارنة ${maxCompareItems} منتجات كحد أقصى`);
return;
}
selectedProducts.push(productId);
} else {
selectedProducts.splice(index, 1);
}
updateComparisonUI();
}
// تحديث واجهة المقارنة
function updateComparisonUI() {
const compareBtn = document.getElementById('compare-btn');
const comparisonList = document.getElementById('comparison-list');
compareBtn.disabled = selectedProducts.length < 2;
// تحديث قائمة المنتجات المحددة للمقارنة
if (selectedProducts.length > 0) {
fetchProductsDetails(selectedProducts).then(products => {
comparisonList.innerHTML = products.map(product => `
<div class="comparison-item">
<img src="${product.image}" alt="${product.name}">
<span>${product.name}</span>
<button onclick="toggleCompare(${product.id})">
<i class="fas fa-times"></i>
</button>
</div>
`).join('');
});
} else {
comparisonList.innerHTML = '<p>اختر منتجات للمقارنة</p>';
}
}
// دالة مساعدة للحد من تكرار الطلبات
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// عرض رسائل الخطأ
function showError(message) {
const resultsContainer = document.getElementById('search-results');
resultsContainer.innerHTML = `<div class="error-message">${message}</div>`;
}
// جلب تفاصيل المنتجات للمقارنة
async function fetchProductsDetails(productIds) {
try {
const response = await fetch('/api/products.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids: productIds })
});
if (!response.ok) throw new Error('فشل جلب تفاصيل المنتجات');
return await response.json();
} catch (error) {
console.error('Error fetching product details:', error);
return [];
}
}
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.querySelector('.search-input');
const searchResults = document.querySelector('.search-results');
const searchIcon = document.querySelector('.search-icon');
const voiceSearchBtn = document.querySelector('.voice-search-btn');
const categoryFilters = document.querySelectorAll('input[name="category"]');
const minPrice = document.getElementById('min-price');
const maxPrice = document.getElementById('max-price');
const sortBy = document.getElementById('sort-by');
let searchTimeout;
const debounceDelay = 300;
// تفعيل البحث عند الكتابة
searchInput.addEventListener('input', function() {
clearTimeout(searchTimeout);
if (this.value.length > 0) {
searchTimeout = setTimeout(() => {
performSearch();
searchResults.classList.add('active');
}, debounceDelay);
} else {
searchResults.classList.remove('active');
}
});
// إخفاء نتائج البحث عند النقر خارجها
document.addEventListener('click', function(e) {
if (!searchResults.contains(e.target) && !searchInput.contains(e.target)) {
searchResults.classList.remove('active');
}
});
// تفعيل البحث الصوتي
voiceSearchBtn.addEventListener('click', function() {
if ('webkitSpeechRecognition' in window) {
const recognition = new webkitSpeechRecognition();
recognition.lang = 'ar-SA';
recognition.continuous = false;
recognition.interimResults = false;
recognition.onstart = function() {
voiceSearchBtn.classList.add('listening');
};
recognition.onresult = function(event) {
const transcript = event.results[0][0].transcript;
searchInput.value = transcript;
performSearch();
searchResults.classList.add('active');
};
recognition.onerror = function(event) {
console.error('Speech recognition error:', event.error);
voiceSearchBtn.classList.remove('listening');
};
recognition.onend = function() {
voiceSearchBtn.classList.remove('listening');
};
recognition.start();
} else {
alert('عذراً، البحث الصوتي غير مدعوم في متصفحك');
}
});
// تحديث نتائج البحث عند تغيير الفلاتر
categoryFilters.forEach(filter => {
filter.addEventListener('change', performSearch);
});
minPrice.addEventListener('input', performSearch);
maxPrice.addEventListener('input', performSearch);
sortBy.addEventListener('change', performSearch);
// دالة البحث الرئيسية
function performSearch() {
const query = searchInput.value;
const selectedCategories = Array.from(categoryFilters)
.filter(checkbox => checkbox.checked)
.map(checkbox => checkbox.value);
const priceRange = {
min: minPrice.value ? parseInt(minPrice.value) : null,
max: maxPrice.value ? parseInt(maxPrice.value) : null
};
const sortValue = sortBy.value;
// محاكاة طلب API
fetchSearchResults(query, selectedCategories, priceRange, sortValue)
.then(displayResults)
.catch(error => console.error('Search error:', error));
}
// دالة جلب نتائج البحث من الخادم
async function fetchSearchResults(query, categories, priceRange, sort) {
// هنا يمكنك استبدال هذا بطلب API حقيقي
const mockResults = [
{
id: 1,
title: 'زيت اللافندر العطري',
category: 'زيوت عطرية',
price: 120,
image: 'images/products/lavender.jpg'
},
{
id: 2,
title: 'زيت الجوجوبا',
category: 'زيوت ثابتة',
price: 85,
image: 'images/products/jojoba.jpg'
}
];
return new Promise(resolve => {
setTimeout(() => resolve(mockResults), 300);
});
}
// دالة عرض نتائج البحث
function displayResults(results) {
const resultsContainer = document.querySelector('.search-results-list');
resultsContainer.innerHTML = '';
if (results.length === 0) {
resultsContainer.innerHTML = '<div class="no-results">لا توجد نتائج</div>';
return;
}
results.forEach(result => {
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
<img src="${result.image}" alt="${result.title}" class="result-image">
<div class="result-info">
<div class="result-title">${result.title}</div>
<div class="result-category">${result.category}</div>
</div>
<div class="result-price">${result.price} ر.س</div>
`;
resultItem.addEventListener('click', () => {
window.location.href = `/product/${result.id}`;
});
resultsContainer.appendChild(resultItem);
});
}
});
class ProductSearch {
constructor() {
this.searchInput = document.querySelector('.search-input');
this.searchResults = document.querySelector('.search-results');
this.filterForm = document.querySelector('.search-filters');
this.initializeSearch();
}
initializeSearch() {
// إضافة مستمعي الأحداث
this.searchInput?.addEventListener('input', debounce(() => this.handleSearch(), 300));
this.filterForm?.addEventListener('change', () => this.handleSearch());
// إضافة مستمع لإغلاق نتائج البحث عند النقر خارجها
document.addEventListener('click', (e) => {
if (!e.target.closest('.search-container')) {
this.hideResults();
}
});
}
async handleSearch() {
const query = this.searchInput?.value.trim();
if (!query) {
this.hideResults();
return;
}
try {
// جمع معايير التصفية
const filters = this.getFilters();
// إجراء البحث
const response = await fetch('/api/search.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query,
...filters
})
});
if (!response.ok) throw new Error('فشل البحث');
const results = await response.json();
this.displayResults(results);
} catch (error) {
console.error('Search error:', error);
this.showError('حدث خطأ أثناء البحث');
}
}
getFilters() {
const filters = {
category: [],
priceRange: {
min: null,
max: null
},
sortBy: 'relevance'
};
if (this.filterForm) {
// جمع الفئات المحددة
const categoryInputs = this.filterForm.querySelectorAll('input[name="category"]:checked');
filters.category = Array.from(categoryInputs).map(input => input.value);
// جمع نطاق السعر
const minPrice = this.filterForm.querySelector('#min-price')?.value;
const maxPrice = this.filterForm.querySelector('#max-price')?.value;
if (minPrice) filters.priceRange.min = parseFloat(minPrice);
if (maxPrice) filters.priceRange.max = parseFloat(maxPrice);
// جمع معيار الترتيب
filters.sortBy = this.filterForm.querySelector('#sort-by')?.value || 'relevance';
}
return filters;
}
displayResults(results) {
if (!this.searchResults) return;
if (results.length === 0) {
this.searchResults.innerHTML = `
<div class="no-results">
<i class="fas fa-search"></i>
<p>لم يتم العثور على نتائج</p>
</div>
`;
} else {
this.searchResults.innerHTML = `
<div class="results-list">
${results.map(product => `
<a href="${product.url}" class="result-item">
<img src="${product.image}" alt="${product.name}">
<div class="result-info">
<h4>${this.highlightQuery(product.name)}</h4>
<p>${this.highlightQuery(product.description)}</p>
<span class="price">${product.price} ريال</span>
</div>
</a>
`).join('')}
</div>
`;
}
this.showResults();
}
highlightQuery(text) {
if (!this.searchInput?.value.trim()) return text;
const query = this.searchInput.value.trim();
const regex = new RegExp(`(${query})`, 'gi');
return text.replace(regex, '<mark>$1</mark>');
}
showResults() {
this.searchResults?.classList.add('show');
}
hideResults() {
this.searchResults?.classList.remove('show');
}
showError(message) {
if (!this.searchResults) return;
this.searchResults.innerHTML = `
<div class="search-error">
<i class="fas fa-exclamation-circle"></i>
<p>${message}</p>
</div>
`;
this.showResults();
}
}
// دالة مساعدة للحد من تكرار استدعاء البحث
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// تهيئة نظام البحث
const productSearch = new ProductSearch();