mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2026-03-03 03:07:01 +00:00
Refactor blockonomics btc + qr code presentation
This commit is contained in:
48
resources/js/clients/payments/blockonomics.js
vendored
48
resources/js/clients/payments/blockonomics.js
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user