fix: handle tag object structure and move tag input to preview

- Fixed white screen issue: RecipeDetail now handles both string and object tag formats from API
- Moved tag input from import form to preview section
- Tags can now be added after viewing imported recipe details
- Better UX: review recipe, add tags, then save
This commit is contained in:
Paul R Kartchner
2026-01-16 21:16:45 -07:00
parent 9d3bdfc0bf
commit d12021ffdc
2 changed files with 77 additions and 72 deletions

View File

@@ -252,19 +252,23 @@ function RecipeDetail() {
<div className="tags-display-inline">
<strong>Tags:</strong>
{recipe.tags && recipe.tags.length > 0 ? (
recipe.tags.map(tag => (
<span key={tag} className="tag-chip-inline">
{tag}
<button
onClick={() => handleRemoveTag(tag)}
disabled={savingTags}
className="tag-remove-btn-inline"
title="Remove tag"
>
×
</button>
</span>
))
recipe.tags.map(tagItem => {
// Handle both string tags and object tags from API
const tagName = typeof tagItem === 'string' ? tagItem : tagItem.tag?.name || tagItem.name;
return (
<span key={tagName} className="tag-chip-inline">
{tagName}
<button
onClick={() => handleRemoveTag(tagName)}
disabled={savingTags}
className="tag-remove-btn-inline"
title="Remove tag"
>
×
</button>
</span>
);
})
) : (
<span className="no-tags-inline"></span>
)}

View File

@@ -107,65 +107,9 @@ function RecipeImport() {
/>
</div>
<div className="import-actions">
<button type="submit" disabled={loading}>
{loading ? 'Importing...' : 'Import Recipe'}
</button>
<div className="import-tags-inline">
<label>Tags:</label>
<div className="import-tags-display">
{selectedTags.length > 0 ? (
selectedTags.map(tag => (
<span key={tag} className="tag-chip-inline">
{tag}
<button
type="button"
onClick={() => handleRemoveTag(tag)}
className="tag-remove-btn-inline"
title="Remove tag"
>
×
</button>
</span>
))
) : (
<span className="no-tags-inline">None</span>
)}
</div>
<div className="import-tag-input">
<input
ref={tagInputRef}
type="text"
value={tagInput}
onChange={(e) => setTagInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleAddTag();
}
}}
placeholder="Add tag..."
list="import-available-tags"
className="tag-input-small"
/>
<button
type="button"
onClick={handleAddTag}
disabled={!tagInput.trim()}
className="tag-add-btn-small"
title="Add tag"
>
+
</button>
<datalist id="import-available-tags">
{availableTags.map(tag => (
<option key={tag.id} value={tag.name} />
))}
</datalist>
</div>
</div>
</div>
<button type="submit" disabled={loading}>
{loading ? 'Importing...' : 'Import Recipe'}
</button>
</form>
{error && <div className="error">{error}</div>}
@@ -211,6 +155,63 @@ function RecipeImport() {
</div>
)}
{/* Tag Management Section */}
<div className="import-tags-section" style={{ marginTop: '2rem', marginBottom: '2rem' }}>
<h3>Add Tags</h3>
<div className="import-tags-inline">
<div className="import-tags-display">
{selectedTags.length > 0 ? (
selectedTags.map(tag => (
<span key={tag} className="tag-chip-inline">
{tag}
<button
type="button"
onClick={() => handleRemoveTag(tag)}
className="tag-remove-btn-inline"
title="Remove tag"
>
×
</button>
</span>
))
) : (
<span className="no-tags-inline">No tags yet</span>
)}
</div>
<div className="import-tag-input">
<input
ref={tagInputRef}
type="text"
value={tagInput}
onChange={(e) => setTagInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleAddTag();
}
}}
placeholder="Add tag..."
list="import-available-tags"
className="tag-input-small"
/>
<button
type="button"
onClick={handleAddTag}
disabled={!tagInput.trim()}
className="tag-add-btn-small"
title="Add tag"
>
+
</button>
<datalist id="import-available-tags">
{availableTags.map(tag => (
<option key={tag.id} value={tag.name} />
))}
</datalist>
</div>
</div>
</div>
<button onClick={handleSave} disabled={loading}>
Save Recipe
</button>