feat: F015 shortlist management

3-panel Shortlists page with left list, center detail, right decision brief panel. AddToShortlistDialog wired into result feed cards and match detail. Full DRAFT→REVIEW_READY→FINALIZED workflow, AI-generated decision brief draft, duplicate prevention, and compare-view integration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-16 21:10:06 +02:00
parent 2753d1717c
commit 65130efca7
22 changed files with 1079 additions and 195 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
import type { Shortlist, CreateShortlistInput, UpdateShortlistInput } from '../domain/shortlist'
import type { Shortlist, CreateShortlistInput, UpdateShortlistInput, ShortlistItemInput } from '../domain/shortlist'
import type { ShortlistStatus } from '../domain/enums'
export interface ShortlistFilters {
@@ -13,7 +13,7 @@ export interface IShortlistProvider {
getById(id: string): Promise<Shortlist | null>
create(data: CreateShortlistInput): Promise<Shortlist>
update(id: string, data: UpdateShortlistInput): Promise<Shortlist>
addItem(id: string, propertyId: string, note?: string): Promise<Shortlist>
removeItem(id: string, propertyId: string): Promise<Shortlist>
addItem(id: string, item: ShortlistItemInput): Promise<Shortlist>
removeItem(id: string, resultId: string): Promise<Shortlist>
remove(id: string): Promise<void>
}
+6 -6
View File
@@ -1,5 +1,5 @@
import type { IShortlistProvider, ShortlistFilters } from './IShortlistProvider'
import type { Shortlist, CreateShortlistInput, UpdateShortlistInput } from '../domain/shortlist'
import type { Shortlist, CreateShortlistInput, UpdateShortlistInput, ShortlistItemInput } from '../domain/shortlist'
import { mockShortlists } from '../mock-data/shortlists'
import { mockDelay } from '../lib/mockUtils'
@@ -36,25 +36,25 @@ export const MockupShortlistProvider: IShortlistProvider = {
store[idx] = { ...store[idx], ...data, updatedAt: new Date().toISOString() }
return store[idx]
},
async addItem(id, propertyId, note?) {
async addItem(id, item: ShortlistItemInput) {
await mockDelay()
const idx = store.findIndex(s => s.id === id)
const alreadyAdded = store[idx].items.some(i => i.propertyId === propertyId)
const alreadyAdded = store[idx].items.some(i => i.resultId === item.resultId)
if (!alreadyAdded) {
store[idx] = {
...store[idx],
items: [...store[idx].items, { propertyId, addedAt: new Date().toISOString(), note }],
items: [...store[idx].items, { ...item, addedAt: new Date().toISOString() }],
updatedAt: new Date().toISOString(),
}
}
return store[idx]
},
async removeItem(id, propertyId) {
async removeItem(id, resultId) {
await mockDelay()
const idx = store.findIndex(s => s.id === id)
store[idx] = {
...store[idx],
items: store[idx].items.filter(i => i.propertyId !== propertyId),
items: store[idx].items.filter(i => i.resultId !== resultId),
updatedAt: new Date().toISOString(),
}
return store[idx]