feat: add offline indicator and increase CoinGecko cache to avoid rate limits
This commit is contained in:
@@ -88,6 +88,42 @@ export function setupGlobalErrorHandler() {
|
||||
console.error('Unhandled promise rejection:', event.reason)
|
||||
showErrorToast(event.reason?.message || 'Ein Fehler ist aufgetreten')
|
||||
})
|
||||
|
||||
// Offline/Online detection
|
||||
setupOfflineIndicator()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/hides offline indicator based on network status
|
||||
*/
|
||||
function setupOfflineIndicator() {
|
||||
const updateStatus = () => {
|
||||
let indicator = document.querySelector('.offline-indicator')
|
||||
|
||||
if (!navigator.onLine) {
|
||||
if (!indicator) {
|
||||
indicator = document.createElement('div')
|
||||
indicator.className = 'offline-indicator'
|
||||
indicator.innerHTML = `
|
||||
<span class="offline-icon">📡</span>
|
||||
<span class="offline-text">Offline</span>
|
||||
`
|
||||
document.body.appendChild(indicator)
|
||||
requestAnimationFrame(() => indicator.classList.add('visible'))
|
||||
}
|
||||
} else {
|
||||
if (indicator) {
|
||||
indicator.classList.remove('visible')
|
||||
setTimeout(() => indicator.remove(), 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('online', updateStatus)
|
||||
window.addEventListener('offline', updateStatus)
|
||||
|
||||
// Check on init
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,6 +250,40 @@ style.textContent = /* css */`
|
||||
.error-toast-close:hover {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
/* Offline Indicator */
|
||||
.offline-indicator {
|
||||
position: fixed;
|
||||
top: var(--space-md);
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-100px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
padding: var(--space-xs) var(--space-md);
|
||||
background: var(--color-bg-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-full);
|
||||
box-shadow: var(--shadow-md);
|
||||
z-index: 10001;
|
||||
opacity: 0;
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.offline-indicator.visible {
|
||||
transform: translateX(-50%) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.offline-indicator .offline-icon {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.offline-indicator .offline-text {
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-text);
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ const CURRENCY_SYMBOLS = {
|
||||
JPY: '¥'
|
||||
}
|
||||
|
||||
const CACHE_DURATION = 10 * 60 * 1000 // 10 minutes (CoinGecko free tier: 10-30 req/min)
|
||||
const MIN_REQUEST_INTERVAL = 6 * 1000 // 6 seconds between requests (max ~10/min)
|
||||
const CACHE_DURATION = 30 * 60 * 1000 // 30 minutes (CoinGecko free tier is strict)
|
||||
const MIN_REQUEST_INTERVAL = 60 * 1000 // 60 seconds between requests
|
||||
|
||||
let cachedRates = null
|
||||
let cacheTimestamp = 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE_NAME = 'dgray-v27';
|
||||
const CACHE_NAME = 'dgray-v28';
|
||||
const STATIC_ASSETS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
@@ -16,6 +16,8 @@ const STATIC_ASSETS = [
|
||||
'/js/components/chat-widget.js',
|
||||
'/js/components/listing-card.js',
|
||||
'/js/components/search-box.js',
|
||||
'/js/components/error-boundary.js',
|
||||
'/js/services/currency.js',
|
||||
'/locales/de.json',
|
||||
'/locales/en.json',
|
||||
'/locales/fr.json',
|
||||
|
||||
Reference in New Issue
Block a user