180 lines
5.0 KiB
TypeScript
180 lines
5.0 KiB
TypeScript
/**
|
|
* German Grading System Utilities
|
|
* German grades: 1 (best) to 6 (worst)
|
|
*/
|
|
|
|
export type GradeSystem = "percentage" | "german" | "us-letter";
|
|
|
|
export interface GradeSystemConfig {
|
|
type: GradeSystem;
|
|
displayName: string;
|
|
description: string;
|
|
}
|
|
|
|
export const GRADE_SYSTEMS: Record<GradeSystem, GradeSystemConfig> = {
|
|
percentage: {
|
|
type: "percentage",
|
|
displayName: "Percentage (0-100%)",
|
|
description: "Standard percentage-based grading",
|
|
},
|
|
german: {
|
|
type: "german",
|
|
displayName: "German (1-6)",
|
|
description: "1 = sehr gut (very good), 6 = ungenügend (insufficient)",
|
|
},
|
|
"us-letter": {
|
|
type: "us-letter",
|
|
displayName: "US Letter (A-F)",
|
|
description: "A = 90-100%, F = below 60%",
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Convert percentage (0-100) to German grade (1-6)
|
|
* German grading scale:
|
|
* 1 (sehr gut / very good): 92-100%
|
|
* 2 (gut / good): 81-91%
|
|
* 3 (befriedigend / satisfactory): 67-80%
|
|
* 4 (ausreichend / sufficient): 50-66%
|
|
* 5 (mangelhaft / deficient): 30-49%
|
|
* 6 (ungenügend / insufficient): 0-29%
|
|
*/
|
|
export function percentageToGermanGrade(percentage: number): number {
|
|
if (percentage >= 92) return 1.0;
|
|
if (percentage >= 81) return 2.0;
|
|
if (percentage >= 67) return 3.0;
|
|
if (percentage >= 50) return 4.0;
|
|
if (percentage >= 30) return 5.0;
|
|
return 6.0;
|
|
}
|
|
|
|
/**
|
|
* Convert percentage to German grade with decimal precision
|
|
* Uses linear interpolation within each grade range
|
|
*/
|
|
export function percentageToGermanGradeDetailed(percentage: number): number {
|
|
if (percentage >= 92) {
|
|
// 1.0 - 1.5 range (92-100%)
|
|
const position = (100 - percentage) / (100 - 92);
|
|
return 1.0 + position * 0.5;
|
|
} else if (percentage >= 81) {
|
|
// 1.5 - 2.5 range (81-91%)
|
|
const position = (92 - percentage) / (92 - 81);
|
|
return 1.5 + position * 1.0;
|
|
} else if (percentage >= 67) {
|
|
// 2.5 - 3.5 range (67-80%)
|
|
const position = (81 - percentage) / (81 - 67);
|
|
return 2.5 + position * 1.0;
|
|
} else if (percentage >= 50) {
|
|
// 3.5 - 4.5 range (50-66%)
|
|
const position = (67 - percentage) / (67 - 50);
|
|
return 3.5 + position * 1.0;
|
|
} else if (percentage >= 30) {
|
|
// 4.5 - 5.5 range (30-49%)
|
|
const position = (50 - percentage) / (50 - 30);
|
|
return 4.5 + position * 1.0;
|
|
} else {
|
|
// 5.5 - 6.0 range (0-29%)
|
|
const position = (30 - percentage) / 30;
|
|
return 5.5 + position * 0.5;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert German grade (1-6) to approximate percentage
|
|
*/
|
|
export function germanGradeToPercentage(grade: number): number {
|
|
if (grade <= 1.5) return 92 + (1.5 - grade) * 16; // 92-100%
|
|
if (grade <= 2.5) return 81 + (2.5 - grade) * 11; // 81-91%
|
|
if (grade <= 3.5) return 67 + (3.5 - grade) * 14; // 67-80%
|
|
if (grade <= 4.5) return 50 + (4.5 - grade) * 17; // 50-66%
|
|
if (grade <= 5.5) return 30 + (5.5 - grade) * 20; // 30-49%
|
|
return Math.max(0, 30 - (grade - 5.5) * 60); // 0-29%
|
|
}
|
|
|
|
/**
|
|
* Get German grade description
|
|
*/
|
|
export function getGermanGradeDescription(grade: number): string {
|
|
if (grade <= 1.5) return "sehr gut (very good)";
|
|
if (grade <= 2.5) return "gut (good)";
|
|
if (grade <= 3.5) return "befriedigend (satisfactory)";
|
|
if (grade <= 4.5) return "ausreichend (sufficient)";
|
|
if (grade <= 5.5) return "mangelhaft (deficient)";
|
|
return "ungenügend (insufficient)";
|
|
}
|
|
|
|
/**
|
|
* Get color for German grade
|
|
*/
|
|
export function getGermanGradeColor(grade: number): string {
|
|
if (grade <= 2.0) return "text-green-600";
|
|
if (grade <= 3.0) return "text-blue-600";
|
|
if (grade <= 4.0) return "text-yellow-600";
|
|
if (grade <= 5.0) return "text-orange-600";
|
|
return "text-red-600";
|
|
}
|
|
|
|
/**
|
|
* Format grade based on system
|
|
*/
|
|
export function formatGradeBySystem(
|
|
percentage: number,
|
|
system: GradeSystem,
|
|
decimals: number = 2
|
|
): string {
|
|
switch (system) {
|
|
case "german": {
|
|
const germanGrade = percentageToGermanGradeDetailed(percentage);
|
|
return germanGrade.toFixed(1);
|
|
}
|
|
case "us-letter": {
|
|
if (percentage >= 90) return "A";
|
|
if (percentage >= 80) return "B";
|
|
if (percentage >= 70) return "C";
|
|
if (percentage >= 60) return "D";
|
|
return "F";
|
|
}
|
|
case "percentage":
|
|
default:
|
|
return `${percentage.toFixed(decimals)}%`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get color for grade based on system
|
|
*/
|
|
export function getGradeColorBySystem(
|
|
percentage: number,
|
|
system: GradeSystem
|
|
): string {
|
|
switch (system) {
|
|
case "german": {
|
|
const germanGrade = percentageToGermanGradeDetailed(percentage);
|
|
return getGermanGradeColor(germanGrade);
|
|
}
|
|
case "percentage":
|
|
case "us-letter":
|
|
default:
|
|
if (percentage >= 90) return "text-green-600";
|
|
if (percentage >= 80) return "text-blue-600";
|
|
if (percentage >= 70) return "text-yellow-600";
|
|
if (percentage >= 60) return "text-orange-600";
|
|
return "text-red-600";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get description for grade
|
|
*/
|
|
export function getGradeDescription(
|
|
percentage: number,
|
|
system: GradeSystem
|
|
): string | null {
|
|
if (system === "german") {
|
|
const germanGrade = percentageToGermanGradeDetailed(percentage);
|
|
return getGermanGradeDescription(germanGrade);
|
|
}
|
|
return null;
|
|
}
|