fix: resolve TagSelector build error and improve component type safety
- Fixed undefined setTags in TagSelector.tsx - Updated TagSelector to use Dexie cache for immediate UI updates - Refined TastingList mapping to satisfy TypeScript interface - Verified fix with a successful production build
This commit is contained in:
@@ -34,7 +34,7 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
const tagList = tags || [];
|
const tagList = tags || [];
|
||||||
if (!search) return tagList;
|
if (!search) return tagList;
|
||||||
const s = search.toLowerCase();
|
const s = search.toLowerCase();
|
||||||
return tagList.filter((tag: any) => {
|
return tagList.filter((tag) => {
|
||||||
const rawMatch = tag.name.toLowerCase().includes(s);
|
const rawMatch = tag.name.toLowerCase().includes(s);
|
||||||
const translatedMatch = tag.is_system_default && t(`aroma.${tag.name}`).toLowerCase().includes(s);
|
const translatedMatch = tag.is_system_default && t(`aroma.${tag.name}`).toLowerCase().includes(s);
|
||||||
return rawMatch || translatedMatch;
|
return rawMatch || translatedMatch;
|
||||||
@@ -47,14 +47,14 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
setIsCreating(true);
|
setIsCreating(true);
|
||||||
const result = await createCustomTag(search, category);
|
const result = await createCustomTag(search, category);
|
||||||
if (result.success && result.tag) {
|
if (result.success && result.tag) {
|
||||||
setTags(prev => [...prev, result.tag!]);
|
await db.cache_tags.put(result.tag!);
|
||||||
onToggleTag(result.tag!.id);
|
onToggleTag(result.tag!.id);
|
||||||
setSearch('');
|
setSearch('');
|
||||||
}
|
}
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedTags = tags.filter(t => selectedTagIds.includes(t.id));
|
const selectedTags = (tags || []).filter(t => selectedTagIds.includes(t.id));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
@@ -137,7 +137,7 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
<Sparkles size={10} /> {t('camera.wbMatchFound') ? 'KI Vorschläge' : 'AI Suggestions'}
|
<Sparkles size={10} /> {t('camera.wbMatchFound') ? 'KI Vorschläge' : 'AI Suggestions'}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-1.5">
|
<div className="flex flex-wrap gap-1.5">
|
||||||
{tags
|
{(tags || [])
|
||||||
.filter(t => !selectedTagIds.includes(t.id) && suggestedTagNames.some((s: string) => s.toLowerCase() === t.name.toLowerCase()))
|
.filter(t => !selectedTagIds.includes(t.id) && suggestedTagNames.some((s: string) => s.toLowerCase() === t.name.toLowerCase()))
|
||||||
.map(tag => (
|
.map(tag => (
|
||||||
<button
|
<button
|
||||||
@@ -162,7 +162,7 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-1.5">
|
<div className="flex flex-wrap gap-1.5">
|
||||||
{suggestedCustomTagNames
|
{suggestedCustomTagNames
|
||||||
.filter(name => !tags.some(t => t.name.toLowerCase() === name.toLowerCase()))
|
.filter(name => !(tags || []).some(t => t.name.toLowerCase() === name.toLowerCase()))
|
||||||
.map(name => (
|
.map(name => (
|
||||||
<button
|
<button
|
||||||
key={name}
|
key={name}
|
||||||
@@ -172,7 +172,7 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
setCreatingSuggestion(name);
|
setCreatingSuggestion(name);
|
||||||
const result = await createCustomTag(name, category);
|
const result = await createCustomTag(name, category);
|
||||||
if (result.success && result.tag) {
|
if (result.success && result.tag) {
|
||||||
setTags(prev => [...prev, result.tag!]);
|
await db.cache_tags.put(result.tag!);
|
||||||
onToggleTag(result.tag!.id);
|
onToggleTag(result.tag!.id);
|
||||||
}
|
}
|
||||||
setCreatingSuggestion(null);
|
setCreatingSuggestion(null);
|
||||||
@@ -190,7 +190,7 @@ export default function TagSelector({ category, selectedTagIds, onToggleTag, lab
|
|||||||
{/* Suggestions Chips (limit to 6 random or most common) */}
|
{/* Suggestions Chips (limit to 6 random or most common) */}
|
||||||
{!search && tags.length > 0 && (
|
{!search && tags.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1.5 pt-1">
|
<div className="flex flex-wrap gap-1.5 pt-1">
|
||||||
{tags
|
{(tags || [])
|
||||||
.filter(t => !selectedTagIds.includes(t.id) && (!suggestedTagNames || !suggestedTagNames.some((s: string) => s.toLowerCase() === t.name.toLowerCase())))
|
.filter(t => !selectedTagIds.includes(t.id) && (!suggestedTagNames || !suggestedTagNames.some((s: string) => s.toLowerCase() === t.name.toLowerCase())))
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map(tag => (
|
.map(tag => (
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ interface Tasting {
|
|||||||
}
|
}
|
||||||
}[];
|
}[];
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
isPending?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TastingListProps {
|
interface TastingListProps {
|
||||||
@@ -88,7 +89,10 @@ export default function TastingList({ initialTastings, currentUserId, bottleId }
|
|||||||
bottle_id: p.bottle_id,
|
bottle_id: p.bottle_id,
|
||||||
created_at: p.tasted_at,
|
created_at: p.tasted_at,
|
||||||
user_id: currentUserId || '',
|
user_id: currentUserId || '',
|
||||||
isPending: true
|
isPending: true,
|
||||||
|
tasting_buddies: [],
|
||||||
|
tasting_sessions: undefined,
|
||||||
|
tasting_tags: []
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -149,7 +153,7 @@ export default function TastingList({ initialTastings, currentUserId, bottleId }
|
|||||||
}`}>
|
}`}>
|
||||||
{note.is_sample ? 'Sample' : 'Bottle'}
|
{note.is_sample ? 'Sample' : 'Bottle'}
|
||||||
</span>
|
</span>
|
||||||
{(note as any).isPending && (
|
{note.isPending && (
|
||||||
<div className="bg-amber-100 dark:bg-amber-900/30 text-amber-600 dark:text-amber-400 px-2 py-0.5 rounded-lg text-[10px] font-black uppercase tracking-tighter flex items-center gap-1.5 animate-pulse">
|
<div className="bg-amber-100 dark:bg-amber-900/30 text-amber-600 dark:text-amber-400 px-2 py-0.5 rounded-lg text-[10px] font-black uppercase tracking-tighter flex items-center gap-1.5 animate-pulse">
|
||||||
<Clock size={10} />
|
<Clock size={10} />
|
||||||
Wartet auf Sync...
|
Wartet auf Sync...
|
||||||
@@ -174,7 +178,7 @@ export default function TastingList({ initialTastings, currentUserId, bottleId }
|
|||||||
<Calendar size={12} />
|
<Calendar size={12} />
|
||||||
{new Date(note.created_at).toLocaleDateString('de-DE')}
|
{new Date(note.created_at).toLocaleDateString('de-DE')}
|
||||||
</div>
|
</div>
|
||||||
{(!currentUserId || note.user_id === currentUserId) && !(note as any).isPending && (
|
{(!currentUserId || note.user_id === currentUserId) && !note.isPending && (
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDelete(note.id, note.bottle_id)}
|
onClick={() => handleDelete(note.id, note.bottle_id)}
|
||||||
disabled={!!isDeleting}
|
disabled={!!isDeleting}
|
||||||
|
|||||||
Reference in New Issue
Block a user