Refactor blockonomics btc + qr code presentation

This commit is contained in:
David Bomba
2025-11-26 15:05:56 +11:00
parent 019a688047
commit 4e9a756d52
11 changed files with 345 additions and 91 deletions

View File

@@ -50,50 +50,14 @@ class Blockonomics {
}
async fetchAndDisplayQRCode (newBtcAmount = null) {
try {
const btcAddress = document.querySelector('meta[name="btc_address"]').content;
const btcAmount = newBtcAmount || '{{$btc_amount}}';
const qrString = encodeURIComponent(`bitcoin:${btcAddress}?amount=${btcAmount}`);
const response = await fetch(`/api/v1/get-blockonomics-qr-code?qr_string=${qrString}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const svgText = await response.text();
document.getElementById('qrcode-container').innerHTML = svgText;
} catch (error) {
console.error('Error fetching QR code:', error);
document.getElementById('qrcode-container').textContent = 'Error loading QR code';
}
// QR code fetching is now handled by Livewire component (BlockonomicsQRCode)
async fetchAndDisplayQRCode () {
// This method is deprecated - use Livewire component instead
};
startTimer = (seconds) => {
const countDownDate = new Date().getTime() + seconds * 1000;
document.getElementById("countdown").innerHTML = "10" + ":" + "00" + " min";
const updateCountdown = () => {
const now = new Date().getTime();
const distance = countDownDate - now;
const isRefreshing = document.getElementsByClassName("btc-value")[0].innerHTML.includes("Refreshing");
if (isRefreshing) {
return;
}
if (distance < 0) {
refreshBTCPrice();
return;
}
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(seconds).padStart(2, '0');
document.getElementById("countdown").innerHTML = formattedMinutes + ":" + formattedSeconds + " min";
}
clearInterval(window.countdownInterval);
window.countdownInterval = setInterval(updateCountdown, 1000);
// Countdown timer is now handled by Livewire component (BlockonomicsPriceDisplay)
startTimer = () => {
// This method is deprecated - use Livewire component instead
}

View File

@@ -0,0 +1,98 @@
<div class="btc-value-wrapper">
<div class="btc-value">
1 BTC = {{ $btc_price }} {{ $currency }}, updates in <span id="countdown-livewire">{{ $countdown }}</span>
</div>
<span class="icon-refresh {{ $is_refreshing ? 'rotating' : '' }}" wire:click="refreshBTCPrice"
{{ $is_refreshing ? 'style="pointer-events: none;"' : '' }}></span>
<style>
.btc-value-wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
.btc-value {
font-size: 14px;
text-align: center;
}
.icon-refresh {
cursor: pointer;
margin-left: 5px;
width: 28px;
display: flex;
font-size: 32px;
margin-bottom: 5px;
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.rotating {
animation: rotating 2s linear infinite;
}
</style>
@script
<script>
let countdownInterval = null;
let countdownDate = null;
const updateCountdown = () => {
if (!countdownDate) return;
const now = new Date().getTime();
const distance = countdownDate - now;
if (distance <= 0) {
clearInterval(countdownInterval);
countdownInterval = null;
$wire.refreshBTCPrice();
return;
}
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
if (!isNaN(minutes) && !isNaN(seconds)) {
const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(seconds).padStart(2, '0');
const countdownElement = document.getElementById('countdown-livewire');
if (countdownElement) {
countdownElement.textContent = formattedMinutes + ':' + formattedSeconds;
}
}
};
const startCountdownTimer = ({ duration }) => {
clearInterval(countdownInterval);
countdownInterval = null;
countdownDate = new Date().getTime() + duration * 1000;
updateCountdown();
countdownInterval = setInterval(updateCountdown, 1000);
};
$wire.on('start-countdown', startCountdownTimer);
// Listen for updates after price refresh
$wire.on('btc-price-updated', () => {
startCountdownTimer({ duration: 600 });
});
// Initialize countdown on component mount with a small delay to ensure DOM is ready
setTimeout(() => {
startCountdownTimer({ duration: 600 });
}, 100);
</script>
@endscript
</div>

View File

@@ -0,0 +1,41 @@
<div class="qrcode-wrapper">
@if ($error_message)
<div class="error-message">{{ $error_message }}</div>
@elseif ($is_loading)
<div class="loading-message">Loading QR code...</div>
@else
<a href="bitcoin:{{ $btc_address }}?amount={{ $btc_amount }}" id="qr-code-link" target="_blank">
<div id="qrcode-container">
{!! $qr_code_svg !!}
</div>
</a>
@endif
<style>
.qrcode-wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.error-message {
color: #d32f2f;
padding: 20px;
text-align: center;
font-size: 14px;
}
.loading-message {
color: #666;
padding: 20px;
text-align: center;
font-size: 14px;
}
#qrcode-container {
display: flex;
justify-content: center;
align-items: center;
}
</style>
</div>

View File

@@ -20,9 +20,10 @@
<div class="scan-section">
<div class="title">Scan</div>
<span class="input-wrapper">
<a href="bitcoin:{{$btc_address}}?amount={{$btc_amount}}" id="qr-code-link" target="_blank">
<div id="qrcode-container"></div>
</a>
<livewire:billing-portal.payments.blockonomics-qr-code
:btc_address="$btc_address"
:btc_amount="$btc_amount"
/>
</span>
<a href="bitcoin:{{$btc_address}}?amount={{$btc_amount}}" target="_blank" id="open-in-wallet-link">Open in Wallet</a>
</div>
@@ -40,10 +41,11 @@
</div>
<img onclick='copyToClipboard("btc-amount", this)' src="{{ 'data:image/svg+xml;base64,' . base64_encode('<svg width="22" height="24" viewBox="0 0 22 24" fill="none" xmlns="http://www.w3.org/2000/svg" ><path d="M15.5 1H3.5C2.4 1 1.5 1.9 1.5 3V17H3.5V3H15.5V1ZM18.5 5H7.5C6.4 5 5.5 5.9 5.5 7V21C5.5 22.1 6.4 23 7.5 23H18.5C19.6 23 20.5 22.1 20.5 21V7C20.5 5.9 19.6 5 18.5 5ZM18.5 21H7.5V7H18.5V21Z" fill="#000"/></svg>') }}" class="icon" alt="Copy Icon">
</span>
<div class="btc-value-wrapper">
<div class="btc-value">1 BTC = {{$btc_price}} {{$currency}}, updates in <span id="countdown"></span></div>
<span class="icon-refresh" onclick='refreshBTCPrice()'></span>
</div>
<livewire:billing-portal.payments.blockonomics-price-display
:currency="$currency"
:btc_price="$btc_price"
:btc_amount="$btc_amount"
/>
</div>
</div>
</div>

View File

@@ -19,9 +19,10 @@
<div class="scan-section">
<div class="title">Scan</div>
<span class="input-wrapper">
<a href="bitcoin:{{$btc_address}}?amount={{$btc_amount}}" id="qr-code-link" target="_blank">
<div id="qrcode-container"></div>
</a>
<livewire:billing-portal.payments.blockonomics-qr-code
:btc_address="$btc_address"
:btc_amount="$btc_amount"
/>
</span>
<a href="bitcoin:{{$btc_address}}?amount={{$btc_amount}}" target="_blank" id="open-in-wallet-link">Open in Wallet</a>
</div>
@@ -39,10 +40,11 @@
</div>
<img onclick='copyToClipboard("btc-amount", this)' src="{{ 'data:image/svg+xml;base64,' . base64_encode('<svg width="22" height="24" viewBox="0 0 22 24" fill="none" xmlns="http://www.w3.org/2000/svg" ><path d="M15.5 1H3.5C2.4 1 1.5 1.9 1.5 3V17H3.5V3H15.5V1ZM18.5 5H7.5C6.4 5 5.5 5.9 5.5 7V21C5.5 22.1 6.4 23 7.5 23H18.5C19.6 23 20.5 22.1 20.5 21V7C20.5 5.9 19.6 5 18.5 5ZM18.5 21H7.5V7H18.5V21Z" fill="#000"/></svg>') }}" class="icon" alt="Copy Icon">
</span>
<div class="btc-value-wrapper">
<div class="btc-value">1 BTC = {{$btc_price}} {{$currency}}, updates in <span id="countdown"></span></div>
<span class="icon-refresh" onclick='refreshBTCPrice()'></span>
</div>
<livewire:billing-portal.payments.blockonomics-price-display
:currency="$currency"
:btc_price="$btc_price"
:btc_amount="$btc_amount"
/>
</div>
</div>
</div>