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:
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user