feat: complete workspace, triage, outliner and sharing overhaul (tasks 1-26)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 57s

This commit is contained in:
sandrodach committed 2026-10-27 19:46:46 +01:00
1 parent df2f2bac67
commit d39d1d1122
17 files changed
+1173 -501

No files matched your search

+103 -9
View File
@@ -85,6 +85,8 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
const [newItemText, setNewItemText] = useState('');
const [newItemQty, setNewItemQty] = useState('');
const [isSubmittingItem, setIsSubmittingItem] = useState(false);
const [editingQtyItemId, setEditingQtyItemId] = useState<string | null>(null);
const [editingQtyValue, setEditingQtyValue] = useState('');
const [wsConnected, setWsConnected] = useState(false);
const [realtimeTransport, setRealtimeTransport] = useState<RealtimeTransport>('none');
@@ -174,7 +176,7 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
return { ...l, items: deduplicateItems([newItem, ...l.items]) };
})
);
} else if (msg.event === 'ITEM_TOGGLED' && msgListId) {
} else if ((msg.event === 'ITEM_TOGGLED' || msg.event === 'ITEM_UPDATED') && msgListId) {
const updatedItem: ListItem = msg.payload;
setLists((prev) =>
prev.map((l) => {
@@ -273,6 +275,26 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
}
};
const handleSaveQuantity = async (itemId: string, quantity: string) => {
setEditingQtyItemId(null);
if (!activeList) return;
const trimmed = quantity.trim();
try {
const updated = await api.updateListItem(activeList.id, itemId, { quantity: trimmed });
setLists((prev) =>
prev.map((l) => {
if (l.id !== activeList.id) return l;
return {
...l,
items: l.items.map((i) => (i.id === itemId ? { ...i, quantity: updated.quantity } : i)),
};
})
);
} catch (err: any) {
console.error('Fehler beim Aktualisieren der Menge', err);
}
};
const handleToggleItem = async (item: ListItem) => {
if (!activeList) return;
triggerHaptic(10);
@@ -1085,8 +1107,8 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
<input
type="text"
value={newItemQty}
onChange={(e) => setNewItemQty(e.target.value)}
placeholder="Menge (z.B. 2x)"
onChange={(e) => setNewItemQty(e.target.value.replace(/[^0-9.,xX]/g, ''))}
placeholder="Menge (z.B. 2)"
className="flex-1 sm:flex-none sm:w-28 h-9 sm:h-7 px-2.5 sm:px-2 input-field text-xs"
/>
<button
@@ -1196,10 +1218,45 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
{displayContent}
</span>
{item.quantity && (
<span className="badge-accent">
{item.quantity}
</span>
{editingQtyItemId === item.id ? (
<div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
<input
type="text"
autoFocus
value={editingQtyValue}
onChange={(e) => setEditingQtyValue(e.target.value.replace(/[^0-9.,xX]/g, ''))}
onKeyDown={async (e) => {
if (e.key === 'Enter') {
e.preventDefault();
await handleSaveQuantity(item.id, editingQtyValue);
} else if (e.key === 'Escape') {
setEditingQtyItemId(null);
}
}}
onBlur={async () => {
await handleSaveQuantity(item.id, editingQtyValue);
}}
className="w-16 h-6 px-1.5 text-xs input-field font-semibold text-accent text-center"
placeholder="Menge"
/>
</div>
) : (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
setEditingQtyItemId(item.id);
setEditingQtyValue(item.quantity || '');
}}
className={`text-xs px-2 py-0.5 rounded-full transition-colors ${
item.quantity
? 'badge-accent cursor-pointer hover:brightness-125'
: 'opacity-0 group-hover:opacity-60 hover:!opacity-100 text-muted hover:text-accent border border-dashed border-border/70 hover:border-accent text-[11px]'
}`}
title="Menge bearbeiten"
>
{item.quantity || '+ Menge'}
</button>
)}
{cat && !group.label && (
@@ -1274,8 +1331,45 @@ export const SharedListsView: React.FC<SharedListsViewProps> = ({ onRefreshGloba
{displayContent}
</span>
{item.quantity && (
<span className="text-xs text-faint">({item.quantity})</span>
{editingQtyItemId === item.id ? (
<div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
<input
type="text"
autoFocus
value={editingQtyValue}
onChange={(e) => setEditingQtyValue(e.target.value.replace(/[^0-9.,xX]/g, ''))}
onKeyDown={async (e) => {
if (e.key === 'Enter') {
e.preventDefault();
await handleSaveQuantity(item.id, editingQtyValue);
} else if (e.key === 'Escape') {
setEditingQtyItemId(null);
}
}}
onBlur={async () => {
await handleSaveQuantity(item.id, editingQtyValue);
}}
className="w-16 h-6 px-1.5 text-xs input-field font-semibold text-accent text-center"
placeholder="Menge"
/>
</div>
) : (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
setEditingQtyItemId(item.id);
setEditingQtyValue(item.quantity || '');
}}
className={`text-xs px-1.5 py-0.5 rounded transition-colors ${
item.quantity
? 'text-faint hover:text-main cursor-pointer'
: 'opacity-0 group-hover:opacity-60 text-faint hover:text-main text-[11px]'
}`}
title="Menge bearbeiten"
>
{item.quantity ? `(${item.quantity})` : '+ Menge'}
</button>
)}
</div>