// FavouritesService.js - Manages favourites functionality
|
class FavouritesService {
|
constructor(apiUrl, nonce) {
|
this.apiUrl = apiUrl;
|
this.nonce = nonce;
|
this.cache = {};
|
this.eventHandlersBound = false;
|
this.initialized = false;
|
}
|
|
/**
|
* Initialize the service
|
*/
|
async init() {
|
if (this.initialized) return;
|
|
// Load cached favourites from localStorage
|
this.loadFromLocalStorage();
|
|
// Bind event handlers if not already bound
|
if (!this.eventHandlersBound) {
|
this.bindEventHandlers();
|
}
|
|
// Mark as initialized
|
this.initialized = true;
|
|
// If user is logged in, fetch favourites from server
|
if (feedSettings.currentUser) {
|
await this.fetchFavourites();
|
}
|
}
|
|
/**
|
* Load favourites from localStorage
|
*/
|
loadFromLocalStorage() {
|
try {
|
const storedCache = localStorage.getItem('userFavourites');
|
if (storedCache) {
|
this.cache = JSON.parse(storedCache);
|
} else {
|
this.cache = {};
|
localStorage.setItem('userFavourites', '{}');
|
}
|
} catch (e) {
|
console.error('Error loading favourites from localStorage', e);
|
this.cache = {};
|
localStorage.setItem('userFavourites', '{}');
|
}
|
}
|
|
/**
|
* Save favourites to localStorage
|
*/
|
saveToLocalStorage() {
|
try {
|
localStorage.setItem('userFavourites', JSON.stringify(this.cache));
|
} catch (e) {
|
console.error('Error saving favourites to localStorage', e);
|
}
|
}
|
|
/**
|
* Bind event handlers for favourites
|
*/
|
bindEventHandlers() {
|
// Listen for favourites updated events
|
document.addEventListener('favourites-updated', this.handleFavouritesUpdate.bind(this));
|
|
// Listen for document clicks to handle favourite buttons
|
document.addEventListener('click', this.handleClick.bind(this));
|
|
this.eventHandlersBound = true;
|
}
|
|
/**
|
* Handle click events for favourite buttons
|
*/
|
handleClick(event) {
|
const target = event.target.closest('button.favourite');
|
if (!target) return;
|
|
// Check if user is logged in
|
if (!feedSettings.currentUser) {
|
// Redirect to login if not logged in
|
window.location.href = feedSettings.loginUrl;
|
return;
|
}
|
|
// Get favourite data
|
const type = target.dataset.type;
|
const id = target.dataset.id;
|
const artistId = target.dataset.artist || '';
|
|
// Toggle favourite
|
const isFavourited = target.classList.contains('favourited');
|
this.toggleFavourite(type, id, !isFavourited, artistId);
|
|
// Prevent default behavior
|
event.preventDefault();
|
event.stopPropagation();
|
}
|
|
/**
|
* Handle favourites update events
|
*/
|
handleFavouritesUpdate(event) {
|
const { type, id, isFavourited } = event.detail;
|
|
// Update cache
|
this.updateCache(type, id, isFavourited);
|
|
// Update UI
|
this.updateUI(type, id, isFavourited);
|
}
|
|
/**
|
* Update UI elements for a favourite
|
*/
|
updateUI(type, id, isFavourited) {
|
// Find all matching buttons
|
const buttons = document.querySelectorAll(
|
`button.favourite[data-type="${type.replace('e_', '')}"][data-id="${id}"]`
|
);
|
|
// Update each button
|
buttons.forEach(button => {
|
button.classList.toggle('favourited', isFavourited);
|
button.innerHTML = feedSettings.icons[isFavourited ? 'heart-filled' : 'heart'];
|
button.title = isFavourited ? 'Remove from favourites' : 'Add to favourites';
|
});
|
}
|
|
/**
|
* Toggle a favourite
|
*/
|
async toggleFavourite(type, id, favourite, artistId = '') {
|
try {
|
// Prepare request data
|
const data = new FormData();
|
data.append('user_id', feedSettings.currentUser.id);
|
data.append('type', `e_${type}`);
|
data.append('target_id', id);
|
data.append('isFavourited', favourite ? '1' : '0');
|
|
// Optional artist data
|
if (artistId) {
|
data.append('artist_id', artistId);
|
}
|
|
// Make request
|
const response = await fetch(`${this.apiUrl}favourites/toggle`, {
|
method: 'POST',
|
headers: {
|
'X-WP-Nonce': this.nonce
|
},
|
body: data
|
});
|
|
if (!response.ok) {
|
throw new Error('Failed to toggle favourite');
|
}
|
|
// Update cache
|
this.updateCache(`e_${type}`, id, favourite);
|
|
// Dispatch event for other components
|
document.dispatchEvent(new CustomEvent('favourites-updated', {
|
detail: {
|
type: `e_${type}`,
|
id: id,
|
isFavourited: favourite
|
}
|
}));
|
|
return true;
|
|
} catch (error) {
|
console.error('Error toggling favourite:', error);
|
|
// Show error notification
|
if (window.jvbNotifications) {
|
window.jvbNotifications.queuePopupNotification({
|
type: 'error',
|
message: 'Failed to update favourite',
|
priority: 'medium',
|
displayDuration: 3000
|
});
|
}
|
|
return false;
|
}
|
}
|
|
/**
|
* Fetch favourites from the server
|
*/
|
async fetchFavourites() {
|
if (!feedSettings.currentUser) return;
|
|
try {
|
const userId = feedSettings.currentUser.id;
|
const queryParams = new URLSearchParams({ user_id: userId });
|
|
const response = await fetch(`${this.apiUrl}favourites/all?${queryParams.toString()}`, {
|
headers: {
|
'X-WP-Nonce': this.nonce
|
}
|
});
|
|
if (!response.ok) {
|
throw new Error(`HTTP error! status: ${response.status}`);
|
}
|
|
const data = await response.json();
|
|
if (data && data.favourites) {
|
// Convert to cache format
|
const newCache = {};
|
data.favourites.forEach(fav => {
|
newCache[`${fav.type}_${fav.target_id}`] = true;
|
});
|
|
// Update cache
|
this.cache = newCache;
|
this.saveToLocalStorage();
|
}
|
|
return this.cache;
|
|
} catch (error) {
|
console.error('Failed to load favourites:', error);
|
return this.cache;
|
}
|
}
|
|
/**
|
* Check if an item is favourited
|
*/
|
isFavourited(type, id) {
|
// Ensure type has prefix
|
if (!type.startsWith('e_')) {
|
type = `e_${type}`;
|
}
|
|
return !!this.cache[`${type}_${id}`];
|
}
|
|
/**
|
* Update the cache
|
*/
|
updateCache(type, id, isFavourited) {
|
// Ensure type has prefix
|
if (!type.startsWith('e_')) {
|
type = `e_${type}`;
|
}
|
|
// Update cache
|
if (isFavourited) {
|
this.cache[`${type}_${id}`] = true;
|
} else {
|
delete this.cache[`${type}_${id}`];
|
}
|
|
// Save to localStorage
|
this.saveToLocalStorage();
|
}
|
}
|
|
export default FavouritesService;
|