feat: Marktchancen — Netzwerk-Hinweise tab (human-sourced market intel)

- MarktHinweis domain type: SUCHE/VERFUEGBARKEIT direction, INTERN/PLATTFORM
  visibility, anonymization flag, source tracking
- Full data layer: IMarktHinweisProvider, MockupMarktHinweisProvider, service, hooks
- 7 seed entries: mix of intern/shared, demand/supply, own/partner Verwaltungen
- Marktchancen gets two-tab layout: Digitale Signale (crawler) + Netzwerk (human)
- HinweisListItem: direction icon, visibility badge (Intern/Geteilt/partner name)
- HinweisDetail: note card, portfolio match (SUCHE) or availability info (VERFUEGBARKEIT)
- HinweisErfassenDialog: direction toggle, asset type, location, area range,
  company + anonymize switch, source, note, card-based visibility picker
- HinweisPropertyCard: same Anschreiben composer pattern as crawler side

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-24 23:47:50 +02:00
parent 63909c8caf
commit 7f6b7766e6
7 changed files with 960 additions and 53 deletions
+8
View File
@@ -0,0 +1,8 @@
import type { MarktHinweis, CreateMarktHinweisInput } from '../domain/marktHinweis'
export interface IMarktHinweisProvider {
getAll(): Promise<MarktHinweis[]>
getById(id: string): Promise<MarktHinweis | null>
create(data: CreateMarktHinweisInput): Promise<MarktHinweis>
update(id: string, data: Partial<MarktHinweis>): Promise<MarktHinweis>
}
@@ -0,0 +1,36 @@
import type { IMarktHinweisProvider } from './IMarktHinweisProvider'
import type { MarktHinweis, CreateMarktHinweisInput } from '../domain/marktHinweis'
import { marktHinweise as seed } from '../mock-data/marktHinweise'
const store: MarktHinweis[] = [...seed]
export const MockupMarktHinweisProvider: IMarktHinweisProvider = {
async getAll() {
return [...store]
},
async getById(id: string) {
return store.find(h => h.id === id) ?? null
},
async create(data: CreateMarktHinweisInput) {
const next: MarktHinweis = {
...data,
id: `mh-${Date.now()}`,
createdAt: new Date().toISOString(),
createdBy: 'Thomas Müller',
verwaltungId: 'v-001',
verwaltungName: 'Wincasa AG',
}
store.push(next)
return next
},
async update(id: string, data: Partial<MarktHinweis>) {
const idx = store.findIndex(h => h.id === id)
if (idx === -1) throw new Error(`MarktHinweis ${id} not found`)
const updated: MarktHinweis = { ...store[idx], ...data }
store[idx] = updated
return updated
},
}