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>
|
|||
|
|
)
|
|||
|
|
}
|