From 917c10c1d3bfd3ff4552aba73c145c94031e2aa1 Mon Sep 17 00:00:00 2001 From: Jeppe B <2jepp9350@gmail.com> Date: Sun, 2 Aug 2026 09:42:47 +0200 Subject: [PATCH] Fix mobile Stripe reader recovery action (#241) ## Summary - keep the mobile Stripe terminal menu in normal document flow so it cannot cover the reader recovery action - preserve the existing desktop dropdown overlay behavior - replace pre-existing dynamic subuser-access translations with direct literal calls - explicitly review Bird's bounded health-state translation signatures in the full view-i18n gate ## Root causes Exact master CI run `30484128661` exposed two deterministic failures: 1. All three attempts of `reader unavailable state is recoverable and non-fatal` timed out because the open terminal dropdown intercepted pointer events on `pos-stripe-no-readers`. 2. The full Chromium desktop/customer view-i18n gate rejected two bounded Bird health-state signatures plus three pre-existing dynamic subuser-access calls. The PR matrix did not run this full scanner. ## Verification - exact Chromium mobile failing scenario: 1/1 passed - Chromium mobile repeat stress: 5/5 passed - exact full view-i18n scanner: 1/1 passed - Bird configuration units: 5/5 passed - Firefox mobile scenario: skipped by the existing project/browser gate - ESLint: passed - test Prettier check: passed - `git diff --check`: passed - Vite production build: passed --- .../displays/StripeTerminalReaderSelect.vue | 8 ++++++++ .../pages/auth/SubuserAccessDecisionPage.vue | 18 +++++++----------- tests/e2e/i18n.views.spec.ts | 2 ++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/components/displays/department/pos/displays/StripeTerminalReaderSelect.vue b/src/components/displays/department/pos/displays/StripeTerminalReaderSelect.vue index 9e8ece7a..bc969e31 100644 --- a/src/components/displays/department/pos/displays/StripeTerminalReaderSelect.vue +++ b/src/components/displays/department/pos/displays/StripeTerminalReaderSelect.vue @@ -506,4 +506,12 @@ onBeforeUnmount(() => { .stripe-terminal-select--mobile .stripe-terminal-select__trigger { min-height: 3rem; } + +.stripe-terminal-select--mobile { + flex-direction: column; +} + +.stripe-terminal-select--mobile .stripe-terminal-select__menu { + position: static; +} diff --git a/src/views/pages/auth/SubuserAccessDecisionPage.vue b/src/views/pages/auth/SubuserAccessDecisionPage.vue index 60f97778..cdea9805 100644 --- a/src/views/pages/auth/SubuserAccessDecisionPage.vue +++ b/src/views/pages/auth/SubuserAccessDecisionPage.vue @@ -7,7 +7,7 @@ import logo from "@/assets/img/truckwash-banner.png"; import i18n from "@/i18n"; const route = useRoute(); -const t = (key, values = undefined) => i18n.global.t(key, values); +const { t } = i18n.global; const token = ref(String(route.query.token || "")); const request = ref(null); const loading = ref(true); @@ -68,11 +68,9 @@ onMounted(() => { {{ - t( - result === "approved" - ? "subuser_access_decision.approved" - : "subuser_access_decision.denied" - ) + result === "approved" + ? t("subuser_access_decision.approved") + : t("subuser_access_decision.denied") }} @@ -99,11 +97,9 @@ onMounted(() => { @click="confirmDecision" > {{ - t( - request.action === "approve" - ? "subuser_access_decision.approve" - : "subuser_access_decision.deny" - ) + request.action === "approve" + ? t("subuser_access_decision.approve") + : t("subuser_access_decision.deny") }} diff --git a/tests/e2e/i18n.views.spec.ts b/tests/e2e/i18n.views.spec.ts index b22370a8..f79f54be 100644 --- a/tests/e2e/i18n.views.spec.ts +++ b/tests/e2e/i18n.views.spec.ts @@ -6,6 +6,8 @@ import { scanViewTranslationKeys, type ViewTranslationKeyUsage } from "./support const ACTIVE_LOCALES = ["da", "en", "sv", "de", "no"] as const; const GENERATED_LOCALES_DIRECTORY = path.join(process.cwd(), "src", "i18n", "generated"); const REVIEWED_NON_LITERAL_CALLS = new Set([ + 'src/views/dashboards/superUserDashboard/configuration/ConfigurationBird.vue|$t|:subtitle="$t(`configuration.bird.state.${healthState}`)"', + "src/views/dashboards/superUserDashboard/configuration/ConfigurationBird.vue|$t|{{ $t(`configuration.bird.state.${healthState}`) }}", "src/views/backoffice/LimitedBackofficeEmployees.vue|t|return `${option.flag} +${option.value} ${t(`templates.limited_backoffice.employees.country_codes.${option.labelKey}`)}`;", "src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/components/InvoicingPeriodFlagList.vue|t|const translated = t(key, params);", "src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/components/InvoicingPeriodObjectTree.vue|t|const translated = t(key, params);",