www/components/_gc.ts
2021-12-07 22:38:31 -05:00

199 lines
5.4 KiB
TypeScript

import React, { ReactElement } from 'react';
export default class GradeCalc {
maxscore = 0;
sections: Array<ReactElement> = [];
inputSection: Array<ReactElement[]> = [[]];
outputSection: Array<ReactElement> = [];
fields: Array<ReactElement[]> = [];
grades: number[] = [];
ugrades: number[] = [];
both = false;
totalOutput: ReactElement;
config: any[];
constructor(config: {title: string, percentage: number}, outCallback: (arg: Array<ReactElement>) => void) {
this.totalOutput = React.createElement('div');
let dConfig = JSON.parse(JSON.stringify(config)); // dirty clone
let sanConfig = [];
for (let conf of dConfig) {
if (conf.percentage === undefined || conf.name === undefined)
continue;
if (conf.title === undefined)
conf.title = conf.name[0].toUpperCase() + conf.name.slice(1);
sanConfig.push(conf);
}
this.config = sanConfig;
for (let [i, conf] of this.config.entries()) {
this.maxscore += conf.percentage;
this.inputSection[i] = [];
this.outputSection[i] = React.createElement('div');
if (conf.bothMethods) {
this.both = true;
}
this.sections[i] = (this.createSection(i));
}
// for (let [k, v] of this.fields.entries()) {
// for (let field of v) {
// this.addInputEventListener(k, field);
// }
// }
outCallback(this.sections);
}
createSection(id: number): ReactElement {
const conf = this.config[id];
const heading = React.createElement('h2', {}, `${conf.title} (${conf.percentage}%)`);
let info = null
if (conf.info !== undefined)
info = (React.createElement('div', {}, conf.info));
this.fields[id] = [];
let inputSection: Array<ReactElement> | ReactElement = [];
if (conf.points !== undefined) {
for (let i = 0; i < conf.points.length; i++) {
inputSection[i] = this.createInputSection(id, i);
}
}
else {
inputSection = this.createInputSection(id, 0, true);
}
const section = React.createElement('div', {className: conf.name}, heading, info, inputSection,
// this.outputSection[id]
);
return section;
}
createInputSection(sectId: number, inputId: number, soleInput: boolean = false): ReactElement {
const conf = this.config[sectId];
let label = '';
if (soleInput)
label = `${conf.title} Score: `;
else
label = `${conf.title} ${inputId + 1} Score: `;
const field = React.createElement('input', {
className: `input ${conf.name}-score`,
onKeyUp: () => {
if (conf.output !== undefined && conf.output)
this.showSectionGrade(inputId);
this.showTotalGrade();
}
});
this.fields[sectId][inputId] = field;
let suffix = (soleInput) ? '%' : ` / ${conf.points[inputId]} pts`;
const inputSection = React.createElement('div', {className: 'input-section'}, label, field, suffix);
this.inputSection[sectId][inputId] = inputSection;
return inputSection;
}
calculateSectionGrade(id: number, unweighted = false): number {
// let conf = this.config[id];
// let fields = this.fields[id];
// if (fields === undefined)
// return 0;
// if (conf.points === undefined) {
// return parseFloat(fields[0].value);
// }
// let total = 0;
// if (unweighted) {
// let counter = 0;
// for (let [i, field] of fields.entries()) {
// let val = parseFloat(field.value);
// if (isNaN(val))
// continue;
// total += val / conf.points[i];
// counter++;
// }
// return (total / counter * 100);
// }
// total = fields.reduce((acc, cur) => {
// const c = parseFloat(cur.value);
// return isNaN(c) ? acc : acc + c;
// }, 0);
// let max_total = 0;
// for (const [i, field] of conf.points.entries()) {
// if (isNaN(parseFloat(fields[i].value)))
// continue;
// max_total += field;
// }
// return (total / max_total * 100);
return 0;
}
showSectionGrade(id: number) {
let conf = this.config[id];
let grade = this.calculateSectionGrade(id);
let ugrade = this.calculateSectionGrade(id, true);
this.grades[id] = grade * parseFloat(conf.percentage) / 100;
this.ugrades[id] = ugrade * parseFloat(conf.percentage) / 100;
const outGrade = !isNaN(grade) ? grade.toFixed(2) : "...";
const outUgrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
if (conf.bothMethods) {
this.outputSection[id].props.children
= `Score (weighted): ${outGrade}%<br> Score (unweighted): ${outUgrade}%`;
return;
}
this.outputSection[id].props.value = `Score: ${grade}`;
}
showTotalGrade() {
for (let [k, conf] of this.config.entries()) {
if (!conf.output) {
this.grades[k] = this.calculateSectionGrade(k) * parseFloat(conf.percentage) / 100;
this.ugrades[k] = this.calculateSectionGrade(k, true) * parseFloat(conf.percentage) / 100;
}
}
let grade: number = this.grades.reduce((a, c) => {
if (isNaN(c))
return a;
return a + c
}, 0);
let ugrade: number = this.ugrades.reduce((a, c) => {
if (isNaN(c))
return a;
return a + c
}, 0);
const outGrade = !isNaN(grade) ? grade.toFixed(2) : "...";
const outUgrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
if (this.both) {
// this.totalOutput.props.children
// = `Total Score (weighted): ${outGrade}%<br> Total Score (unweighted): ${outUgrade}%`;
return;
}
// this.totalOutput.props.children = `Total Score: ${outGrade}%`;
}
get elemTotal() {
return this.totalOutput;
}
}