diff --git a/frontend/src/dialogues/falukant/MoneyHistoryGraphDialog.vue b/frontend/src/dialogues/falukant/MoneyHistoryGraphDialog.vue index c3ce6ba..da805fc 100644 --- a/frontend/src/dialogues/falukant/MoneyHistoryGraphDialog.vue +++ b/frontend/src/dialogues/falukant/MoneyHistoryGraphDialog.vue @@ -32,13 +32,46 @@ {{ $t('falukant.moneyHistory.graph.noData') }}
- + + + + + {{ label.text }} + + + + + + + {{ label.text }} + + + + + + + +
@@ -59,6 +92,10 @@ export default { graphRange: '24h', graphData: [], graphLoading: false, + _minX: null, + _maxX: null, + _minY: null, + _maxY: null, } }, computed: { @@ -70,19 +107,52 @@ export default { if (d.moneyBefore != null) return Number(d.moneyBefore) return 0 }) - const minX = Math.min(...xs) - const maxX = Math.max(...xs) - const minY = Math.min(...ys) - const maxY = Math.max(...ys) - const spanX = maxX - minX || 1 - const spanY = maxY - minY || 1 + this._minX = Math.min(...xs) + this._maxX = Math.max(...xs) + this._minY = Math.min(...ys) + this._maxY = Math.max(...ys) + const spanX = this._maxX - this._minX || 1 + const spanY = this._maxY - this._minY || 1 return xs.map((x, i) => { - const normX = ((x - minX) / spanX) * 100 - const normY = 40 - ((ys[i] - minY) / spanY) * 35 - 2 // etwas Rand oben/unten + const normX = 8 + ((x - this._minX) / spanX) * 90 // 8-98 Bereich für X + const normY = 42 - ((ys[i] - this._minY) / spanY) * 38 // 2-42 Bereich für Y return `${normX.toFixed(2)},${normY.toFixed(2)}` }).join(' ') }, + yAxisLabels() { + if (!this.graphData.length || !this._minY || !this._maxY) return [] + const labels = [] + const numLabels = 5 + const span = this._maxY - this._minY || 1 + + for (let i = 0; i <= numLabels; i++) { + const value = this._minY + (span * i / numLabels) + const y = 42 - (i / numLabels) * 38 + labels.push({ + y: y + 1.5, // Zentrierung + text: this.formatMoney(value) + }) + } + return labels + }, + xAxisLabels() { + if (!this.graphData.length || !this._minX || !this._maxX) return [] + const labels = [] + const numLabels = 5 + const span = this._maxX - this._minX || 1 + + for (let i = 0; i <= numLabels; i++) { + const timestamp = this._minX + (span * i / numLabels) + const x = 8 + (i / numLabels) * 90 + const date = new Date(timestamp) + labels.push({ + x: x, + text: this.formatDate(date) + }) + } + return labels + }, }, methods: { open() { @@ -96,6 +166,11 @@ export default { range: this.graphRange, }) this.graphData = Array.isArray(response.data) ? response.data : [] + // Reset min/max für computed properties + this._minX = null + this._maxX = null + this._minY = null + this._maxY = null } catch (error) { console.error('Error loading money history graph data:', error) this.graphData = [] @@ -103,6 +178,35 @@ export default { this.graphLoading = false } }, + formatMoney(amount) { + return new Intl.NumberFormat(navigator.language, { + minimumFractionDigits: 0, + maximumFractionDigits: 0, + style: 'currency', + currency: 'EUR' + }).format(amount) + }, + formatDate(date) { + const now = new Date() + const diffMs = now - date + const diffHours = diffMs / (1000 * 60 * 60) + + if (diffHours < 24) { + // Heute: nur Uhrzeit + return date.toLocaleTimeString(navigator.language, { hour: '2-digit', minute: '2-digit' }) + } else if (diffHours < 48) { + // Gestern: "Gestern" + Uhrzeit + return this.$t('falukant.moneyHistory.graph.yesterday') + ' ' + date.toLocaleTimeString(navigator.language, { hour: '2-digit', minute: '2-digit' }) + } else { + // Älter: Datum + Uhrzeit + return date.toLocaleString(navigator.language, { + day: '2-digit', + month: '2-digit', + hour: '2-digit', + minute: '2-digit' + }) + } + }, }, } @@ -141,6 +245,19 @@ export default { border-radius: 4px; } +.axis-label { + font-size: 2.5px; + fill: #333; +} + +.y-label { + dominant-baseline: middle; +} + +.x-label { + dominant-baseline: hanging; +} + .graph-loading, .graph-no-data { margin: 1rem 0; diff --git a/frontend/src/i18n/locales/de/falukant.json b/frontend/src/i18n/locales/de/falukant.json index 00bceb1..7262285 100644 --- a/frontend/src/i18n/locales/de/falukant.json +++ b/frontend/src/i18n/locales/de/falukant.json @@ -587,6 +587,7 @@ "close": "Schließen", "loading": "Lade Verlauf...", "noData": "Für den gewählten Zeitraum liegen keine Buchungen vor.", + "yesterday": "Gestern", "range": { "label": "Zeitraum", "today": "Heute", diff --git a/frontend/src/i18n/locales/en/falukant.json b/frontend/src/i18n/locales/en/falukant.json index afe0335..1b3c98d 100644 --- a/frontend/src/i18n/locales/en/falukant.json +++ b/frontend/src/i18n/locales/en/falukant.json @@ -117,6 +117,7 @@ "close": "Close", "loading": "Loading history...", "noData": "No entries for the selected period.", + "yesterday": "Yesterday", "range": { "label": "Range", "today": "Today",