fix(research): move all form fields to reactive state, add setField dispatcher

All Input fields used market?.xxx as initial value, so a Svelte re-render
triggered by researchResult=null would reset them back to the server-loaded
value, wiping every applied research suggestion.

Replace all research-applicable fields with $state variables and route all
apply calls through setField() instead of querySelector+dispatch. Country
name->code mapping added for LLM-returned values like "Deutschland" -> "DE".
writeReverseResult also updated to use setField.
This commit is contained in:
2026-04-25 11:25:21 +02:00
parent cc69bf51bc
commit da9754cb2f
2 changed files with 81 additions and 45 deletions

View File

@@ -42,9 +42,35 @@
let marktName = $state(untrack(() => market?.name ?? ''));
let description = $state(untrack(() => market?.description ?? ''));
let street = $state(untrack(() => market?.street ?? ''));
let city = $state(untrack(() => market?.city ?? ''));
let marketState = $state(untrack(() => market?.state ?? ''));
let zip = $state(untrack(() => market?.zip ?? ''));
let selectedCountry = $state(untrack(() => market?.country ?? 'DE'));
let startDate = $state(untrack(() => market?.start_date ?? ''));
let endDate = $state(untrack(() => market?.end_date ?? ''));
let website = $state(untrack(() => market?.website ?? ''));
let organizerName = $state(untrack(() => market?.organizer_name ?? ''));
let imageUrl = $state(untrack(() => market?.image_url ?? ''));
const currency = $derived(currencyByCountry[selectedCountry] ?? 'EUR');
const countryNameToCode: Record<string, string> = {
Deutschland: 'DE',
Oesterreich: 'AT',
Österreich: 'AT',
Schweiz: 'CH',
Frankreich: 'FR',
Italien: 'IT',
Spanien: 'ES',
Polen: 'PL',
Tschechien: 'CZ',
Niederlande: 'NL',
Belgien: 'BE',
Dänemark: 'DK',
Schweden: 'SE',
Norwegen: 'NO'
};
let hours: OpeningHoursEntry[] = $state(
untrack(() => (market?.opening_hours?.length ? [...market.opening_hours] : []))
);
@@ -173,14 +199,10 @@
['zip', data.zip]
];
let count = 0;
for (const [name, value] of writes) {
for (const [field, value] of writes) {
if (!value) continue;
const el = document.querySelector<HTMLInputElement>(`[name="${name}"]`);
if (el) {
el.value = value;
el.dispatchEvent(new Event('input', { bubbles: true }));
count++;
}
setField(field, value);
count++;
}
return count;
}
@@ -200,6 +222,47 @@
export function setName(val: string) {
marktName = val;
}
export function setField(field: string, value: string) {
switch (field) {
case 'name':
marktName = value;
break;
case 'description':
description = value;
break;
case 'street':
street = value;
break;
case 'city':
city = value;
break;
case 'state':
marketState = value;
break;
case 'zip':
zip = value;
break;
case 'country':
selectedCountry = countryNameToCode[value] ?? value;
break;
case 'start_date':
startDate = value;
break;
case 'end_date':
endDate = value;
break;
case 'website':
website = value;
break;
case 'organizer_name':
organizerName = value;
break;
case 'image_url':
imageUrl = value;
break;
}
}
</script>
{#if error}
@@ -249,7 +312,7 @@
label="Straße"
name="street"
type="text"
value={market?.street ?? ''}
value={street}
placeholder={mode === 'public' ? 'z.B. Marienplatz 1' : ''}
/>
@@ -259,14 +322,14 @@
name="city"
type="text"
required
value={market?.city ?? ''}
value={city}
placeholder={mode === 'public' ? 'z.B. München' : ''}
/>
<Input
label="Bundesland"
name="state"
type="text"
value={market?.state ?? ''}
value={marketState}
placeholder={mode === 'public' ? 'z.B. Bayern' : ''}
/>
</div>
@@ -276,7 +339,7 @@
label="PLZ"
name="zip"
type="text"
value={market?.zip ?? ''}
value={zip}
placeholder={mode === 'public' ? 'z.B. 80331' : ''}
/>
<div class="space-y-1">
@@ -390,20 +453,8 @@
<legend class="text-lg font-semibold text-stone-800 dark:text-stone-100">Zeitraum</legend>
<div class="grid grid-cols-2 gap-4">
<Input
label="Startdatum *"
name="start_date"
type="date"
required
value={market?.start_date ?? ''}
/>
<Input
label="Enddatum *"
name="end_date"
type="date"
required
value={market?.end_date ?? ''}
/>
<Input label="Startdatum *" name="start_date" type="date" required value={startDate} />
<Input label="Enddatum *" name="end_date" type="date" required value={endDate} />
</div>
</fieldset>
@@ -414,7 +465,7 @@
label="Website"
name="website"
type="url"
value={market?.website ?? ''}
value={website}
placeholder={mode === 'public' ? 'https://...' : ''}
/>
@@ -422,11 +473,11 @@
label="Veranstalter"
name="organizer_name"
type="text"
value={market?.organizer_name ?? ''}
value={organizerName}
placeholder={mode === 'public' ? 'Name des Veranstalters' : ''}
/>
<Input label="Bild-URL" name="image_url" type="url" value={market?.image_url ?? ''} />
<Input label="Bild-URL" name="image_url" type="url" value={imageUrl} />
</fieldset>
<fieldset class="space-y-4">

View File

@@ -84,23 +84,8 @@
}
continue;
}
if (s.field === 'description' && typeof s.suggested_value === 'string') {
marketForm.setDescription(s.suggested_value);
continue;
}
if (s.field === 'name' && typeof s.suggested_value === 'string') {
marketForm.setName(s.suggested_value);
continue;
}
const el = document.querySelector<HTMLInputElement | HTMLTextAreaElement>(
`[name="${s.field}"]`
);
if (el) {
el.value =
typeof s.suggested_value === 'string'
? s.suggested_value
: JSON.stringify(s.suggested_value);
el.dispatchEvent(new Event('input', { bubbles: true }));
if (typeof s.suggested_value === 'string') {
marketForm.setField(s.field, s.suggested_value);
}
}
const notesEl = document.querySelector<HTMLTextAreaElement>('[name="admin_notes"]');