mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-14 22:38:10 +01:00
nmc: Add to test_xmr_persistent.
This commit is contained in:
BIN
basicswap/static/images/coins/Namecoin-20.png
Normal file
BIN
basicswap/static/images/coins/Namecoin-20.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 743 B |
BIN
basicswap/static/images/coins/Namecoin.png
Normal file
BIN
basicswap/static/images/coins/Namecoin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
|
||||
'Firo': 'FIRO',
|
||||
'Dash': 'DASH',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Wownero': 'WOW',
|
||||
'Bitcoin Cash': 'BCH',
|
||||
'Dogecoin': 'DOGE'
|
||||
@@ -335,13 +336,13 @@ const createBidTableRow = async (bid) => {
|
||||
</a>
|
||||
</div>
|
||||
<div class="monospace text-xs text-gray-500 dark:text-gray-300">
|
||||
<span class="font-semibold">Offer ID:</span>
|
||||
<span class="font-semibold">Offer ID:</span>
|
||||
<a href="/offer/${bid.offer_id}" data-tooltip-target="tooltip-offer-${uniqueId}" class="hover:underline">
|
||||
${formatAddress(bid.offer_id)}
|
||||
</a>
|
||||
</div>
|
||||
<div class="monospace text-xs text-gray-500 dark:text-gray-300">
|
||||
<span class="font-semibold">Bid ID:</span>
|
||||
<span class="font-semibold">Bid ID:</span>
|
||||
<a href="/bid/${bid.bid_id}" data-tooltip-target="tooltip-bid-${uniqueId}" class="hover:underline">
|
||||
${formatAddress(bid.bid_id)}
|
||||
</a>
|
||||
@@ -366,8 +367,8 @@ const createBidTableRow = async (bid) => {
|
||||
<div class="py-3 px-4 text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
<span class="inline-flex mr-3 align-middle items-center justify-center w-18 h-20 rounded">
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${bid.coin_from.replace(' ', '-')}.png"
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${bid.coin_from.replace(' ', '-')}.png"
|
||||
alt="${bid.coin_from}"
|
||||
onerror="this.src='/static/images/coins/default.png'">
|
||||
</span>
|
||||
@@ -375,15 +376,14 @@ const createBidTableRow = async (bid) => {
|
||||
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"></path>
|
||||
</svg>
|
||||
<span class="inline-flex ml-3 align-middle items-center justify-center w-18 h-20 rounded">
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${bid.coin_to.replace(' ', '-')}.png"
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${bid.coin_to.replace(' ', '-')}.png"
|
||||
alt="${bid.coin_to}"
|
||||
onerror="this.src='/static/images/coins/default.png'">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- You Get Column -->
|
||||
<td class="py-0">
|
||||
<div class="py-3 px-4 text-right">
|
||||
@@ -410,7 +410,7 @@ const createBidTableRow = async (bid) => {
|
||||
|
||||
<!-- Actions Column -->
|
||||
<td class="py-3 px-4 text-center">
|
||||
<a href="/bid/${bid.bid_id}/accept"
|
||||
<a href="/bid/${bid.bid_id}/accept"
|
||||
class="inline-block w-20 py-1 px-2 font-medium text-center text-sm rounded-md bg-blue-500 text-white border border-blue-500 hover:bg-blue-600 transition duration-200">
|
||||
Accept
|
||||
</a>
|
||||
@@ -506,13 +506,13 @@ const createDetailsColumn = (bid, identity, uniqueId) => `
|
||||
</a>
|
||||
</div>
|
||||
<div class="monospace text-xs text-gray-500 dark:text-gray-300">
|
||||
<span class="font-semibold">Offer ID:</span>
|
||||
<span class="font-semibold">Offer ID:</span>
|
||||
<a href="/offer/${bid.offer_id}" data-tooltip-target="tooltip-offer-${uniqueId}" class="hover:underline">
|
||||
${formatAddress(bid.offer_id)}
|
||||
</a>
|
||||
</div>
|
||||
<div class="monospace text-xs text-gray-500 dark:text-gray-300">
|
||||
<span class="font-semibold">Bid ID:</span>
|
||||
<span class="font-semibold">Bid ID:</span>
|
||||
<a href="/bid/${bid.bid_id}" data-tooltip-target="tooltip-bid-${uniqueId}" class="hover:underline">
|
||||
${formatAddress(bid.bid_id)}
|
||||
</a>
|
||||
|
||||
@@ -220,7 +220,7 @@ const ApiManager = (function() {
|
||||
.filter(coin => coin.usesCoinGecko)
|
||||
.map(coin => coin.name)
|
||||
.join(',') :
|
||||
'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred';
|
||||
'bitcoin,monero,particl,bitcoincash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
|
||||
|
||||
//console.log('Fetching coin prices for:', coins);
|
||||
const response = await this.fetchCoinPrices(coins);
|
||||
@@ -254,7 +254,7 @@ const ApiManager = (function() {
|
||||
.filter(coin => coin.usesCoinGecko)
|
||||
.map(coin => getCoinBackendId ? getCoinBackendId(coin.name) : coin.name)
|
||||
.join(',') :
|
||||
'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred';
|
||||
'bitcoin,monero,particl,bitcoin-cash,pivx,firo,dash,litecoin,dogecoin,decred,namecoin';
|
||||
|
||||
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coins}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`;
|
||||
|
||||
|
||||
@@ -504,13 +504,14 @@ const CacheManager = (function() {
|
||||
'bitcoin': 'BTC',
|
||||
'litecoin': 'LTC',
|
||||
'monero': 'XMR',
|
||||
'wownero': 'WOW',
|
||||
'particl': 'PART',
|
||||
'pivx': 'PIVX',
|
||||
'firo': 'FIRO',
|
||||
'zcoin': 'FIRO',
|
||||
'dash': 'DASH',
|
||||
'decred': 'DCR',
|
||||
'wownero': 'WOW',
|
||||
'namecoin': 'NMR',
|
||||
'bitcoin-cash': 'BCH',
|
||||
'dogecoin': 'DOGE'
|
||||
};
|
||||
|
||||
@@ -72,6 +72,7 @@ const ConfigManager = (function() {
|
||||
{ symbol: 'LTC', name: 'litecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
|
||||
{ symbol: 'DOGE', name: 'dogecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
|
||||
{ symbol: 'DCR', name: 'decred', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
|
||||
{ symbol: 'NMC', name: 'namecoin', usesCryptoCompare: true, usesCoinGecko: true, historicalDays: 30 },
|
||||
{ symbol: 'WOW', name: 'wownero', usesCryptoCompare: false, usesCoinGecko: true, historicalDays: 30 }
|
||||
],
|
||||
|
||||
@@ -88,6 +89,7 @@ const ConfigManager = (function() {
|
||||
'Zcoin': 'FIRO',
|
||||
'Dash': 'DASH',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Wownero': 'WOW',
|
||||
'Bitcoin Cash': 'BCH',
|
||||
'Dogecoin': 'DOGE'
|
||||
@@ -105,13 +107,14 @@ const ConfigManager = (function() {
|
||||
'Zcoin': 'Firo',
|
||||
'Dash': 'Dash',
|
||||
'Decred': 'Decred',
|
||||
'Namecoin': 'Namecoin',
|
||||
'Wownero': 'Wownero',
|
||||
'Bitcoin Cash': 'Bitcoin Cash',
|
||||
'Dogecoin': 'Dogecoin'
|
||||
},
|
||||
|
||||
idToName: {
|
||||
1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred',
|
||||
1: 'particl', 2: 'bitcoin', 3: 'litecoin', 4: 'decred', 5: 'namecoin',
|
||||
6: 'monero', 7: 'particl blind', 8: 'particl anon',
|
||||
9: 'wownero', 11: 'pivx', 13: 'firo', 17: 'bitcoincash',
|
||||
18: 'dogecoin'
|
||||
@@ -130,6 +133,7 @@ const ConfigManager = (function() {
|
||||
'litecoin': 'litecoin',
|
||||
'dogecoin': 'dogecoin',
|
||||
'decred': 'decred',
|
||||
'namecoin': 'namecoin',
|
||||
'wownero': 'wownero'
|
||||
}
|
||||
},
|
||||
@@ -367,6 +371,7 @@ const ConfigManager = (function() {
|
||||
'dash': { usd: null, btc: null },
|
||||
'dogecoin': { usd: null, btc: null },
|
||||
'decred': { usd: null, btc: null },
|
||||
'namecoin': { usd: null, btc: null },
|
||||
'litecoin': { usd: null, btc: null },
|
||||
'particl': { usd: null, btc: null },
|
||||
'pivx': { usd: null, btc: null },
|
||||
|
||||
@@ -35,6 +35,7 @@ const WalletManager = (function() {
|
||||
'Dash': 'DASH',
|
||||
'PIVX': 'PIVX',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Bitcoin Cash': 'BCH'
|
||||
},
|
||||
|
||||
@@ -49,6 +50,7 @@ const WalletManager = (function() {
|
||||
'DASH': 'dash',
|
||||
'PIVX': 'pivx',
|
||||
'DCR': 'dcr',
|
||||
'NMC': 'nmc',
|
||||
'BCH': 'bch'
|
||||
},
|
||||
|
||||
@@ -63,6 +65,7 @@ const WalletManager = (function() {
|
||||
'Dash': 'DASH',
|
||||
'PIVX': 'PIVX',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Bitcoin Cash': 'BCH',
|
||||
'Dogecoin': 'DOGE'
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ window.tableRateModule = {
|
||||
'Dash': 'DASH',
|
||||
'PIVX': 'PIVX',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Zano': 'ZANO',
|
||||
'Bitcoin Cash': 'BCH',
|
||||
'Dogecoin': 'DOGE'
|
||||
@@ -56,9 +57,9 @@ window.tableRateModule = {
|
||||
},
|
||||
|
||||
setCachedValue(key, value, resourceType = null) {
|
||||
const ttl = resourceType ?
|
||||
window.config.cacheConfig.ttlSettings[resourceType] ||
|
||||
window.config.cacheConfig.defaultTTL :
|
||||
const ttl = resourceType ?
|
||||
window.config.cacheConfig.ttlSettings[resourceType] ||
|
||||
window.config.cacheConfig.defaultTTL :
|
||||
900000;
|
||||
|
||||
const item = {
|
||||
@@ -306,13 +307,14 @@ async function calculateProfitLoss(fromCoin, toCoin, fromAmount, toAmount, isOwn
|
||||
'ltc': 'litecoin',
|
||||
'doge': 'dogecoin',
|
||||
'dcr': 'decred',
|
||||
'nmc': 'namecoin',
|
||||
'wow': 'wownero'
|
||||
};
|
||||
|
||||
if (lowerCoin === 'zcoin') return 'firo';
|
||||
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
|
||||
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
|
||||
|
||||
|
||||
return symbolToName[lowerCoin] || lowerCoin;
|
||||
};
|
||||
|
||||
@@ -406,7 +408,7 @@ async function fetchLatestPrices() {
|
||||
const coinIds = [
|
||||
'bitcoin', 'particl', 'monero', 'litecoin',
|
||||
'dogecoin', 'firo', 'dash', 'pivx',
|
||||
'decred', 'bitcoincash'
|
||||
'decred', 'namecoin', 'bitcoincash'
|
||||
];
|
||||
|
||||
let processedData = {};
|
||||
@@ -419,7 +421,7 @@ async function fetchLatestPrices() {
|
||||
if (mainResponse && mainResponse.rates) {
|
||||
Object.entries(mainResponse.rates).forEach(([coinId, price]) => {
|
||||
const normalizedCoinId = coinId === 'bitcoincash' ? 'bitcoin-cash' : coinId.toLowerCase();
|
||||
|
||||
|
||||
processedData[normalizedCoinId] = {
|
||||
usd: price,
|
||||
btc: normalizedCoinId === 'bitcoin' ? 1 : price / (mainResponse.rates.bitcoin || 1)
|
||||
@@ -453,7 +455,7 @@ async function fetchLatestPrices() {
|
||||
} catch (error) {
|
||||
console.error(`Price fetch attempt ${attempt + 1} failed:`, error);
|
||||
NetworkManager.handleNetworkError(error);
|
||||
|
||||
|
||||
if (attempt < MAX_RETRIES - 1) {
|
||||
const delay = Math.min(500 * Math.pow(2, attempt), 5000);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
@@ -520,7 +522,7 @@ async function fetchOffers() {
|
||||
originalJsonData = [...jsonData];
|
||||
|
||||
latestPrices = pricesData || getEmptyPriceData();
|
||||
|
||||
|
||||
CacheManager.set('offers_cached', jsonData, 'offers');
|
||||
|
||||
await updateOffersTable();
|
||||
@@ -1353,7 +1355,7 @@ function createRateColumn(offer, coinFrom, coinTo) {
|
||||
|
||||
const getPriceKey = (coin) => {
|
||||
const lowerCoin = coin.toLowerCase();
|
||||
|
||||
|
||||
const symbolToName = {
|
||||
'btc': 'bitcoin',
|
||||
'xmr': 'monero',
|
||||
@@ -1365,13 +1367,14 @@ function createRateColumn(offer, coinFrom, coinTo) {
|
||||
'ltc': 'litecoin',
|
||||
'doge': 'dogecoin',
|
||||
'dcr': 'decred',
|
||||
'nmc': 'namecoin',
|
||||
'wow': 'wownero'
|
||||
};
|
||||
|
||||
|
||||
if (lowerCoin === 'zcoin') return 'firo';
|
||||
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
|
||||
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
|
||||
|
||||
|
||||
return symbolToName[lowerCoin] || lowerCoin;
|
||||
};
|
||||
|
||||
@@ -1655,23 +1658,24 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou
|
||||
'ltc': 'litecoin',
|
||||
'doge': 'dogecoin',
|
||||
'dcr': 'decred',
|
||||
'nmc': 'namecoin',
|
||||
'wow': 'wownero'
|
||||
};
|
||||
|
||||
if (lowerCoin === 'zcoin') return 'firo';
|
||||
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
|
||||
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
|
||||
|
||||
|
||||
return symbolToName[lowerCoin] || lowerCoin;
|
||||
};
|
||||
|
||||
|
||||
if (latestPrices && latestPrices['firo'] && !latestPrices['zcoin']) {
|
||||
latestPrices['zcoin'] = JSON.parse(JSON.stringify(latestPrices['firo']));
|
||||
}
|
||||
|
||||
const fromSymbol = getPriceKey(coinFrom);
|
||||
const toSymbol = getPriceKey(coinTo);
|
||||
|
||||
|
||||
let fromPriceUSD = latestPrices && latestPrices[fromSymbol] ? latestPrices[fromSymbol].usd : null;
|
||||
let toPriceUSD = latestPrices && latestPrices[toSymbol] ? latestPrices[toSymbol].usd : null;
|
||||
|
||||
@@ -1685,7 +1689,7 @@ function createTooltipContent(isSentOffers, coinFrom, coinTo, fromAmount, toAmou
|
||||
isNaN(fromPriceUSD) || isNaN(toPriceUSD)) {
|
||||
return `<p class="font-bold mb-1">Price Information Unavailable</p>
|
||||
<p>Current market prices are temporarily unavailable.</p>
|
||||
<p class="mt-2">You are ${isSentOffers ? 'selling' : 'buying'} ${fromAmount.toFixed(8)} ${coinFrom}
|
||||
<p class="mt-2">You are ${isSentOffers ? 'selling' : 'buying'} ${fromAmount.toFixed(8)} ${coinFrom}
|
||||
for ${toAmount.toFixed(8)} ${coinTo}.</p>
|
||||
<p class="font-bold mt-2">Note:</p>
|
||||
<p>Profit/loss calculations will be available when price data is restored.</p>`;
|
||||
@@ -1757,13 +1761,14 @@ function createCombinedRateTooltip(offer, coinFrom, coinTo, treatAsSentOffer) {
|
||||
'ltc': 'litecoin',
|
||||
'doge': 'dogecoin',
|
||||
'dcr': 'decred',
|
||||
'nmc': 'namecoin',
|
||||
'wow': 'wownero'
|
||||
};
|
||||
|
||||
if (lowerCoin === 'zcoin') return 'firo';
|
||||
if (lowerCoin === 'bitcoin cash') return 'bitcoin-cash';
|
||||
if (lowerCoin === 'particl anon' || lowerCoin === 'particl blind') return 'particl';
|
||||
|
||||
|
||||
return symbolToName[lowerCoin] || lowerCoin;
|
||||
};
|
||||
|
||||
@@ -1876,7 +1881,7 @@ function clearFilters() {
|
||||
|
||||
jsonData = [...originalJsonData];
|
||||
currentPage = 1;
|
||||
|
||||
|
||||
const storageKey = isSentOffers ? 'sentOffersTableSettings' : 'networkOffersTableSettings';
|
||||
localStorage.removeItem(storageKey);
|
||||
|
||||
@@ -2194,7 +2199,7 @@ async function initializeTableAndData() {
|
||||
function loadSavedSettings() {
|
||||
const storageKey = isSentOffers ? 'sentOffersTableSettings' : 'networkOffersTableSettings';
|
||||
const saved = localStorage.getItem(storageKey);
|
||||
|
||||
|
||||
if (saved) {
|
||||
const settings = JSON.parse(saved);
|
||||
|
||||
@@ -2229,7 +2234,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
NetworkManager.initialize({
|
||||
connectionTestEndpoint: '/json',
|
||||
connectionTestTimeout: 3000,
|
||||
reconnectDelay: 5000,
|
||||
reconnectDelay: 5000,
|
||||
maxReconnectAttempts: 5
|
||||
});
|
||||
window.networkManagerInitialized = true;
|
||||
@@ -2252,7 +2257,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
});
|
||||
|
||||
const tableLoadPromise = initializeTableAndData();
|
||||
|
||||
|
||||
WebSocketManager.initialize({
|
||||
debug: false
|
||||
});
|
||||
@@ -2262,7 +2267,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (!NetworkManager.isOnline()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const endpoint = isSentOffers ? '/json/sentoffers' : '/json/offers';
|
||||
const response = await fetch(endpoint);
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
@@ -2349,7 +2354,7 @@ async function cleanup() {
|
||||
lastRefreshTime = null;
|
||||
|
||||
const domRefs = [
|
||||
'offersBody', 'filterForm', 'prevPageButton', 'nextPageButton',
|
||||
'offersBody', 'filterForm', 'prevPageButton', 'nextPageButton',
|
||||
'currentPageSpan', 'totalPagesSpan', 'lastRefreshTimeSpan', 'newEntriesCountSpan'
|
||||
];
|
||||
|
||||
|
||||
@@ -548,7 +548,7 @@ const ui = {
|
||||
},
|
||||
|
||||
setActiveContainer: (containerId) => {
|
||||
const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'zano', 'wow', 'bch'].map(id => `${id}-container`);
|
||||
const containerIds = ['btc', 'xmr', 'part', 'pivx', 'firo', 'dash', 'ltc', 'doge', 'eth', 'dcr', 'nmc', 'zano', 'wow', 'bch'].map(id => `${id}-container`);
|
||||
containerIds.forEach(id => {
|
||||
const container = document.getElementById(id);
|
||||
if (container) {
|
||||
|
||||
@@ -10,6 +10,7 @@ const COIN_NAME_TO_SYMBOL = {
|
||||
'Firo': 'FIRO',
|
||||
'Dash': 'DASH',
|
||||
'Decred': 'DCR',
|
||||
'Namecoin': 'NMC',
|
||||
'Wownero': 'WOW',
|
||||
'Bitcoin Cash': 'BCH',
|
||||
'Dogecoin': 'DOGE'
|
||||
@@ -383,8 +384,8 @@ const createSwapTableRow = async (swap) => {
|
||||
<div class="py-3 px-4 text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
<span class="inline-flex mr-3 align-middle items-center justify-center w-18 h-20 rounded">
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${swap.coin_from.replace(' ', '-')}.png"
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${swap.coin_from.replace(' ', '-')}.png"
|
||||
alt="${swap.coin_from}"
|
||||
onerror="this.src='/static/images/coins/default.png'">
|
||||
</span>
|
||||
@@ -392,8 +393,8 @@ const createSwapTableRow = async (swap) => {
|
||||
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"></path>
|
||||
</svg>
|
||||
<span class="inline-flex ml-3 align-middle items-center justify-center w-18 h-20 rounded">
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${swap.coin_to.replace(' ', '-')}.png"
|
||||
<img class="h-12"
|
||||
src="/static/images/coins/${swap.coin_to.replace(' ', '-')}.png"
|
||||
alt="${swap.coin_to}"
|
||||
onerror="this.src='/static/images/coins/default.png'">
|
||||
</span>
|
||||
@@ -421,7 +422,7 @@ const createSwapTableRow = async (swap) => {
|
||||
|
||||
<!-- Actions Column -->
|
||||
<td class="py-3 px-4 text-center">
|
||||
<a href="/bid/${swap.bid_id}"
|
||||
<a href="/bid/${swap.bid_id}"
|
||||
class="inline-block w-20 py-1 px-2 font-medium text-center text-sm rounded-md bg-blue-500 text-white border border-blue-500 hover:bg-blue-600 transition duration-200">
|
||||
Details
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user