Lumi Studio Tahiti

Choisir un thème

Connexion / Inscription

Astuce: cette démonstration est locale, aucune donnée n’est envoyée. oxarion.pro

oxarion.pro
Offre limitée: -10% sur les réservations en ligne. Se termine dans --:--:--

Catalogue

Détails de l’offre

-10% sur le montant total pour toute réservation effectuée en ligne avant la fin du compte à rebours.

  • Applicable sur les nouvelles réservations.
  • Non cumulable avec d’autres promotions.
  • Annulation gratuite 24h avant la séance.

Politique de cookies

Nous utilisons des cookies pour améliorer votre expérience, analyser le trafic et mémoriser vos préférences. Vous pouvez modifier votre choix à tout moment.

Les cookies nécessaires sont requis pour le fonctionnement du site (panier, favoris, thème). Les cookies analytiques sont optionnels.

'; document.querySelector('footer').outerHTML = ''; } const t = localStorage.getItem('theme') || 'light'; setTheme(t); } function getFavorites(){ try { return JSON.parse(localStorage.getItem('favorites')||'[]'); } catch { return []; } } function setFavorites(arr){ localStorage.setItem('favorites', JSON.stringify(arr)); } function inFavorites(id){ return getFavorites().includes(id); } function getCart(){ try { return JSON.parse(localStorage.getItem('cart')||'{}'); } catch { return {}; } } function setCart(obj){ localStorage.setItem('cart', JSON.stringify(obj)); } function showGridSkeleton(){ const grid = document.getElementById('grid'); grid.innerHTML = ''; for(let i=0;i
`; grid.appendChild(li); } } function render(items){ const grid = document.getElementById('grid'); const noRes = document.getElementById('noResults'); grid.innerHTML = ''; const start = (page-1)*PER_PAGE; const paginated = items.slice(start, start+PER_PAGE); if(paginated.length===0){ noRes.classList.remove('hidden'); } else { noRes.classList.add('hidden'); } for(const it of paginated){ const available = it.stock>0; const li = document.createElement('li'); li.innerHTML = `
${it.title}
${available?'Disponible':'Complet'}

${it.title}

${it.description}

