From 76f45512d14d0839b0bcd165e7cf34a20a025ed0 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sun, 13 Sep 2026 21:07:55 +0200 Subject: [PATCH] feat(admin): the phone's API-keys card, rebuilt like the desktop tab The desktop tab was reshaped around one idea: a key should be the exception rather than the thing you are expected to paste. The phone still had the older shape, where Google wore the "Recommended" chip and the TREK Places API was not on the screen at all. Two pages, opposite advice, same setting. So the phone gets the same three comparable blocks in the same order: the TREK index first, with its own ribbon and a folded panel of what it does and does not carry, then the two keys under theirs. The Google caveat is said before the field rather than after it, because somebody about to paste a key should read it while deciding. The four Google switches moved under the key they spend, folded away: they are set once and never touched again, and open they were longer than the rest of the card together. Open-Meteo left the card entirely, as it did on the desktop, since it takes no key and had the loudest treatment of anything there. The provider choice is TREK's own picker now. A native select is drawn by the operating system and was the one control on the page that did not belong to the app. Its description was also describing a TREK that no longer exists: it said one service answers place search. The index and OpenStreetMap answer every search and the setting only decides who is asked once they come up empty (maps.service.ts, keyedProvider). Both that line and the missing-key notice say so now, in all 23 languages, and the two key hints have short forms for the narrow screen. --- .../screens/admin/MAdminSettingsSection.tsx | 184 +++++++------- .../screens/admin/MApiProviderBlocks.tsx | 227 ++++++++++++++++++ .../src/pages/admin/AdminSettingsTab.test.tsx | 2 +- .../admin/MAdminSettingsSection.test.tsx | 22 +- .../journey/MJourneyEntrySheet.test.tsx | 4 +- shared/src/i18n/ar/admin.ts | 7 +- shared/src/i18n/br/admin.ts | 8 +- shared/src/i18n/ca/admin.ts | 7 +- shared/src/i18n/cs/admin.ts | 7 +- shared/src/i18n/de/admin.ts | 8 +- shared/src/i18n/en/admin.ts | 8 +- shared/src/i18n/es/admin.ts | 8 +- shared/src/i18n/fr/admin.ts | 8 +- shared/src/i18n/gr/admin.ts | 7 +- shared/src/i18n/hu/admin.ts | 7 +- shared/src/i18n/id/admin.ts | 7 +- shared/src/i18n/it/admin.ts | 8 +- shared/src/i18n/ja/admin.ts | 7 +- shared/src/i18n/ko/admin.ts | 7 +- shared/src/i18n/nl/admin.ts | 8 +- shared/src/i18n/pl/admin.ts | 7 +- shared/src/i18n/ru/admin.ts | 7 +- shared/src/i18n/sv/admin.ts | 7 +- shared/src/i18n/tr/admin.ts | 7 +- shared/src/i18n/uk/admin.ts | 7 +- shared/src/i18n/vi/admin.ts | 7 +- shared/src/i18n/zh-TW/admin.ts | 7 +- shared/src/i18n/zh/admin.ts | 7 +- 28 files changed, 448 insertions(+), 159 deletions(-) create mode 100644 client/src/mobile/screens/admin/MApiProviderBlocks.tsx diff --git a/client/src/mobile/screens/admin/MAdminSettingsSection.tsx b/client/src/mobile/screens/admin/MAdminSettingsSection.tsx index 0c561a90d..c60306c0f 100644 --- a/client/src/mobile/screens/admin/MAdminSettingsSection.tsx +++ b/client/src/mobile/screens/admin/MAdminSettingsSection.tsx @@ -1,9 +1,12 @@ -import { AlertTriangle, RefreshCw, Sun } from 'lucide-react' +import { useState } from 'react' +import { AlertTriangle, ChevronDown, RefreshCw } from 'lucide-react' import { adminApi, authApi } from '../../../api/client' import { getApiErrorMessage } from '../../../types' import type { TranslationFn } from '../../../types' import type { useAdmin } from '../../../pages/admin/useAdmin' import MToggle from '../../components/MToggle' +import { MBlockDisclosure, MProviderBlock, MTrekApiBlock } from './MApiProviderBlocks' +import MSetPickerSheet from '../settings/MSetPickerSheet' import { MAdminButton, MAdminCard, @@ -23,6 +26,7 @@ interface MAdminSettingsSectionProps { // types, API keys, OIDC and the danger zone — the full desktop settings tab // relaid as mobile cards. All state and mutations come from useAdmin. export default function MAdminSettingsSection({ admin, t }: MAdminSettingsSectionProps) { + const [providerPickerOpen, setProviderPickerOpen] = useState(false) const { toast, setPlacesPhotosEnabled, setPlacesAutocompleteEnabled, setPlacesDetailsEnabled, setPlacesEnrichEnabled, setPlaceShadowEnabled, @@ -217,20 +221,22 @@ export default function MAdminSettingsSection({ admin, t }: MAdminSettingsSectio
+ {/* Comparable blocks in the order we would have somebody choose them, + matching the desktop tab: the free source first, the keys after it. + The recommendation used to sit on the Google field here, which told + a phone admin the opposite of what the same setting says on a + laptop. */} + + {/* The keys belong to the operator on a managed install, same as on the desktop tab; the provider choice below stays the admin's. */} {!managed && (<> - - {t('admin.mapsKey')} - - {t('admin.recommended')} - - - } - hint={t('admin.mapsKeyHintLong')} - > + + {/* Said before the field, not after it: somebody about to paste a key + should read this while deciding, not once they already have. */} +

+ {t('admin.mapsKeyHintShort')} +

{validation.maps === true && ( -

+

{t('admin.keyValid')}

)} {validation.maps === false && ( -

+

{t('admin.keyInvalid')}

)} - - - {/* No Test button, same as the desktop tab: /auth/validate-keys only - knows how to probe Google Places and OpenWeatherMap. */} - - setAmapKey(e.target.value)} - placeholder={t('settings.keyPlaceholder')} - /> - - - - setUnsplashKey(e.target.value)} - placeholder={t('settings.keyPlaceholder')} - /> - - )} - - - - {/* From app-config, like the desktop card: the key fields are empty - on a managed install and on an operator key set by environment. */} - {((placesProvider === 'google' && !hasMapsKey) || (placesProvider === 'amap' && !hasAmapKey)) && ( -

- {t('admin.placesProvider.missingKey')} -

- )} -
- -
- {/* The four Google switches trade away quota that is the operator's on - a managed install; the search log below is the instance's own. */} - {!managed && (<> + {/* What the key is allowed to be spent on. Under the key rather than + loose at the foot of the card: every one of them is a Google + request, and none of them mean anything without it. */} + } /> - )} + + + + {/* No Test button, same as the desktop tab: /auth/validate-keys only + knows how to probe Google Places and OpenWeatherMap. */} + +

{t('admin.amapKeyHintShort')}

+ setAmapKey(e.target.value)} + placeholder={t('settings.keyPlaceholder')} + /> +
+ + +

{t('admin.unsplashKeyHint')}

+ setUnsplashKey(e.target.value)} + placeholder={t('settings.keyPlaceholder')} + /> +
+ )} + + + {/* The app's own picker rather than a bare