refactor: use CreateIngredientList and CreateStepList in translation approval UI

Replaced the plain EditableIngredients and EditableInstructions components
with the styled CreateIngredientList and CreateStepList components to match
the German recipe editing UI above:

- Now displays English translation with same styling as German recipe
- Ingredients and instructions shown in familiar two-column layout
- Timing fields (preparation, baking, fermentation, cooking, total_time)
  integrated into CreateStepList component instead of separate fields
- Added getters/setters for add_info object to enable two-way binding
  between CreateStepList edits and editableEnglish data
- Removed redundant field editors for baking/fermentation since they're
  now part of CreateStepList

Translation approval UI now has consistent styling with the rest of the
edit page for a more cohesive user experience.
This commit is contained in:
2026-01-04 21:35:52 +01:00
parent 03df3b0d14
commit 1d4daf11ad

View File

@@ -2,10 +2,8 @@
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import type { TranslatedRecipeType } from '$types/types'; import type { TranslatedRecipeType } from '$types/types';
import TranslationFieldComparison from './TranslationFieldComparison.svelte'; import TranslationFieldComparison from './TranslationFieldComparison.svelte';
import EditableIngredients from './EditableIngredients.svelte'; import CreateIngredientList from './CreateIngredientList.svelte';
import EditableInstructions from './EditableInstructions.svelte'; import CreateStepList from './CreateStepList.svelte';
import IngredientsPage from './IngredientsPage.svelte';
import InstructionsPage from './InstructionsPage.svelte';
export let germanData: any; export let germanData: any;
export let englishData: TranslatedRecipeType | null = null; export let englishData: TranslatedRecipeType | null = null;
@@ -100,21 +98,45 @@
} }
} }
// Handle ingredients changes // Create add_info object for CreateStepList that references editableEnglish properties
function handleIngredientsChange(event: CustomEvent) { // This allows CreateStepList to modify the values directly
if (editableEnglish) { $: englishAddInfo = editableEnglish ? {
editableEnglish.ingredients = event.detail.ingredients; get preparation() { return editableEnglish.preparation || ''; },
editableEnglish = editableEnglish; // Trigger reactivity set preparation(value) { editableEnglish.preparation = value; },
} fermentation: {
} get bulk() { return editableEnglish.fermentation?.bulk || ''; },
set bulk(value) {
// Handle instructions changes if (!editableEnglish.fermentation) editableEnglish.fermentation = { bulk: '', final: '' };
function handleInstructionsChange(event: CustomEvent) { editableEnglish.fermentation.bulk = value;
if (editableEnglish) { },
editableEnglish.instructions = event.detail.instructions; get final() { return editableEnglish.fermentation?.final || ''; },
editableEnglish = editableEnglish; // Trigger reactivity set final(value) {
} if (!editableEnglish.fermentation) editableEnglish.fermentation = { bulk: '', final: '' };
} editableEnglish.fermentation.final = value;
},
},
baking: {
get length() { return editableEnglish.baking?.length || ''; },
set length(value) {
if (!editableEnglish.baking) editableEnglish.baking = { length: '', temperature: '', mode: '' };
editableEnglish.baking.length = value;
},
get temperature() { return editableEnglish.baking?.temperature || ''; },
set temperature(value) {
if (!editableEnglish.baking) editableEnglish.baking = { length: '', temperature: '', mode: '' };
editableEnglish.baking.temperature = value;
},
get mode() { return editableEnglish.baking?.mode || ''; },
set mode(value) {
if (!editableEnglish.baking) editableEnglish.baking = { length: '', temperature: '', mode: '' };
editableEnglish.baking.mode = value;
},
},
get total_time() { return editableEnglish.total_time || ''; },
set total_time(value) { editableEnglish.total_time = value; },
get cooking() { return editableEnglish.cooking || ''; },
set cooking(value) { editableEnglish.cooking = value; },
} : null;
// Handle approval // Handle approval
function handleApprove() { function handleApprove() {
@@ -229,12 +251,31 @@
} }
.translation-preview { .translation-preview {
max-width: 800px; max-width: 1000px;
margin: 1.5rem auto; margin: 1.5rem auto;
} }
.field-section { .field-section {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.list-wrapper {
margin-inline: auto;
display: flex;
flex-direction: row;
max-width: 1000px;
gap: 2rem;
justify-content: center;
margin-bottom: 2rem;
}
@media screen and (max-width: 700px) {
.list-wrapper {
flex-direction: column;
}
} }
.column-header { .column-header {
@@ -529,118 +570,19 @@ button:disabled {
</div> </div>
{/if} {/if}
{#if editableEnglish?.preparation !== undefined} <!-- Ingredients and Instructions in two-column layout -->
<div class="field-section"> {#if editableEnglish?.ingredients || editableEnglish?.instructions}
<TranslationFieldComparison <div class="list-wrapper">
label="Preparation Time" <div>
germanValue={germanData.preparation || ''} {#if editableEnglish?.ingredients}
englishValue={editableEnglish.preparation} <CreateIngredientList bind:ingredients={editableEnglish.ingredients} />
fieldName="preparation" {/if}
readonly={false} </div>
on:change={handleFieldChange} <div>
/> {#if editableEnglish?.instructions && englishAddInfo}
</div> <CreateStepList bind:instructions={editableEnglish.instructions} add_info={englishAddInfo} />
{/if} {/if}
</div>
{#if editableEnglish?.cooking !== undefined}
<div class="field-section">
<TranslationFieldComparison
label="Cooking Time"
germanValue={germanData.cooking || ''}
englishValue={editableEnglish.cooking}
fieldName="cooking"
readonly={false}
on:change={handleFieldChange}
/>
</div>
{/if}
{#if editableEnglish?.total_time !== undefined}
<div class="field-section">
<TranslationFieldComparison
label="Total Time"
germanValue={germanData.total_time || ''}
englishValue={editableEnglish.total_time}
fieldName="total_time"
readonly={false}
on:change={handleFieldChange}
/>
</div>
{/if}
{#if editableEnglish?.baking}
<div class="field-section">
<h4 style="margin-bottom: 0.5rem;">Baking</h4>
<TranslationFieldComparison
label="Temperature"
germanValue={germanData.baking?.temperature || ''}
englishValue={editableEnglish.baking.temperature || ''}
fieldName="baking.temperature"
readonly={false}
on:change={handleFieldChange}
/>
<TranslationFieldComparison
label="Time"
germanValue={germanData.baking?.length || ''}
englishValue={editableEnglish.baking.length || ''}
fieldName="baking.length"
readonly={false}
on:change={handleFieldChange}
/>
<TranslationFieldComparison
label="Mode"
germanValue={germanData.baking?.mode || ''}
englishValue={editableEnglish.baking.mode || ''}
fieldName="baking.mode"
readonly={false}
on:change={handleFieldChange}
/>
</div>
{/if}
{#if editableEnglish?.fermentation}
<div class="field-section">
<h4 style="margin-bottom: 0.5rem;">Fermentation</h4>
<TranslationFieldComparison
label="Bulk"
germanValue={germanData.fermentation?.bulk || ''}
englishValue={editableEnglish.fermentation.bulk || ''}
fieldName="fermentation.bulk"
readonly={false}
on:change={handleFieldChange}
/>
<TranslationFieldComparison
label="Final"
germanValue={germanData.fermentation?.final || ''}
englishValue={editableEnglish.fermentation.final || ''}
fieldName="fermentation.final"
readonly={false}
on:change={handleFieldChange}
/>
</div>
{/if}
<!-- Ingredients -->
{#if editableEnglish?.ingredients && editableEnglish.ingredients.length > 0}
<div class="field-section">
<h4 style="margin-bottom: 0.5rem;">Ingredients</h4>
<EditableIngredients
ingredients={editableEnglish.ingredients}
translationMetadata={translationMetadata?.ingredientTranslations}
on:change={handleIngredientsChange}
/>
</div>
{/if}
<!-- Instructions -->
{#if editableEnglish?.instructions && editableEnglish.instructions.length > 0}
<div class="field-section">
<h4 style="margin-bottom: 0.5rem;">Instructions</h4>
<EditableInstructions
instructions={editableEnglish.instructions}
translationMetadata={translationMetadata?.instructionTranslations}
on:change={handleInstructionsChange}
/>
</div> </div>
{/if} {/if}