refactor: move PipelineItems from Zustand to Provider→Service→React Query

PipelineItems are domain data and must not live in Zustand. Moves the
full stack to the correct layer: MockupPipelineProvider (localStorage
persistence + seed fallback) → pipelineService → usePipeline hooks
(useQuery for reads, useMutation for writes with cache invalidation).

pipelineStore is now UI-only: dialogOpen, pendingItem, openSavedDialog,
closeSavedDialog. All consumers updated to use the new hooks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-24 12:32:57 +02:00
parent 0582031930
commit 723f553939
12 changed files with 303 additions and 115 deletions
@@ -7,7 +7,7 @@ import {
AlertTriangle, ChevronRight, CheckCircle, ExternalLink, FileText,
MapPin, MessageSquare, Sparkles, StickyNote, X,
} from 'lucide-react'
import { usePipelineStore } from '../../stores/pipelineStore'
import { useMoveStage, useUpdateNotes, useLoseItem } from '../../hooks/usePipeline'
import type { PipelineItem } from '../../domain/pipeline'
import { STAGES, NEXT_STAGE, MOCK_DOCS } from './pipelineConstants'
import { scoreColor, detailPath, getKiInsight } from './pipelineUtils'
@@ -16,7 +16,9 @@ import { scoreColor, detailPath, getKiInsight } from './pipelineUtils'
export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: () => void }) {
const navigate = useNavigate()
const { moveStage, updateNotes, loseItem } = usePipelineStore()
const { mutate: moveStage } = useMoveStage()
const { mutate: updateNotes } = useUpdateNotes()
const { mutate: loseItem } = useLoseItem()
const path = detailPath(item)
const [notes, setNotes] = useState(item.notes ?? '')
const stageConfig = STAGES.find(s => s.key === item.stage)!
@@ -128,7 +130,7 @@ export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: ()
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{nextStage && (
<Button size="small" variant="contained" endIcon={<ChevronRight size={14} />}
onClick={() => moveStage(item.id, nextStage.key)}
onClick={() => moveStage({ id: item.id, stage: nextStage.key })}
sx={{ bgcolor: stageConfig.color, '&:hover': { filter: 'brightness(0.9)' }, fontSize: '0.75rem', py: 0.5 }}
>
{nextStage.label}
@@ -157,7 +159,7 @@ export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: ()
placeholder="Notiz hinzufügen…"
value={notes}
onChange={e => setNotes(e.target.value)}
onBlur={() => updateNotes(item.id, notes)}
onBlur={() => updateNotes({ id: item.id, notes })}
sx={{ '& .MuiOutlinedInput-root': { fontSize: '0.8rem', borderRadius: 1.5 } }}
/>
</Box>