feat(ItemsList): add item content validation and improve row management logic
This commit is contained in:
parent
f616d73826
commit
c31b195b5e
1 changed files with 54 additions and 44 deletions
|
@ -210,6 +210,13 @@ async function fetchWikidataSuggestions(query: string): Promise<WikidataSuggesti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to check if an item has content
|
||||||
|
function itemHasContent(item: Item): boolean {
|
||||||
|
return item.name.trim() !== '' ||
|
||||||
|
item.description.trim() !== '' ||
|
||||||
|
Object.values(item.customProperties).some(prop => prop.trim() !== '');
|
||||||
|
}
|
||||||
|
|
||||||
export function ItemsList({ url }: ItemsListProps) {
|
export function ItemsList({ url }: ItemsListProps) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
@ -249,7 +256,22 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
};
|
};
|
||||||
setItems([emptyItem]);
|
setItems([emptyItem]);
|
||||||
} else {
|
} else {
|
||||||
setItems(loadedItems);
|
// Check if we need to add an empty row at the end
|
||||||
|
const lastItem = loadedItems[loadedItems.length - 1];
|
||||||
|
const needsEmptyRow = itemHasContent(lastItem);
|
||||||
|
|
||||||
|
if (needsEmptyRow) {
|
||||||
|
const emptyItem: Item = {
|
||||||
|
id: uuidv4(),
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
wikidataId: undefined,
|
||||||
|
customProperties: {}
|
||||||
|
};
|
||||||
|
setItems([...loadedItems, emptyItem]);
|
||||||
|
} else {
|
||||||
|
setItems(loadedItems);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set selected properties
|
// Set selected properties
|
||||||
|
@ -283,8 +305,10 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
// Mutations
|
// Mutations
|
||||||
const saveItemMutation = useMutation({
|
const saveItemMutation = useMutation({
|
||||||
mutationFn: (item: Item) => saveItemToDb(url, item),
|
mutationFn: (item: Item) => saveItemToDb(url, item),
|
||||||
onSuccess: () => {
|
// REMOVED: onSuccess invalidation that was causing the issue
|
||||||
queryClient.invalidateQueries({ queryKey: ['items', url] });
|
onError: (error) => {
|
||||||
|
console.error('Failed to save item:', error);
|
||||||
|
// You could add a toast notification here
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -312,6 +336,9 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
const newItems = [...prevItems];
|
const newItems = [...prevItems];
|
||||||
const item = { ...newItems[index] };
|
const item = { ...newItems[index] };
|
||||||
|
|
||||||
|
// Store the previous state of the item to check if it was empty before
|
||||||
|
const wasEmpty = !itemHasContent(item);
|
||||||
|
|
||||||
if (field === 'name') {
|
if (field === 'name') {
|
||||||
item.name = value;
|
item.name = value;
|
||||||
// Fetch Wikidata suggestions only if value is not empty
|
// Fetch Wikidata suggestions only if value is not empty
|
||||||
|
@ -344,53 +371,36 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
|
|
||||||
newItems[index] = item;
|
newItems[index] = item;
|
||||||
|
|
||||||
// Only save if the item has some content
|
// Check if the item now has content after the update
|
||||||
const hasContent = item.name.trim() ||
|
const nowHasContent = itemHasContent(item);
|
||||||
item.description.trim() ||
|
|
||||||
Object.values(item.customProperties).some(prop => prop.trim());
|
|
||||||
|
|
||||||
if (hasContent) {
|
// Only save if the item has some content
|
||||||
|
if (nowHasContent) {
|
||||||
// Auto-save with error handling
|
// Auto-save with error handling
|
||||||
saveItemMutation.mutate(item, {
|
saveItemMutation.mutate(item);
|
||||||
onError: (error) => {
|
|
||||||
console.error('Failed to save item:', error);
|
|
||||||
// You could add a toast notification here
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
// After successful save, reload items to get any synchronized properties
|
|
||||||
// This ensures that if another item with the same name exists,
|
|
||||||
// its properties are updated in the UI
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['items', url] });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new row if editing last row and value is not empty
|
// Add new row logic: only add if we're editing the last item AND
|
||||||
// Only add if the last item doesn't already have content and we're not already at the end
|
// the item transitioned from empty to having content
|
||||||
if (index === newItems.length - 1 && value.trim()) {
|
const isLastItem = index === newItems.length - 1;
|
||||||
const lastItem = newItems[newItems.length - 1];
|
const transitionedToContent = wasEmpty && nowHasContent;
|
||||||
const lastItemHasContent = lastItem.name.trim() ||
|
|
||||||
lastItem.description.trim() ||
|
|
||||||
Object.values(lastItem.customProperties).some(prop => prop.trim());
|
|
||||||
|
|
||||||
if (lastItemHasContent) {
|
if (isLastItem && transitionedToContent) {
|
||||||
const newItem: Item = {
|
// Add a new empty row
|
||||||
id: uuidv4(),
|
const newItem: Item = {
|
||||||
name: '',
|
id: uuidv4(),
|
||||||
description: '',
|
name: '',
|
||||||
wikidataId: undefined,
|
description: '',
|
||||||
customProperties: {}
|
wikidataId: undefined,
|
||||||
};
|
customProperties: {}
|
||||||
newItems.push(newItem);
|
};
|
||||||
|
newItems.push(newItem);
|
||||||
// Don't auto-save empty items immediately
|
console.log('Added new empty row after item got content');
|
||||||
// They will be saved when user starts typing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newItems;
|
return newItems;
|
||||||
});
|
});
|
||||||
}, [saveItemMutation, queryClient, url]);
|
}, [saveItemMutation]);
|
||||||
|
|
||||||
const removeItem = useCallback((index: number) => {
|
const removeItem = useCallback((index: number) => {
|
||||||
const itemId = items[index].id;
|
const itemId = items[index].id;
|
||||||
|
@ -414,7 +424,7 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
})));
|
})));
|
||||||
}, [deletePropertyMutation]);
|
}, [deletePropertyMutation]);
|
||||||
|
|
||||||
const fetchPropertyLabelsHelper = useCallback(async (propertyIds: string[]): Promise<Record<string, string>> => {
|
const fetchPropertyLabelsHelper = useCallback(async (propertyIds: string[]): Promise<Record<string, string>> => {
|
||||||
const labels = await fetchPropertyLabels(propertyIds);
|
const labels = await fetchPropertyLabels(propertyIds);
|
||||||
setPropertyLabels(prev => ({ ...prev, ...labels }));
|
setPropertyLabels(prev => ({ ...prev, ...labels }));
|
||||||
return labels;
|
return labels;
|
||||||
|
@ -527,7 +537,7 @@ export function ItemsList({ url }: ItemsListProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Property addition completed:', normalizedProperty);
|
console.log('Property addition completed:', normalizedProperty);
|
||||||
}, [selectedProperties, propertyLabels, items, propertyCache, url]);
|
}, [customProperties, propertyLabels, items, propertyCache, url]);
|
||||||
|
|
||||||
const handleWikidataSelect = useCallback(async (suggestion: WikidataSuggestion, itemId: string) => {
|
const handleWikidataSelect = useCallback(async (suggestion: WikidataSuggestion, itemId: string) => {
|
||||||
console.log('Wikidata selection for item:', itemId, suggestion);
|
console.log('Wikidata selection for item:', itemId, suggestion);
|
||||||
|
|
Loading…
Add table
Reference in a new issue