From 8b45a281be9091984f614fab4ada67ca013bd8ab Mon Sep 17 00:00:00 2001 From: Schalli Date: Tue, 22 Sep 2026 08:21:23 +0200 Subject: [PATCH] fix(dashboard): Bilderrahmen - "1 Stunde" statt "60 Minuten", Bildanzahl in der Einstellungs-Kopfzeile Zwei Kosmetik-Punkte nach dem Browser-Rundgang vom 21.09.2026: - Das laengste Wechselintervall (3600 s) hiess "60 Minuten", beim XFrame heisst dieselbe Stufe "Jede Stunde". Neuer Schluessel `pictureFrame.intervalHours` (ICU-Plural, de + en). - Unter Einstellungen -> Dashboard zeigte "XFrame #1 - Board" seinen Titel, "Bilderrahmen #1" nichts. Die Kopfzeile nennt jetzt "- 1 Bild" bzw. "- N Bilder" (Schluessel `imageCountOne`/`imageCountMany`, zwei Schluessel statt ICU, weil die Panel-Tests eine einfache Uebersetzungs-Attrappe nutzen). Web-Tests 603 -> 604, type-check und lint unveraendert gruen. Co-Authored-By: Claude Opus 5 (1M context) --- .../picture-frame-config-form.test.tsx | 2 ++ .../settings/picture-frame-config-form.tsx | 2 ++ .../settings/widget-settings-panel.test.tsx | 22 +++++++++++++++++++ .../settings/widget-settings-panel.tsx | 13 +++++++++++ apps/web/src/messages/de.json | 3 +++ apps/web/src/messages/en.json | 3 +++ 6 files changed, 45 insertions(+) diff --git a/apps/web/src/components/settings/picture-frame-config-form.test.tsx b/apps/web/src/components/settings/picture-frame-config-form.test.tsx index 508a12b..ae9a2c8 100644 --- a/apps/web/src/components/settings/picture-frame-config-form.test.tsx +++ b/apps/web/src/components/settings/picture-frame-config-form.test.tsx @@ -66,6 +66,8 @@ describe('PictureFrameConfigForm (quick-260921-pi9)', () => { expect(Array.from(interval.options).map((o) => o.textContent)).toContain('5 Sekunden'); expect(Array.from(interval.options).map((o) => o.textContent)).toContain('30 Minuten'); expect(Array.from(interval.options).map((o) => o.textContent)).toContain('1 Minute'); + expect(Array.from(interval.options).map((o) => o.textContent)).toContain('1 Stunde'); + expect(Array.from(interval.options).map((o) => o.textContent)).not.toContain('60 Minuten'); fireEvent.change(fit, { target: { value: 'cover' } }); expect(onChange).toHaveBeenLastCalledWith({ fit: 'cover' }); diff --git a/apps/web/src/components/settings/picture-frame-config-form.tsx b/apps/web/src/components/settings/picture-frame-config-form.tsx index 0462815..160dd6a 100644 --- a/apps/web/src/components/settings/picture-frame-config-form.tsx +++ b/apps/web/src/components/settings/picture-frame-config-form.tsx @@ -128,6 +128,8 @@ export function PictureFrameConfigForm({ config, onChange }: PictureFrameConfigF function intervalLabel(seconds: number): string { if (seconds === 0) return t('pictureFrame.intervalOff'); if (seconds < 60) return t('pictureFrame.intervalSeconds', { n: seconds }); + // 3600 s heisst wie beim XFrame „1 Stunde“, nicht „60 Minuten“. + if (seconds >= 3600) return t('pictureFrame.intervalHours', { n: seconds / 3600 }); return t('pictureFrame.intervalMinutes', { n: seconds / 60 }); } diff --git a/apps/web/src/components/settings/widget-settings-panel.test.tsx b/apps/web/src/components/settings/widget-settings-panel.test.tsx index b4a867d..c9b2f6c 100644 --- a/apps/web/src/components/settings/widget-settings-panel.test.tsx +++ b/apps/web/src/components/settings/widget-settings-panel.test.tsx @@ -263,3 +263,25 @@ describe('WidgetSettingsPanel — XFrame (quick-260921-qd3)', () => { expect(updateWidgetConfig).toHaveBeenCalledWith('x1', { url: 'https://b.de/' }); }); }); + +describe('WidgetSettingsPanel — Bilderrahmen-Kopfzeile (Kosmetik nach quick-260921-pi9)', () => { + it('Test P1: Kopfzeile zeigt "— 1 Bild" bzw. "— 3 Bilder", ohne Bilder keinen Zusatz', () => { + const one = { id: 'p1', widgetType: 'picture-frame', config: { images: [{ kind: 'url', url: 'https://a.de/x.png' }] } }; + const three = { + id: 'p2', + widgetType: 'picture-frame', + config: { + images: [ + { kind: 'url', url: 'https://a.de/1.png' }, + { kind: 'upload', imageId: 'b' }, + { kind: 'url', url: 'https://a.de/3.png' }, + ], + }, + }; + const none = { id: 'p3', widgetType: 'picture-frame', config: {} }; + render(); + expect(screen.getByRole('button', { name: /Bilderrahmen #1/ })).toHaveTextContent('— 1 Bild'); + expect(screen.getByRole('button', { name: /Bilderrahmen #2/ })).toHaveTextContent('— 3 Bilder'); + expect(screen.getByRole('button', { name: /Bilderrahmen #3/ })).not.toHaveTextContent('—'); + }); +}); diff --git a/apps/web/src/components/settings/widget-settings-panel.tsx b/apps/web/src/components/settings/widget-settings-panel.tsx index c3e4310..bc9146a 100644 --- a/apps/web/src/components/settings/widget-settings-panel.tsx +++ b/apps/web/src/components/settings/widget-settings-panel.tsx @@ -18,6 +18,7 @@ import { CALENDAR_MAX_EVENTS_LIMIT, resolveCalendarConfig, } from '@/components/dashboard/widgets/calendar-month'; +import { resolvePictureFrameConfig } from '@/components/dashboard/widgets/picture-frame-config'; /** * IANA timezones offered for clock configuration (D-12). @@ -128,6 +129,18 @@ export function WidgetSettingsPanel({ — {widget.config.title.trim()} )} + {/* Bilderrahmen hat keinen Titel — die Kopfzeile nennt die Bildanzahl */} + {widget.widgetType === 'picture-frame' && + resolvePictureFrameConfig(widget.config).images.length > 0 && ( + + —{' '} + {resolvePictureFrameConfig(widget.config).images.length === 1 + ? t('pictureFrame.imageCountOne') + : t('pictureFrame.imageCountMany', { + n: resolvePictureFrameConfig(widget.config).images.length, + })} + + )}