init projectmycelium

This commit is contained in:
mik-tf
2025-09-01 21:37:01 -04:00
commit b41efb0e99
319 changed files with 128160 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
(function(){
'use strict';
function showAuthenticationModal(message){
const html=`<div class="modal fade" id="authModal" tabindex="-1" aria-labelledby="authModalLabel" aria-hidden="true"><div class="modal-dialog modal-dialog-centered"><div class="modal-content"><div class="modal-header"><h5 class="modal-title" id="authModalLabel"><i class="bi bi-lock me-2"></i>Authentication Required</h5><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div><div class="modal-body text-center"><div class="mb-3"><i class="bi bi-person-circle text-primary" style="font-size: 3rem;"></i></div><p class="mb-3">${message}</p><div class="d-grid gap-2 d-md-flex justify-content-md-center"><a href="/login" class="btn btn-primary me-md-2"><i class="bi bi-box-arrow-in-right me-2"></i>Log In</a><a href="/register" class="btn btn-outline-primary"><i class="bi bi-person-plus me-2"></i>Register</a></div></div></div></div></div>`;
document.getElementById('authModal')?.remove();
document.body.insertAdjacentHTML('beforeend', html);
new bootstrap.Modal(document.getElementById('authModal')).show();
document.getElementById('authModal').addEventListener('hidden.bs.modal', function(){ this.remove(); });
}
function formatLocationDisplays(){
document.querySelectorAll('.node-location').forEach(el=>{
const loc=el.getAttribute('data-location');
if(!loc) return; const parts=loc.split(',').map(s=>s.trim());
el.textContent=(parts.length>=2 && parts[0]==='Unknown')?parts[1]:loc;
});
}
document.addEventListener('DOMContentLoaded', function(){
formatLocationDisplays();
document.querySelectorAll('.rent-product-btn').forEach(btn=>{
btn.addEventListener('click', async function(){
const id=this.dataset.productId, name=this.dataset.productName, price=this.dataset.price;
if(!confirm(`Rent "${name}" for $${price} per month?`)) return;
const orig=this.innerHTML; this.innerHTML='<i class="bi bi-hourglass-split me-1"></i>Processing...'; this.disabled=true;
try{
await window.apiJson(`/api/products/${id}/rent`, {
method:'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id:id, duration:'monthly' })
});
this.innerHTML='<i class="bi bi-check-circle me-1"></i>Rented!';
this.classList.replace('btn-success','btn-info');
if (typeof window.showToast === 'function') { window.showToast(`Successfully rented "${name}"!`, 'success'); }
else { alert(`Successfully rented "${name}"!`); }
setTimeout(()=>{window.location.href='/dashboard';},1000);
}catch(e){
if (e && e.status === 402){ this.innerHTML=orig; this.disabled=false; return; }
this.innerHTML='<i class="bi bi-exclamation-triangle me-1"></i>Error';
this.classList.replace('btn-success','btn-danger');
if (typeof window.showToast === 'function') { window.showToast(`Rental failed: ${e.message || 'Unknown error'}`, 'error'); }
else { alert(`Rental failed: ${e.message || 'Unknown error'}`); }
setTimeout(()=>{ this.innerHTML=orig; this.classList.replace('btn-danger','btn-success'); this.disabled=false;},3000);
}
});
});
document.querySelectorAll('.buy-product-btn').forEach(btn=>{
btn.addEventListener('click', async function(){
const id=this.dataset.productId, name=this.dataset.productName, price=this.dataset.price;
if(!confirm(`Purchase "${name}" for $${price}?`)) return;
const orig=this.innerHTML; this.innerHTML='<i class="bi bi-hourglass-split me-1"></i>Processing...'; this.disabled=true;
try{
await window.apiJson(`/api/products/${id}/purchase`, { method:'POST' });
this.innerHTML='<i class="bi bi-check-circle me-1"></i>Purchased!';
this.classList.replace('btn-primary','btn-info');
if (typeof window.showToast === 'function') { window.showToast(`Successfully purchased "${name}"!`, 'success'); }
else { alert(`Successfully purchased "${name}"!`); }
setTimeout(()=>{window.location.href='/dashboard';},1000);
}catch(e){
if (e && e.status === 402){ this.innerHTML=orig; this.disabled=false; return; }
this.innerHTML='<i class="bi bi-exclamation-triangle me-1"></i>Error';
this.classList.replace('btn-primary','btn-danger');
if (typeof window.showToast === 'function') { window.showToast(`Purchase failed: ${e.message || 'Unknown error'}`, 'error'); }
else { alert(`Purchase failed: ${e.message || 'Unknown error'}`); }
setTimeout(()=>{ this.innerHTML=orig; this.classList.replace('btn-danger','btn-primary'); this.disabled=false;},3000);
}
});
});
document.querySelectorAll('.add-to-cart-btn').forEach(btn=>{
btn.addEventListener('click', function(){
const id=this.dataset.productId; const orig=this.innerHTML; this.innerHTML='<i class="bi bi-hourglass-split me-1"></i>Adding...'; this.disabled=true;
window.apiJson('/api/cart/add', { method:'POST', body:{ product_id:id, quantity:1 } })
.then(()=>{
this.innerHTML='<i class="bi bi-check-circle me-1"></i>Added!';
this.classList.replace('btn-primary','btn-success');
try { if (typeof window.updateCartCount === 'function') window.updateCartCount(); } catch(_){}
try { if (typeof window.emitCartUpdated === 'function') window.emitCartUpdated(); } catch(_){}
setTimeout(()=>{ this.innerHTML=orig; this.classList.replace('btn-success','btn-primary'); this.disabled=false;},2000);
})
.catch(e=>{
if (e && e.status === 401){ showAuthenticationModal(e.message || 'Make sure to register or log in to continue'); this.innerHTML=orig; this.disabled=false; return; }
if (e && e.status === 402){ this.innerHTML=orig; this.disabled=false; return; }
console.error('Error adding to cart:',e);
this.innerHTML='<i class="bi bi-exclamation-triangle me-1"></i>Error';
this.classList.replace('btn-primary','btn-danger');
setTimeout(()=>{ this.innerHTML=orig; this.classList.replace('btn-danger','btn-primary'); this.disabled=false;},2000);
});
});
});
});
})();