mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 15:06:32 +00:00
feat(settings): make the display currency optional, falling back to the trip's
Costs already resolved `default_currency || trip.currency || 'EUR'`, but the setting could never actually be empty: the store seeded 'USD', so a user who had never touched it silently had every trip converted into dollars, and the picker offered no way to unset it. Seed it empty and lead the picker with a "Trip currency" option, so an unset preference means "show each trip in its own currency" instead of forcing them all through one code. An explicit empty value persists and beats the admin-set instance default — it is a deliberate choice, not an absence. This also brings the public share's fallback to life: the share payload has resolved sharer's currency -> trip currency since #1361, but the trip-currency branch was unreachable while every owner had a currency forced on them. Plugins are handed `formats.currency` as a concrete code, so PluginFrame now resolves the same chain rather than passing an empty string through the bridge.
This commit is contained in:
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from '../../i18n'
|
||||
import { useAuthStore } from '../../store/authStore'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { useTripStore } from '../../store/tripStore'
|
||||
import { useToast } from '../shared/Toast'
|
||||
import ConfirmDialog from '../shared/ConfirmDialog'
|
||||
import { pluginsApi } from '../../api/client'
|
||||
@@ -141,6 +142,10 @@ export default function PluginFrame({ pluginId, tripId = null, placeId = null, d
|
||||
const userAvatar = useAuthStore((s) => s.user?.avatar_url ?? null)
|
||||
const isAdmin = useAuthStore((s) => s.user?.role === 'admin')
|
||||
const settings = useSettingsStore((s) => s.settings)
|
||||
// Plugins format money against a concrete code, so resolve the same chain Costs
|
||||
// uses: the user's display currency, else the trip's own.
|
||||
const tripCurrency = useTripStore((s) => s.trip?.currency)
|
||||
const displayCurrency = (settings.default_currency || tripCurrency || 'EUR').toUpperCase()
|
||||
const [height, setHeight] = useState<number | null>(null)
|
||||
// A host-rendered ConfirmDialog on the plugin's behalf: sandboxed frames have no
|
||||
// allow-modals and can't overlay the host, so destructive plugin actions get the
|
||||
@@ -177,7 +182,7 @@ export default function PluginFrame({ pluginId, tripId = null, placeId = null, d
|
||||
appearance: readAppearance(),
|
||||
formats: {
|
||||
locale,
|
||||
currency: settings.default_currency,
|
||||
currency: displayCurrency,
|
||||
timeFormat: settings.time_format,
|
||||
distanceUnit: settings.distance_unit,
|
||||
temperatureUnit: settings.temperature_unit,
|
||||
|
||||
@@ -40,13 +40,18 @@ export default function DisplaySettingsTab(): React.ReactElement {
|
||||
{/* Display currency */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2 text-content-secondary">{t('settings.currency')}</label>
|
||||
{/* Unset ('') means "no personal preference": Costs then shows each trip in its
|
||||
own currency, instead of forcing every trip through one display currency. */}
|
||||
<CustomSelect
|
||||
value={settings.default_currency || 'EUR'}
|
||||
value={settings.default_currency || ''}
|
||||
onChange={async v => {
|
||||
try { await updateSetting('default_currency', String(v)) }
|
||||
catch (e: unknown) { toast.error(e instanceof Error ? e.message : t('common.error')) }
|
||||
}}
|
||||
options={currenciesWith(settings.default_currency).map(c => ({ value: c, label: `${c} — ${SYMBOLS[c] || c}` }))}
|
||||
options={[
|
||||
{ value: '', label: t('settings.currencyTrip') },
|
||||
...currenciesWith(settings.default_currency || '').map(c => ({ value: c, label: `${c} — ${SYMBOLS[c] || c}` })),
|
||||
]}
|
||||
searchable
|
||||
/>
|
||||
<p className="text-xs text-content-faint mt-2">{t('settings.currencyHint')}</p>
|
||||
|
||||
Reference in New Issue
Block a user