const SKIN_CACHE_KEY = 'cachedSkins'; const SELECTED_SKINS_CACHE_KEY = 'cachedSelectedSkins'; const SKIN_CACHE_TIMESTAMP_KEY = 'skinCacheTimestamp'; const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours in milliseconds let loadSkinsDebounceTimer; function loadSkinOptions() { if (!currentUser) { displayNoSkinsMessage("Please sign in to view and select skins."); return; } clearTimeout(loadSkinsDebounceTimer); loadSkinsDebounceTimer = setTimeout(() => { const cachedSkins = localStorage.getItem(SKIN_CACHE_KEY); const cachedSelectedSkins = localStorage.getItem(SELECTED_SKINS_CACHE_KEY); const cacheTimestamp = localStorage.getItem(SKIN_CACHE_TIMESTAMP_KEY); const currentTime = Date.now(); if (cachedSkins && cachedSelectedSkins && cacheTimestamp && (currentTime - parseInt(cacheTimestamp) < CACHE_DURATION)) { console.log('Using cached skins and selected skins'); displayUnlockedSkins(JSON.parse(cachedSkins), JSON.parse(cachedSelectedSkins)); } else { fetchAndCacheSkins(); } }, 300); } function fetchAndCacheSkins() { const skinCustomization = document.getElementById('skinCustomization'); // if (skinCustomization) { // skinCustomization.innerHTML = '
Loading skins...
'; // } const cachedEtag = localStorage.getItem('skinCacheEtag'); const headers = { 'Content-Type': 'application/json', }; if (cachedEtag) { headers['If-None-Match'] = cachedEtag; } Promise.all([ fetch('/get-unlocked-skins', { method: 'POST', headers: headers, body: JSON.stringify({ username: currentUser }), }), fetch('/get-player-skin', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: currentUser }), }) ]) .then(([unlockedResponse, selectedResponse]) => { return Promise.all([ handleUnlockedSkinsResponse(unlockedResponse), handleSelectedSkinsResponse(selectedResponse) ]); }) .then(([unlockedSkins, selectedSkins]) => { displayUnlockedSkins(unlockedSkins, selectedSkins); }) .catch(error => { console.error('Error loading skin options:', error); displayNoSkinsMessage("An error occurred while loading skins. Please try again later."); }); } function handleUnlockedSkinsResponse(response) { if (response.status === 304) { console.log('Server returned 304 for unlocked skins, using cached data'); return JSON.parse(localStorage.getItem(SKIN_CACHE_KEY)); } if (!response.ok) { throw new Error('Network response was not ok for unlocked skins'); } const newEtag = response.headers.get('ETag'); if (newEtag) { localStorage.setItem('skinCacheEtag', newEtag); } return response.json().then(data => { localStorage.setItem(SKIN_CACHE_KEY, JSON.stringify(data.skins)); localStorage.setItem(SKIN_CACHE_TIMESTAMP_KEY, Date.now().toString()); return data.skins; }); } function handleSelectedSkinsResponse(response) { if (!response.ok) { throw new Error('Network response was not ok for selected skins'); } return response.json().then(data => { localStorage.setItem(SELECTED_SKINS_CACHE_KEY, JSON.stringify(data)); return data; }); } function selectSkin(skinType, skinId, element) { if (!currentUser) { console.log('No user logged in'); return; } fetch(`/select-skin`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: currentUser, skin_type: skinType, skin_id: skinId }), }) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { if (data.success) { console.log('Skin selected successfully'); // Remove 'selected' class from all skin options of the same type const options = document.querySelectorAll(`#${skinType}Options .skin-option`); options.forEach(option => option.classList.remove('selected')); // Add 'selected' class to the clicked element element.classList.add('selected'); // Update the local cache updateLocalSelectedSkinCache(skinType, { name: element.getAttribute('title').split(' (')[0], value: skinType === 'color' ? element.style.backgroundColor : element.style.backgroundImage, effect: element.classList.contains('glow-effect') ? 'glow' : null }); loadPlayerSkin(currentUser); } else { console.error('Failed to select skin:', data.error); } }) .catch(error => { console.error('Error selecting skin:', error); }); } function updateLocalSelectedSkinCache(skinType, skinData) { const cachedSelectedSkins = JSON.parse(localStorage.getItem(SELECTED_SKINS_CACHE_KEY) || '{}'); cachedSelectedSkins[skinType] = skinData; localStorage.setItem(SELECTED_SKINS_CACHE_KEY, JSON.stringify(cachedSelectedSkins)); } function updateSkinCache(skinType, skinId) { const cachedSkins = JSON.parse(localStorage.getItem(SKIN_CACHE_KEY) || '[]'); const updatedSkins = cachedSkins.map(skin => { if (skin.type === skinType) { return { ...skin, id: skinId }; } return skin; }); localStorage.setItem(SKIN_CACHE_KEY, JSON.stringify(updatedSkins)); } function displayUnlockedSkins(skins, selectedSkins) { const skinCustomization = document.getElementById('skinCustomization'); if (!skinCustomization) { console.error('skinCustomization element not found'); return; } // Create a document fragment to build the new content const fragment = document.createDocumentFragment(); const colorSelector = document.createElement('div'); colorSelector.id = 'colorSelector'; colorSelector.className = 'skin-section'; colorSelector.innerHTML = '

Colors

'; fragment.appendChild(colorSelector); const hatSelector = document.createElement('div'); hatSelector.id = 'hatSelector'; hatSelector.className = 'skin-section'; hatSelector.innerHTML = '

Hats

'; fragment.appendChild(hatSelector); // Append the fragment to skinCustomization skinCustomization.innerHTML = ''; skinCustomization.appendChild(fragment); const colorOptions = document.getElementById('colorOptions'); const hatOptions = document.getElementById('hatOptions'); let hasColors = false; let hasHats = false; skins.forEach(skin => { const optionElement = document.createElement('div'); optionElement.classList.add('skin-option'); optionElement.setAttribute('data-skin-id', skin.id); optionElement.setAttribute('title', `${skin.name} (${skin.rarity})`); if (selectedSkins[skin.type] && selectedSkins[skin.type].name === skin.name) { optionElement.classList.add('selected'); } switch (skin.type) { case 'color': optionElement.style.backgroundColor = skin.value; if (skin.effect === 'glow') { optionElement.classList.add('glow-effect'); } colorOptions.appendChild(optionElement); hasColors = true; break; case 'hat': optionElement.style.backgroundImage = `url(${skin.value})`; hatOptions.appendChild(optionElement); hasHats = true; break; } optionElement.addEventListener('click', () => selectSkin(skin.type, skin.id, optionElement)); }); if (selectedSkins.color && !hasColors) { const defaultColorElement = document.createElement('div'); defaultColorElement.classList.add('skin-option', 'selected'); defaultColorElement.style.backgroundColor = selectedSkins.color.value; defaultColorElement.setAttribute('title', selectedSkins.color.name); colorOptions.appendChild(defaultColorElement); hasColors = true; } if (!hasColors) colorOptions.innerHTML = '

No colors unlocked yet

'; if (!hasHats) hatOptions.innerHTML = '

No hats unlocked yet

'; // Fade in the skin sections setTimeout(() => { document.getElementById('colorSelector').classList.add('loaded'); document.getElementById('hatSelector').classList.add('loaded'); }, 50); if (!hasColors && !hasHats) { displayNoSkinsMessage("You haven't unlocked any skins yet. Keep playing to earn skins!"); } } function displayNoSkinsMessage(message) { const skinCustomization = document.getElementById('skinCustomization'); if (skinCustomization) { skinCustomization.innerHTML = `

${message}

`; } else { console.error('skinCustomization element not found'); } } // Call this function when the customization tab is opened function onCustomizationTabOpen() { loadSkinOptions(); }