723f553939
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>
86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
import { MockupPipelineProvider } from '../provider/MockupPipelineProvider'
|
||
import type { PipelineItem, PipelineStage, PendingPipelineItem } from '../domain/pipeline'
|
||
import type { ListResponse, ItemResponse } from './types'
|
||
import { throwServiceError } from './errors'
|
||
|
||
const provider = MockupPipelineProvider
|
||
|
||
export const pipelineService = {
|
||
async getAll(): Promise<ListResponse<PipelineItem>> {
|
||
try {
|
||
const data = await provider.getAll()
|
||
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
|
||
async confirmSaved(pending: PendingPipelineItem, notes?: string): Promise<ItemResponse<'added' | 'duplicate'>> {
|
||
try {
|
||
const items = await provider.getAll()
|
||
const alreadyExists = items.some(
|
||
i => i.id === pending.resultId || (pending.propertyId && i.propertyId === pending.propertyId)
|
||
)
|
||
if (alreadyExists) return { data: 'duplicate' }
|
||
const newItem: PipelineItem = {
|
||
id: pending.resultId,
|
||
matchId: pending.resultId,
|
||
title: pending.title,
|
||
location: pending.location ?? '–',
|
||
matchScore: pending.matchScore,
|
||
resultType: pending.resultType,
|
||
stage: 'SAVED',
|
||
propertyId: pending.propertyId,
|
||
unitId: pending.unitId,
|
||
propertyAddress: pending.propertyAddress,
|
||
areaLabel: pending.areaLabel,
|
||
rentLabel: pending.rentLabel,
|
||
availabilityLabel: pending.availabilityLabel,
|
||
notes: notes || undefined,
|
||
addedAt: new Date().toISOString(),
|
||
updatedAt: new Date().toISOString(),
|
||
}
|
||
await provider.add(newItem)
|
||
return { data: 'added' }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
|
||
async moveStage(id: string, stage: PipelineStage): Promise<ItemResponse<void>> {
|
||
try {
|
||
await provider.moveStage(id, stage)
|
||
return { data: undefined }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
|
||
async updateNotes(id: string, notes: string): Promise<ItemResponse<void>> {
|
||
try {
|
||
await provider.updateNotes(id, notes)
|
||
return { data: undefined }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
|
||
async loseItem(id: string): Promise<ItemResponse<void>> {
|
||
try {
|
||
await provider.loseItem(id)
|
||
return { data: undefined }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
|
||
async linkInquiry(id: string, inquiryId: string): Promise<ItemResponse<void>> {
|
||
try {
|
||
await provider.linkInquiry(id, inquiryId)
|
||
return { data: undefined }
|
||
} catch (err) {
|
||
throwServiceError(err)
|
||
}
|
||
},
|
||
}
|