${Number(it.price_xpf||0).toLocaleString('fr-PF')} XPF
${Number(it.rating||0).toFixed(1)}
`; grid.appendChild(li); } } function renderPagination(total){ const p = document.getElementById('pagination'); const pages = Math.ceil(total / PER_PAGE) || 1; p.innerHTML = ''; if(pages<=1) return; const prev = document.createElement('button'); prev.textContent = '‹'; prev.className = 'w-10 h-10 rounded-full border hover:bg-zinc-50 '+(page===1?'opacity-40 cursor-not-allowed':''); prev.disabled = page===1; prev.addEventListener('click',()=>{ if(page>1){ page--; apply(); window.scrollTo({top:0, behavior:'smooth'});} }); p.appendChild(prev); for(let i=1;i<=pages;i++){ const b = document.createElement('button'); b.textContent = i; b.className = 'w-10 h-10 rounded-full border ' + (i===page?'bg-zinc-900 text-white border-zinc-900':'hover:bg-zinc-50'); b.addEventListener('click',()=>{ page=i; apply(); window.scrollTo({top:0, behavior:'smooth'}); }); p.appendChild(b); } const next = document.createElement('button'); next.textContent = '›'; next.className = 'w-10 h-10 rounded-full border hover:bg-zinc-50 '+(page===pages?'opacity-40 cursor-not-allowed':''); next.disabled = page===pages; next.addEventListener('click',()=>{ if(page5){ msg = 'La note minimale doit être comprise entre 0 et 5.'; } if(msg){ err.textContent = msg; err.classList.remove('hidden'); return false; } else { err.classList.add('hidden'); return true; } } function apply(){ if(!validateFilters()) return; const q = document.getElementById('q').value.trim().toLowerCase(); const cat = document.getElementById('category').value; const min = parseInt(document.getElementById('min').value||'0',10); const max = parseInt(document.getElementById('max').value||'0',10); const rating = parseFloat(document.getElementById('rating').value||'0'); const sort = document.getElementById('sort').value; let items = DATA.filter(it=>{ if(cat && it.category!==cat) return false; if(min && Number(it.price_xpf) < min) return false; if(max && Number(it.price_xpf) > max) return false; if(rating && Number(it.rating) < rating) return false; if(q){ const blob = (String(it.title||'')+' '+String(it.description||'')+' '+(Array.isArray(it.tags)?it.tags.join(' '):'')).toLowerCase(); if(!blob.includes(q)) return false; } return true; }); if(sort==='price_asc') items.sort((a,b)=>a.price_xpf-b.price_xpf); if(sort==='price_desc') items.sort((a,b)=>b.price_xpf-a.price_xpf); if(sort==='rating_desc') items.sort((a,b)=>b.rating-a.rating); FILTERED_CACHE = items; render(items); renderPagination(items.length); setTimeout(()=>{ document.querySelectorAll('[data-fav]').forEach(btn=>{ btn.addEventListener('click', ()=>{ const id = btn.getAttribute('data-fav'); const favs = getFavorites(); const idx = favs.indexOf(id); if(idx>-1) favs.splice(idx,1); else favs.push(id); setFavorites(favs); apply(); }); }); document.querySelectorAll('[data-open]').forEach(btn=>{ btn.addEventListener('click', ()=>{ const id = btn.getAttribute('data-open'); const it = DATA.find(x=>x.id===id); if(!it) return; const dlg = document.getElementById('productModal'); document.getElementById('pmTitle').textContent = it.title; document.getElementById('pmImg').src = (it.images && it.images[0]) ? it.images[0] : it.thumbnail; document.getElementById('pmImg').alt = it.title; document.getElementById('pmDesc').textContent = it.description; const meta = [ `Catégorie: ${it.category}`, `Durée: ${it.duration_min} min`, `Prix: ${Number(it.price_xpf||0).toLocaleString('fr-PF')} XPF`, `Note: ${Number(it.rating||0).toFixed(1)}/5`, `Disponibilité: ${it.stock>0?'Oui':'Non'}` ].join(' • '); document.getElementById('pmMeta').textContent = meta; const favBtn = document.getElementById('pmFav'); favBtn.textContent = inFavorites(it.id) ? 'Retirer des suivis' : 'Ajouter aux suivis'; favBtn.onclick = ()=>{ const favs = getFavorites(); const idx = favs.indexOf(it.id); if(idx>-1) favs.splice(idx,1); else favs.push(it.id); setFavorites(favs); apply(); const f2 = getFavorites(); document.getElementById('pmFav').textContent = f2.includes(it.id) ? 'Retirer des suivis' : 'Ajouter aux suivis'; }; document.getElementById('pmCart').onclick = ()=>{ if(it.stock<=0) return; const cart = getCart(); cart[it.id] = (cart[it.id]||0) + 1; setCart(cart); toast('Ajouté au panier'); }; dlg.showModal(); }); }); document.querySelectorAll('[data-cart]').forEach(btn=>{ btn.addEventListener('click', ()=>{ const id = btn.getAttribute('data-cart'); const it = DATA.find(x=>x.id===id); if(!it || it.stock<=0) return; const cart = getCart(); cart[it.id] = (cart[it.id]||0) + 1; setCart(cart); toast('Ajouté au panier'); }); }); },0); } async function load(){ showGridSkeleton(); try{ const res = await fetch('./catalog.json', {cache:'no-store'}); if(!res.ok) throw new Error('HTTP '+res.status); DATA = await res.json(); }catch(e){ const grid = document.getElementById('grid'); grid.innerHTML = '
  • Impossible de charger le catalogue. Veuillez réessayer plus tard.
  • '; return; } if(location.hash.startsWith('#cat-')){ const pre = decodeURIComponent(location.hash.replace('#cat-','')); const sel = document.getElementById('category'); if([...sel.options].some(o=>o.value===pre)) sel.value = pre; } apply(); } function toast(msg){ let el = document.getElementById('toast'); if(!el){ el = document.createElement('div'); el.id = 'toast'; el.className = 'fixed bottom-5 left-1/2 -translate-x-1/2 z-50'; document.body.appendChild(el); } const box = document.createElement('div'); box.className = 'mb-2 px-4 py-2 bg-zinc-900 text-white rounded-full shadow'; box.textContent = msg; el.appendChild(box); setTimeout(()=>{ box.classList.add('opacity-0'); box.classList.add('transition'); box.classList.add('duration-300'); }, 1600); setTimeout(()=>{ box.remove(); }, 2000); } function startCountdown(){ const el = document.getElementById('countdown'); function endOfMonth(d){ return new Date(d.getFullYear(), d.getMonth()+1, 1, 0, 0, 0, 0).getTime()-1; } function tick(){ const now = Date.now(); const end = endOfMonth(new Date()); let diff = Math.max(0, Math.floor((end - now)/1000)); const d = Math.floor(diff/86400); diff%=86400; const h = Math.floor(diff/3600); diff%=3600; const m = Math.floor(diff/60); const s = diff%60; el.textContent = `${d}j ${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`; } tick(); setInterval(tick, 1000); } function setupCookieBanner(){ const key='cookiesConsent'; const banner = document.getElementById('cookieBanner'); const accept = document.getElementById('cookieAccept'); const decline = document.getElementById('cookieDecline'); const more = document.getElementById('cookieMore'); const val = localStorage.getItem(key); if(!val){ banner.classList.remove('hidden'); } accept.addEventListener('click', ()=>{ localStorage.setItem(key, JSON.stringify({necessary:true, analytics:true, ts:Date.now()})); banner.classList.add('hidden'); toast('Préférences enregistrées'); }); decline.addEventListener('click', ()=>{ localStorage.setItem(key, JSON.stringify({necessary:true, analytics:false, ts:Date.now()})); banner.classList.add('hidden'); toast('Préférences enregistrées'); }); more.addEventListener('click', ()=>{ document.getElementById('cookiePolicy').showModal(); }); document.querySelectorAll('[data-close-policy]').forEach(b=>b.addEventListener('click', ()=>{ document.getElementById('cookiePolicy').close(); })); } function setupThemeToggle(){ const btn = document.getElementById('themeToggle'); btn.addEventListener('click', ()=>{ const cur = localStorage.getItem('theme')||'light'; setTheme(cur==='light'?'dark':'light'); toast('Thème: '+(localStorage.getItem('theme')||'light')); }); } injectPartials().then(()=>{ load(); startCountdown(); setupCookieBanner(); setupThemeToggle(); }); document.addEventListener('input', (e)=>{ const ids = ['q','category','min','max','rating','sort']; if(ids.includes(e.target.id)){ if(debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(()=>{ page=1; apply(); }, 120); } }); document.getElementById('promoInfo').addEventListener('click', ()=>{ document.getElementById('offerModal').showModal(); }); document.querySelectorAll('[data-close-offer]').forEach(b=>b.addEventListener('click', ()=>document.getElementById('offerModal').close())); document.getElementById('pmClose').addEventListener('click', ()=>document.getElementById('productModal').close()); document.getElementById('productModal').addEventListener('click', (e)=>{ const dlg = document.getElementById('productModal'); const rect = dlg.getBoundingClientRect(); if(e.clientYrect.bottom || e.clientXrect.right){ dlg.close(); } }); document.addEventListener('keydown', (e)=>{ if(e.key==='Escape'){ const d1=document.getElementById('productModal'); const d2=document.getElementById('offerModal'); const d3=document.getElementById('cookiePolicy'); if(d1.open) d1.close(); if(d2.open) d2.close(); if(d3.open) d3.close(); } });