first commit
This commit is contained in:
179
app/utils/gradeSystems.ts
Normal file
179
app/utils/gradeSystems.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user