feat: expose all 13 scoring criteria as weighting sliders
Previously only 8 of the 13 engine criteria had sliders — flexibility, visibility, footfall, talentAccess, esg were scored using fixed defaults with no user control. Now all 13 criteria appear in the WeightingEditor. - needBuilder.ts: WEIGHTING_KEYS and WEIGHTING_LABELS extended to all 13 - scoreCalculator.ts: CORE array in resolveProfile now includes all 13 - need.ts: WeightingProfile interface explicit for all 13 fields - needs.ts: all 11 mock need profiles updated with asset-type-appropriate weights (RETAIL needs high footfall/visibility; LOGISTICS low; OFFICE high talentAccess; TechStart high taxEnvironment for Zug, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,11 @@ export interface WeightingProfile {
|
||||
prestige: number
|
||||
accessibility: number
|
||||
expansionPotential: number
|
||||
flexibility: number
|
||||
visibility: number
|
||||
footfall: number
|
||||
talentAccess: number
|
||||
esg: number
|
||||
taxEnvironment: number
|
||||
[key: string]: number
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@ export const NeedBuilderStep = {
|
||||
} as const
|
||||
export type NeedBuilderStep = typeof NeedBuilderStep[keyof typeof NeedBuilderStep]
|
||||
|
||||
export const WEIGHTING_KEYS = ['area', 'location', 'budget', 'timing', 'prestige', 'accessibility', 'expansionPotential', 'taxEnvironment'] as const
|
||||
export const WEIGHTING_KEYS = [
|
||||
'area', 'location', 'budget', 'timing',
|
||||
'prestige', 'accessibility', 'expansionPotential', 'flexibility',
|
||||
'visibility', 'footfall', 'talentAccess', 'esg', 'taxEnvironment',
|
||||
] as const
|
||||
export type WeightingKey = typeof WEIGHTING_KEYS[number]
|
||||
|
||||
export const WEIGHTING_LABELS: Record<WeightingKey, string> = {
|
||||
@@ -65,5 +69,10 @@ export const WEIGHTING_LABELS: Record<WeightingKey, string> = {
|
||||
prestige: 'Prestige',
|
||||
accessibility: 'Erreichbarkeit',
|
||||
expansionPotential: 'Expansionspotenzial',
|
||||
flexibility: 'Flexibilität',
|
||||
visibility: 'Sichtbarkeit',
|
||||
footfall: 'Passantenfrequenz',
|
||||
talentAccess: 'Talent-Zugang',
|
||||
esg: 'ESG',
|
||||
taxEnvironment: 'Steuerlast',
|
||||
}
|
||||
|
||||
@@ -22,7 +22,11 @@ function resolveProfile(need: Need, property: Property): ScoringWeightProfile {
|
||||
if (!np) return base
|
||||
|
||||
// Apply need's custom core weights, then renormalize the full profile to 1.00
|
||||
const CORE = ['area', 'location', 'budget', 'timing', 'prestige', 'accessibility', 'expansionPotential', 'taxEnvironment']
|
||||
const CORE = [
|
||||
'area', 'location', 'budget', 'timing',
|
||||
'prestige', 'accessibility', 'expansionPotential', 'flexibility',
|
||||
'visibility', 'footfall', 'talentAccess', 'esg', 'taxEnvironment',
|
||||
]
|
||||
for (const key of CORE) {
|
||||
if (typeof np[key] === 'number') base[key] = np[key]
|
||||
}
|
||||
|
||||
+33
-88
@@ -26,14 +26,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 6,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.20,
|
||||
location: 0.20,
|
||||
budget: 0.15,
|
||||
timing: 0.15,
|
||||
prestige: 0.10,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.05,
|
||||
flexibility: 0.05,
|
||||
area: 0.18, location: 0.18, budget: 0.14, timing: 0.13,
|
||||
prestige: 0.08, accessibility: 0.10, expansionPotential: 0.04, flexibility: 0.05,
|
||||
visibility: 0.02, footfall: 0.01, talentAccess: 0.06, esg: 0.02, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.88,
|
||||
extractedFromText: 'Wir suchen moderne Büroflächen in Zürich-West, ca. 700–900m², Budget max CHF 42/m², Bezug Herbst 2025.',
|
||||
@@ -62,14 +57,9 @@ export const mockNeeds: Need[] = [
|
||||
requireParking: true,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.25,
|
||||
location: 0.20,
|
||||
budget: 0.20,
|
||||
timing: 0.15,
|
||||
prestige: 0.02,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.05,
|
||||
flexibility: 0.03,
|
||||
area: 0.23, location: 0.18, budget: 0.18, timing: 0.13,
|
||||
prestige: 0.02, accessibility: 0.10, expansionPotential: 0.05, flexibility: 0.03,
|
||||
visibility: 0.01, footfall: 0.00, talentAccess: 0.02, esg: 0.02, taxEnvironment: 0.03,
|
||||
},
|
||||
confidenceInCriteria: 0.94,
|
||||
organizationId: 'org-wincasa',
|
||||
@@ -101,14 +91,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 10,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.20,
|
||||
location: 0.25,
|
||||
budget: 0.20,
|
||||
timing: 0.10,
|
||||
prestige: 0.12,
|
||||
accessibility: 0.08,
|
||||
expansionPotential: 0.03,
|
||||
flexibility: 0.02,
|
||||
area: 0.18, location: 0.22, budget: 0.17, timing: 0.09,
|
||||
prestige: 0.10, accessibility: 0.08, expansionPotential: 0.03, flexibility: 0.02,
|
||||
visibility: 0.02, footfall: 0.01, talentAccess: 0.08, esg: 0.05, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.91,
|
||||
extractedFromText: 'Suche repräsentative Büroflächen im Raum Basel/Allschwil, 500–800m², max. CHF 38/m², Bezug Q4 2025.',
|
||||
@@ -140,14 +125,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 5,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.15,
|
||||
location: 0.35,
|
||||
budget: 0.15,
|
||||
timing: 0.10,
|
||||
prestige: 0.15,
|
||||
accessibility: 0.05,
|
||||
expansionPotential: 0.02,
|
||||
flexibility: 0.03,
|
||||
area: 0.10, location: 0.20, budget: 0.12, timing: 0.08,
|
||||
prestige: 0.06, accessibility: 0.04, expansionPotential: 0.02, flexibility: 0.04,
|
||||
visibility: 0.12, footfall: 0.15, talentAccess: 0.01, esg: 0.01, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.96,
|
||||
extractedFromText: 'Exklusive Retailfläche in Zürich Innenstadt gesucht, 250–450m², Schaufenster, max. CHF 95/m².',
|
||||
@@ -180,14 +160,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 10,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.20,
|
||||
location: 0.25,
|
||||
budget: 0.20,
|
||||
timing: 0.15,
|
||||
prestige: 0.05,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.03,
|
||||
flexibility: 0.02,
|
||||
area: 0.17, location: 0.22, budget: 0.17, timing: 0.12,
|
||||
prestige: 0.05, accessibility: 0.10, expansionPotential: 0.03, flexibility: 0.02,
|
||||
visibility: 0.02, footfall: 0.01, talentAccess: 0.08, esg: 0.02, taxEnvironment: 0.04,
|
||||
},
|
||||
confidenceInCriteria: 0.85,
|
||||
extractedFromText: 'Junges Tech-Unternehmen sucht Büro in Zug oder Zürich, 350–600m², moderner Ausbau, max. CHF 45/m².',
|
||||
@@ -216,14 +191,9 @@ export const mockNeeds: Need[] = [
|
||||
requireParking: true,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.30,
|
||||
location: 0.25,
|
||||
budget: 0.20,
|
||||
timing: 0.10,
|
||||
prestige: 0.01,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.02,
|
||||
flexibility: 0.02,
|
||||
area: 0.27, location: 0.22, budget: 0.18, timing: 0.10,
|
||||
prestige: 0.01, accessibility: 0.10, expansionPotential: 0.02, flexibility: 0.02,
|
||||
visibility: 0.01, footfall: 0.00, talentAccess: 0.02, esg: 0.02, taxEnvironment: 0.02,
|
||||
},
|
||||
confidenceInCriteria: 0.92,
|
||||
organizationId: 'org-wincasa',
|
||||
@@ -255,14 +225,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 12,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.20,
|
||||
location: 0.20,
|
||||
budget: 0.15,
|
||||
timing: 0.15,
|
||||
prestige: 0.10,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.05,
|
||||
flexibility: 0.05,
|
||||
area: 0.17, location: 0.15, budget: 0.13, timing: 0.12,
|
||||
prestige: 0.07, accessibility: 0.09, expansionPotential: 0.04, flexibility: 0.06,
|
||||
visibility: 0.07, footfall: 0.05, talentAccess: 0.06, esg: 0.03, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.82,
|
||||
extractedFromText: 'Kreativagentur sucht Gewerbe-/Bürofläche in Zürich oder Bern, 900–1400m², gemischte Nutzung, Budget max. CHF 50/m².',
|
||||
@@ -291,14 +256,9 @@ export const mockNeeds: Need[] = [
|
||||
requireParking: true,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.30,
|
||||
location: 0.20,
|
||||
budget: 0.20,
|
||||
timing: 0.10,
|
||||
prestige: 0.01,
|
||||
accessibility: 0.10,
|
||||
expansionPotential: 0.07,
|
||||
flexibility: 0.02,
|
||||
area: 0.26, location: 0.18, budget: 0.18, timing: 0.10,
|
||||
prestige: 0.01, accessibility: 0.12, expansionPotential: 0.07, flexibility: 0.02,
|
||||
visibility: 0.01, footfall: 0.00, talentAccess: 0.03, esg: 0.03, taxEnvironment: 0.02,
|
||||
},
|
||||
confidenceInCriteria: 0.95,
|
||||
organizationId: 'org-wincasa',
|
||||
@@ -329,14 +289,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 5,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.15,
|
||||
location: 0.35,
|
||||
budget: 0.15,
|
||||
timing: 0.10,
|
||||
prestige: 0.15,
|
||||
accessibility: 0.05,
|
||||
expansionPotential: 0.02,
|
||||
flexibility: 0.03,
|
||||
area: 0.10, location: 0.22, budget: 0.12, timing: 0.08,
|
||||
prestige: 0.07, accessibility: 0.04, expansionPotential: 0.01, flexibility: 0.04,
|
||||
visibility: 0.12, footfall: 0.14, talentAccess: 0.01, esg: 0.01, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.93,
|
||||
extractedFromText: 'Recherche surface commerciale en centre-ville de Genève, 200–350m², vitrine obligatoire, budget max CHF 115/m².',
|
||||
@@ -368,14 +323,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 5,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.15,
|
||||
location: 0.35,
|
||||
budget: 0.15,
|
||||
timing: 0.10,
|
||||
prestige: 0.15,
|
||||
accessibility: 0.05,
|
||||
expansionPotential: 0.02,
|
||||
flexibility: 0.03,
|
||||
area: 0.10, location: 0.22, budget: 0.12, timing: 0.08,
|
||||
prestige: 0.06, accessibility: 0.04, expansionPotential: 0.01, flexibility: 0.04,
|
||||
visibility: 0.12, footfall: 0.15, talentAccess: 0.01, esg: 0.01, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.92,
|
||||
extractedFromText: 'Suche Retailfläche in Bern Innenstadt, 200–400m², Schaufensterfront, Fussgängerzone, max. CHF 150/m².',
|
||||
@@ -408,14 +358,9 @@ export const mockNeeds: Need[] = [
|
||||
maxPublicTransportMinutes: 8,
|
||||
},
|
||||
weightingProfile: {
|
||||
area: 0.22,
|
||||
location: 0.28,
|
||||
budget: 0.20,
|
||||
timing: 0.12,
|
||||
prestige: 0.08,
|
||||
accessibility: 0.06,
|
||||
expansionPotential: 0.02,
|
||||
flexibility: 0.02,
|
||||
area: 0.20, location: 0.25, budget: 0.18, timing: 0.11,
|
||||
prestige: 0.07, accessibility: 0.06, expansionPotential: 0.02, flexibility: 0.02,
|
||||
visibility: 0.02, footfall: 0.01, talentAccess: 0.05, esg: 0.02, taxEnvironment: 0.00,
|
||||
},
|
||||
confidenceInCriteria: 0.87,
|
||||
extractedFromText: 'Büroflächen in St. Gallen oder Umgebung gesucht, 450–750m², max. CHF 32/m², Bezug Anfang 2026.',
|
||||
|
||||
Reference in New Issue
Block a user