80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { useEffect, useState } from 'react'
|
||
import { db } from '../db'
|
||
import { DEFAULT_RATING_TREND_WEIGHT_STEP } from '../config/constants'
|
||
import { previewWeights } from '../utils/ratingTrend'
|
||
|
||
export default function RatingWeightConfig() {
|
||
const [weightStep, setWeightStep] = useState(DEFAULT_RATING_TREND_WEIGHT_STEP)
|
||
const [saved, setSaved] = useState(false)
|
||
|
||
useEffect(() => {
|
||
const load = async () => {
|
||
let settings = await db.appSettings.get(1)
|
||
if (!settings) {
|
||
await db.appSettings.add({ id: 1, ratingTrendWeightStep: DEFAULT_RATING_TREND_WEIGHT_STEP })
|
||
settings = await db.appSettings.get(1)
|
||
}
|
||
setWeightStep(settings?.ratingTrendWeightStep ?? DEFAULT_RATING_TREND_WEIGHT_STEP)
|
||
}
|
||
load()
|
||
}, [])
|
||
|
||
const save = async () => {
|
||
await db.appSettings.put({ id: 1, ratingTrendWeightStep: weightStep })
|
||
setSaved(true)
|
||
setTimeout(() => setSaved(false), 2500)
|
||
}
|
||
|
||
return (
|
||
<div className="bg-white rounded-xl border border-gray-100 shadow-sm p-5 space-y-4">
|
||
<div>
|
||
<h2 className="font-semibold text-gray-800">Zeitgewichtung des Bewertungs-Vorschlags</h2>
|
||
<p className="text-sm text-gray-500 mt-1">
|
||
Steuert, wie stark spätere Meetings in den Bewertungs-Vorschlag auf der Auswertungs- und
|
||
Feedback-Seite einfließen. 0 = alle Meetings gleich gewichtet, höher = stärkere Gewichtung
|
||
späterer Bewertungen.
|
||
</p>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<div className="flex items-center justify-between">
|
||
<label className="text-sm font-medium text-gray-700">Gewichtungsfaktor</label>
|
||
<span className="text-sm font-semibold text-brand">{weightStep.toFixed(1)}</span>
|
||
</div>
|
||
<input
|
||
type="range"
|
||
min={0}
|
||
max={2}
|
||
step={0.1}
|
||
value={weightStep}
|
||
onChange={e => setWeightStep(Number(e.target.value))}
|
||
className="w-full"
|
||
/>
|
||
</div>
|
||
|
||
<div className="bg-gray-50 rounded-lg border border-gray-100 p-3">
|
||
<div className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1.5">
|
||
Beispiel bei 3 bewerteten Meetings
|
||
</div>
|
||
<div className="flex gap-2 text-sm text-gray-600">
|
||
{previewWeights(3, weightStep).map((w, i) => (
|
||
<span key={i} className="bg-white border border-gray-200 rounded px-2 py-1">
|
||
Meeting {i + 1}: ×{w.toFixed(1)}
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<button onClick={save}
|
||
className="w-full py-2.5 bg-brand text-white rounded-xl text-sm font-semibold">
|
||
Speichern
|
||
</button>
|
||
{saved && (
|
||
<div className="text-xs text-green-700 bg-green-50 border border-green-200 rounded-lg px-3 py-2 text-center">
|
||
Gespeichert.
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|