From 5ce0b6edc3fef41f2f22dd585a668f471ac47a2e Mon Sep 17 00:00:00 2001 From: Luca <102960244+Luca-Timo@users.noreply.github.com> Date: Wed, 27 May 2026 16:06:35 +0200 Subject: [PATCH] fix(quote-response): compute minutes-remaining for the DE changeWithin string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous fix (45f0606) papered over the bug by changing the German wording from "innerhalb von {{minutes}} Minuten" to "bis {{at}}" — that worked but changed the UX intent. The original German wording ("you have N minutes left") was deliberate and clearer than an absolute clock time; the actual bug was that no caller ever computed `minutes` from `responseLockedAt`. Revert the DE translation to its original wording, then build a { at, minutes } object at the call site so EN ("until {{at}}") and DE ("innerhalb von {{minutes}} Minuten") each pick up the variable they need. `minutes` rounds UP so a 14m 32s remainder displays as "15 Minuten" rather than promising 14 the customer can't actually hit. --- frontend/src/i18n/locales/de.json | 2 +- frontend/src/pages/public/QuoteResponsePage.tsx | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index d8804c28..11dea9ad 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -3798,7 +3798,7 @@ "acceptedLocked": "Dieses Angebot wurde bereits angenommen.", "declinedLocked": "Dieses Angebot wurde abgelehnt.", "cannotRespond": "Es ist nicht mehr möglich, auf dieses Angebot zu antworten.", - "changeWithin": "Sie können Ihre Antwort bis {{at}} ändern.", + "changeWithin": "Sie können Ihre Antwort innerhalb von {{minutes}} Minuten ändern.", "intro": "Vielen Dank für Ihre Anfrage. Bitte prüfen Sie das folgende Angebot und antworten Sie unten.", "accept": "Angebot annehmen", "decline": "Angebot ablehnen" diff --git a/frontend/src/pages/public/QuoteResponsePage.tsx b/frontend/src/pages/public/QuoteResponsePage.tsx index 212ed383..4d651e18 100644 --- a/frontend/src/pages/public/QuoteResponsePage.tsx +++ b/frontend/src/pages/public/QuoteResponsePage.tsx @@ -297,7 +297,22 @@ export const QuoteResponsePage: React.FC = () => { <>

{quote.respondedAt - ? t('quoteResponse.changeWithin', 'You can change your response until {{at}}.', { at: quote.responseLockedAt ? new Date(quote.responseLockedAt).toLocaleTimeString() : '' }) + ? t('quoteResponse.changeWithin', 'You can change your response until {{at}}.', (() => { + // Provide both variables so EN ("until {{at}}") + // and DE ("innerhalb von {{minutes}} Minuten") + // each render correctly without needing locale- + // specific call sites. `minutes` rounds UP so a + // 14m 32s remainder shows as "15 Minuten" — never + // promise a number the user can't actually hit. + const lockAt = quote.responseLockedAt ? new Date(quote.responseLockedAt) : null; + const minutes = lockAt + ? Math.max(0, Math.ceil((lockAt.getTime() - Date.now()) / 60000)) + : 0; + return { + at: lockAt ? lockAt.toLocaleTimeString() : '', + minutes, + }; + })()) : t('quoteResponse.intro', 'Please accept or decline this quote:')}