From 3c5e8481cdec4567c439efbd0fc3264b12ac829d Mon Sep 17 00:00:00 2001
From: nahuhh <50635951+nahuhh@users.noreply.github.com>
Date: Sat, 22 Feb 2025 02:30:16 +0000
Subject: [PATCH] bids/offers: responsive and styling tweaks
---
basicswap/static/js/bids_available.js | 6 +-
basicswap/static/js/bids_sentreceived.js | 159 ++++++++++++-----------
basicswap/static/js/offers.js | 24 ++--
basicswap/templates/bids.html | 47 +++----
basicswap/templates/offers.html | 23 ++--
5 files changed, 132 insertions(+), 127 deletions(-)
diff --git a/basicswap/static/js/bids_available.js b/basicswap/static/js/bids_available.js
index 921918e..b3b7e48 100644
--- a/basicswap/static/js/bids_available.js
+++ b/basicswap/static/js/bids_available.js
@@ -189,7 +189,7 @@ const formatAddress = (address, displayLength = 15) => {
const getTimeStrokeColor = (expireTime) => {
const now = Math.floor(Date.now() / 1000);
const timeLeft = expireTime - now;
-
+
if (timeLeft <= 300) return '#9CA3AF'; // 5 minutes or less
if (timeLeft <= 1800) return '#3B82F6'; // 30 minutes or less
return '#10B981'; // More than 30 minutes
@@ -781,7 +781,7 @@ async function updateBidsTable(options = {}) {
}
const totalPages = Math.ceil(state.jsonData.length / PAGE_SIZE);
-
+
if (resetPage && state.jsonData.length > 0) {
state.currentPage = 1;
}
@@ -861,7 +861,7 @@ if (elements.refreshBidsButton) {
updateLoadingState(true);
await new Promise(resolve => setTimeout(resolve, 500));
-
+
try {
await updateBidsTable({ resetPage: true, refreshData: true });
} finally {
diff --git a/basicswap/static/js/bids_sentreceived.js b/basicswap/static/js/bids_sentreceived.js
index 924aaf2..61e1522 100644
--- a/basicswap/static/js/bids_sentreceived.js
+++ b/basicswap/static/js/bids_sentreceived.js
@@ -192,7 +192,13 @@ const safeParseInt = (value) => {
return isNaN(parsed) ? 0 : parsed;
};
-const formatAddress = (address, displayLength = 15) => {
+const formatAddress = (address, displayLength = 20) => {
+ if (!address) return '';
+ if (address.length <= displayLength) return address;
+ return `${address.slice(8, displayLength)}...`;
+};
+
+const formatAddressSMSG = (address, displayLength = 14) => {
if (!address) return '';
if (address.length <= displayLength) return address;
return `${address.slice(0, displayLength)}...`;
@@ -218,17 +224,17 @@ const getTimeStrokeColor = (expireTime) => {
const getStatusClass = (status) => {
switch (status) {
case 'Completed':
- return 'bg-green-100 text-green-800 dark:bg-green-500 dark:text-white';
+ return 'bg-green-300 text-black dark:bg-green-600 dark:text-white';
case 'Expired':
- return 'bg-gray-100 text-gray-800 dark:bg-gray-400 dark:text-white';
- case 'Abandoned':
- return 'bg-red-100 text-red-800 dark:bg-red-500 dark:text-white';
+ return 'bg-gray-200 text-black dark:bg-gray-400 dark:text-white';
+ case 'Error':
+ return 'bg-red-300 text-black dark:bg-red-600 dark:text-white';
case 'Failed':
- return 'bg-rose-100 text-rose-800 dark:bg-rose-500 dark:text-white';
+ return 'bg-red-300 text-black dark:bg-red-600 dark:text-white';
case 'Failed, refunded':
- return 'bg-gray-100 text-orange-800 dark:bg-gray-400 dark:text-red-500';
+ return 'bg-gray-200 text-black dark:bg-gray-400 dark:text-red-500';
default:
- return 'bg-blue-100 text-blue-800 dark:bg-blue-500 dark:text-white';
+ return 'bg-blue-300 text-black dark:bg-blue-500 dark:text-white';
}
};
@@ -274,10 +280,10 @@ function hasActiveFilters() {
const hasNonDefaultCoinTo = coinToSelect && coinToSelect.value !== 'any';
const hasNonDefaultExpired = withExpiredSelect && withExpiredSelect.value !== 'true';
- return hasNonDefaultState ||
- hasSearchQuery ||
- hasNonDefaultCoinFrom ||
- hasNonDefaultCoinTo ||
+ return hasNonDefaultState ||
+ hasSearchQuery ||
+ hasNonDefaultCoinFrom ||
+ hasNonDefaultCoinTo ||
hasNonDefaultExpired;
}
@@ -305,7 +311,7 @@ function filterAndSortData(bids) {
const coinFromSelect = document.getElementById('coin_from');
const selectedOption = coinFromSelect?.querySelector(`option[value="${state.filters.coin_from}"]`);
const coinName = selectedOption?.textContent.trim();
-
+
if (coinName) {
const coinToMatch = state.currentTab === 'sent' ? bid.coin_from : bid.coin_to;
if (!coinMatches(coinToMatch, coinName)) {
@@ -318,7 +324,7 @@ function filterAndSortData(bids) {
const coinToSelect = document.getElementById('coin_to');
const selectedOption = coinToSelect?.querySelector(`option[value="${state.filters.coin_to}"]`);
const coinName = selectedOption?.textContent.trim();
-
+
if (coinName) {
const coinToMatch = state.currentTab === 'sent' ? bid.coin_to : bid.coin_from;
if (!coinMatches(coinToMatch, coinName)) {
@@ -334,7 +340,7 @@ function filterAndSortData(bids) {
const identity = IdentityManager.cache.get(bid.addr_from);
const label = identity?.data?.label || '';
const matchesLabel = label.toLowerCase().includes(searchStr);
-
+
if (!(matchesBidId || matchesIdentity || matchesLabel)) {
return false;
}
@@ -358,10 +364,10 @@ function updateCoinFilterImages() {
function updateButtonImage(select, button) {
if (!select || !button) return;
-
+
const selectedOption = select.options[select.selectedIndex];
const imagePath = selectedOption.getAttribute('data-image');
-
+
if (imagePath && select.value !== 'any') {
button.style.backgroundImage = `url(${imagePath})`;
button.style.backgroundSize = '25px';
@@ -385,7 +391,7 @@ const updateLoadingState = (isLoading) => {
const refreshButton = elements[`refresh${type}Bids`];
const refreshText = refreshButton?.querySelector(`#refresh${type}Text`);
const refreshIcon = refreshButton?.querySelector('svg');
-
+
if (refreshButton) {
refreshButton.disabled = isLoading;
if (isLoading) {
@@ -431,7 +437,7 @@ const updateConnectionStatus = (status) => {
};
const config = statusConfig[status] || statusConfig.connected;
-
+
['sent', 'received'].forEach(type => {
const dot = elements[`statusDot${type.charAt(0).toUpperCase() + type.slice(1)}`];
const text = elements[`statusText${type.charAt(0).toUpperCase() + type.slice(1)}`];
@@ -613,12 +619,12 @@ const createTableRow = async (bid) => {
const identity = await IdentityManager.getIdentityData(bid.addr_from);
const uniqueId = `${bid.bid_id}_${Date.now()}`;
const timeColor = getTimeStrokeColor(bid.expire_at);
-
+
return `
-
-
+
+
|
-
-
+ |
-
- ${state.currentTab === 'sent' ? 'Out' : 'In'}
+
-
|
-
-
- }.png)
+
+
- ${bid.amount_from}
- ${bid.coin_from}
+ ${state.currentTab === 'sent' ? bid.amount_to : bid.amount_from}
+ ${state.currentTab === 'sent' ? bid.coin_to : bid.coin_from}
|
-
-
- }.png)
+
+
- ${bid.amount_to}
- ${bid.coin_to}
+ ${state.currentTab === 'sent' ? bid.amount_from : bid.amount_to}
+ ${state.currentTab === 'sent' ? bid.coin_from : bid.coin_to}
|
-
-
-
+
+
${bid.bid_state}
@@ -688,11 +695,13 @@ const createTableRow = async (bid) => {
|
-
-
- View Bid
-
+ |
+
|
|
@@ -759,12 +768,12 @@ const updateTableContent = async (type) => {
const initializeTooltips = () => {
if (window.TooltipManager) {
window.TooltipManager.cleanup();
-
+
const tooltipTriggers = document.querySelectorAll('[data-tooltip-target]');
tooltipTriggers.forEach(trigger => {
const targetId = trigger.getAttribute('data-tooltip-target');
const tooltipContent = document.getElementById(targetId);
-
+
if (tooltipContent) {
window.TooltipManager.create(trigger, tooltipContent.innerHTML, {
placement: trigger.getAttribute('data-tooltip-placement') || 'top',
@@ -786,7 +795,7 @@ const fetchBids = async () => {
const endpoint = state.currentTab === 'sent' ? '/json/sentbids' : '/json/bids';
const withExpiredSelect = document.getElementById('with_expired');
const includeExpired = withExpiredSelect ? withExpiredSelect.value === 'true' : true;
-
+
console.log('Fetching bids, include expired:', includeExpired);
const response = await fetch(endpoint, {
@@ -814,7 +823,7 @@ const fetchBids = async () => {
state.filters.with_expired = includeExpired;
data = filterAndSortData(data);
-
+
return data;
} catch (error) {
console.error('Error in fetchBids:', error);
@@ -827,18 +836,18 @@ const updateBidsTable = async () => {
console.log('Already loading, skipping update');
return;
}
-
+
try {
console.log('Starting updateBidsTable for tab:', state.currentTab);
console.log('Current filters:', state.filters);
-
+
state.isLoading = true;
updateLoadingState(true);
const bids = await fetchBids();
-
+
console.log('Fetched bids:', bids.length);
-
+
const filteredBids = bids.filter(bid => {
// State filter
if (state.filters.state !== -1) {
@@ -860,7 +869,7 @@ const updateBidsTable = async () => {
const coinFromSelect = document.getElementById('coin_from');
const selectedOption = coinFromSelect?.querySelector(`option[value="${state.filters.coin_from}"]`);
const coinName = selectedOption?.textContent.trim();
-
+
if (coinName) {
const coinToMatch = state.currentTab === 'sent' ? bid.coin_from : bid.coin_to;
yourCoinMatch = coinMatches(coinToMatch, coinName);
@@ -876,7 +885,7 @@ const updateBidsTable = async () => {
const coinToSelect = document.getElementById('coin_to');
const selectedOption = coinToSelect?.querySelector(`option[value="${state.filters.coin_to}"]`);
const coinName = selectedOption?.textContent.trim();
-
+
if (coinName) {
const coinToMatch = state.currentTab === 'sent' ? bid.coin_to : bid.coin_from;
theirCoinMatch = coinMatches(coinToMatch, coinName);
@@ -896,11 +905,11 @@ const updateBidsTable = async () => {
const searchStr = state.filters.searchQuery.toLowerCase();
const matchesBidId = bid.bid_id.toLowerCase().includes(searchStr);
const matchesIdentity = bid.addr_from?.toLowerCase().includes(searchStr);
-
+
const identity = IdentityManager.cache.get(bid.addr_from);
const label = identity?.data?.label || '';
const matchesLabel = label.toLowerCase().includes(searchStr);
-
+
if (!(matchesBidId || matchesIdentity || matchesLabel)) {
return false;
}
@@ -981,7 +990,7 @@ function handleSearch(event) {
if (searchTimeout) {
clearTimeout(searchTimeout);
}
-
+
searchTimeout = setTimeout(() => {
state.filters.searchQuery = event.target.value.toLowerCase();
updateBidsTable();
@@ -1114,7 +1123,7 @@ function setupFilterEventListeners() {
if (searchTimeout) {
clearTimeout(searchTimeout);
}
-
+
searchTimeout = setTimeout(() => {
state.filters.searchQuery = event.target.value.toLowerCase();
updateBidsTable();
@@ -1178,7 +1187,7 @@ const setupEventListeners = () => {
elements.tabButtons.forEach(tab => {
const isSelected = tab.getAttribute('data-tabs-target') === targetId;
tab.setAttribute('aria-selected', isSelected);
-
+
if (isSelected) {
tab.classList.add('bg-gray-100', 'dark:bg-gray-600', 'text-gray-900', 'dark:text-white');
tab.classList.remove('hover:text-gray-600', 'hover:bg-gray-50', 'dark:hover:bg-gray-500');
@@ -1263,7 +1272,7 @@ const setupEventListeners = () => {
const stateValue = parseInt(filterElements.stateSelect.value);
state.filters.state = isNaN(stateValue) ? -1 : stateValue;
-
+
console.log('State filter changed:', {
selectedValue: filterElements.stateSelect.value,
parsedState: state.filters.state
@@ -1275,8 +1284,8 @@ const setupEventListeners = () => {
}
[
- filterElements.sortBySelect,
- filterElements.sortDirSelect,
+ filterElements.sortBySelect,
+ filterElements.sortDirSelect,
filterElements.withExpiredSelect
].forEach(element => {
if (element) {
@@ -1299,7 +1308,7 @@ const setupEventListeners = () => {
document.addEventListener('change', (event) => {
const target = event.target;
const filterForm = document.querySelector('.flex.flex-wrap.justify-center');
-
+
if (filterForm && filterForm.contains(target)) {
const formData = {
state: filterElements.stateSelect?.value,
@@ -1347,7 +1356,7 @@ const setupRefreshButtons = () => {
if (refreshButton) {
refreshButton.addEventListener('click', async () => {
const lowerType = type.toLowerCase();
-
+
if (state.isRefreshing) {
console.log('Already refreshing, skipping');
return;
@@ -1416,7 +1425,7 @@ document.addEventListener('DOMContentLoaded', () => {
WebSocketManager.initialize();
setupEventListeners();
- setupRefreshButtons();
+ setupRefreshButtons();
setupFilterEventListeners();
updateClearFiltersButton();
diff --git a/basicswap/static/js/offers.js b/basicswap/static/js/offers.js
index 7f3b30e..9ec63ae 100644
--- a/basicswap/static/js/offers.js
+++ b/basicswap/static/js/offers.js
@@ -200,7 +200,7 @@ const WebSocketManager = {
this.isPageHidden = false;
this.lastVisibilityChange = Date.now();
this.isIntentionallyClosed = false;
-
+
setTimeout(() => {
this.priceUpdatePaused = false;
if (!this.isConnected()) {
@@ -848,7 +848,7 @@ function continueInitialization() {
listingLabel.textContent = isSentOffers ? 'Total Listings: ' : 'Network Listings: ';
}
//console.log('Initialization completed');
-
+
}
function initializeTooltips() {
@@ -875,7 +875,7 @@ function filterAndSortData() {
localStorage.setItem('offersTableSettings', JSON.stringify({
coin_to: filters.coin_to,
- coin_from: filters.coin_from,
+ coin_from: filters.coin_from,
status: filters.status,
sent_from: filters.sent_from,
sortColumn: currentSortColumn,
@@ -936,7 +936,7 @@ function filterAndSortData() {
const calculateValue = offer => {
const fromUSD = parseFloat(offer.amount_from) * getPrice(offer.coin_from);
const toUSD = parseFloat(offer.amount_to) * getPrice(offer.coin_to);
- return (isSentOffers || offer.is_own_offer) ?
+ return (isSentOffers || offer.is_own_offer) ?
((toUSD / fromUSD) - 1) * 100 :
((fromUSD / toUSD) - 1) * 100;
};
@@ -967,7 +967,7 @@ function filterAndSortData() {
return currentSortDirection === 'desc' ? -comparison : comparison;
});
}
-
+
return filteredData;
}
@@ -1081,7 +1081,7 @@ async function fetchLatestPrices() {
const existingCache = CacheManager.get(PRICES_CACHE_KEY, true);
const fallbackData = existingCache ? existingCache.value : null;
const url = `${offersConfig.apiEndpoints.coinGecko}/simple/price?ids=bitcoin,bitcoin-cash,dash,dogecoin,decred,litecoin,particl,pivx,monero,zano,wownero,zcoin&vs_currencies=USD,BTC&api_key=${offersConfig.apiKeys.coinGecko}`;
-
+
const response = await fetch('/json/readurl', {
method: 'POST',
headers: {
@@ -1102,7 +1102,7 @@ async function fetchLatestPrices() {
}
const data = await response.json();
-
+
if (data.Error) {
if (fallbackData) {
return fallbackData;
@@ -1177,7 +1177,7 @@ async function fetchOffers() {
const data = await offersResponse.json();
const processedData = Array.isArray(data) ? data : Object.values(data);
-
+
jsonData = formatInitialData(processedData);
originalJsonData = [...jsonData];
@@ -2502,7 +2502,7 @@ if (refreshButton) {
const currentTime = Date.now();
const elapsedTime = currentTime - startTime;
const remainingTime = Math.ceil((REFRESH_COOLDOWN - elapsedTime) / 1000);
-
+
if (remainingTime <= 0) {
clearInterval(countdownInterval);
refreshText.textContent = 'Refresh';
@@ -2527,7 +2527,7 @@ if (refreshButton) {
try {
const cachedPrices = CacheManager.get('prices_coingecko');
- let previousPrices = cachedPrices ? cachedPrices.value : null;
+ const previousPrices = cachedPrices ? cachedPrices.value : null;
CacheManager.clear();
window.isManualRefresh = true;
const endpoint = isSentOffers ? '/json/sentoffers' : '/json/offers';
@@ -2660,7 +2660,7 @@ function handleTableSort(columnIndex, header) {
if (window.sortTimeout) {
clearTimeout(window.sortTimeout);
}
-
+
window.sortTimeout = setTimeout(() => {
applyFilters();
}, 100);
@@ -2719,7 +2719,7 @@ function loadSavedSettings() {
const saved = localStorage.getItem('offersTableSettings');
if (saved) {
const settings = JSON.parse(saved);
-
+
['coin_to', 'coin_from', 'status', 'sent_from'].forEach(id => {
const element = document.getElementById(id);
if (element && settings[id]) element.value = settings[id];
diff --git a/basicswap/templates/bids.html b/basicswap/templates/bids.html
index ea27b9f..29589be 100644
--- a/basicswap/templates/bids.html
+++ b/basicswap/templates/bids.html
@@ -1,9 +1,9 @@
{% include 'header.html' %}
{% from 'style.html' import breadcrumb_line_svg, page_back_svg, page_forwards_svg, filter_clear_svg, filter_apply_svg, circular_arrows_svg, input_arrow_down_svg, arrow_right_svg %}
-
+
-
+

@@ -49,7 +49,10 @@
-
+