/* Falah Shortcodes — Client Logic */ (function () { 'use strict'; const cfg = window.FalahSC || {}; // ── Prayer Times ───────────────────────────────────────────────────────── const prayerWidget = document.querySelector('.falah-prayer-times'); if (prayerWidget) { const city = prayerWidget.dataset.city || cfg.prayerCity || 'Kuala Lumpur'; const country = prayerWidget.dataset.country || cfg.prayerCountry || 'Malaysia'; const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); fetch(`https://api.aladhan.com/v1/timingsByCity/${dd}-${mm}-${yyyy}?city=${encodeURIComponent(city)}&country=${encodeURIComponent(country)}&method=3`) .then(r => r.json()) .then(data => { if (data.code !== 200) throw new Error('API error'); const t = data.data.timings; const h = data.data.date.hijri; const prayers = [ { key: 'Fajr', label: 'Fajr' }, { key: 'Sunrise', label: 'Sunrise' }, { key: 'Dhuhr', label: 'Dhuhr' }, { key: 'Asr', label: 'Asr' }, { key: 'Maghrib', label: 'Maghrib' }, { key: 'Isha', label: 'Isha' }, ]; const now = today.getHours() * 60 + today.getMinutes(); const grid = document.getElementById('falah-prayer-grid'); let nextName = '', nextTime = ''; grid.innerHTML = prayers.map(p => { const raw = t[p.key] || ''; const parts = raw.split(' ')[0].split(':'); const pMin = parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10); const isNext = !nextName && pMin > now && p.key !== 'Sunrise'; if (isNext) { nextName = p.label; nextTime = raw.split(' ')[0]; } return `
Unable to load verse. Please try again.
'; }); } // ── Dhikr Counter ──────────────────────────────────────────────────────── const dhikrWidget = document.getElementById('falah-dhikr-widget'); if (dhikrWidget) { let list = []; try { list = JSON.parse(dhikrWidget.dataset.list || '[]'); } catch (e) {} const arabicMap = { 'SubhanAllah': 'سُبْحَانَ اللَّهِ', 'Alhamdulillah': 'الْحَمْدُ لِلَّهِ', 'Allahu Akbar': 'اللَّهُ أَكْبَرُ', 'La ilaha illallah': 'لَا إِلَٰهَ إِلَّا اللَّهُ', 'Astaghfirullah': 'أَسْتَغْفِرُ اللَّهَ', }; const storageKey = 'falah_dhikr_' + new Date().toDateString(); let state = JSON.parse(localStorage.getItem(storageKey) || '{"idx":0,"counts":[0,0,0,0,0],"total":0}'); const ring = document.getElementById('falah-ring'); const numEl = document.getElementById('falah-counter-number'); const targetEl = document.getElementById('falah-counter-target'); const arabicEl = document.getElementById('falah-dhikr-arabic'); const meaningEl = document.getElementById('falah-dhikr-meaning'); const sessionEl = document.getElementById('falah-session-total'); const tapBtn = document.getElementById('falah-btn-tap'); const resetBtn = document.getElementById('falah-btn-reset'); const circumference = 2 * Math.PI * 50; // r=50 function render() { const d = list[state.idx]; const cnt = state.counts[state.idx] || 0; const tgt = d ? d.target : 33; const pct = Math.min(cnt / tgt, 1); numEl.textContent = cnt; targetEl.textContent = `/ ${tgt}`; arabicEl.textContent = (d && arabicMap[d.text]) || ''; meaningEl.textContent = (d && d.meaning) || ''; ring.style.strokeDashoffset = circumference * (1 - pct); const total = state.counts.reduce((a, b) => a + b, 0); sessionEl.textContent = total > 0 ? `Session total: ${total} counts` : ''; // Dashboard const dd = document.getElementById('falah-dash-dhikr-count'); if (dd) dd.textContent = total; } function save() { localStorage.setItem(storageKey, JSON.stringify(state)); } // Button handlers document.querySelectorAll('.falah-dhikr-btn').forEach(btn => { btn.addEventListener('click', () => { state.idx = parseInt(btn.dataset.index, 10); document.querySelectorAll('.falah-dhikr-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); save(); render(); }); }); tapBtn.addEventListener('click', () => { const d = list[state.idx]; const tgt = d ? d.target : 33; state.counts[state.idx] = (state.counts[state.idx] || 0) + 1; if (state.counts[state.idx] === tgt) { setTimeout(() => { // Flash completion numEl.style.color = '#1a7a4a'; setTimeout(() => { numEl.style.color = ''; }, 1000); }, 10); } save(); render(); }); resetBtn.addEventListener('click', () => { state.counts[state.idx] = 0; save(); render(); }); ring.style.strokeDasharray = circumference; render(); } // ── Qibla Compass ──────────────────────────────────────────────────────── const qiblaBtn = document.getElementById('falah-qibla-locate'); if (qiblaBtn) { qiblaBtn.addEventListener('click', () => { if (!navigator.geolocation) { qiblaBtn.textContent = '⚠️ Geolocation not supported'; return; } qiblaBtn.textContent = '📍 Getting location…'; qiblaBtn.disabled = true; navigator.geolocation.getCurrentPosition(pos => { const lat = pos.coords.latitude; const lon = pos.coords.longitude; const qiblaAngle = calcQibla(lat, lon); document.getElementById('falah-qibla-status').style.display = 'none'; document.getElementById('falah-qibla-display').style.display = 'block'; document.getElementById('falah-qibla-angle').textContent = `Qibla: ${Math.round(qiblaAngle)}° from North`; document.getElementById('falah-qibla-location').textContent = `Your location: ${lat.toFixed(4)}°, ${lon.toFixed(4)}°`; const needle = document.getElementById('falah-qibla-needle'); // Try device orientation if (window.DeviceOrientationEvent && typeof DeviceOrientationEvent.requestPermission === 'function') { DeviceOrientationEvent.requestPermission().then(perm => { if (perm === 'granted') listenOrientation(needle, qiblaAngle); }); } else if (window.DeviceOrientationEvent) { listenOrientation(needle, qiblaAngle); } else { needle.style.transform = `rotate(${qiblaAngle}deg)`; } }, () => { qiblaBtn.textContent = '⚠️ Location denied. Enable location access and try again.'; qiblaBtn.disabled = false; }); }); } function listenOrientation(needle, qiblaAngle) { window.addEventListener('deviceorientationabsolute', e => { const heading = e.alpha ? (360 - e.alpha) : 0; needle.style.transform = `rotate(${qiblaAngle - heading}deg)`; }, true); } function calcQibla(lat, lon) { // Kaaba coordinates const kLat = 21.3891; const kLon = 39.8579; const φ1 = lat * Math.PI / 180; const φ2 = kLat * Math.PI / 180; const Δλ = (kLon - lon) * Math.PI / 180; const y = Math.sin(Δλ) * Math.cos(φ2); const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ); const θ = Math.atan2(y, x); return ((θ * 180 / Math.PI) + 360) % 360; } // ── Dashboard ───────────────────────────────────────────────────────────── const dashDate = document.getElementById('falah-dash-date'); if (dashDate) { const opts = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; dashDate.textContent = new Date().toLocaleDateString('en-GB', opts); } // Hijri date on dashboard fetch('https://api.aladhan.com/v1/gToH?date=' + new Date().toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric' })) .then(r => r.json()) .then(data => { const h = data?.data?.hijri; if (!h) return; const dashHijri = document.getElementById('falah-dash-hijri'); if (dashHijri) dashHijri.textContent = `${h.day} ${h.month.en} ${h.year} AH`; const hijriEl = document.getElementById('falah-hijri'); if (hijriEl) hijriEl.textContent = `${h.day} ${h.month.en} ${h.year} AH`; }) .catch(() => {}); // ── Falah Wallet ────────────────────────────────────────────────────────── const walletWidget = document.getElementById('falah-wallet-widget'); if (walletWidget) { const balanceEl = document.getElementById('falah-wallet-balance'); const balanceFiat = document.getElementById('falah-wallet-balance-fiat'); const btnSend = document.getElementById('falah-wallet-btn-send'); const btnReceive = document.getElementById('falah-wallet-btn-receive'); const txList = document.getElementById('falah-wallet-tx-list'); const loginPrompt = document.getElementById('falah-wallet-login-prompt'); const sendModal = document.getElementById('falah-wallet-send-modal'); const receiveModal = document.getElementById('falah-wallet-receive-modal'); function openModal(el) { el.style.display = 'flex'; document.body.style.overflow = 'hidden'; } function closeModal(el) { el.style.display = 'none'; document.body.style.overflow = ''; } if (btnSend) btnSend.addEventListener('click', () => sendModal && openModal(sendModal)); if (btnReceive) btnReceive.addEventListener('click', () => receiveModal && openModal(receiveModal)); document.getElementById('falah-wallet-send-backdrop')?.addEventListener('click', () => closeModal(sendModal)); document.getElementById('falah-wallet-send-close')?.addEventListener('click', () => closeModal(sendModal)); document.getElementById('falah-wallet-receive-backdrop')?.addEventListener('click', () => closeModal(receiveModal)); document.getElementById('falah-wallet-receive-close')?.addEventListener('click', () => closeModal(receiveModal)); // Copy address document.getElementById('falah-wallet-copy-addr')?.addEventListener('click', function () { const addr = document.getElementById('falah-wallet-address-text')?.textContent || ''; if (!addr) return; navigator.clipboard?.writeText(addr).then(() => { this.title = 'Copied!'; setTimeout(() => { this.title = 'Copy address'; }, 1500); }); }); // Send form document.getElementById('falah-wallet-send-submit')?.addEventListener('click', function () { const to = document.getElementById('falah-wallet-send-to')?.value.trim(); const amount = parseFloat(document.getElementById('falah-wallet-send-amount')?.value); const errEl = document.getElementById('falah-wallet-send-err'); if (!to || !to.startsWith('0x') || to.length < 10) { if (errEl) errEl.textContent = 'Please enter a valid recipient address.'; return; } if (!amount || amount <= 0) { if (errEl) errEl.textContent = 'Please enter a valid amount.'; return; } if (errEl) errEl.textContent = ''; // Redirect to wallet app with prefilled params const base = (cfg.mobileUrl || 'https://falahos.my/mobile').replace(/\/$/, ''); const url = `${base}/wallet/send?to=${encodeURIComponent(to)}&amount=${encodeURIComponent(amount)}`; window.open(url, '_blank', 'noopener,noreferrer'); closeModal(sendModal); }); // Fetch wallet data from Falah Mobile REST API function fetchWalletData() { const base = (cfg.mobileUrl || 'https://falahos.my/mobile').replace(/\/$/, ''); fetch(`${base}/api/wallet/balance`, { credentials: 'include', headers: { 'X-WP-Nonce': cfg.nonce || '' }, }) .then(r => { if (r.status === 401 || r.status === 403) throw new Error('unauthenticated'); if (!r.ok) throw new Error('api_error'); return r.json(); }) .then(data => { if (balanceEl) balanceEl.textContent = (data.balance || '0') + ' ' + (data.currency || 'FLH'); if (balanceFiat && data.fiat_value) balanceFiat.textContent = '≈ ' + data.fiat_value; if (btnSend) btnSend.disabled = false; if (btnReceive) btnReceive.disabled = false; // Render receive address + QR if (data.address) { const addrEl = document.getElementById('falah-wallet-address-text'); if (addrEl) addrEl.textContent = data.address; const qrInner = document.getElementById('falah-wallet-qr-inner'); if (qrInner) { const img = document.createElement('img'); img.alt = 'Wallet QR Code'; img.src = `https://api.qrserver.com/v1/create-qr-code/?data=${encodeURIComponent(data.address)}&size=160x160&margin=4`; img.width = 160; img.height = 160; qrInner.innerHTML = ''; qrInner.appendChild(img); } } return fetch(`${base}/api/wallet/transactions?limit=5`, { credentials: 'include', headers: { 'X-WP-Nonce': cfg.nonce || '' }, }); }) .then(r => r && r.ok ? r.json() : null) .then(data => { if (!txList || !data) return; const items = Array.isArray(data.transactions) ? data.transactions : []; txList.innerHTML = ''; if (!items.length) { txList.innerHTML = '