-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
231 lines (198 loc) · 10.2 KB
/
script.js
File metadata and controls
231 lines (198 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
let translations = {};
// current exchange rate (null when not loaded)
let exchangeRate = null;
// Load user's preferred language
const userLanguage = navigator.language.startsWith("de") ? "de" : "en";
// Load localization file
async function loadLocale(lang) {
try {
const response = await fetch(`locales/${lang}.json`);
translations = await response.json();
localizePage();
} catch (error) {
console.error("Error loading locale file:", error);
}
}
// Apply translations to the page
function localizePage() {
document.getElementById("sourceLabel").textContent = translations.sourceLabel;
document.getElementById("targetLabel").textContent = translations.targetLabel;
document.getElementById("priceLabel").textContent = translations.priceLabel;
document.getElementById("weightLabel").textContent = translations.weightLabel;
document.getElementById("unitWeightLabel").textContent = translations.unitWeightLabel;
document.getElementById("exchangeRateLabel").textContent = translations.exchangeRateLabel;
// initialize optional summary label (static title)
const optionalSummary = document.getElementById("optionalSummary");
if (optionalSummary && translations.optionalSummaryTitle) {
optionalSummary.textContent = translations.optionalSummaryTitle;
}
// localize reset button tooltip / aria-label if present
const resetBtn = document.getElementById('resetButton');
if (resetBtn && translations.resetTooltip) {
resetBtn.title = translations.resetTooltip;
resetBtn.setAttribute('aria-label', translations.resetTooltip);
}
// localize bankenrate label if present
const bankenrateLabel = document.getElementById('bankenrateLabel');
if (bankenrateLabel && translations.bankenrateLabel) {
bankenrateLabel.textContent = translations.bankenrateLabel;
}
}
// Save currency settings to localStorage
function saveCurrencySettings() {
const sourceCurrency = document.getElementById("sourceCurrency").value;
const targetCurrency = document.getElementById("targetCurrency").value;
localStorage.setItem("sourceCurrency", sourceCurrency);
localStorage.setItem("targetCurrency", targetCurrency);
}
// Load saved currency settings from localStorage
function loadCurrencySettings() {
const sourceCurrency = localStorage.getItem("sourceCurrency") || "PLN";
const targetCurrency = localStorage.getItem("targetCurrency") || "EUR";
document.getElementById("sourceCurrency").value = sourceCurrency;
document.getElementById("targetCurrency").value = targetCurrency;
}
// Internal function that actually fetches and applies the exchange rate
async function fetchAndApplyExchangeRate() {
const sourceCurrency = document.getElementById("sourceCurrency").value;
const targetCurrency = document.getElementById("targetCurrency").value;
// replace labels with currency (safely)
const priceLabelEl = document.getElementById("priceLabel");
const weightLabelEl = document.getElementById("weightLabel");
const unitWeightLabelEl = document.getElementById("unitWeightLabel");
if (priceLabelEl) priceLabelEl.textContent = translations.priceLabel.replace("{sourceCurrency}", `${sourceCurrency}`);
if (weightLabelEl) weightLabelEl.textContent = translations.weightLabel.replace("{sourceCurrency}", `${sourceCurrency}`);
if (unitWeightLabelEl) unitWeightLabelEl.textContent = translations.unitWeightLabel.replace("{targetCurrency}", `${targetCurrency}`);
try {
const response = await fetch(`https://api.frankfurter.dev/v2/rates?base=${sourceCurrency}"es=${targetCurrency}`);
if (!response.ok) throw new Error("Failed to fetch exchange rate");
const data = await response.json();
exchangeRate = data[0]?.rate;
const exchangeTimestamp = data[0]?.date
? new Date(data[0].date).toLocaleString("de-DE", {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
})
: 'Unknown';
// Save to local storage
localStorage.setItem('exchangeRate', JSON.stringify({ rate: exchangeRate, timestamp: exchangeTimestamp }));
const exchangeRateEl = document.getElementById("exchangeRate");
const exchangeInfoEl = document.getElementById("exchangeInfo");
if (exchangeRate && exchangeRateEl) {
exchangeRateEl.value = `1 ${sourceCurrency} = ${exchangeRate.toFixed(4)} ${targetCurrency}`;
}
if (exchangeInfoEl) {
const lastUpdatedText = translations.lastUpdated ? translations.lastUpdated.replace("{exchangeTimestamp}", exchangeTimestamp) : `Last updated: ${exchangeTimestamp}`;
exchangeInfoEl.textContent = lastUpdatedText;
}
performCalculations(); // Recalculate based on the new rate
} catch (error) {
console.error("Error updating exchange rate:", error);
// Load from local storage
const savedData = JSON.parse(localStorage.getItem('exchangeRate'));
const exchangeRateEl = document.getElementById("exchangeRate");
const exchangeInfoEl = document.getElementById("exchangeInfo");
if (savedData) {
exchangeRate = savedData.rate;
const exchangeTimestamp = savedData.timestamp;
if (exchangeRateEl) exchangeRateEl.value = `1 ${sourceCurrency} = ${exchangeRate.toFixed(4)} ${targetCurrency}`;
if (exchangeInfoEl) {
const lastUpdatedText = translations.lastUpdated ? translations.lastUpdated.replace("{exchangeTimestamp}", exchangeTimestamp) : `Last updated: ${exchangeTimestamp}`;
exchangeInfoEl.textContent = lastUpdatedText;
}
performCalculations(); // Recalculate based on the saved rate
} else {
if (exchangeRateEl) exchangeRateEl.value = "Exchange rate data not available";
if (exchangeInfoEl) exchangeInfoEl.textContent = "Last updated: Unknown";
}
}
}
// Debounced wrapper to avoid rapid repeated API calls from UI events
function updateExchangeRate() {
if (updateExchangeRate._timer) clearTimeout(updateExchangeRate._timer);
// schedule actual fetch after a short delay (coalesce rapid calls)
updateExchangeRate._timer = setTimeout(() => {
fetchAndApplyExchangeRate().catch(err => console.error(err));
updateExchangeRate._timer = null;
}, 50);
}
// Perform calculations
function performCalculations() {
// normalize numeric input (allow comma as decimal separator)
function parseNumberInput(elId) {
const el = document.getElementById(elId);
if (!el) return 0;
const raw = (el.value || '').toString().trim();
if (!raw) return 0;
// replace comma with dot for parseFloat
const normalized = raw.replace(',', '.');
const n = parseFloat(normalized);
return Number.isFinite(n) ? n : 0;
}
const price = parseNumberInput('price');
const weight = parseNumberInput('weight');
const unitWeight = parseNumberInput('unitWeight');
const bankenrate = parseNumberInput('bankenrate');
const sourceCurrency = document.getElementById("sourceCurrency").value;
const targetCurrency = document.getElementById("targetCurrency").value;
// Apply bank markup to exchange rate (positive % = fee reduces rate, negative % = discount increases rate)
const rateWithMarkup = exchangeRate * (1 - bankenrate / 100);
let result = "";
if (price && exchangeRate) {
const convertedPrice = (price * rateWithMarkup).toFixed(2);
result += `${translations.convertedPrice.replace("{sourceCurrency}", sourceCurrency)
.replace("{targetCurrency}", targetCurrency)
.replace("{price}", price)
.replace("{convertedPrice}", convertedPrice)}<br>`;
if (weight) {
const pricePerKg = ((price / weight) * 1000 * rateWithMarkup).toFixed(2);
result += `${translations.pricePerKg.replace("{pricePerKg}", pricePerKg)
.replace("{targetCurrency}", targetCurrency)}<br>`;
}
if (unitWeight) {
const unitPrice = ((price / weight) * unitWeight * rateWithMarkup).toFixed(2);
result += `${translations.unitPrice.replace("{unitWeight}", unitWeight)
.replace("{unitPrice}", unitPrice)
.replace("{targetCurrency}", targetCurrency)}<br>`;
}
}
document.getElementById("output").innerHTML = result;
}
// Update the collapsed optional summary text based on current optional inputs
// Note: dynamic optional summary removed; the <summary> shows a static localized title and native
// expand/collapse behavior is used.
function onOptionalInput() {
performCalculations();
}
// Reset only user inputs (price, weight, unitWeight, bankenrate) but keep currency settings
function resetInputs() {
const priceEl = document.getElementById('price');
const weightEl = document.getElementById('weight');
const unitWeightEl = document.getElementById('unitWeight');
const bankenrateEl = document.getElementById('bankenrate');
const outputEl = document.getElementById('output');
if (priceEl) priceEl.value = '';
if (weightEl) weightEl.value = '';
if (unitWeightEl) unitWeightEl.value = '';
if (bankenrateEl) bankenrateEl.value = '';
if (outputEl) outputEl.innerHTML = '';
// keep currency settings in localStorage unchanged
performCalculations();
// Focus on price input for new input
if (priceEl) priceEl.focus();
}
// Initialize the app (wait for DOM ready before touching DOM)
(async function initializeApp() {
if (document.readyState === 'loading') {
await new Promise(resolve => document.addEventListener('DOMContentLoaded', resolve));
}
await loadLocale(userLanguage);
loadCurrencySettings();
// initial exchange rate fetch (debounced wrapper)
updateExchangeRate();
})();