add currency service, update directus setup
This commit is contained in:
205
js/services/currency.js
Normal file
205
js/services/currency.js
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Currency Service - XMR/Fiat Conversion
|
||||
*
|
||||
* Uses Kraken API for real-time exchange rates
|
||||
* Supports two modes: fiat-fix and xmr-fix
|
||||
*/
|
||||
|
||||
const KRAKEN_API = 'https://api.kraken.com/0/public/Ticker';
|
||||
|
||||
const PAIRS = {
|
||||
USD: 'XXMRZUSD',
|
||||
EUR: 'XXMRZEUR',
|
||||
GBP: 'XXMRZGBP',
|
||||
CHF: 'XMRCHF',
|
||||
JPY: 'XMRJPY'
|
||||
};
|
||||
|
||||
const CURRENCY_SYMBOLS = {
|
||||
XMR: 'ɱ',
|
||||
EUR: '€',
|
||||
USD: '$',
|
||||
GBP: '£',
|
||||
CHF: 'CHF',
|
||||
JPY: '¥'
|
||||
};
|
||||
|
||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
let cachedRates = null;
|
||||
let cacheTimestamp = 0;
|
||||
|
||||
/**
|
||||
* Fetches current XMR rates from Kraken
|
||||
* @returns {Promise<Object>} Rates per currency (e.g. { EUR: 150.5, USD: 165.2 })
|
||||
*/
|
||||
export async function getXmrRates() {
|
||||
// Check cache
|
||||
if (cachedRates && Date.now() - cacheTimestamp < CACHE_DURATION) {
|
||||
return cachedRates;
|
||||
}
|
||||
|
||||
try {
|
||||
const pairs = Object.values(PAIRS).join(',');
|
||||
const response = await fetch(`${KRAKEN_API}?pair=${pairs}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error && data.error.length > 0) {
|
||||
console.error('Kraken API Error:', data.error);
|
||||
return cachedRates || getDefaultRates();
|
||||
}
|
||||
|
||||
const rates = {};
|
||||
for (const [currency, pair] of Object.entries(PAIRS)) {
|
||||
const ticker = data.result[pair];
|
||||
if (ticker) {
|
||||
rates[currency] = parseFloat(ticker.c[0]); // Last trade price
|
||||
}
|
||||
}
|
||||
|
||||
// Update cache
|
||||
cachedRates = rates;
|
||||
cacheTimestamp = Date.now();
|
||||
|
||||
return rates;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch XMR rates:', error);
|
||||
return cachedRates || getDefaultRates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback rates if API is unreachable
|
||||
*/
|
||||
function getDefaultRates() {
|
||||
return {
|
||||
EUR: 150,
|
||||
USD: 165,
|
||||
GBP: 130,
|
||||
CHF: 145,
|
||||
JPY: 24000
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts amount to XMR
|
||||
* @param {number} amount - Amount in source currency
|
||||
* @param {string} currency - Source currency (EUR, USD, etc.)
|
||||
* @param {Object} rates - Rates from getXmrRates()
|
||||
* @returns {number} Amount in XMR
|
||||
*/
|
||||
export function convertToXmr(amount, currency, rates) {
|
||||
if (currency === 'XMR') return amount;
|
||||
if (!rates[currency]) return amount;
|
||||
return amount / rates[currency];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts XMR to fiat
|
||||
* @param {number} xmrAmount - Amount in XMR
|
||||
* @param {string} currency - Target currency (EUR, USD, etc.)
|
||||
* @param {Object} rates - Rates from getXmrRates()
|
||||
* @returns {number} Amount in target currency
|
||||
*/
|
||||
export function convertFromXmr(xmrAmount, currency, rates) {
|
||||
if (currency === 'XMR') return xmrAmount;
|
||||
if (!rates[currency]) return xmrAmount;
|
||||
return xmrAmount * rates[currency];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a price for display
|
||||
* @param {Object} listing - Listing with price, currency, price_mode
|
||||
* @param {Object} rates - Rates from getXmrRates()
|
||||
* @returns {Object} { primary, secondary, xmrAmount }
|
||||
*/
|
||||
export function formatPrice(listing, rates) {
|
||||
const { price, currency, price_mode } = listing;
|
||||
|
||||
if (!price || price === 0) {
|
||||
return {
|
||||
primary: 'Free',
|
||||
secondary: null,
|
||||
xmrAmount: 0
|
||||
};
|
||||
}
|
||||
|
||||
// XMR mode: XMR is the reference price
|
||||
if (price_mode === 'xmr' || currency === 'XMR') {
|
||||
const xmrPrice = currency === 'XMR' ? price : convertToXmr(price, currency, rates);
|
||||
const fiatEquivalent = currency !== 'XMR' ? price : convertFromXmr(price, 'EUR', rates);
|
||||
|
||||
return {
|
||||
primary: formatXmr(xmrPrice),
|
||||
secondary: currency !== 'XMR' ? `≈ ${formatFiat(price, currency)}` : `≈ ${formatFiat(fiatEquivalent, 'EUR')}`,
|
||||
xmrAmount: xmrPrice
|
||||
};
|
||||
}
|
||||
|
||||
// Fiat mode: Fiat is the reference price
|
||||
const xmrEquivalent = convertToXmr(price, currency, rates);
|
||||
|
||||
return {
|
||||
primary: formatFiat(price, currency),
|
||||
secondary: `≈ ${formatXmr(xmrEquivalent)}`,
|
||||
xmrAmount: xmrEquivalent
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats XMR amount
|
||||
* @param {number} amount - Amount in XMR
|
||||
* @returns {string} Formatted string (e.g. "0.5234 XMR")
|
||||
*/
|
||||
export function formatXmr(amount) {
|
||||
if (amount >= 1) {
|
||||
return `${amount.toFixed(4)} XMR`;
|
||||
}
|
||||
return `${amount.toFixed(6)} XMR`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats fiat amount
|
||||
* @param {number} amount - Amount
|
||||
* @param {string} currency - Currency
|
||||
* @returns {string} Formatted string (e.g. "€ 150,00")
|
||||
*/
|
||||
export function formatFiat(amount, currency) {
|
||||
const symbol = CURRENCY_SYMBOLS[currency] || currency;
|
||||
|
||||
const formatted = new Intl.NumberFormat('de-DE', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(amount);
|
||||
|
||||
// Symbol before or after amount
|
||||
if (['EUR', 'GBP', 'USD'].includes(currency)) {
|
||||
return `${symbol} ${formatted}`;
|
||||
}
|
||||
return `${formatted} ${symbol}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency symbol
|
||||
* @param {string} currency - Currency code
|
||||
* @returns {string} Symbol
|
||||
*/
|
||||
export function getCurrencySymbol(currency) {
|
||||
return CURRENCY_SYMBOLS[currency] || currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of supported currencies
|
||||
*/
|
||||
export const SUPPORTED_CURRENCIES = ['XMR', 'EUR', 'CHF', 'USD', 'GBP', 'JPY'];
|
||||
|
||||
export default {
|
||||
getXmrRates,
|
||||
convertToXmr,
|
||||
convertFromXmr,
|
||||
formatPrice,
|
||||
formatXmr,
|
||||
formatFiat,
|
||||
getCurrencySymbol,
|
||||
SUPPORTED_CURRENCIES
|
||||
};
|
||||
Reference in New Issue
Block a user