Dalam rangka digitalisasi administrasi madrasah, mulai tahun ini proses input nilai praktik akan dialihkan sepenuhnya menggunakan Aplikasi Asesmen Praktik .
Aplikasi ini hadir untuk membantu Bapak/Ibu agar tidak lagi terbebani dengan penghitungan rumus manual. Cukup masukkan skor mentah per aspek penilaian, dan sistem akan mengolahnya secara otomatis.
Langkah Singkat Penggunaan:
Pilih Mata Pelajaran praktik yang diuji.
Input Nilai sesuai rubrik yang tersedia.
Klik Simpan/Sync untuk mengirim data ke server pusat.
Mari kita dukung transisi digital ini untuk kerja yang lebih efektif!
import React, { useState, useEffect } from 'react';
import {
BookOpen,
FileSpreadsheet,
ArrowLeft,
Download,
Database,
CloudUpload,
Settings,
CheckCircle2,
AlertCircle,
Save
} from 'lucide-react';
import * as XLSX from 'xlsx';
const App = () => {
const [activeScreen, setActiveScreen] = useState('menu');
const [activeSubject, setActiveSubject] = useState(null);
const [syncMessage, setSyncMessage] = useState(null);
const [isSyncing, setIsSyncing] = useState(false);
// Menghubungkan langsung ke URL yang diberikan user
const DEFAULT_URL = "https://script.google.com/macros/s/AKfycbxGPU6QmAs9AlXvcD9NNw6rvKJ8Md1zoTe6J3inbgPrm8jGHrdayLtKre2wPrUB2qIibw/exec";
const [sheetUrl, setSheetUrl] = useState(localStorage.getItem('mi_sheet_url') || DEFAULT_URL);
const [scores, setScores] = useState(() => {
const saved = localStorage.getItem('mi_assess_data_2026_final');
return saved ? JSON.parse(saved) : {};
});
const students = [
{ id: "S001", name: "ADLY ADHYASTA MAHANIPUNA" }, { id: "S002", name: "AKBAR NUR RAMADHAN" },
{ id: "S003", name: "CHELSY RIBY AZZAHRA" }, { id: "S004", name: "CHIKA NUR ALIFFAH" },
{ id: "S005", name: "HAFIZA KHAIRA" }, { id: "S006", name: "HANUNG FATKUROHMAN" },
{ id: "S007", name: "JIHAN TALITA ZULFA" }, { id: "S008", name: "JOVAN ANGGA PRATAMA" },
{ id: "S009", name: "MAULANA KHOIRUL AZKA" }, { id: "S010", name: "MONICA RISKI AMELIA" },
{ id: "S011", name: "MUHAMAD KHAZIM RAMADHAN" }, { id: "S012", name: "MUHAMMAD ABDUL MAJID" },
{ id: "S013", name: "MUHAMMAD ABIL AL GHIFARI" }, { id: "S014", name: "MUHAMMAD BARIZI" },
{ id: "S015", name: "MUHAMMAD SYAHDAN IHSAN SALIS" }, { id: "S016", name: "MUHAMMAD YUSUF" },
{ id: "S017", name: "NAILA MUAZAHRA ULFA" }, { id: "S018", name: "NISA'UL KHUSNA" },
{ id: "S019", name: "NUH QOLBURROHIM" }, { id: "S020", name: "NUH QOLBURROHMAN" },
{ id: "S021", name: "NUR DAFFA AQILLA PRANAJA" }, { id: "S022", name: "RAISSA ERLY" },
{ id: "S023", name: "SRI RATU SEKAR ARUM DJOYONINGRAT" }, { id: "S024", name: "SUFRAN ARIS SANDY" },
{ id: "S025", name: "SYARIFATUL MUKARROMAH" }, { id: "S026", name: "VERONICA AULIYANI" },
{ id: "S027", name: "YESI NOVITASARI" }, { id: "S028", name: "ANASTASYA PUTRI OKTAVIANI" },
{ id: "S029", name: "DINDA RODHATUL JANAH" }, { id: "S030", name: "FIKRI IKHWAN AZZAKI" },
{ id: "S031", name: "HILAL AQILA TSAQIF" }, { id: "S032", name: "NAURA HASNA ANNIDA" }
];
const subjects = [
{ id: 'qh', name: "Al-Qur'an Hadits" },
{ id: 'fik', name: "Fikih" },
{ id: 'arb', name: "Bahasa Arab" },
{ id: 'ind', name: "Bahasa Indonesia" },
{ id: 'ipas', name: "IPAS" },
{ id: 'pjok', name: "PJOK" },
{ id: 'sbdp', name: "SBdP" },
{ id: 'jw', name: "Bahasa Jawa" },
{ id: 'ing', name: "Bahasa Inggris" },
];
useEffect(() => {
localStorage.setItem('mi_assess_data_2026_final', JSON.stringify(scores));
}, [scores]);
useEffect(() => {
localStorage.setItem('mi_sheet_url', sheetUrl);
}, [sheetUrl]);
const getStudentTotal = (subjectId, studentId) => {
const data = scores[subjectId]?.[studentId] || {};
return data.score || 0;
};
// KIRIM DATA KE GOOGLE SHEETS
const syncToCloud = async () => {
if (!sheetUrl || sheetUrl.trim() === "") {
setSyncMessage("URL Spreadsheet belum diset!");
setTimeout(() => setSyncMessage(null), 3000);
return;
}
setIsSyncing(true);
setSyncMessage("Menghubungkan ke Cloud...");
const allData = students.map(s => {
const row = { nis: s.id, nama: s.name };
subjects.forEach(sub => {
row[sub.id] = getStudentTotal(sub.id, s.id);
});
return row;
});
try {
// Menggunakan fetch dengan mode no-cors karena keterbatasan Apps Script
await fetch(sheetUrl, {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(allData)
});
setSyncMessage("Data Berhasil Terkirim!");
} catch (error) {
console.error("Sync Error:", error);
setSyncMessage("Gagal Menghubungkan ke Server");
} finally {
setIsSyncing(false);
setTimeout(() => setSyncMessage(null), 4000);
}
};
return (
{/* HEADER UTAMA */}
{/* NOTIFIKASI FLOATING */}
{syncMessage && (
{isSyncing ? (
) : (
)}
{syncMessage}
)}
{/* PENGATURAN URL SPREADSHEET */}
{activeScreen === 'settings' && (
Koneksi Spreadsheet
Google Apps Script API
URL Web App Script Anda
Terhubung
Data yang dikirim akan secara otomatis membuat sheet bernama REKAP_NILAI di Google Spreadsheet Anda. Pastikan Deployment Apps Script sudah aktif.
setActiveScreen('menu')}
className="flex-1 bg-slate-900 hover:bg-slate-800 text-white py-4 rounded-2xl font-black text-xs uppercase tracking-widest shadow-lg transition-transform active:scale-95"
>
Simpan Konfigurasi
)}
{/* DASHBOARD MATA PELAJARAN */}
{activeScreen === 'menu' && (
{subjects.map(s => {
const entries = Object.keys(scores[s.id] || {}).length;
return (
{ setActiveSubject(s); setActiveScreen('list'); }}
className="bg-white p-6 rounded-2xl border border-slate-200 hover:border-indigo-500 hover:shadow-xl transition-all text-left group"
>
{entries}/{students.length}
{s.name}
Input Nilai Praktik
);
})}
)}
{/* REKAP KOLEKTIF */}
{activeScreen === 'rekap' && (
Tabel Nilai Kolektif
Seluruh Mata Pelajaran
{isSyncing ? 'MENGIRIM...' : 'KIRIM KE SPREADSHEET'}
Nama Siswa
{subjects.map(s => (
{s.id}
))}
Rata
{students.map((s, idx) => {
let total = 0;
return (
{s.name}
{subjects.map(sub => {
const val = getStudentTotal(sub.id, s.id);
total += val;
return (
{val || '-'}
);
})}
{(total / subjects.length).toFixed(1)}
);
})}
)}
{/* LIST SISWA PER MAPEL */}
{activeScreen === 'list' && (
{students.map(s => {
const val = getStudentTotal(activeSubject.id, s.id);
return (
);
})}
)}
);
};
export default App;
0 Post a Comment:
Post a Comment