NeatGate Floristry Academy

Courses Catalog

Search, filter, and save favorites. Open quick details in a modal and add to cart instantly.

0 courses found Favorites: 0 Cart items: 0

Sign In

Create Account

Theme

Syllabus

    Price
    Starts in

    Favorites

    Saved locally on this device.

    Notice

    Something went wrong.

    } function b1u6c(){ const form = v0a9n('#filtersForm'); form.addEventListener('submit', (e)=>{ e.preventDefault(); i5l0h(); }); v0a9n('#resetFilters').addEventListener('click', ()=>{ form.reset(); v0a9n('#sortBy').value = 'relevance'; v0a9n('#minRating').value = ''; state.page = 1; i5l0h(); }); v0a9n('#q').addEventListener('input', ()=>{ clearTimeout(b1u6c._t); b1u6c._t = setTimeout(()=> i5l0h(), 180); }); ['#level','#format','#minPrice','#maxPrice','#maxDuration','#minRating','#sortBy'].forEach(sel=>{ v0a9n(sel).addEventListener('change', ()=> i5l0h()); }); v0a9n('#tq6b1').addEventListener('click', z1h6f); v0a9n('#h1p7x').addEventListener('click', ()=>{ x2z1n(); v0a9n('#favModal').showModal(); }); v0a9n('#c3n8v').addEventListener('click', ()=>{ l8n0q(); v0a9n('#cartModal').showModal(); }); v0a9n('#s4k2r').addEventListener('click', ()=>{ state.mode = (state.mode === 'favorites') ? 'all' : 'favorites'; i5l0h(); }); v0a9n('#g6j1q').addEventListener('click', ()=>{ state.mode = (state.mode === 'cart') ? 'all' : 'cart'; i5l0h(); }); v0a9n('#y8s0a').addEventListener('click', ()=>{ const ok = confirm('Clear favorites and cart on this device?'); if(!ok) return; state.favorites = []; state.cart = []; p4b7x('favorites', []); p4b7x('cart', []); q9f2a(); i5l0h(); }); v0a9n('#fclr1').addEventListener('click', ()=>{ const ok = confirm('Clear favorites?'); if(!ok) return; state.favorites = []; p4b7x('favorites', []); q9f2a(); x2z1n(); if(state.mode === 'favorites') i5l0h(); }); v0a9n('#cclr1').addEventListener('click', ()=>{ const ok = confirm('Clear cart?'); if(!ok) return; state.cart = []; p4b7x('cart', []); q9f2a(); l8n0q(); if(state.mode === 'cart') i5l0h(); }); v0a9n('#goCheckout').addEventListener('click', ()=>{ v0a9n('#ckName').focus(); }); v0a9n('#submitCheckout').addEventListener('click', ()=>{ const name = (v0a9n('#ckName').value || '').trim(); const email = (v0a9n('#ckEmail').value || '').trim(); const phone = (v0a9n('#ckPhone').value || '').trim(); const note = (v0a9n('#ckNote').value || '').trim(); const showErr = (id, msg) => { const el = v0a9n(id); if(!msg){ el.classList.add('hidden'); el.textContent = ''; }else{ el.classList.remove('hidden'); el.textContent = msg; } }; const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(email); const phoneOk = /^\+?[0-9\s().-]{10,}$/.test(phone); const nameOk = name.length >= 2; showErr('#errName', nameOk ? '' : 'Please enter your name.'); showErr('#errEmail', emailOk ? '' : 'Please enter a valid email.'); showErr('#errPhone', phoneOk ? '' : 'Please enter a valid phone number.'); const msg = v0a9n('#ckMsg'); if(!nameOk || !emailOk || !phoneOk){ msg.textContent = 'Fix the highlighted fields to continue.'; msg.className = 'text-sm text-red-600 dark:text-red-400'; return; } if(state.cart.length === 0){ msg.textContent = 'Your cart is empty. Add a course first.'; msg.className = 'text-sm text-red-600 dark:text-red-400'; return; } const payload = { name, email, phone, note, items: state.cart.map(ci=>{ const it = state.all.find(x=>x.id===ci.id); return { id: ci.id, title: it?.title || '', qty: ci.qty || 1, price: it?.price || 0, currency: it?.currency || 'USD' }; }), createdAt: new Date().toISOString() }; localStorage.setItem('lastCheckoutRequest', JSON.stringify(payload)); msg.textContent = 'Request submitted. We’ll contact you shortly to confirm details.'; msg.className = 'text-sm text-emerald-700 dark:text-emerald-300'; setTimeout(()=>{ state.cart = []; p4b7x('cart', []); q9f2a(); l8n0q(); if(state.mode === 'cart') i5l0h(); }, 900); }); v0a9n('#favModal').addEventListener('close', ()=>{}); v0a9n('#cartModal').addEventListener('close', ()=>{}); } function x2z1n(){ const ul = v0a9n('#favList'); ul.innerHTML = ''; const ids = state.favorites.slice(); const items = ids.map(id=>state.all.find(x=>x.id===id)).filter(Boolean); if(items.length === 0){ const li = document.createElement('li'); li.className = 'rounded-lg border border-gray-200 bg-gray-50 p-4 text-sm text-gray-700 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-200'; li.textContent = 'No favorites yet. Save courses to compare later.'; ul.appendChild(li); return; } items.forEach(it=>{ const li = document.createElement('li'); li.className = 'rounded-lg border border-gray-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900'; li.innerHTML = `
    ${escapeHtml(it.title || '')}
    ${escapeHtml(it.level)} • ${escapeHtml(it.format)} • ${escapeHtml(String(it.durationHours))}h
    `; ul.appendChild(li); }); m9k2w('[data-fvdt]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-fvdt'); v0a9n('#favModal').close(); n7v3m(id); })); m9k2w('[data-fvcl]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-fvcl'); u4r8d(id); x2z1n(); })); } function l8n0q(){ const ul = v0a9n('#cartList'); ul.innerHTML = ''; const items = state.cart.map(ci=>{ const it = state.all.find(x=>x.id===ci.id); return it ? {it, qty: ci.qty || 1} : null; }).filter(Boolean); if(items.length === 0){ const li = document.createElement('li'); li.className = 'rounded-lg border border-gray-200 bg-gray-50 p-4 text-sm text-gray-700 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-200'; li.textContent = 'Your cart is empty. Add courses from the catalog.'; ul.appendChild(li); }else{ items.forEach(({it, qty})=>{ const sym = h8m1q(it.currency || 'USD'); const li = document.createElement('li'); li.className = 'rounded-lg border border-gray-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900'; li.innerHTML = `
    ${escapeHtml(it.title || '')}
    ${escapeHtml(it.level)} • ${escapeHtml(it.format)} • ${escapeHtml(String(it.durationHours))}h
    ${escapeHtml(sym)}${Number(it.price).toFixed(0)} each
    ${escapeHtml(String(qty))}
    `; ul.appendChild(li); }); } const subtotalByCurrency = new Map(); let totalItems = 0; items.forEach(({it, qty})=>{ totalItems += qty; const cur = it.currency || 'USD'; const prev = subtotalByCurrency.get(cur) || 0; subtotalByCurrency.set(cur, prev + Number(it.price || 0) * qty); }); v0a9n('#cartItemsCount').textContent = String(totalItems); const formatMoney = (cur, amount)=> `${h8m1q(cur)}${Math.round(amount).toFixed(0)}${cur !== 'USD' ? ' ' + cur : ''}`; let subtotalStr = '$0'; let taxStr = '$0'; let totalStr = '$0'; if(subtotalByCurrency.size === 0){ subtotalStr = '$0'; taxStr = '$0'; totalStr = '$0'; }else if(subtotalByCurrency.size === 1){ const [cur, sub] = Array.from(subtotalByCurrency.entries())[0]; const tax = sub * 0.08; const total = sub + tax; subtotalStr = formatMoney(cur, sub); taxStr = formatMoney(cur, tax); totalStr = formatMoney(cur, total); }else{ const lines = Array.from(subtotalByCurrency.entries()).map(([cur, sub])=> formatMoney(cur, sub)); subtotalStr = lines.join(' + '); taxStr = 'Calculated at checkout'; totalStr = 'Multiple currencies'; } v0a9n('#cartSubtotal').textContent = subtotalStr; v0a9n('#cartTax').textContent = taxStr; v0a9n('#cartTotal').textContent = totalStr; m9k2w('[data-cmps]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-cmps'); a2w9z(id, 1); l8n0q(); if(state.mode === 'cart') i5l0h(); })); m9k2w('[data-cmns]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-cmns'); const item = t3j7s(id); if(!item) return; if((item.qty || 1) <= 1){ d6c1p(id); }else{ a2w9z(id, -1); } l8n0q(); if(state.mode === 'cart') i5l0h(); })); m9k2w('[data-cmpr]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-cmpr'); d6c1p(id); l8n0q(); if(state.mode === 'cart') i5l0h(); })); m9k2w('[data-cmdt]').forEach(b=>b.addEventListener('click', ()=>{ const id = b.getAttribute('data-cmdt'); v0a9n('#cartModal').close(); n7v3m(id); })); } function k0d4s(){ let total = 10 * 60; const el = v0a9n('#ckTimer'); const tick = ()=>{ const min = Math.floor(total / 60); const sec = total % 60; el.textContent = `Offer expires in ${String(min).padStart(2,'0')}:${String(sec).padStart(2,'0')}`; if(total <= 0){ el.textContent = 'Offer ended'; el.className = 'rounded-full bg-zinc-200 px-3 py-1 text-xs font-semibold text-zinc-900 dark:bg-zinc-800 dark:text-zinc-100'; clearInterval(k0d4s._i); return; } total -= 1; }; clearInterval(k0d4s._i); tick(); k0d4s._i = setInterval(tick, 1000); } async function loadCatalog(){ let data; try{ const res = await fetch('./catalog.json', {cache:'no-store'}); if(!res.ok) throw new Error('Failed to load catalog.json'); data = await res.json(); }catch(e){ data = []; } state.all = Array.isArray(data) ? data.filter(x=>x && x.id) : []; state.filtered = state.all.slice(); const dedupe = (arr)=> Array.from(new Set(arr.map(String))); state.favorites = dedupe(state.favorites).filter(id=> state.all.some(x=>x.id===id)); state.cart = state.cart .map(x=>({id:String(x.id||''), qty: Math.max(1, Number(x.qty||1))})) .filter(x=> state.all.some(it=>it.id===x.id)); p4b7x('favorites', state.favorites); p4b7x('cart', state.cart); q9f2a(); y3e8o(); i5l0h(); } document.addEventListener('keydown', (e)=>{ if((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k'){ e.preventDefault(); v0a9n('#q')?.focus(); } }); (async function init(){ await loadPartials(); s6v8e(); b1u6c(); k0d4s(); await loadCatalog(); })(); })();