mirror of
https://github.com/basicswap/basicswap.git
synced 2026-04-08 10:27:23 +02:00
Fix bid tooltips (Adaptor / Secret hash) and progress bar.
This commit is contained in:
@@ -6,9 +6,15 @@ const BidPage = {
|
||||
elapsedTimeInterval: null,
|
||||
AUTO_REFRESH_SECONDS: 60,
|
||||
refreshPaused: false,
|
||||
swapType: null,
|
||||
coinFrom: null,
|
||||
coinTo: null,
|
||||
previousStateInd: null,
|
||||
|
||||
INACTIVE_STATES: [8, 17, 18, 19, 21, 22, 23, 25, 31], // Completed, Failed variants, Timed-out, Abandoned, Error, Rejected, Expired
|
||||
|
||||
DELAYING_STATE: 20,
|
||||
|
||||
STATE_TOOLTIPS: {
|
||||
'Bid Sent': 'Your bid has been broadcast to the network',
|
||||
'Bid Receiving': 'Receiving partial bid message from the network',
|
||||
@@ -18,14 +24,14 @@ const BidPage = {
|
||||
'Bid Initiated': 'Swap initiated. First lock transaction is being created',
|
||||
'Bid Participating': 'Participating in the swap. Second lock transaction is being created',
|
||||
'Bid Completed': 'Swap completed successfully! Both parties received their coins',
|
||||
'Bid Script coin locked': 'Your coins are locked in the atomic swap contract on the script chain (e.g., BTC/LTC)',
|
||||
'Bid Script coin spend tx valid': 'The spend transaction for the script coin has been validated and is ready',
|
||||
'Bid Scriptless coin locked': 'The other party\'s coins are locked using adaptor signatures (e.g., XMR)',
|
||||
'Bid Script coin lock released': 'Secret key revealed. The script coin can now be claimed',
|
||||
'Bid Script tx redeemed': 'Script coin has been successfully claimed',
|
||||
'Bid Script coin locked': null,
|
||||
'Bid Script coin spend tx valid': null,
|
||||
'Bid Scriptless coin locked': null,
|
||||
'Bid Script coin lock released': 'Adaptor signature revealed. The script coin can now be claimed',
|
||||
'Bid Script tx redeemed': null,
|
||||
'Bid Script pre-refund tx in chain': 'Pre-refund transaction detected. Swap may be failing',
|
||||
'Bid Scriptless tx redeemed': 'Scriptless coin (e.g., XMR) has been successfully claimed',
|
||||
'Bid Scriptless tx recovered': 'Scriptless coin recovered after swap failure',
|
||||
'Bid Scriptless tx redeemed': null,
|
||||
'Bid Scriptless tx recovered': null,
|
||||
'Bid Failed, refunded': 'Swap failed but your coins have been refunded',
|
||||
'Bid Failed, swiped': 'Swap failed due to an unexpected issue. Please check the event log for details',
|
||||
'Bid Failed': 'Swap failed. Check events for details',
|
||||
@@ -35,7 +41,7 @@ const BidPage = {
|
||||
'Bid Error': 'An error occurred. Check events for details',
|
||||
'Bid Rejected': 'Bid was rejected by the offer owner',
|
||||
'Bid Stalled (debug)': 'Debug mode: swap intentionally stalled for testing',
|
||||
'Bid Exchanged script lock tx sigs msg': 'Exchanging cryptographic signatures needed for lock transactions',
|
||||
'Bid Exchanged script lock tx sigs msg': 'Exchanging adaptor signatures needed for lock transactions',
|
||||
'Bid Exchanged script lock spend tx msg': 'Exchanging signed spend transaction for locked coins',
|
||||
'Bid Request sent': 'Connection request sent to the other party',
|
||||
'Bid Request accepted': 'Connection request accepted',
|
||||
@@ -44,7 +50,7 @@ const BidPage = {
|
||||
'Bid Auto accept failed': 'Automation failed to accept this bid',
|
||||
'Bid Connect request sent': 'Sent connection request to peer',
|
||||
'Bid Unknown bid state': 'Unknown state - please check the swap details',
|
||||
|
||||
|
||||
'ITX Sent': 'Initiate transaction has been broadcast to the network',
|
||||
'ITX Confirmed': 'Initiate transaction has been confirmed by miners',
|
||||
'ITX Redeemed': 'Initiate transaction has been successfully claimed',
|
||||
@@ -59,6 +65,38 @@ const BidPage = {
|
||||
'PTX In Chain': 'Participate transaction is included in a block'
|
||||
},
|
||||
|
||||
getStateTooltip: function(stateText) {
|
||||
const staticTooltip = this.STATE_TOOLTIPS[stateText];
|
||||
if (staticTooltip !== null && staticTooltip !== undefined) {
|
||||
return staticTooltip;
|
||||
}
|
||||
|
||||
const scriptlessCoins = ['XMR', 'WOW'];
|
||||
let scriptCoin, scriptlessCoin;
|
||||
|
||||
if (scriptlessCoins.includes(this.coinFrom)) {
|
||||
scriptlessCoin = this.coinFrom;
|
||||
scriptCoin = this.coinTo;
|
||||
} else if (scriptlessCoins.includes(this.coinTo)) {
|
||||
scriptlessCoin = this.coinTo;
|
||||
scriptCoin = this.coinFrom;
|
||||
} else {
|
||||
scriptCoin = this.coinFrom;
|
||||
scriptlessCoin = this.coinTo;
|
||||
}
|
||||
|
||||
const dynamicTooltips = {
|
||||
'Bid Script coin locked': `${scriptCoin} is locked in the atomic swap contract`,
|
||||
'Bid Script coin spend tx valid': `The ${scriptCoin} spend transaction has been validated and is ready`,
|
||||
'Bid Scriptless coin locked': `${scriptlessCoin} is locked using adaptor signatures`,
|
||||
'Bid Script tx redeemed': `${scriptCoin} has been successfully claimed`,
|
||||
'Bid Scriptless tx redeemed': `${scriptlessCoin} has been successfully claimed`,
|
||||
'Bid Scriptless tx recovered': `${scriptlessCoin} recovered after swap failure`,
|
||||
};
|
||||
|
||||
return dynamicTooltips[stateText] || null;
|
||||
},
|
||||
|
||||
EVENT_TOOLTIPS: {
|
||||
'Lock tx A published': 'First lock transaction broadcast to the blockchain network',
|
||||
'Lock tx A seen in mempool': 'First lock transaction detected in mempool (unconfirmed)',
|
||||
@@ -131,13 +169,22 @@ const BidPage = {
|
||||
34: { phase: 'negotiation', order: 0.4, label: 'Negotiation' } // CONNECT_REQ_SENT
|
||||
},
|
||||
|
||||
init: function(bidId, bidStateInd, createdAtTimestamp, stateTimeTimestamp) {
|
||||
init: function(bidId, bidStateInd, createdAtTimestamp, stateTimeTimestamp, options) {
|
||||
this.bidId = bidId;
|
||||
this.bidStateInd = bidStateInd;
|
||||
this.createdAtTimestamp = createdAtTimestamp;
|
||||
this.stateTimeTimestamp = stateTimeTimestamp;
|
||||
this.tooltipCounter = 0;
|
||||
|
||||
options = options || {};
|
||||
this.swapType = options.swapType || 'secret-hash';
|
||||
this.coinFrom = options.coinFrom || '';
|
||||
this.coinTo = options.coinTo || '';
|
||||
|
||||
if (this.bidStateInd === this.DELAYING_STATE) {
|
||||
this.previousStateInd = this.findPreviousState();
|
||||
}
|
||||
|
||||
this.applyStateTooltips();
|
||||
this.applyEventTooltips();
|
||||
this.createProgressBar();
|
||||
@@ -145,6 +192,59 @@ const BidPage = {
|
||||
this.setupAutoRefresh();
|
||||
},
|
||||
|
||||
findPreviousState: function() {
|
||||
const sections = document.querySelectorAll('section');
|
||||
let oldStatesSection = null;
|
||||
|
||||
sections.forEach(section => {
|
||||
const h4 = section.querySelector('h4');
|
||||
if (h4 && h4.textContent.includes('Old states')) {
|
||||
oldStatesSection = section.nextElementSibling;
|
||||
}
|
||||
});
|
||||
|
||||
if (oldStatesSection) {
|
||||
const table = oldStatesSection.querySelector('table');
|
||||
if (table) {
|
||||
const rows = table.querySelectorAll('tr');
|
||||
|
||||
for (let i = rows.length - 1; i >= 0; i--) {
|
||||
const cells = rows[i].querySelectorAll('td');
|
||||
if (cells.length >= 2) {
|
||||
const stateText = cells[cells.length - 1].textContent.trim();
|
||||
if (!stateText.includes('Delaying')) {
|
||||
return this.stateTextToIndex(stateText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
stateTextToIndex: function(stateText) {
|
||||
const stateMap = {
|
||||
'Sent': 1, 'Receiving': 2, 'Received': 3, 'Receiving accept': 4,
|
||||
'Accepted': 5, 'Initiated': 6, 'Participating': 7, 'Completed': 8,
|
||||
'Script coin locked': 9, 'Script coin spend tx valid': 10,
|
||||
'Scriptless coin locked': 11, 'Script coin lock released': 12,
|
||||
'Script tx redeemed': 13, 'Script pre-refund tx in chain': 14,
|
||||
'Scriptless tx redeemed': 15, 'Scriptless tx recovered': 16,
|
||||
'Failed, refunded': 17, 'Failed, swiped': 18, 'Failed': 19,
|
||||
'Delaying': 20, 'Timed-out': 21, 'Abandoned': 22, 'Error': 23,
|
||||
'Rejected': 25, 'Exchanged script lock tx sigs msg': 27,
|
||||
'Exchanged script lock spend tx msg': 28, 'Request sent': 29,
|
||||
'Request accepted': 30, 'Expired': 31
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(stateMap)) {
|
||||
if (stateText.includes(key)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
isActiveState: function() {
|
||||
return !this.INACTIVE_STATES.includes(this.bidStateInd);
|
||||
},
|
||||
@@ -243,7 +343,7 @@ const BidPage = {
|
||||
if (cells.length >= 2) {
|
||||
const stateCell = cells[cells.length - 1];
|
||||
const stateText = stateCell.textContent.trim();
|
||||
const tooltip = this.STATE_TOOLTIPS[stateText];
|
||||
const tooltip = this.getStateTooltip(stateText) || this.getStateTooltip('Bid ' + stateText);
|
||||
if (tooltip) {
|
||||
this.addHelpIcon(stateCell, tooltip);
|
||||
}
|
||||
@@ -261,7 +361,7 @@ const BidPage = {
|
||||
const valueCell = row.querySelectorAll('td')[1];
|
||||
if (valueCell) {
|
||||
const stateText = valueCell.textContent.trim();
|
||||
const tooltip = this.STATE_TOOLTIPS[stateText] || this.STATE_TOOLTIPS['Bid ' + stateText];
|
||||
const tooltip = this.getStateTooltip(stateText) || this.getStateTooltip('Bid ' + stateText);
|
||||
if (tooltip) {
|
||||
this.addHelpIcon(valueCell, tooltip);
|
||||
}
|
||||
@@ -340,7 +440,15 @@ const BidPage = {
|
||||
},
|
||||
|
||||
createProgressBar: function() {
|
||||
const phaseInfo = this.STATE_PHASES[this.bidStateInd];
|
||||
let stateForProgress = this.bidStateInd;
|
||||
let isDelaying = false;
|
||||
|
||||
if (this.bidStateInd === this.DELAYING_STATE && this.previousStateInd) {
|
||||
stateForProgress = this.previousStateInd;
|
||||
isDelaying = true;
|
||||
}
|
||||
|
||||
const phaseInfo = this.STATE_PHASES[stateForProgress];
|
||||
if (!phaseInfo) return;
|
||||
|
||||
let progressPercent = 0;
|
||||
@@ -373,7 +481,17 @@ const BidPage = {
|
||||
const isError = ['failed', 'error'].includes(phase);
|
||||
const isComplete = phase === 'complete';
|
||||
const barColor = isError ? 'bg-red-500' : (isComplete ? 'bg-green-500' : 'bg-blue-500');
|
||||
const phaseLabel = isError ? phaseInfo.label : (isComplete ? 'Complete' : `${phaseInfo.label} (${progressPercent}%)`);
|
||||
|
||||
let phaseLabel;
|
||||
if (isError) {
|
||||
phaseLabel = phaseInfo.label;
|
||||
} else if (isComplete) {
|
||||
phaseLabel = 'Complete';
|
||||
} else if (isDelaying) {
|
||||
phaseLabel = `${phaseInfo.label} (${progressPercent}%) - Delaying`;
|
||||
} else {
|
||||
phaseLabel = `${phaseInfo.label} (${progressPercent}%)`;
|
||||
}
|
||||
|
||||
progressRow.innerHTML = `
|
||||
<td class="py-3 px-6 bold">Swap Progress</td>
|
||||
|
||||
@@ -692,7 +692,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<script src="/static/js/pages/bid-page.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
BidPage.init('{{ bid_id }}', {{ data.bid_state_ind }}, {{ data.created_at_timestamp }}, {{ data.state_time_timestamp or 'null' }});
|
||||
BidPage.init('{{ bid_id }}', {{ data.bid_state_ind }}, {{ data.created_at_timestamp }}, {{ data.state_time_timestamp or 'null' }}, {
|
||||
swapType: 'secret-hash',
|
||||
coinFrom: '{{ data.ticker_from }}',
|
||||
coinTo: '{{ data.ticker_to }}'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
@@ -968,7 +968,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<script src="/static/js/pages/bid-page.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
BidPage.init('{{ bid_id }}', {{ data.bid_state_ind }}, {{ data.created_at_timestamp }}, {{ data.state_time_timestamp or 'null' }});
|
||||
BidPage.init('{{ bid_id }}', {{ data.bid_state_ind }}, {{ data.created_at_timestamp }}, {{ data.state_time_timestamp or 'null' }}, {
|
||||
swapType: 'adaptor-sig',
|
||||
coinFrom: '{{ data.ticker_from }}',
|
||||
coinTo: '{{ data.ticker_to }}'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user