/* ===== FURRY AJAX LIBRARY ===== */ /* Moderne AJAX-Funktionen für kasico.de */ class FurryAjax { constructor() { this.csrfToken = this.getCSRFToken(); this.baseURL = window.location.origin; this.setupGlobalHandlers(); } // CSRF Token aus Meta-Tag oder Cookie holen getCSRFToken() { const metaTag = document.querySelector('meta[name=csrf-token]'); if (metaTag) return metaTag.getAttribute('content'); const cookie = document.cookie.match(/csrftoken=([^;]+)/); return cookie ? cookie[1] : ''; } // Globale Event-Handler einrichten setupGlobalHandlers() { // Loading States für alle AJAX-Requests document.addEventListener('furry-ajax-start', this.showLoading.bind(this)); document.addEventListener('furry-ajax-end', this.hideLoading.bind(this)); // Error Handler document.addEventListener('furry-ajax-error', this.handleError.bind(this)); } // Haupt-AJAX-Funktion async request(url, options = {}) { const defaultOptions = { method: 'GET', headers: { 'X-CSRFToken': this.csrfToken, 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin' }; const config = { ...defaultOptions, ...options }; // Loading State triggern this.triggerEvent('furry-ajax-start'); try { const response = await fetch(url, config); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const contentType = response.headers.get('content-type'); let data; if (contentType && contentType.includes('application/json')) { data = await response.json(); } else { data = await response.text(); } this.triggerEvent('furry-ajax-end'); return { success: true, data, response }; } catch (error) { this.triggerEvent('furry-ajax-error', { error }); return { success: false, error: error.message }; } } // Warenkorb-Funktionen async addToCart(productId, quantity = 1) { const result = await this.request(`/add-to-cart/${productId}/`, { method: 'POST', body: JSON.stringify({ quantity }) }); if (result.success) { this.showSuccess('Produkt wurde zum Warenkorb hinzugefügt!'); this.updateCartCount(result.data.cart_count); } else { this.showError('Fehler beim Hinzufügen zum Warenkorb'); } return result; } async updateCartItem(itemId, quantity) { const result = await this.request(`/update-cart-item/${itemId}/`, { method: 'POST', body: JSON.stringify({ quantity }) }); if (result.success) { this.updateCartTotal(result.data.total); this.showSuccess('Warenkorb aktualisiert!'); } else { this.showError('Fehler beim Aktualisieren des Warenkorbs'); } return result; } async removeFromCart(itemId) { const result = await this.request(`/remove-cart-item/${itemId}/`, { method: 'POST' }); if (result.success) { this.showSuccess('Produkt aus Warenkorb entfernt!'); this.updateCartCount(result.data.cart_count); // Element aus DOM entfernen const cartItem = document.querySelector(`[data-cart-item="${itemId}"]`); if (cartItem) { cartItem.style.animation = 'fadeOut 0.3s ease'; setTimeout(() => cartItem.remove(), 300); } } else { this.showError('Fehler beim Entfernen aus Warenkorb'); } return result; } // Wunschliste-Funktionen async addToWishlist(productId) { const result = await this.request(`/add-to-wishlist/${productId}/`, { method: 'POST' }); if (result.success) { this.showSuccess('Produkt zur Wunschliste hinzugefügt!'); this.updateWishlistCount(result.data.wishlist_count); } else { this.showError('Fehler beim Hinzufügen zur Wunschliste'); } return result; } async removeFromWishlist(productId) { const result = await this.request(`/remove-from-wishlist/${productId}/`, { method: 'POST' }); if (result.success) { this.showSuccess('Produkt aus Wunschliste entfernt!'); this.updateWishlistCount(result.data.wishlist_count); } else { this.showError('Fehler beim Entfernen aus Wunschliste'); } return result; } // Bewertungen async submitReview(productId, rating, comment) { const result = await this.request(`/submit-review/${productId}/`, { method: 'POST', body: JSON.stringify({ rating, comment }) }); if (result.success) { this.showSuccess('Bewertung erfolgreich abgegeben!'); this.updateProductRating(productId, result.data.average_rating); } else { this.showError('Fehler beim Abgeben der Bewertung'); } return result; } // Live-Suche async searchProducts(query) { const result = await this.request(`/search-products/?q=${encodeURIComponent(query)}`); if (result.success) { this.updateSearchResults(result.data.products); } return result; } // Filter-Funktionen async applyFilters(filters) { const queryString = new URLSearchParams(filters).toString(); const result = await this.request(`/filter-products/?${queryString}`); if (result.success) { this.updateProductGrid(result.data.products); this.updateFilterCounts(result.data.counts); } return result; } // Loading States showLoading(element = null) { const target = element || document.body; target.classList.add('loading'); // Loading Spinner hinzufügen const spinner = document.createElement('div'); spinner.className = 'furry-loading furry-loading-lg'; spinner.id = 'furry-loading-spinner'; target.appendChild(spinner); } hideLoading(element = null) { const target = element || document.body; target.classList.remove('loading'); // Loading Spinner entfernen const spinner = document.getElementById('furry-loading-spinner'); if (spinner) spinner.remove(); } // Benachrichtigungen showSuccess(message, duration = 3000) { this.showNotification(message, 'success', duration); } showError(message, duration = 5000) { this.showNotification(message, 'error', duration); } showWarning(message, duration = 4000) { this.showNotification(message, 'warning', duration); } showInfo(message, duration = 3000) { this.showNotification(message, 'info', duration); } showNotification(message, type = 'info', duration = 3000) { const alert = document.createElement('div'); alert.className = `furry-alert furry-alert-${type}`; alert.style.position = 'fixed'; alert.style.top = '20px'; alert.style.right = '20px'; alert.style.zIndex = '9999'; alert.style.maxWidth = '400px'; alert.style.animation = 'slideInRight 0.3s ease'; alert.innerHTML = `
${product.fursuit_type} • ${product.style}
${product.description}