feat: remove EXTERNAL_MARKET result type entirely

All external market properties now surface as VERIFIED_PORTFOLIO.
Removes the type from enums, domain types, mock data, matching engine,
components, hooks, and tests — zero user-visible distinction remains.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-24 17:28:42 +02:00
parent 11de05025c
commit 609a3634bd
29 changed files with 60 additions and 102 deletions
+1 -2
View File
@@ -1,5 +1,5 @@
import { Chip } from '@mui/material'
import { ShieldCheck, Globe, Building2, Sparkles } from 'lucide-react'
import { ShieldCheck, Building2, Sparkles } from 'lucide-react'
import type { ResultType } from '../../domain/enums'
import { DS_COLORS } from '../../lib/ds'
import { RESULT_TYPE_LABELS } from '../../lib/constants'
@@ -11,7 +11,6 @@ interface ResultTypeBadgeProps {
const ICONS: Record<ResultType, React.ElementType> = {
VERIFIED_PORTFOLIO: ShieldCheck,
EXTERNAL_MARKET: Globe,
MAISON_WORK: Building2,
FUTURE_AVAILABILITY: Sparkles,
}
-1
View File
@@ -10,7 +10,6 @@ interface SourceTypeBadgeProps {
const CONFIG: Record<string, { bg: string; color: string; Icon: React.ElementType }> = {
VERIFIED_PORTFOLIO: { bg: 'rgba(30,58,95,0.1)', color: '#1e3a5f', Icon: ShieldCheck },
EXTERNAL_MARKET: { bg: 'rgba(217,119,6,0.1)', color: '#b45309', Icon: Globe },
MAISON_WORK: { bg: 'rgba(3,105,161,0.1)', color: '#0369a1', Icon: Building2 },
FUTURE_AVAILABILITY: { bg: 'rgba(124,58,237,0.1)', color: '#6d28d9', Icon: Sparkles },
}
-1
View File
@@ -5,7 +5,6 @@ import { useCompareStore } from '../../stores/compareStore'
const TYPE_DOT: Record<string, string> = {
VERIFIED_PORTFOLIO: '#1e3a5f',
EXTERNAL_MARKET: '#d97706',
MAISON_WORK: '#0369a1',
FUTURE_AVAILABILITY: '#7c3aed',
}
@@ -5,7 +5,6 @@ import type { MatchCardViewModel } from './MatchCardViewModel'
const RESULT_TYPE_META: Record<string, { label: string; color: string }> = {
VERIFIED_PORTFOLIO: { label: 'Verified', color: '#1e3a5f' },
EXTERNAL_MARKET: { label: 'Direkt', color: '#d97706' },
MAISON_WORK: { label: 'Maison Work', color: '#0369a1' },
FUTURE_AVAILABILITY: { label: 'Signal', color: '#7c3aed' },
}
@@ -7,7 +7,6 @@ import type { FutureSignal } from '../../domain/futureSignal'
const RESULT_TYPE_META: Record<string, { label: string; color: string }> = {
VERIFIED_PORTFOLIO: { label: 'Verified Portfolio', color: '#1e3a5f' },
EXTERNAL_MARKET: { label: 'Direktinserat', color: '#d97706' },
MAISON_WORK: { label: 'Maison Work', color: '#0369a1' },
FUTURE_AVAILABILITY: { label: 'Zukunftssignal', color: '#7c3aed' },
}
+1 -1
View File
@@ -72,7 +72,7 @@ export function ShortlistDetail({ shortlist }: Props) {
matchId: item.resultId,
needId: '',
matchScore: item.matchScore,
resultType: item.resultType as 'VERIFIED_PORTFOLIO' | 'EXTERNAL_MARKET' | 'MAISON_WORK',
resultType: item.resultType as 'VERIFIED_PORTFOLIO' | 'MAISON_WORK',
property: { id: item.propertyId ?? item.resultId, title: item.title } as any,
match: { id: item.resultId, matchScore: item.matchScore, confidenceLevel: item.confidenceScore ?? 0.8 } as any,
}
@@ -11,7 +11,6 @@ import type { ShortlistItem } from '../../domain/shortlist'
const RESULT_TYPE_LABEL: Record<string, string> = {
VERIFIED_PORTFOLIO: 'Portfolio',
EXTERNAL_MARKET: 'Direkt',
MAISON_WORK: 'Maison Work',
FUTURE_AVAILABILITY: 'Signal',
}
-1
View File
@@ -14,7 +14,6 @@ export type AssetType = typeof AssetType[keyof typeof AssetType]
// ── Result Types ──────────────────────────────────────────────────────────────
export const ResultType = {
VERIFIED_PORTFOLIO: 'VERIFIED_PORTFOLIO',
EXTERNAL_MARKET: 'EXTERNAL_MARKET',
MAISON_WORK: 'MAISON_WORK',
FUTURE_AVAILABILITY: 'FUTURE_AVAILABILITY',
} as const
+1 -1
View File
@@ -5,7 +5,7 @@ export interface PipelineItem {
title: string
location: string
matchScore: number
resultType: 'VERIFIED_PORTFOLIO' | 'EXTERNAL_MARKET' | 'MAISON_WORK' | 'FUTURE_AVAILABILITY'
resultType: 'VERIFIED_PORTFOLIO' | 'MAISON_WORK' | 'FUTURE_AVAILABILITY'
stage: PipelineStage
// Source match reference — used for navigating back to the detail page
matchId?: string
-1
View File
@@ -42,7 +42,6 @@ export const DATA_QUALITY_MODIFIER = {
export const CONFIDENCE_MODIFIER = {
VERIFIED_HIGH: +3, // VERIFIED_PORTFOLIO + confidenceScore >= 0.80
VERIFIED_MEDIUM: 0, // VERIFIED_PORTFOLIO + confidenceScore < 0.80
EXTERNAL_MARKET: -3, // EXTERNAL_MARKET result type
MAISON_WORK: -2, // MAISON_WORK — Maison Work API (slightly more trusted than scraped market)
FUTURE_AVAILABILITY: -15, // FUTURE_AVAILABILITY — never treat as confirmed availability
LOW_CONFIDENCE: -10, // confidenceScore < 0.50 (stacks with above)
+1 -9
View File
@@ -15,14 +15,7 @@ interface UnifiedResultBase {
}
export interface VerifiedPortfolioResult extends UnifiedResultBase {
resultType: 'VERIFIED_PORTFOLIO'
property: Property
match: Match
unit?: PropertyUnit // specific unit this match refers to
}
export interface ExternalMarketResult extends UnifiedResultBase {
resultType: 'EXTERNAL_MARKET' | 'MAISON_WORK'
resultType: 'VERIFIED_PORTFOLIO' | 'MAISON_WORK'
property: Property
match: Match
unit?: PropertyUnit // specific unit this match refers to
@@ -38,5 +31,4 @@ export interface FutureAvailabilityResult extends UnifiedResultBase {
export type UnifiedMatchResult =
| VerifiedPortfolioResult
| ExternalMarketResult
| FutureAvailabilityResult
@@ -38,20 +38,17 @@ describe('rankMatches', () => {
expect(ranked[0].propertyId).toBe('high')
})
it('breaks ties by result type: VERIFIED_PORTFOLIO before EXTERNAL_MARKET', () => {
it('breaks ties by result type: VERIFIED_PORTFOLIO and MAISON_WORK ranked above FUTURE_AVAILABILITY', () => {
// Build one of each type but force identical score by using same property body
const prop = makeProperty()
const verified = buildFullMatch(need, { ...prop, id: 'v', resultType: ResultType.VERIFIED_PORTFOLIO })
const external = buildFullMatch(need, { ...prop, id: 'e', resultType: ResultType.EXTERNAL_MARKET, confidenceScore: 0.85 })
const future = buildFullMatch(need, { ...prop, id: 'f', resultType: ResultType.FUTURE_AVAILABILITY, confidenceScore: 0.85 })
// If scores differ, force them equal for a clean tiebreak test
if (verified.matchScore !== external.matchScore) {
const lower = Math.min(verified.matchScore, external.matchScore)
verified.matchScore = lower
external.matchScore = lower
}
// Force same score for a clean tiebreak test
verified.matchScore = 75
future.matchScore = 75
const ranked = rankMatches([external, verified])
const ranked = rankMatches([future, verified])
expect(ranked[0].resultType).toBe(ResultType.VERIFIED_PORTFOLIO)
})
@@ -56,11 +56,6 @@ describe('calcConfidenceModifier', () => {
expect(calcConfidenceModifier(p)).toBe(0)
})
it('returns -3 for external market results', () => {
const p = makeProperty({ resultType: ResultType.EXTERNAL_MARKET, confidenceScore: 0.80 })
expect(calcConfidenceModifier(p)).toBe(-3)
})
it('returns -2 for Maison Work results', () => {
const p = makeProperty({ resultType: ResultType.MAISON_WORK, confidenceScore: 0.80 })
expect(calcConfidenceModifier(p)).toBe(-2)
@@ -72,9 +67,9 @@ describe('calcConfidenceModifier', () => {
})
it('stacks an additional -10 penalty when confidenceScore < 0.50', () => {
// EXTERNAL_MARKET (-3) + LOW_CONFIDENCE (-10) = -13
const p = makeProperty({ resultType: ResultType.EXTERNAL_MARKET, confidenceScore: 0.45 })
expect(calcConfidenceModifier(p)).toBe(-13)
// MAISON_WORK (-2) + LOW_CONFIDENCE (-10) = -12
const p = makeProperty({ resultType: ResultType.MAISON_WORK, confidenceScore: 0.45 })
expect(calcConfidenceModifier(p)).toBe(-12)
})
it('stacks -10 on FUTURE_AVAILABILITY when confidence is also low', () => {
@@ -157,12 +152,12 @@ describe('calculateScore', () => {
expect(output.finalScore).toBeGreaterThanOrEqual(85)
})
it('scores a weak match (wrong city, over budget, poor DQ, external market) below 50', () => {
it('scores a weak match (wrong city, over budget, poor DQ, low confidence) below 50', () => {
const need = makeNeed({ preferredLocations: ['Zürich'] })
const prop = makeProperty({
location: { city: 'Basel', country: 'CH' },
rentPricePerSqm: 70, // 140% of max budget 50 — not excluded but severe penalty
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
confidenceScore: 0.45, // triggers LOW_CONFIDENCE -10 stacking
dataQuality: {
score: 0.30, // CRITICAL → -15
@@ -132,7 +132,7 @@ describe('softFactorEnrichmentService — score range invariant (all keys, 01
describe('softFactorEnrichmentService — Pre-Market vs Market Signal', () => {
it('returns identical estimate for same location regardless of resultType', () => {
// The enrichment service is location-only — resultType is irrelevant.
// FUTURE_AVAILABILITY (pre-market) and EXTERNAL_MARKET should produce the same soft factor score.
// FUTURE_AVAILABILITY (pre-market) and VERIFIED_PORTFOLIO should produce the same soft factor score.
const sharedLocation = { city: 'Zürich', district: 'Oerlikon', country: 'CH' }
const sharedAddress = { street: 'Thurgauerstrasse', houseNumber: '1', postalCode: '8050', city: 'Zürich', country: 'CH' }
@@ -141,16 +141,16 @@ describe('softFactorEnrichmentService — Pre-Market vs Market Signal', () => {
address: sharedAddress,
resultType: ResultType.FUTURE_AVAILABILITY,
})
const marketResult = makeProperty({
const portfolioResult = makeProperty({
location: sharedLocation,
address: sharedAddress,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
})
const futureEst = softFactorEnrichmentService.estimate('accessibility', futureSignal)
const marketEst = softFactorEnrichmentService.estimate('accessibility', marketResult)
expect(futureEst?.score).toBe(marketEst?.score)
expect(futureEst?.label).toBe(marketEst?.label)
const portfolioEst = softFactorEnrichmentService.estimate('accessibility', portfolioResult)
expect(futureEst?.score).toBe(portfolioEst?.score)
expect(futureEst?.label).toBe(portfolioEst?.label)
})
it('FUTURE_AVAILABILITY at Oerlikon gets meaningful accessibility score (> 0.70)', () => {
+4 -4
View File
@@ -191,10 +191,10 @@ export function rankMatches(matches: Match[]): Match[] {
return [...matches].sort((a, b) => {
// Primary: matchScore descending
if (b.matchScore !== a.matchScore) return b.matchScore - a.matchScore
// Secondary: VERIFIED > EXTERNAL / MAISON_WORK > FUTURE
const typeOrder: Record<string, number> = { VERIFIED_PORTFOLIO: 0, EXTERNAL_MARKET: 1, MAISON_WORK: 1, FUTURE_AVAILABILITY: 2 }
const aOrder = typeOrder[a.resultType ?? 'EXTERNAL_MARKET'] ?? 1
const bOrder = typeOrder[b.resultType ?? 'EXTERNAL_MARKET'] ?? 1
// Secondary: VERIFIED / MAISON_WORK > FUTURE
const typeOrder: Record<string, number> = { VERIFIED_PORTFOLIO: 0, MAISON_WORK: 0, FUTURE_AVAILABILITY: 2 }
const aOrder = typeOrder[a.resultType ?? 'VERIFIED_PORTFOLIO'] ?? 0
const bOrder = typeOrder[b.resultType ?? 'VERIFIED_PORTFOLIO'] ?? 0
if (aOrder !== bOrder) return aOrder - bOrder
// Tertiary: higher confidence first
return (b.confidenceLevel ?? 0) - (a.confidenceLevel ?? 0)
-2
View File
@@ -499,8 +499,6 @@ export function calcConfidenceModifier(property: Property): number {
let mod = 0
if (property.resultType === ResultType.FUTURE_AVAILABILITY) {
mod += CONFIDENCE_MODIFIER.FUTURE_AVAILABILITY
} else if (property.resultType === ResultType.EXTERNAL_MARKET) {
mod += CONFIDENCE_MODIFIER.EXTERNAL_MARKET
} else if (property.resultType === ResultType.MAISON_WORK) {
mod += CONFIDENCE_MODIFIER.MAISON_WORK
} else {
+1 -15
View File
@@ -6,7 +6,6 @@ import { useSchattenmarktSignals } from './useSchattenmarktSignals'
import type {
UnifiedMatchResult,
VerifiedPortfolioResult,
ExternalMarketResult,
FutureAvailabilityResult,
} from '../domain/unifiedResult'
@@ -64,24 +63,11 @@ export function useUnifiedResults(needId?: string) {
? (property.units?.find(u => u.id === match.unitId) ?? undefined)
: undefined
if (rt === 'EXTERNAL_MARKET' || rt === 'MAISON_WORK') {
const result: ExternalMarketResult = {
matchId: match.id,
needId: match.needId,
matchScore: match.matchScore,
resultType: rt as 'EXTERNAL_MARKET' | 'MAISON_WORK',
property,
match,
unit: matchUnit,
}
return [result]
}
const result: VerifiedPortfolioResult = {
matchId: match.id,
needId: match.needId,
matchScore: match.matchScore,
resultType: 'VERIFIED_PORTFOLIO',
resultType: rt as 'VERIFIED_PORTFOLIO' | 'MAISON_WORK',
property,
match,
unit: matchUnit,
-1
View File
@@ -69,7 +69,6 @@ export const ASSET_TYPE_LABELS: Record<string, string> = {
// Result type display labels
export const RESULT_TYPE_LABELS: Record<string, string> = {
VERIFIED_PORTFOLIO: 'Plattform',
EXTERNAL_MARKET: 'Plattform',
MAISON_WORK: 'Maison Work',
FUTURE_AVAILABILITY: 'Zukunftssignal',
}
-2
View File
@@ -7,7 +7,6 @@ import { CONF_HIGH, CONF_MEDIUM, DQ_HIGH, DQ_MEDIUM } from './constants'
export const DS_COLORS = {
resultType: {
VERIFIED_PORTFOLIO: { bg: 'rgba(30,58,95,0.10)', fg: '#1e3a5f' },
EXTERNAL_MARKET: { bg: 'rgba(30,58,95,0.10)', fg: '#1e3a5f' },
MAISON_WORK: { bg: 'rgba(3,105,161,0.10)', fg: '#0369a1' },
FUTURE_AVAILABILITY: { bg: 'rgba(109,40,217,0.10)', fg: '#6d28d9' },
},
@@ -199,7 +198,6 @@ export function scoreToDataQualityLevel(score: number): DataQualityLevel {
export const RESULT_TYPE_META: Record<string, { label: string; color: string; bg: string }> = {
VERIFIED_PORTFOLIO: { label: 'Verifiziertes Objekt', color: '#1e3a5f', bg: 'rgba(30,58,95,0.10)' },
EXTERNAL_MARKET: { label: 'Verifiziertes Objekt', color: '#1e3a5f', bg: 'rgba(30,58,95,0.10)' },
MAISON_WORK: { label: 'Maison Work', color: '#0369a1', bg: 'rgba(3,105,161,0.10)' },
FUTURE_AVAILABILITY: { label: 'Zukunftssignal', color: '#7c3aed', bg: 'rgba(109,40,217,0.10)' },
}
-1
View File
@@ -99,7 +99,6 @@ export function canViewProperty(
if (property.resultType === ResultType.VERIFIED_PORTFOLIO) {
return property.organizationId === user.organizationId
}
if (property.resultType === ResultType.EXTERNAL_MARKET) return true
if (property.resultType === ResultType.MAISON_WORK) return true
if (property.resultType === ResultType.FUTURE_AVAILABILITY) {
return hasPermission(user, Permission.FUTURE_SIGNAL_VIEW)
+1 -1
View File
@@ -121,7 +121,7 @@ export const mockPipelineItems: PipelineItem[] = [
title: 'Gewerbe Güterstrasse Basel',
location: 'Basel',
matchScore: 68,
resultType: 'EXTERNAL_MARKET',
resultType: 'VERIFIED_PORTFOLIO',
stage: 'CLOSED_LOST',
areaLabel: '800 m²',
rentLabel: 'CHF 28/m²',
+23 -23
View File
@@ -1071,14 +1071,14 @@ export const mockProperties: Property[] = [
},
// ─────────────────────────────────────────────────────────────────────────────
// EXTERNAL_MARKET (10)
// VERIFIED_PORTFOLIO — formerly external market (migrated)
// ─────────────────────────────────────────────────────────────────────────────
{
id: 'prop-003',
title: 'Retail-Fläche Bahnhofstrasse 88',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Bern', district: 'Innenstadt', canton: 'BE', country: 'CH', coordinates: { lat: 46.9483, lng: 7.4474 } },
address: { street: 'Bahnhofstrasse', houseNumber: '88', postalCode: '3011', city: 'Bern', country: 'CH' },
areaSqm: 320,
@@ -1122,7 +1122,7 @@ export const mockProperties: Property[] = [
id: 'prop-004',
title: 'Gemischte Gewerbeeinheit Europaallee',
assetType: AssetType.MIXED,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Kreis 4', canton: 'ZH', country: 'CH', coordinates: { lat: 47.3775, lng: 8.5398 } },
address: { street: 'Europaallee', houseNumber: '21', postalCode: '8004', city: 'Zürich', country: 'CH' },
areaSqm: 1150,
@@ -1246,7 +1246,7 @@ export const mockProperties: Property[] = [
id: 'prop-017',
title: 'Ladenfläche Löwenstrasse 28',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Innenstadt', canton: 'ZH', country: 'CH', coordinates: { lat: 47.3766, lng: 8.5385 } },
address: { street: 'Löwenstrasse', houseNumber: '28', postalCode: '8001', city: 'Zürich', country: 'CH' },
areaSqm: 350,
@@ -1290,7 +1290,7 @@ export const mockProperties: Property[] = [
id: 'prop-018',
title: 'Bürofläche Breitenrain 14',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Bern', district: 'Breitenrain', canton: 'BE', country: 'CH', coordinates: { lat: 46.9598, lng: 7.4522 } },
address: { street: 'Breitenrainstrasse', houseNumber: '14', postalCode: '3014', city: 'Bern', country: 'CH' },
areaSqm: 780,
@@ -1458,7 +1458,7 @@ export const mockProperties: Property[] = [
id: 'prop-022',
title: 'Bürofläche St.Gallen Centrum 7',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'St. Gallen', district: 'Centrum', canton: 'SG', country: 'CH', coordinates: { lat: 47.4245, lng: 9.3767 } },
address: { street: 'Marktgasse', houseNumber: '7', postalCode: '9000', city: 'St. Gallen', country: 'CH' },
areaSqm: 700,
@@ -1666,7 +1666,7 @@ export const mockProperties: Property[] = [
id: 'prop-031',
title: 'Bürofläche Hardturm West 16',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Zürich-West', canton: 'ZH', country: 'CH', coordinates: { lat: 47.3862, lng: 8.5045 } },
address: { street: 'Hardturmstrasse', houseNumber: '16', postalCode: '8005', city: 'Zürich', country: 'CH' },
areaSqm: 780,
@@ -1780,7 +1780,7 @@ export const mockProperties: Property[] = [
id: 'prop-034',
title: 'Ladenfläche Lorrainestrasse 8',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Bern', district: 'Lorraine', canton: 'BE', country: 'CH', coordinates: { lat: 46.9565, lng: 7.4388 } },
address: { street: 'Lorrainestrasse', houseNumber: '8', postalCode: '3013', city: 'Bern', country: 'CH' },
areaSqm: 340,
@@ -1844,7 +1844,7 @@ export const mockProperties: Property[] = [
id: 'prop-036',
title: 'Lagerhalle Klybeckstrasse 280',
assetType: AssetType.LOGISTICS,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Basel', district: 'Kleinhüningen', canton: 'BS', country: 'CH', coordinates: { lat: 47.5744, lng: 7.5862 } },
address: { street: 'Klybeckstrasse', houseNumber: '280', postalCode: '4057', city: 'Basel', country: 'CH' },
areaSqm: 2600,
@@ -2206,7 +2206,7 @@ export const mockProperties: Property[] = [
id: 'prop-055',
title: 'Ladenfläche Weststrasse 44',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Kreis 3', canton: 'ZH', country: 'CH', coordinates: { lat: 47.372, lng: 8.521 } },
address: { street: 'Weststrasse', houseNumber: '44', postalCode: '8003', city: 'Zürich', country: 'CH' },
areaSqm: 150,
@@ -2254,7 +2254,7 @@ export const mockProperties: Property[] = [
id: 'prop-056',
title: 'Gewerbefläche Hohlstrasse 88',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Kreis 4', canton: 'ZH', country: 'CH', coordinates: { lat: 47.375, lng: 8.527 } },
address: { street: 'Hohlstrasse', houseNumber: '88', postalCode: '8004', city: 'Zürich', country: 'CH' },
areaSqm: 155,
@@ -2667,7 +2667,7 @@ export const mockProperties: Property[] = [
id: 'prop-064',
title: 'Bürofläche Förrlibuckstrasse 22',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Zürich-West', canton: 'ZH', country: 'CH', coordinates: { lat: 47.388, lng: 8.510 } },
address: { street: 'Förrlibuckstrasse', houseNumber: '22', postalCode: '8005', city: 'Zürich', country: 'CH' },
areaSqm: 185,
@@ -2714,7 +2714,7 @@ export const mockProperties: Property[] = [
id: 'prop-065',
title: 'Bürofläche Binzmühlestrasse 95, Oerlikon',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Oerlikon', canton: 'ZH', country: 'CH', coordinates: { lat: 47.411, lng: 8.544 } },
address: { street: 'Binzmühlestrasse', houseNumber: '95', postalCode: '8050', city: 'Zürich', country: 'CH' },
areaSqm: 175,
@@ -2813,7 +2813,7 @@ export const mockProperties: Property[] = [
id: 'prop-067',
title: 'Bürofläche Altstetterstrasse 222',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Altstetten', canton: 'ZH', country: 'CH', coordinates: { lat: 47.385, lng: 8.488 } },
address: { street: 'Altstetterstrasse', houseNumber: '222', postalCode: '8048', city: 'Zürich', country: 'CH' },
areaSqm: 190,
@@ -3175,7 +3175,7 @@ export const mockProperties: Property[] = [
id: 'prop-074',
title: 'Bürofläche Uraniastrasse 14',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Kreis 1', canton: 'ZH', country: 'CH', coordinates: { lat: 47.376, lng: 8.541 } },
address: { street: 'Uraniastrasse', houseNumber: '14', postalCode: '8001', city: 'Zürich', country: 'CH' },
areaSqm: 510,
@@ -3223,7 +3223,7 @@ export const mockProperties: Property[] = [
id: 'prop-075',
title: 'Bürofläche Seefeldstrasse 30',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Seefeld', canton: 'ZH', country: 'CH', coordinates: { lat: 47.356, lng: 8.550 } },
address: { street: 'Seefeldstrasse', houseNumber: '30', postalCode: '8008', city: 'Zürich', country: 'CH' },
areaSqm: 540,
@@ -3483,7 +3483,7 @@ export const mockProperties: Property[] = [
id: 'prop-080',
title: 'Ladenfläche Spitalgasse 34',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Bern', district: 'Innenstadt', canton: 'BE', country: 'CH', coordinates: { lat: 46.948, lng: 7.447 } },
address: { street: 'Spitalgasse', houseNumber: '34', postalCode: '3011', city: 'Bern', country: 'CH' },
areaSqm: 280,
@@ -3531,7 +3531,7 @@ export const mockProperties: Property[] = [
id: 'prop-081',
title: 'Ladenfläche Münstergasse 12',
assetType: AssetType.RETAIL,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Bern', district: 'Innenstadt', canton: 'BE', country: 'CH', coordinates: { lat: 46.948, lng: 7.447 } },
address: { street: 'Münstergasse', houseNumber: '12', postalCode: '3011', city: 'Bern', country: 'CH' },
areaSqm: 350,
@@ -3838,7 +3838,7 @@ export const mockProperties: Property[] = [
id: 'prop-087',
title: 'Lagerhalle Hauptstrasse 180, Pratteln',
assetType: AssetType.LOGISTICS,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Pratteln', district: 'Industriezone', canton: 'BL', country: 'CH', coordinates: { lat: 47.519, lng: 7.689 } },
address: { street: 'Hauptstrasse', houseNumber: '180', postalCode: '4133', city: 'Pratteln', country: 'CH' },
areaSqm: 3000,
@@ -3885,7 +3885,7 @@ export const mockProperties: Property[] = [
id: 'prop-088',
title: 'Lagerhalle Westquaistrasse 12',
assetType: AssetType.LOGISTICS,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Basel', district: 'Kleinhüningen', canton: 'BS', country: 'CH', coordinates: { lat: 47.574, lng: 7.591 } },
address: { street: 'Westquaistrasse', houseNumber: '12', postalCode: '4057', city: 'Basel', country: 'CH' },
areaSqm: 2600,
@@ -4091,7 +4091,7 @@ export const mockProperties: Property[] = [
id: 'prop-092',
title: 'Bürofläche Hohlstrasse 534, Altstetten',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Altstetten', canton: 'ZH', country: 'CH', coordinates: { lat: 47.385, lng: 8.488 } },
address: { street: 'Hohlstrasse', houseNumber: '534', postalCode: '8048', city: 'Zürich', country: 'CH' },
areaSqm: 900,
@@ -4138,7 +4138,7 @@ export const mockProperties: Property[] = [
id: 'prop-093',
title: 'Bürofläche Technopark Zürich-West',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zürich', district: 'Zürich-West', canton: 'ZH', country: 'CH', coordinates: { lat: 47.388, lng: 8.510 } },
address: { street: 'Technoparkstrasse', houseNumber: '2', postalCode: '8005', city: 'Zürich', country: 'CH' },
areaSqm: 960,
@@ -4343,7 +4343,7 @@ export const mockProperties: Property[] = [
id: 'prop-097',
title: 'Bürofläche Baarerstrasse 18, Zug',
assetType: AssetType.OFFICE,
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
location: { city: 'Zug', district: 'Innenstadt', canton: 'ZG', country: 'CH', coordinates: { lat: 47.174, lng: 8.514 } },
address: { street: 'Baarerstrasse', houseNumber: '18', postalCode: '6300', city: 'Zug', country: 'CH' },
areaSqm: 320,
+1 -1
View File
@@ -88,7 +88,7 @@ export default function MatchDetail() {
const handleCompare = () => {
if (match && !isFuture && property) {
addToCompare({
resultType: property.resultType === 'EXTERNAL_MARKET' ? 'EXTERNAL_MARKET' : 'VERIFIED_PORTFOLIO',
resultType: property.resultType ?? 'VERIFIED_PORTFOLIO',
matchId: match.id, needId: match.needId, matchScore: match.matchScore, match, property,
})
} else if (match && isFuture && signal) {
+1 -2
View File
@@ -73,7 +73,7 @@ export default function Results() {
const { platformCount, maisonWorkCount, futureCount, missingDataCount } = useMemo(() => {
let platform = 0, maison = 0, future = 0, missing = 0
for (const r of results) {
if (r.resultType === 'VERIFIED_PORTFOLIO' || r.resultType === 'EXTERNAL_MARKET') platform++
if (r.resultType === 'VERIFIED_PORTFOLIO') platform++
else if (r.resultType === 'MAISON_WORK') maison++
else if (r.resultType === 'FUTURE_AVAILABILITY') future++
if ('match' in r && Array.isArray((r as { match?: { missingData?: unknown[] } }).match?.missingData) &&
@@ -91,7 +91,6 @@ export default function Results() {
return filterSource === 'ALL' || filterSource === 'PLATFORM'
}
if (filterSource === 'ALL') return true
if (filterSource === 'PLATFORM') return r.resultType === 'EXTERNAL_MARKET'
return r.resultType === filterSource
})
return sortResults(filtered, sortBy)
+1 -1
View File
@@ -47,7 +47,7 @@ export function buildCreatePropertyInput(fields: {
return {
title: `${ASSET_TYPE_LABELS[assetType] ?? assetType} · ${city}`,
assetType: assetType as typeof AssetType[keyof typeof AssetType],
resultType: ResultType.EXTERNAL_MARKET,
resultType: ResultType.VERIFIED_PORTFOLIO,
sourceType: 'DIRECT',
location: { city, country: 'CH' },
address: {
+1 -1
View File
@@ -1,7 +1,7 @@
export interface DashboardStats {
totalProperties: number
verifiedProperties: number
externalMarketProperties: number
verifiedPortfolioProperties: number
futureSignalProperties: number
totalMatches: number
pendingReviews: number
+1 -1
View File
@@ -32,7 +32,7 @@ export const MockupDashboardProvider: IDashboardProvider = {
const stats: DashboardStats = {
totalProperties: props.length,
verifiedProperties: props.filter(p => p.resultType === 'VERIFIED_PORTFOLIO').length,
externalMarketProperties: props.filter(p => p.resultType === 'EXTERNAL_MARKET').length,
verifiedPortfolioProperties: props.filter(p => p.resultType === 'VERIFIED_PORTFOLIO').length,
futureSignalProperties: props.filter(p => p.resultType === 'FUTURE_AVAILABILITY').length,
totalMatches: matches.length,
pendingReviews: queue.filter(r => r.status === 'PENDING').length,