fix(base): FiatToggleField reads form state via useFormContext

The previous version called useField directly with a getter for the
field name. That created a child-local field rather than connecting
to the parent form's allow_fiat / fiat_currency state — so the
Switch's on/off visually toggled but the form never knew, and the
conditional Fiat currency dropdown never appeared.

Rewrite around the proven pattern used elsewhere in the dialog: bind
the inputs through FormField (the shadcn-vue / vee-validate Field
component) and reach for cross-field state via useFormContext.
showCurrencyDropdown now reads form.values[allowFiatField] directly,
which mirrors the parent's actual state, and the denomination-mirror
watch goes through form.setFieldValue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-23 19:30:03 +02:00
commit d6efbd2c65

View file

@ -1,9 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, watch } from 'vue' import { computed, watch } from 'vue'
import { useField } from 'vee-validate' import { useFormContext } from 'vee-validate'
import { import {
FormControl, FormControl,
FormDescription, FormDescription,
FormField,
FormItem, FormItem,
FormLabel, FormLabel,
FormMessage, FormMessage,
@ -37,21 +38,19 @@ const props = defineProps<{
disabled?: boolean disabled?: boolean
}>() }>()
const { value: allowFiat, handleChange: setAllowFiat } = useField<boolean>( const form = useFormContext()
() => props.allowFiatField,
)
const { value: fiatCurrency, setValue: setFiatCurrency } = useField<string>(
() => props.fiatCurrencyField,
)
const { hasAnyProvider, refresh } = useFiatProviders() const { hasAnyProvider, refresh } = useFiatProviders()
// Refresh once on mount so the disabled-state reflects providers the // Refresh once on mount so the disabled-state reflects providers the
// user may have just configured in another tab. // user may have just configured in another tab.
refresh() refresh()
const allowFiatValue = computed(() =>
Boolean(form.values[props.allowFiatField as keyof typeof form.values]),
)
const showCurrencyDropdown = computed( const showCurrencyDropdown = computed(
() => allowFiat.value && props.denomination === 'sat', () => allowFiatValue.value && props.denomination === 'sat',
) )
// When the price is denominated in a fiat currency, the rail currency // When the price is denominated in a fiat currency, the rail currency
@ -59,8 +58,8 @@ const showCurrencyDropdown = computed(
watch( watch(
() => props.denomination, () => props.denomination,
(d) => { (d) => {
if (d && d !== 'sat' && fiatCurrency.value !== d) { if (d && d !== 'sat' && form.values[props.fiatCurrencyField as keyof typeof form.values] !== d) {
setFiatCurrency(d) form.setFieldValue(props.fiatCurrencyField, d)
} }
}, },
{ immediate: true }, { immediate: true },
@ -69,60 +68,60 @@ watch(
<template> <template>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3 items-end"> <div class="grid grid-cols-1 sm:grid-cols-3 gap-3 items-end">
<FormItem class="sm:col-span-2 flex flex-row items-center justify-between rounded-md border p-3"> <FormField v-slot="{ value, handleChange }" :name="allowFiatField">
<div class="space-y-0.5"> <FormItem class="sm:col-span-2 flex flex-row items-center justify-between rounded-md border p-3">
<FormLabel>Also accept fiat</FormLabel> <div class="space-y-0.5">
<FormDescription class="text-xs"> <FormLabel>Also accept fiat</FormLabel>
Buyers can pay with card or bank through your configured provider. <FormDescription class="text-xs">
</FormDescription> Buyers can pay with card or bank through your configured provider.
</div> </FormDescription>
<FormControl> </div>
<TooltipProvider v-if="!hasAnyProvider" :delay-duration="200"> <FormControl>
<Tooltip> <TooltipProvider v-if="!hasAnyProvider" :delay-duration="200">
<TooltipTrigger as-child> <Tooltip>
<span class="inline-flex"> <TooltipTrigger as-child>
<Switch :model-value="false" disabled /> <span class="inline-flex">
</span> <Switch :model-value="false" disabled />
</TooltipTrigger> </span>
<TooltipContent class="max-w-xs"> </TooltipTrigger>
Your LNbits user has no fiat provider configured. Open <TooltipContent class="max-w-xs">
LNbits Account Fiat providers and add Stripe, PayPal, Your LNbits user has no fiat provider configured. Open
or Square to enable this. LNbits Account Fiat providers and add Stripe, PayPal,
</TooltipContent> or Square to enable this.
</Tooltip> </TooltipContent>
</TooltipProvider> </Tooltip>
<Switch </TooltipProvider>
v-else <Switch
:model-value="allowFiat" v-else
:disabled="disabled" :model-value="value as boolean"
@update:model-value="setAllowFiat" :disabled="disabled"
/> @update:model-value="handleChange"
</FormControl> />
</FormItem> </FormControl>
</FormItem>
</FormField>
<FormItem v-show="showCurrencyDropdown"> <FormField v-slot="{ componentField }" :name="fiatCurrencyField">
<FormLabel>Fiat currency</FormLabel> <FormItem v-show="showCurrencyDropdown">
<FormControl> <FormLabel>Fiat currency</FormLabel>
<Select <FormControl>
:model-value="fiatCurrency" <Select v-bind="componentField" :disabled="disabled">
:disabled="disabled" <SelectTrigger>
@update:model-value="(v) => setFiatCurrency(v as string)" <SelectValue placeholder="USD" />
> </SelectTrigger>
<SelectTrigger> <SelectContent>
<SelectValue placeholder="USD" /> <SelectItem
</SelectTrigger> v-for="c in availableFiatCurrencies"
<SelectContent> :key="c"
<SelectItem :value="c"
v-for="c in availableFiatCurrencies" >
:key="c" {{ c }}
:value="c" </SelectItem>
> </SelectContent>
{{ c }} </Select>
</SelectItem> </FormControl>
</SelectContent> <FormMessage />
</Select> </FormItem>
</FormControl> </FormField>
<FormMessage />
</FormItem>
</div> </div>
</template> </template>