feat: split WeightingEditor into Harte / Weiche Kriterien sections

Hard criteria (Fläche, Standort, Budget, Verfügbarkeit) in dark blue,
soft criteria (Prestige, Erreichbarkeit, …) in purple — separated by
a divider with group labels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-22 10:13:46 +02:00
parent 9f877614c1
commit 0de48a14d7
+49 -29
View File
@@ -1,10 +1,16 @@
import { useState } from 'react'
import { Box, Button, Card, Slider, Typography } from '@mui/material'
import { Box, Button, Card, Divider, Slider, Typography } from '@mui/material'
import { RotateCcw } from 'lucide-react'
import { WEIGHTING_KEYS, WEIGHTING_LABELS } from '../../domain/needBuilder'
import { WEIGHTING_LABELS } from '../../domain/needBuilder'
import type { WeightingKey } from '../../domain/needBuilder'
import { weightingService } from '../../services/weightingService'
const HARD_KEYS: WeightingKey[] = ['area', 'location', 'budget', 'timing']
const SOFT_KEYS: WeightingKey[] = [
'prestige', 'accessibility', 'expansionPotential', 'flexibility',
'visibility', 'footfall', 'talentAccess', 'esg', 'taxEnvironment',
]
interface Props {
weights: Record<WeightingKey, number>
onChange: (weights: Record<WeightingKey, number>) => void
@@ -28,6 +34,44 @@ function rawToWeights(raw: Record<WeightingKey, number>): Record<WeightingKey, n
) as Record<WeightingKey, number>
}
function SliderGroup({
label, keys, raw, onSlider, color,
}: {
label: string
keys: WeightingKey[]
raw: Record<WeightingKey, number>
onSlider: (key: WeightingKey, v: number) => void
color: string
}) {
return (
<Box>
<Typography variant="caption" sx={{ fontWeight: 700, color, textTransform: 'uppercase', letterSpacing: 0.5, fontSize: '0.65rem', display: 'block', mb: 1.5 }}>
{label}
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px 32px' }}>
{keys.map(key => {
const importance = raw[key] ?? 3
return (
<Box key={key}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 0.5 }}>
<Typography variant="body2" sx={{ fontWeight: 500 }}>{WEIGHTING_LABELS[key]}</Typography>
<Typography variant="caption" color="text.secondary">{IMPORTANCE_LABELS[importance]}</Typography>
</Box>
<Slider
value={importance}
min={1} max={5} step={1} marks
onChange={(_, v) => onSlider(key, v as number)}
size="small"
sx={{ color }}
/>
</Box>
)
})}
</Box>
</Box>
)
}
export function WeightingEditor({ weights, onChange, assetType }: Props) {
const [raw, setRaw] = useState<Record<WeightingKey, number>>(() => toRaw(weights))
@@ -65,33 +109,9 @@ export function WeightingEditor({ weights, onChange, assetType }: Props) {
</Box>
<Card sx={{ p: 3 }}>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px 32px' }}>
{WEIGHTING_KEYS.map(key => {
const importance = raw[key] ?? 3
return (
<Box key={key}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 0.5 }}>
<Typography variant="body2" sx={{ fontWeight: 500 }}>
{WEIGHTING_LABELS[key]}
</Typography>
<Typography variant="caption" color="text.secondary">
{IMPORTANCE_LABELS[importance]}
</Typography>
</Box>
<Slider
value={importance}
min={1}
max={5}
step={1}
marks
onChange={(_, v) => handleSlider(key, v as number)}
size="small"
sx={{ color: '#1e3a5f' }}
/>
</Box>
)
})}
</Box>
<SliderGroup label="Harte Kriterien" keys={HARD_KEYS} raw={raw} onSlider={handleSlider} color="#1e3a5f" />
<Divider sx={{ my: 2.5 }} />
<SliderGroup label="Weiche Kriterien" keys={SOFT_KEYS} raw={raw} onSlider={handleSlider} color="#7c3aed" />
</Card>
</Box>
)