70 lines
3.5 KiB
TypeScript
70 lines
3.5 KiB
TypeScript
import {
|
|
getAllRows, getRowById, getRowsWhereEquals, insertRow, updateRow,
|
|
deleteRowsWhereEquals, deleteRowsWhereIn, deleteRowById,
|
|
} from '../crud'
|
|
import type {
|
|
MeetingInstance, PhaseTemplate, Assignment, Consultant,
|
|
ConversationEntry, ConversationSkillScore, Assessment,
|
|
} from '../../../src/db/types'
|
|
import { getConsultantsByIds } from './consultants'
|
|
|
|
export const getMeetingInstance = (id: number): MeetingInstance | undefined => getRowById<MeetingInstance>('meetingInstances', id)
|
|
export const listMeetingInstancesForAssignment = (assignmentId: number): MeetingInstance[] =>
|
|
getRowsWhereEquals<MeetingInstance>('meetingInstances', 'assignmentId', assignmentId)
|
|
|
|
/**
|
|
* Kanonischer Filter für Aggregationen über mehrere Meetings: Papierkorb-/unfertige Meetings ausschließen,
|
|
* chronologisch sortiert. Siehe CLAUDE.md — immer diese Funktion nutzen, nicht erneut inline filtern.
|
|
*/
|
|
export function listDoneMeetingsChronological(assignmentId: number): MeetingInstance[] {
|
|
const instances = listMeetingInstancesForAssignment(assignmentId)
|
|
return instances
|
|
.filter(m => !m.deletedAt && m.status === 'done')
|
|
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
|
|
}
|
|
|
|
export const addMeetingInstance = (m: Omit<MeetingInstance, 'id'>): number => insertRow('meetingInstances', m)
|
|
export const updateMeetingInstance = (id: number, patch: Partial<MeetingInstance>): number =>
|
|
updateRow('meetingInstances', id, patch)
|
|
export const softDeleteMeetingInstance = (id: number): number =>
|
|
updateRow('meetingInstances', id, { deletedAt: new Date().toISOString() })
|
|
export const restoreMeetingInstance = (id: number): number =>
|
|
updateRow('meetingInstances', id, { deletedAt: null })
|
|
|
|
/** Cascade: conversationSkillScores der Entries → conversationEntries → assessments → meetingInstance. */
|
|
export function hardDeleteMeetingInstance(id: number): void {
|
|
const entryIds = getRowsWhereEquals<ConversationEntry>('conversationEntries', 'meetingInstanceId', id).map(e => e.id!)
|
|
deleteRowsWhereIn('conversationSkillScores', 'conversationEntryId', entryIds)
|
|
deleteRowsWhereEquals('conversationEntries', 'meetingInstanceId', id)
|
|
deleteRowsWhereEquals('assessments', 'meetingInstanceId', id)
|
|
deleteRowById('meetingInstances', id)
|
|
}
|
|
|
|
export interface MeetingExportData {
|
|
meeting: MeetingInstance
|
|
template: PhaseTemplate | undefined
|
|
assignment: Assignment | undefined
|
|
consultants: Consultant[]
|
|
entries: ConversationEntry[]
|
|
allScores: ConversationSkillScore[]
|
|
assessments: Assessment[]
|
|
}
|
|
|
|
/** Gebündelte Rohdaten für Markdown-/JSON-Export eines Meetings — vorher in meetingExport.ts dupliziert. */
|
|
export function getMeetingExportData(meetingId: number): MeetingExportData {
|
|
const meeting = getRowById<MeetingInstance>('meetingInstances', meetingId)
|
|
if (!meeting) throw new Error('Meeting nicht gefunden')
|
|
|
|
const template = getRowById<PhaseTemplate>('phaseTemplates', meeting.phaseTemplateId)
|
|
const assignment = getRowById<Assignment>('assignments', meeting.assignmentId)
|
|
|
|
const instituteeIds = assignment?.instituteeIds ?? []
|
|
const consultants = getConsultantsByIds(instituteeIds)
|
|
const entries = getRowsWhereEquals<ConversationEntry>('conversationEntries', 'meetingInstanceId', meetingId)
|
|
.sort((a, b) => a.sequenceIndex - b.sequenceIndex)
|
|
const allScores = getAllRows<ConversationSkillScore>('conversationSkillScores')
|
|
const assessments = getRowsWhereEquals<Assessment>('assessments', 'meetingInstanceId', meetingId)
|
|
|
|
return { meeting, template, assignment, consultants, entries, allScores, assessments }
|
|
}
|