diff --git a/wordpress-plugins/falah-shortcodes.zip b/wordpress-plugins/falah-shortcodes.zip index 23902bd..6cf0765 100644 Binary files a/wordpress-plugins/falah-shortcodes.zip and b/wordpress-plugins/falah-shortcodes.zip differ diff --git a/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.css b/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.css index 0994f55..1783e57 100644 --- a/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.css +++ b/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.css @@ -541,6 +541,350 @@ background: var(--f-gold-light); } +/* ── Wallet widget ────────────────────────────────────────────────────────── */ +.falah-wallet-widget .falah-widget-header { justify-content: flex-start; } +.falah-wallet-currency-badge { + margin-left: auto; + background: rgba(255,255,255,0.15); + border: 1px solid rgba(255,255,255,0.3); + border-radius: 20px; + padding: 2px 10px; + font-size: 0.72rem; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; + color: #fff; +} + +.falah-wallet-body { padding: 24px; } + +.falah-wallet-balance-card { + background: linear-gradient(135deg, var(--f-navy) 0%, var(--f-navy-mid) 100%); + border-radius: var(--f-radius); + padding: 28px 24px 24px; + color: #fff; + position: relative; + overflow: hidden; + margin-bottom: 24px; +} +.falah-wallet-balance-card::before { + content: ''; + position: absolute; + top: -30px; + right: -30px; + width: 140px; + height: 140px; + border-radius: 50%; + background: rgba(200,146,26,0.12); + pointer-events: none; +} +.falah-wallet-balance-label { + font-size: 0.75rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: rgba(255,255,255,0.55); + margin-bottom: 8px; +} +.falah-wallet-balance-amount { + font-family: var(--f-font-display); + font-size: clamp(2rem, 5vw, 3rem); + font-weight: 600; + letter-spacing: -0.02em; + line-height: 1; + margin-bottom: 6px; + min-height: 1em; +} +.falah-wallet-balance-sub { + font-size: 0.82rem; + color: rgba(255,255,255,0.45); + margin-bottom: 20px; +} +.falah-wallet-actions { + display: flex; + gap: 12px; +} +.falah-wallet-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 9px 18px; + border-radius: var(--f-radius-sm); + border: none; + cursor: pointer; + font-family: var(--f-font-body); + font-size: 0.85rem; + font-weight: 600; + transition: opacity var(--f-fast) var(--f-ease), transform var(--f-fast) var(--f-ease), box-shadow var(--f-fast) var(--f-ease); +} +.falah-wallet-btn svg { width: 15px; height: 15px; flex-shrink: 0; } +.falah-wallet-btn:disabled { opacity: 0.45; cursor: not-allowed; } +.falah-wallet-btn:not(:disabled):hover { opacity: 0.88; transform: translateY(-1px); box-shadow: var(--f-shadow-gold); } +.falah-wallet-btn-send { + background: var(--f-gold); + color: #fff; +} +.falah-wallet-btn-receive { + background: rgba(255,255,255,0.12); + color: #fff; + border: 1px solid rgba(255,255,255,0.2); +} +.falah-wallet-btn-full { width: 100%; justify-content: center; margin-top: 8px; } + +/* Loading dots */ +.falah-wallet-loading-dots { + display: inline-flex; + gap: 5px; + align-items: center; + padding: 4px 0; +} +.falah-wallet-loading-dots span { + width: 6px; + height: 6px; + border-radius: 50%; + background: rgba(255,255,255,0.6); + animation: falah-wallet-dot-pulse 1.2s ease-in-out infinite; +} +.falah-wallet-loading-dots span:nth-child(2) { animation-delay: 0.2s; } +.falah-wallet-loading-dots span:nth-child(3) { animation-delay: 0.4s; } +@keyframes falah-wallet-dot-pulse { + 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } + 40% { opacity: 1; transform: scale(1); } +} + +/* Login prompt */ +.falah-wallet-login-prompt { + text-align: center; + padding: 20px; + color: var(--f-text-muted); + font-size: 0.9rem; +} +.falah-wallet-login-link { + display: inline-block; + margin-top: 8px; + padding: 8px 20px; + background: var(--f-emerald); + color: #fff; + border-radius: var(--f-radius-sm); + text-decoration: none; + font-weight: 600; + font-size: 0.85rem; + transition: background var(--f-fast) var(--f-ease); +} +.falah-wallet-login-link:hover { background: var(--f-emerald-mid); } + +/* Transaction list */ +.falah-wallet-tx-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; +} +.falah-wallet-tx-title { + font-size: 0.78rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--f-text-muted); +} +.falah-wallet-tx-viewall { + font-size: 0.78rem; + color: var(--f-gold); + text-decoration: none; + font-weight: 600; +} +.falah-wallet-tx-viewall:hover { text-decoration: underline; } +.falah-wallet-tx-list { display: flex; flex-direction: column; gap: 2px; } +.falah-wallet-tx-item { + display: flex; + align-items: center; + gap: 12px; + padding: 11px 14px; + border-radius: var(--f-radius-sm); + transition: background var(--f-fast); +} +.falah-wallet-tx-item:hover { background: var(--f-cream); } +.falah-wallet-tx-icon { + width: 36px; + height: 36px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; + flex-shrink: 0; +} +.falah-wallet-tx-icon.sent { background: #FEE2E2; } +.falah-wallet-tx-icon.received { background: var(--f-emerald-light); } +.falah-wallet-tx-info { flex: 1; min-width: 0; } +.falah-wallet-tx-desc { + font-size: 0.88rem; + font-weight: 500; + color: var(--f-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.falah-wallet-tx-date { + font-size: 0.72rem; + color: var(--f-text-muted); + margin-top: 2px; +} +.falah-wallet-tx-amount { + font-size: 0.88rem; + font-weight: 600; + flex-shrink: 0; +} +.falah-wallet-tx-amount.sent { color: #DC2626; } +.falah-wallet-tx-amount.received { color: var(--f-emerald); } +.falah-wallet-tx-empty { + text-align: center; + padding: 20px; + color: var(--f-text-muted); + font-size: 0.85rem; +} + +/* Skeleton loader */ +.falah-wallet-tx-skeleton { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; } +.falah-wallet-tx-skel-row { + height: 44px; + border-radius: var(--f-radius-sm); + background: linear-gradient(90deg, var(--f-border) 25%, rgba(10,22,40,0.04) 50%, var(--f-border) 75%); + background-size: 200% 100%; + animation: falah-skel-shimmer 1.4s ease-in-out infinite; +} +@keyframes falah-skel-shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* Modal */ +.falah-wallet-modal { + position: fixed; + inset: 0; + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; +} +.falah-wallet-modal-backdrop { + position: absolute; + inset: 0; + background: rgba(10,22,40,0.55); + backdrop-filter: blur(4px); +} +.falah-wallet-modal-box { + position: relative; + background: var(--f-surface); + border-radius: var(--f-radius); + box-shadow: var(--f-shadow-lg); + width: 100%; + max-width: 400px; + overflow: hidden; + animation: falah-modal-in var(--f-normal) var(--f-ease); +} +@keyframes falah-modal-in { + from { opacity: 0; transform: translateY(12px) scale(0.97); } + to { opacity: 1; transform: translateY(0) scale(1); } +} +.falah-wallet-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 18px 20px; + border-bottom: 1px solid var(--f-border); +} +.falah-wallet-modal-header h4 { + font-family: var(--f-font-display); + font-size: 1.15rem; + font-weight: 600; + color: var(--f-navy); + margin: 0; +} +.falah-wallet-modal-close { + background: none; + border: none; + cursor: pointer; + color: var(--f-text-muted); + font-size: 1rem; + line-height: 1; + padding: 4px; + border-radius: 4px; + transition: color var(--f-fast), background var(--f-fast); +} +.falah-wallet-modal-close:hover { color: var(--f-text); background: var(--f-border); } +.falah-wallet-modal-body { padding: 20px; display: flex; flex-direction: column; gap: 10px; } +.falah-wallet-field-label { + font-size: 0.78rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--f-text-muted); + margin-bottom: 2px; +} +.falah-wallet-field { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--f-border); + border-radius: var(--f-radius-sm); + font-family: var(--f-font-body); + font-size: 0.9rem; + color: var(--f-text); + background: var(--f-cream); + transition: border-color var(--f-fast); + box-sizing: border-box; +} +.falah-wallet-field:focus { outline: none; border-color: var(--f-emerald-mid); } +.falah-wallet-modal-err { + font-size: 0.8rem; + color: #DC2626; + min-height: 1em; +} + +/* Receive modal */ +.falah-wallet-receive-body { align-items: center; } +.falah-wallet-qr-placeholder { + width: 180px; + height: 180px; + border: 2px solid var(--f-border-gold); + border-radius: var(--f-radius); + display: flex; + align-items: center; + justify-content: center; + background: var(--f-cream); +} +.falah-wallet-qr-inner { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; } +.falah-wallet-qr-inner img { width: 100%; height: 100%; border-radius: calc(var(--f-radius) - 4px); } +.falah-wallet-address-box { + display: flex; + align-items: center; + gap: 8px; + background: var(--f-cream); + border: 1px solid var(--f-border); + border-radius: var(--f-radius-sm); + padding: 10px 12px; + width: 100%; + box-sizing: border-box; +} +.falah-wallet-address-text { + flex: 1; + font-size: 0.72rem; + color: var(--f-text-muted); + word-break: break-all; + font-family: monospace; +} +.falah-wallet-copy-btn { + background: none; + border: none; + cursor: pointer; + color: var(--f-text-muted); + padding: 2px; + flex-shrink: 0; + transition: color var(--f-fast); +} +.falah-wallet-copy-btn svg { width: 16px; height: 16px; display: block; } +.falah-wallet-copy-btn:hover { color: var(--f-emerald); } + /* ── Responsive ───────────────────────────────────────────────────────────── */ @media (max-width: 600px) { .falah-prayer-grid { grid-template-columns: repeat(3, 1fr); } @@ -551,4 +895,6 @@ .falah-compass { width: 180px; height: 180px; } .falah-verse-arabic { font-size: 1.45rem; } .falah-dashboard-header h2 { font-size: 1.6rem; } + .falah-wallet-actions { flex-direction: column; } + .falah-wallet-balance-amount { font-size: 2rem; } } diff --git a/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.js b/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.js index 79000a7..be1676b 100644 --- a/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.js +++ b/wordpress-plugins/falah-shortcodes/assets/falah-shortcodes.js @@ -273,4 +273,150 @@ }) .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 = '
No services listed yet. Be the first to offer your skills to the Ummah.
+ + Add Service + +