Admin Dashboard: Pre-test & Post-test
1. Kontrol Sesi & Pengerjaan Siswa
Buka halaman untuk memilih siswa dan mengisi lembar jawaban tes.
Mulai Sesi Pre-test
Mulai Sesi Post-test
2. Analisis & Laporan Keseluruhan
Jalankan simulasi untuk semua siswa sekaligus dan langsung lihat dashboard analisis statistik lengkap.
Jalankan Analisis Otomatis
Lihat Dashboard Hasil
3. Manajemen Data
Lihat Data Siswa
Lihat Soal Pre-test
Lihat Soal Post-test
Reset Semua Data Tes
`;
const prePostStudentSelectView = (testType) => {
const title = testType === 'pretest' ? 'Mulai Pre-test' : 'Mulai Post-test';
let studentOptions = '';
if (testType === 'pretest') {
studentOptions = prePostModule.students.filter(s => s.pretestScore === null).map(s => `
${s.nis} - ${s.nama} `).join('');
} else {
studentOptions = prePostModule.students.filter(s => s.pretestScore !== null && s.posttestScore === null).map(s => `
${s.nis} - ${s.nama} `).join('');
}
const noStudentMessage = testType === 'pretest'
? 'Semua siswa sudah mengerjakan pre-test.'
: `Semua siswa sudah mengerjakan post-test atau belum menyelesaikan pre-test.
Simulasikan Penyelesaian Pre-test untuk Semua Siswa `;
return `
← Kembali ke Admin Dashboard
${title}
Pilih siswa yang akan mengerjakan ${testType}.
${studentOptions.length > 0 ? `
` : `
Tidak ada siswa yang tersedia.
${noStudentMessage}
`
}
`;
};
const prePostTestView = (student, testType) => {
const questions = testType === 'pretest' ? prePostModule.pretestQuestions : prePostModule.posttestQuestions;
return `
← Pilih Siswa Lain
Lembar Jawaban ${testType.charAt(0).toUpperCase() + testType.slice(1)}
Siswa: ${student.nama} (${student.nis})
`;
}
const prePostStudentResultView = () => {
const result = prePostModule.currentStudentResult;
if (!result) return `
Error: Hasil tidak ditemukan.
`;
let nGainCategory = "Rendah";
let nGainColor = "text-red-600";
if (result.nGain > 0.7) {
nGainCategory = "Tinggi";
nGainColor = "text-green-600";
} else if (result.nGain >= 0.3) {
nGainCategory = "Sedang";
nGainColor = "text-yellow-600";
}
return `
Hasil Tes Siswa
Berikut adalah hasil pengerjaan tes Anda.
NIS:
${result.student.nis}
Nama:
${result.student.nama}
Skor Pre-test ${result.pretestScore}
Skor Post-test ${result.posttestScore}
N-Gain Score ${result.nGain.toFixed(3)}
Kriteria Efektivitas Pembelajaran: ${nGainCategory.toUpperCase()}
Selesai (Kembali)
`;
};
const studentManagementView = `
← Kembali ke Admin Dashboard
Manajemen Siswa
No. NIS Nama Siswa Skor Pre-test Skor Post-test
${prePostModule.students.map((s, i) => `${i+1} ${s.nis} ${s.nama} ${s.pretestScore ?? 'Belum'} ${s.posttestScore ?? 'Belum'} `).join('')}
`;
const questionManagementView = (testType) => {
const questions = testType === 'pretest' ? prePostModule.pretestQuestions : prePostModule.posttestQuestions;
const title = testType === 'pretest' ? 'Bank Soal Pre-test' : 'Bank Soal Post-test';
return `
← Kembali ke Admin Dashboard
${title}
${questions.map((q, i) => `
Soal ${i+1}: ${q.q}
A. ${q.a}
B. ${q.b}
C. ${q.c}
D. ${q.d}
E. ${q.e}
`).join('')}
`;
}
const createStudentAnswersView = (nis, testType) => {
const result = prePostModule.results.find(r => r.nis === nis);
if (!result) return `
Error: Hasil tidak ditemukan.
`;
const student = { nis: result.nis, nama: result.nama };
const questions = testType === 'pretest' ? prePostModule.pretestQuestions : prePostModule.posttestQuestions;
const answers = testType === 'pretest' ? result.pretestAnswers : result.posttestAnswers;
const title = `Lembar Jawaban ${testType.charAt(0).toUpperCase() + testType.slice(1)} (Sudah Diisi)`;
return `
← Kembali ke Tabel Hasil
${title}
Siswa: ${student.nama} (${student.nis})
${questions.map((q, i) => {
const studentAnswer = answers[i];
const isCorrect = studentAnswer === q.ans;
const optionsHtml = ['A', 'B', 'C', 'D', 'E'].map(opt => {
const isStudentChoice = opt === studentAnswer;
const isCorrectChoice = opt === q.ans;
let labelClass = '';
if (isStudentChoice && !isCorrect) labelClass = 'bg-red-100 border-red-300';
if (isCorrectChoice) labelClass = 'bg-green-100 border-green-300 font-semibold';
return `
${opt}. ${q[opt.toLowerCase()]}
`;
}).join('');
return `
Soal ${i+1}: ${q.q}
${optionsHtml}
`
}).join('')}
`;
};
const prePostAnalysisView = () => {
if (!prePostModule.isAnalyzed) {
prePostModule.runSimulation();
return;
}
const stats = prePostModule.calculateStats();
// For calculation breakdown
const n = prePostModule.results.length;
const preScores = prePostModule.results.map(r => r.pretest);
const postScores = prePostModule.results.map(r => r.posttest);
const sumPre = preScores.reduce((a, b) => a + b, 0);
const sumPost = postScores.reduce((a, b) => a + b, 0);
const diffs = postScores.map((post, i) => post - preScores[i]);
const sumDiff = diffs.reduce((a, b) => a + b, 0);
const meanDiff = sumDiff / n;
const sqDiffs = diffs.map(d => Math.pow(d - meanDiff, 2));
const sumSqDiffs = sqDiffs.reduce((a, b) => a + b, 0);
const stdDevDiff = Math.sqrt(sumSqDiffs / (n - 1));
const tValue = meanDiff / (stdDevDiff / Math.sqrt(n));
return `
← Kembali ke Admin Dashboard
Dashboard Analisis Otomatis: Pre-test & Post-test
A. Statistik Deskriptif
Pre-test
Rata-rata:
${stats.pre.mean.toFixed(2)}
Nilai Tertinggi:
${stats.pre.max}
Nilai Terendah:
${stats.pre.min}
Std. Deviasi:
${stats.pre.stdDev.toFixed(2)}
Post-test
Rata-rata:
${stats.post.mean.toFixed(2)}
Nilai Tertinggi:
${stats.post.max}
Nilai Terendah:
${stats.post.min}
Std. Deviasi:
${stats.post.stdDev.toFixed(2)}
B. Hasil Uji Hipotesis (Paired t-Test) Kesimpulan Otomatis:
${stats.tTest.conclusion}
C. Hasil Uji Efektivitas (N-Gain) Rata-rata N-Gain: ${stats.nGain.average.toFixed(3)} (Kategori: ${stats.nGain.category})
Tingkat efektivitas media pembelajaran berada pada kategori ${stats.nGain.category.toUpperCase()} .
D. Tabel Hasil Lengkap per Siswa
Nama Skor Pre-test Skor Post-test N-Gain Score Lembar Jawaban
${prePostModule.results.map(r => `${r.nama} ${r.pretest} ${r.posttest} ${r.nGain.toFixed(3)} Pre Post `).join('')}
E. Rincian Proses Perhitungan Statistik
1. Perhitungan Statistik Deskriptif
Rata-rata (Mean) Pre-test: $$ \\bar{x}_{pre} = \\frac{\\sum x_i}{n} = \\frac{${sumPre}}{${n}} = ${stats.pre.mean.toFixed(2)} $$
Rata-rata (Mean) Post-test: $$ \\bar{x}_{post} = \\frac{\\sum x_i}{n} = \\frac{${sumPost}}{${n}} = ${stats.post.mean.toFixed(2)} $$
Standar Deviasi, Nilai Min, dan Max dihitung dengan cara yang sama menggunakan data skor masing-masing tes.
2. Perhitungan N-Gain Score
Contoh perhitungan untuk siswa pertama (${prePostModule.results[0].nama}):
$$ g = \\frac{(S_{post} - S_{pre})}{(S_{max} - S_{pre})} = \\frac{(${prePostModule.results[0].posttest} - ${prePostModule.results[0].pretest})}{(100 - ${prePostModule.results[0].pretest})} = ${prePostModule.results[0].nGain.toFixed(3)} $$
Rata-rata N-Gain dihitung dengan menjumlahkan semua N-Gain individu dan membaginya dengan jumlah siswa (${n}).
3. Perhitungan Paired Sample t-Test
Hitung selisih skor (D) untuk tiap siswa: $D = S_{post} - S_{pre}$.
Hitung rata-rata dari selisih skor ($$\\bar{D}$$): $$ \\bar{D} = \\frac{\\sum D}{n} = \\frac{${sumDiff}}{${n}} = ${meanDiff.toFixed(2)} $$
Hitung standar deviasi dari selisih ($$s_D$$): $$ s_D = \\sqrt{\\frac{\\sum (D - \\bar{D})^2}{n-1}} = ${stdDevDiff.toFixed(2)} $$
Hitung nilai t-statistik ($$t_{hitung}$$): $$ t = \\frac{\\bar{D}}{s_D / \\sqrt{n}} = \\frac{${meanDiff.toFixed(2)}}{${stdDevDiff.toFixed(2)} / \\sqrt{${n}}} \\approx ${tValue.toFixed(3)} $$
Nilai $t_{hitung}$ yang besar (${tValue.toFixed(3)}) menunjukkan perbedaan yang sangat signifikan, sehingga menghasilkan **p-value < 0.05**.
Cetak Hasil Analisis
`;
};
// --- ROUTER & LOGIC ---
function navigateTo(page, key) {
mainContent.innerHTML = '';
let view;
switch (page) {
case 'dashboard': view = mainDashboardView; break;
case 'input': view = createInputView(key); break;
case 'analysis':
const instrument = instruments[key];
if (instrument.type === 'validator') {
view = instrument.data.scores.length === 0 ? createInputView(key) : createValidatorAnalysisView(key);
} else {
view = createKepraktisanAnalysisView(key);
}
break;
// Pre-Post Module Routes
case 'prePostAdmin': view = prePostAdminDashboardView; break;
case 'studentManagement': view = studentManagementView; break;
case 'questionManagement': view = questionManagementView(key); break;
case 'prePostAnalysis': view = prePostAnalysisView(); break;
case 'prePostStudentSelect': view = prePostStudentSelectView(key); break;
case 'prePostTest':
const [studentNis, testType] = key.split('|');
const student = prePostModule.students.find(s => s.nis === studentNis);
view = prePostTestView(student, testType);
break;
case 'prePostStudentResult': view = prePostStudentResultView(); break;
case 'viewStudentAnswers':
const [nis, type] = key.split('|');
view = createStudentAnswersView(nis, type);
break;
default: view = mainDashboardView;
}
mainContent.innerHTML = view;
if (window.MathJax) { MathJax.typesetPromise(); }
// Add event listeners for dynamic forms
if (page === 'prePostStudentSelect') {
const form = document.getElementById('studentSelectForm');
if(form) {
form.addEventListener('submit', (e) => {
e.preventDefault();
const selectedNis = document.getElementById('studentSelect').value;
const type = e.target.dataset.testType;
navigateTo('prePostTest', `${selectedNis}|${type}`);
});
}
}
if (page === 'prePostTest') {
document.getElementById('studentTestForm').addEventListener('submit', (e) => {
e.preventDefault();
const studentNis = e.target.dataset.studentNis;
const testType = e.target.dataset.testType;
submitStudentTest(studentNis, testType);
});
}
}
function submitForm(key) {
const instrument = instruments[key];
const form = document.getElementById('inputForm');
if (instrument.type === 'validator') {
instrument.data.name = document.getElementById('inputName').value;
} else {
instrument.data.name = document.getElementById('studentNameSelect').value;
}
instrument.data.submissionDate = document.getElementById('submissionDate').value;
if (instrument.type === 'validator') {
instrument.data.scores = [];
instrument.questions.forEach((_, index) => {
instrument.data.scores.push(parseInt(form.elements[`q${index}`].value));
});
instrument.data.iteration = document.getElementById('validationIteration').value;
instrument.data.comments = document.getElementById('comments').value;
instrument.data.suggestions = document.getElementById('suggestions').value;
}
navigateTo('analysis', key);
}
function submitStudentTest(studentNis, testType) {
const form = document.getElementById('studentTestForm');
const questions = testType === 'pretest' ? prePostModule.pretestQuestions : prePostModule.posttestQuestions;
let correctAnswers = 0;
questions.forEach((q, index) => {
const selectedAnswer = form.elements[`q${index}`].value;
if (selectedAnswer === q.ans) {
correctAnswers++;
}
});
const maxScore = 100;
const score = (correctAnswers / questions.length) * maxScore;
const student = prePostModule.students.find(s => s.nis === studentNis);
if(testType === 'pretest') {
student.pretestScore = Math.round(score);
alert(`Pre-test untuk ${student.nama} selesai dengan skor ${student.pretestScore}.`);
navigateTo('prePostStudentSelect', 'pretest');
} else {
student.posttestScore = Math.round(score);
// Ensure pretestScore is not null before calculating nGain
if(student.pretestScore === null) {
// Simulate a pre-test score if it doesn't exist for demo purposes
student.pretestScore = Math.floor(Math.random() * (55 - 35 + 1)) + 35;
}
const nGain = (student.posttestScore - student.pretestScore) / (maxScore - student.pretestScore);
prePostModule.currentStudentResult = {
student: student,
posttestScore: student.posttestScore,
pretestScore: student.pretestScore,
nGain: isNaN(nGain) ? 0 : nGain
};
navigateTo('prePostStudentResult');
}
}
// Initial load
navigateTo('dashboard');