97 lines
3.6 KiB
TypeScript
97 lines
3.6 KiB
TypeScript
type PerformanceSurveyProgressQuestion = {
|
|
id: string
|
|
}
|
|
|
|
type PerformanceSurveyProgressWorkItem = {
|
|
id: string
|
|
scores?: Array<{
|
|
assignmentId?: string | null
|
|
totalScore?: unknown
|
|
scores?: Record<string, unknown> | null
|
|
}> | null
|
|
}
|
|
|
|
export function calculatePerformanceSurveyResponseProgress(input: {
|
|
questions: PerformanceSurveyProgressQuestion[]
|
|
draftScores?: Record<string, unknown> | null
|
|
submittedScores?: Record<string, unknown> | null
|
|
submitted: boolean
|
|
}) {
|
|
const scoreSource = input.submitted
|
|
? input.submittedScores || {}
|
|
: input.draftScores || {}
|
|
const values = input.questions.map((question) => {
|
|
const rawValue = scoreSource[question.id]
|
|
if (rawValue === null || rawValue === undefined || rawValue === '') return null
|
|
const numericValue = Number(rawValue)
|
|
return Number.isFinite(numericValue) ? numericValue : null
|
|
})
|
|
const ratedValues = values.filter((value): value is number => value !== null)
|
|
const totalCount = input.questions.length
|
|
const ratedCount = ratedValues.length
|
|
|
|
return {
|
|
ratedCount,
|
|
totalCount,
|
|
totalScore: ratedValues.reduce((sum, value) => sum + value, 0),
|
|
percent: totalCount > 0 ? Math.min(100, (ratedCount / totalCount) * 100) : 0,
|
|
}
|
|
}
|
|
|
|
export function calculatePerformanceSurveyWorkItemProgress(input: {
|
|
workItems: PerformanceSurveyProgressWorkItem[]
|
|
questions: PerformanceSurveyProgressQuestion[]
|
|
scoreDrafts?: Record<string, { scores?: Record<string, unknown> | null } | undefined> | null
|
|
assignmentId?: string | null
|
|
}) {
|
|
const assignmentId = String(input.assignmentId || '')
|
|
const persistedScores = input.workItems
|
|
.map((item) => ({
|
|
workItemId: item.id,
|
|
score: assignmentId
|
|
? item.scores?.find((candidate) => candidate.assignmentId === assignmentId)
|
|
: undefined,
|
|
}))
|
|
.filter((item) => Boolean(item.score))
|
|
const persistedWorkItemIds = persistedScores.map((item) => item.workItemId)
|
|
const persistedIdSet = new Set(persistedWorkItemIds)
|
|
const draftCompletedWorkItemIds = input.workItems
|
|
.filter((item) => {
|
|
if (persistedIdSet.has(item.id) || input.questions.length === 0) return false
|
|
return input.questions.every((question) => {
|
|
const rawValue = input.scoreDrafts?.[item.id]?.scores?.[question.id]
|
|
if (rawValue === null || rawValue === undefined || rawValue === '') return false
|
|
return Number.isFinite(Number(rawValue))
|
|
})
|
|
})
|
|
.map((item) => item.id)
|
|
const persistedTotalScore = persistedScores.reduce((sum, item) => {
|
|
const totalScore = Number(item.score?.totalScore)
|
|
if (Number.isFinite(totalScore)) return sum + totalScore
|
|
return sum + input.questions.reduce((scoreSum, question) => {
|
|
const value = Number(item.score?.scores?.[question.id])
|
|
return Number.isFinite(value) ? scoreSum + value : scoreSum
|
|
}, 0)
|
|
}, 0)
|
|
const draftTotalScore = input.workItems.reduce((sum, item) => {
|
|
if (persistedIdSet.has(item.id)) return sum
|
|
return sum + input.questions.reduce((scoreSum, question) => {
|
|
const rawValue = input.scoreDrafts?.[item.id]?.scores?.[question.id]
|
|
if (rawValue === null || rawValue === undefined || rawValue === '') return scoreSum
|
|
const value = Number(rawValue)
|
|
return Number.isFinite(value) ? scoreSum + value : scoreSum
|
|
}, 0)
|
|
}, 0)
|
|
|
|
return {
|
|
completedCount: persistedWorkItemIds.length + draftCompletedWorkItemIds.length,
|
|
persistedCount: persistedWorkItemIds.length,
|
|
totalScore: persistedTotalScore + draftTotalScore,
|
|
persistedWorkItemIds,
|
|
draftCompletedWorkItemIds,
|
|
unscoredWorkItemIds: input.workItems
|
|
.filter((item) => !persistedIdSet.has(item.id))
|
|
.map((item) => item.id),
|
|
}
|
|
}
|