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:
parent
63ca6583fa
commit
f57db9d161
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user