CG-Feedback-Monitor/server/db/queries/checklists.ts
Lars d894c3c8e4 V2-Stand: UX-Dashboard, Personen v2, Starter-Paket und Dexie-Legacy entfernt.
Sichert den lokalen Entwicklungsstand nach Gitea: Nav/Dashboard, Personen-Excel/Archiv, Team-Setup, Assignment-Übergabe und C6/C7/T2.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 14:17:25 +02:00

71 lines
3.4 KiB
TypeScript

import {
getAllRows, getRowsWhereEquals, getRowsWhereIn, insertRow, updateRow, deleteRowById, deleteRowsWhereEquals,
} from '../crud'
import type { ChecklistItemDef, ChecklistResponse } from '../../../src/db/types'
export const listChecklistItemDefsForPhaseTemplate = (phaseTemplateId: number): ChecklistItemDef[] => {
const rows = getRowsWhereEquals<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateId)
return rows.sort((a, b) => a.order - b.order)
}
/** Bulk-Variante für Berichte über mehrere Phasentypen hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
export const listChecklistItemDefsForPhaseTemplates = (phaseTemplateIds: number[]): ChecklistItemDef[] =>
getRowsWhereIn<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateIds).sort((a, b) => a.order - b.order)
export const addChecklistItemDef = (def: Omit<ChecklistItemDef, 'id'>): number => insertRow('checklistItemDefs', def)
export const updateChecklistItemDef = (id: number, patch: Partial<ChecklistItemDef>): number =>
updateRow('checklistItemDefs', id, patch)
/** Räumt zugehörige `checklistResponses` mit auf — gleiches Verteidigungs-Prinzip wie `deleteFeedbackCriterionItem`. */
export function deleteChecklistItemDef(id: number): void {
deleteRowsWhereEquals('checklistResponses', 'checklistItemId', id)
deleteRowById('checklistItemDefs', id)
}
/** Cascade-Baustein für `deletePhaseTemplate`/`deleteAssignmentType` — löscht alle Checklisten-Punkte samt Antworten einer Phase. */
export function deleteChecklistItemDefsForPhaseTemplate(phaseTemplateId: number): void {
for (const def of listChecklistItemDefsForPhaseTemplate(phaseTemplateId)) {
deleteChecklistItemDef(def.id!)
}
}
export const listChecklistResponsesForMeeting = (meetingInstanceId: number): ChecklistResponse[] =>
getRowsWhereEquals<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceId)
/** Bulk-Variante für Berichte über mehrere Meetings hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
export const listChecklistResponsesForMeetings = (meetingInstanceIds: number[]): ChecklistResponse[] =>
getRowsWhereIn<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceIds)
/**
* Upsert per Komposit-Schlüssel (meetingInstanceId, checklistItemId, instituteeId ?? null), gleiches
* Find-or-Insert-Muster wie `setAssessmentScore`/`saveAssessmentNote` in MeetingView.tsx. `criterionItemId`
* überschreibt pro Antwort individuell die Konfigurations-Vorgabe (`ChecklistItemDef.linkedCriterionItemId`)
* — siehe CLAUDE.md „Individuelle Kriterium-Zuordnung pro Checklisten-Antwort".
*/
export function upsertChecklistResponse(input: {
meetingInstanceId: number
instituteeId?: number
checklistItemId: number
rating: ChecklistResponse['rating']
note: string
criterionItemId?: number | null
criterionOverride?: boolean
}): number {
const existing = getAllRows<ChecklistResponse>('checklistResponses').find(r =>
r.meetingInstanceId === input.meetingInstanceId &&
r.checklistItemId === input.checklistItemId &&
(r.instituteeId ?? null) === (input.instituteeId ?? null),
)
const row = {
rating: input.rating,
note: input.note,
criterionItemId: input.criterionItemId,
criterionOverride: input.criterionOverride,
}
if (existing?.id) {
updateRow('checklistResponses', existing.id, row)
return existing.id
}
return insertRow('checklistResponses', { ...input, ...row })
}