fix: Evaluation.tsx nach Assignment gruppiert, Papierkorb/Status gefiltert

- Oberste Gliederungsebene ist jetzt das Assignment, Institutees darunter
- Meeting-Filter: nur status='done', keine Papierkorb-Meetings (deletedAt)
- Migriert auf feedbackCriterionItems statt Legacy categories/criteria
- zustand aus package.json entfernt (ungenutzt)
This commit is contained in:
Lars 2026-07-02 11:16:41 +02:00
parent 63ca6583fa
commit f57db9d161

View File

@ -75,7 +75,7 @@ export default function Evaluation() {
for (const a of assignments) { for (const a of assignments) {
const meetingIds = (await db.meetingInstances const meetingIds = (await db.meetingInstances
.where('assignmentId').equals(a.id!).toArray() .where('assignmentId').equals(a.id!).toArray()
).map(m => m.id!) ).filter(m => !m.deletedAt && m.status === 'done').map(m => m.id!)
for (const instId of a.instituteeIds) { for (const instId of a.instituteeIds) {
const inst = consultants.find(c => c.id === instId) const inst = consultants.find(c => c.id === instId)
@ -87,7 +87,7 @@ export default function Evaluation() {
if (instAssessments.length === 0) continue if (instAssessments.length === 0) continue
const getScore = (itemId: number): FeedbackRating | null => { const getScore = (itemId: number): FeedbackRating | null => {
const relevant = instAssessments.filter(a => a.criteriaId === itemId && a.score !== null) const relevant = instAssessments.filter(a => a.criteriaId === itemId && a.score !== null && a.score !== 'na')
if (relevant.length === 0) return null if (relevant.length === 0) return null
const avg = relevant.reduce((s, a) => s + RATING_NUM_MAP[a.score!], 0) / relevant.length const avg = relevant.reduce((s, a) => s + RATING_NUM_MAP[a.score!], 0) / relevant.length
if (avg < 1.5) return 'not_client_ready' if (avg < 1.5) return 'not_client_ready'
@ -114,23 +114,41 @@ export default function Evaluation() {
const rowKey = (r: InstScore) => `${r.assignment.id}-${r.institutee.id}` const rowKey = (r: InstScore) => `${r.assignment.id}-${r.institutee.id}`
const assignmentGroups = data.reduce<Map<number, { assignment: Assignment; rows: InstScore[] }>>(
(map, row) => {
const key = row.assignment.id!
const group = map.get(key)
if (group) group.rows.push(row)
else map.set(key, { assignment: row.assignment, rows: [row] })
return map
},
new Map()
)
return ( return (
<div className="space-y-4"> <div className="space-y-6">
<h1 className="text-xl font-bold text-gray-800">Auswertung</h1> <h1 className="text-xl font-bold text-gray-800">Auswertung</h1>
{data.length === 0 && ( {data.length === 0 && (
<p className="text-gray-500 text-sm">Noch keine Bewertungen vorhanden.</p> <p className="text-gray-500 text-sm">Noch keine Bewertungen vorhanden.</p>
)} )}
{data.map(row => ( {[...assignmentGroups.values()].map(({ assignment, rows }) => (
<div key={assignment.id} className="space-y-2">
<div className="px-1">
{assignment.assignmentNumber && (
<div className="text-xs font-semibold text-brand uppercase tracking-wide">{assignment.assignmentNumber}</div>
)}
<h2 className="font-bold text-gray-800">{assignment.title}</h2>
<div className="text-xs text-gray-400">{assignment.client}</div>
</div>
{rows.map(row => (
<div key={rowKey(row)} className="bg-white rounded-xl shadow-sm border border-gray-100 p-4"> <div key={rowKey(row)} className="bg-white rounded-xl shadow-sm border border-gray-100 p-4">
<div <div
className="flex items-start justify-between cursor-pointer" className="flex items-start justify-between cursor-pointer"
onClick={() => setSelected(selected === rowKey(row) ? null : rowKey(row))}> onClick={() => setSelected(selected === rowKey(row) ? null : rowKey(row))}>
<div>
<div className="font-semibold text-gray-800"> <div className="font-semibold text-gray-800">
{row.institutee.firstName} {row.institutee.lastName} {row.institutee.firstName} {row.institutee.lastName}
</div> </div>
<div className="text-xs text-gray-400">{row.assignment.title} · {row.assignment.client}</div>
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className={`px-3 py-1 rounded-full text-sm font-bold ${ratingColor(row.overall)}`}> <div className={`px-3 py-1 rounded-full text-sm font-bold ${ratingColor(row.overall)}`}>
{ratingLabel(row.overall)} {ratingLabel(row.overall)}
@ -173,5 +191,7 @@ export default function Evaluation() {
</div> </div>
))} ))}
</div> </div>
))}
</div>
) )
} }