import React, { useState, useEffect } from 'react';
import {
School,
ShieldCheck,
Upload,
FileText,
CheckCircle2,
AlertTriangle,
MessageSquare,
Bell,
History,
Send,
Check,
X,
FileCheck,
HelpCircle,
Sparkles,
Download,
ArrowRight,
Info,
ChevronRight,
RefreshCw,
Search,
BookOpen,
FileSignature,
Percent,
CheckSquare,
Award,
UserCheck
} from 'lucide-react';
// Data awal sekolah dampingan Inspektorat Provinsi NTB (Wilayah Lombok & Sumbawa)
const INITIAL_SCHOOLS = [
{
id: 1,
npsn: "50201234",
name: "SMA Negeri 1 Mataram",
status: "Konsultasi Aktif", // Aman, Konsultasi Aktif, Butuh Pendampingan
lastUpdate: "18 Juni 2026",
budget: 450000000,
consultedBudget: 315000000,
address: "Jl. Pendidikan No. 21, Kota Mataram, Lombok",
headmaster: "Drs. H. Lalu Muhammad, M.Pd",
treasurer: "Baiq Rahmawati, S.E",
complianceScore: 75,
isReportSubmitted: false,
signatureName: "",
isSigned: false
},
{
id: 2,
npsn: "50205678",
name: "SMA Negeri 2 Sumbawa Besar",
status: "Butuh Pendampingan",
lastUpdate: "15 Juni 2026",
budget: 520000000,
consultedBudget: 120000000,
address: "Jl. Garuda No. 12, Sumbawa Besar, Sumbawa",
headmaster: "Dr. I Ketut Budi, M.Si",
treasurer: "Rian Hidayat, A.Md",
complianceScore: 25,
isReportSubmitted: false,
signatureName: "",
isSigned: false
},
{
id: 3,
npsn: "50209101",
name: "SMA Swasta Harapan Lombok Barat",
status: "Aman",
lastUpdate: "18 Juni 2026",
budget: 300000000,
consultedBudget: 300000000,
address: "Jl. Raya Senggigi, Lombok Barat",
headmaster: "Elisa Anastasia, M.Hum",
treasurer: "Dewi Lestari",
complianceScore: 100,
isReportSubmitted: true,
signatureName: "Elisa Anastasia, M.Hum",
isSigned: true
}
];
// Data rancangan rencana belanja yang dikonsultasikan (Terdistribusi per Sekolah)
const INITIAL_PROPOSED_ITEMS = [
{
id: "PROP-101",
schoolId: 1,
activity: "Penyediaan Paket Internet Belajar Siswa Kurang Mampu",
plannedCost: 15000000,
consultationStatus: "Disetujui APIP",
notes: "Sesuai dengan Juknis BOS terkait operasional digital daerah NTB. Pastikan daftar penerima dibuat terperinci."
},
{
id: "PROP-102",
schoolId: 1,
activity: "Rehab Sedang Sanitasi Toilet Siswa SMA Mataram",
plannedCost: 45000000,
consultationStatus: "Perbaikan Draft",
notes: "Mohon lampirkan rincian volume bahan bangunan lokal NTB dan foto kondisi awal sanitasi toilet."
},
{
id: "PROP-103",
schoolId: 1,
activity: "Pengadaan Buku Referensi Adat Sasak Samawa Mbojo (SASAMBO)",
plannedCost: 20000000,
consultationStatus: "Draf Diajukan",
notes: "Menunggu penelaahan dari Konsultan Inspektorat NTB."
},
{
id: "PROP-201",
schoolId: 2,
activity: "Sewa Bus Pariwisata Studi Banding Guru ke Mataram",
plannedCost: 35000000,
consultationStatus: "Perbaikan Draft",
notes: "Pariwisata murni/studi banding guru tidak masuk dalam prioritas komponen Juknis BOS reguler. Harap tinjau kembali usulan Anda."
},
{
id: "PROP-301",
schoolId: 3,
activity: "Langganan Aplikasi Pembelajaran Digital Interaktif",
plannedCost: 40000000,
consultationStatus: "Sesuai Juknis (Advisory Issued)",
notes: "Disetujui. Advisory Note resmi No. ADV/BOS-NTB/2026/089 telah diterbitkan."
}
];
// Draft Bukti Transaksi (Kwitansi) sebelum transaksi riil dieksekusi
const INITIAL_DRAFT_SPJ = [
{
id: "CONS-501",
schoolId: 1,
proposedCode: "PROP-101",
description: "Rencana Kuitansi Pembelian Paket Kuota Seluler - Provider Indolink Mataram",
amount: 15000000,
date: "14 Mei 2026",
file: "Draft_Kwitansi_Internet.pdf",
hasAdvice: true,
adviceText: "Draf kwitansi sudah sah secara format perpajakan NTB. Lampirkan lembar penerima manfaat digital saat penutupan.",
status: "Sesuai"
},
{
id: "CONS-502",
schoolId: 1,
proposedCode: "PROP-102",
description: "Rencana Nota Pembelian Semen & Keramik - Toko Bangunan Mataram Jaya",
amount: 28000000,
date: "18 Juni 2026",
file: "Draft_Nota_Sanitasi.pdf",
hasAdvice: true,
adviceText: "Nominal pengadaan di atas 10 juta disarankan melampirkan perbandingan minimal 2 e-commerce atau toko bangunan lokal terdekat di Lombok.",
status: "Butuh Pendampingan"
},
{
id: "CONS-601",
schoolId: 2,
proposedCode: "PROP-201",
description: "Draf Kontrak Penyewaan Bus Pariwisata Sumbawa - PO Lancar Jaya",
amount: 35000000,
date: "10 Juni 2026",
file: "Draf_Sewa_Bus.pdf",
hasAdvice: true,
adviceText: "Sewa transportasi non-operasional harian sekolah dilarang keras dalam petunjuk penggunaan dana BOS reguler.",
status: "Butuh Pendampingan"
}
];
// Riwayat Chat Konsultasi Interaktif
const INITIAL_CHATS = [
{ schoolId: 1, sender: "Sekolah", time: "18 Juni 2026, 10:15", message: "Selamat pagi Pak Auditor Inspektorat NTB, kami berencana melakukan rehabilitasi toilet sekolah senilai 45 juta di SMAN 1 Mataram. Apakah draf rancangan belanja kami sudah aman secara Juknis?" },
{ schoolId: 1, sender: "Konsultan APIP", time: "18 Juni 2026, 11:30", message: "Selamat pagi. Secara prinsip diperbolehkan selama masuk kategori pemeliharaan ringan/sedang. Silakan unggah draf rincian komponen materialnya di Menu Klinik SPJ agar kami teliti terlebih dahulu nilai wajarnya." },
{ schoolId: 2, sender: "Sekolah", time: "15 Juni 2026, 09:00", message: "Mohon bimbingan terkait usulan sewa bus kami yang diberi status Perlu Perbaikan di Sumbawa." },
{ schoolId: 2, sender: "Konsultan APIP", time: "15 Juni 2026, 14:20", message: "Sewa bus pariwisata tidak memiliki landasan hukum di Juknis BOS reguler. Kami sarankan mengalihkan anggaran ini ke penyediaan buku penunjang digital bermuatan lokal NTB (SASAMBO) atau pelatihan guru berbasis modul lokal." }
];
// Kuesioner Kepatuhan Sekolah
const INITIAL_COMPLIANCE_ANSWERS = {
1: { q1: true, q2: true, q3: false, q4: true },
2: { q1: false, q2: false, q3: false, q4: true },
3: { q1: true, q2: true, q3: true, q4: true }
};
export default function App() {
const [role, setRole] = useState('sekolah'); // 'sekolah' | 'auditor'
const [schools, setSchools] = useState(INITIAL_SCHOOLS);
const [proposedItems, setProposedItems] = useState(INITIAL_PROPOSED_ITEMS);
const [draftSpjList, setDraftSpjList] = useState(INITIAL_DRAFT_SPJ);
const [chats, setChats] = useState(INITIAL_CHATS);
const [complianceAnswers, setComplianceAnswers] = useState(INITIAL_COMPLIANCE_ANSWERS);
// ID Sekolah Aktif yang dikonsultasikan / ditelaah
const [selectedSchoolId, setSelectedSchoolId] = useState(1);
// Status Langkah Internal Masing-masing Panel
const [schoolStep, setSchoolStep] = useState(1); // 1: Klinik Perencanaan, 2: Klinik SPJ, 3: Chat Bimbingan & Advisory
const [auditorStep, setAuditorStep] = useState(1); // 1: Peta Pendampingan, 2: Telaah Kwitansi, 3: Otorisasi Advisory
const [activeSpjTab, setActiveSpjTab] = useState('list'); // 'list' | 'add'
const [searchQuery, setSearchQuery] = useState('');
const [filterStatus, setFilterStatus] = useState('Semua');
// Form Input Rencana Anggaran Baru (Sekolah)
const [newActivity, setNewActivity] = useState('');
const [newCost, setNewCost] = useState('');
// Form Input Telaah Transaksi Baru (Sekolah)
const [newDraftDesc, setNewDraftDesc] = useState('');
const [newDraftAmount, setNewDraftAmount] = useState('');
const [newDraftTarget, setNewDraftTarget] = useState('');
const [newDraftFile, setNewDraftFile] = useState(null);
// Custom Modal State untuk Auditor (Coaching Note)
const [isCoachingModalOpen, setIsCoachingModalOpen] = useState(false);
const [coachingTargetId, setCoachingTargetId] = useState(null);
const [coachingText, setCoachingText] = useState('');
const [coachingStatusValue, setCoachingStatusValue] = useState(true); // true = Sesuai, false = Butuh Pendampingan
// Form Advisory Note Baru (APIP)
const [advisoryText, setAdvisoryText] = useState('');
const [isAdvisoryModalOpen, setIsAdvisoryModalOpen] = useState(false);
const [selectedDraftId, setSelectedDraftId] = useState(null);
// States Komunikasi
const [chatMessage, setChatMessage] = useState('');
const [notifications, setNotifications] = useState([
{ id: 1, schoolId: 1, type: "info", message: "Auditor Pendamping NTB memberikan saran perbaikan pada draf belanja Sanitasi.", date: "18 Juni 2026", read: false },
{ id: 2, schoolId: 3, type: "success", message: "Advisory Note resmi e-Review untuk Kegiatan Pembelajaran Digital telah diterbitkan.", date: "17 Juni 2026", read: true }
]);
const [consultingLogs, setConsultingLogs] = useState([
{ id: 1, schoolId: 1, time: "18 Juni 2026, 11:30 WIB", user: "Konsultan APIP", action: "Menambahkan bimbingan preventif pada draf belanja Sanitasi" },
{ id: 2, schoolId: 1, time: "18 Juni 2026, 10:15 WIB", user: "Bendahara BOS", action: "Mengirimkan draf perencanaan internet siswa untuk penelaahan awal" }
]);
// States untuk Chatbot AI Juknis BOS (Gemini API)
const [aiInput, setAiInput] = useState('');
const [aiChat, setAiChat] = useState([
{ role: 'assistant', text: 'Halo! Saya Asisten AI Resmi e-Review Inspektorat NTB. Saya siap membantu menjawab pertanyaan preventif seputar regulasi Juknis BOS di lingkungan Provinsi Nusa Tenggara Barat. Silakan tanyakan hal-hal terkait kegiatan pengawasan BOS NTB!' }
]);
const [isAiLoading, setIsAiLoading] = useState(false);
const [toast, setToast] = useState(null);
// Ambil data sekolah yang aktif saat ini
const activeSchool = schools.find(s => s.id === selectedSchoolId) || schools[0];
// Set default draft target dropdown saat komponen di-load / sekolah diganti
useEffect(() => {
const schoolProposals = proposedItems.filter(p => p.schoolId === selectedSchoolId);
if (schoolProposals.length > 0) {
setNewDraftTarget(schoolProposals[0].id);
} else {
setNewDraftTarget('');
}
}, [selectedSchoolId, proposedItems]);
const showToast = (message, type = 'success') => {
setToast({ message, type });
setTimeout(() => { setToast(null); }, 4000);
};
const handleAskAi = async (e) => {
e.preventDefault();
if (!aiInput.trim()) return;
const userMessage = aiInput;
setAiChat((prev) => [...prev, { role: 'user', text: userMessage }]);
setAiInput('');
setIsAiLoading(true);
const systemPrompt = `
Anda adalah "e-Review Smart Advisor", asisten konsultasi kecerdasan buatan resmi dari Inspektorat Provinsi Nusa Tenggara Barat (NTB).
ATURAN SANGAT KETAT / WAJIB DIPATUHI:
1. Anda HANYA boleh menjawab pertanyaan yang berkaitan dengan kegiatan pengawasan, konsultasi preventif Dana BOS/BOSP, regulasi Juknis BOS, serta hal-hal substantif terkait program kerja di bawah naungan Inspektorat Provinsi Nusa Tenggara Barat (NTB) pada jenjang pendidikan menengah (SMA/SMK/SLB) di wilayah Lombok dan Sumbawa.
2. Jika pengguna menanyakan pertanyaan di luar konteks tersebut (misalnya tentang resep makanan, tips cinta, ilmu pemrograman umum, berita hiburan, matematika non-sekolah, atau daerah di luar NTB seperti Jakarta, Jawa, dll.), Anda HARUS menolaknya secara halus namun tegas.
3. Contoh kalimat penolakan wajib: "Mohon maaf, sebagai Asisten AI Resmi e-Review Inspektorat NTB, saya hanya berwenang melayani konsultasi preventif seputar Dana BOS/BOSP dan program pengawasan di lingkungan Provinsi Nusa Tenggara Barat. Silakan ajukan pertanyaan yang relevan."
4. Jika pertanyaan di dalam konteks, jawablah secara suportif dan berlandaskan aturan hukum nasional Indonesia & peraturan Gubernur NTB yang relevan. Berikan solusi jalan keluar alternatif yang aman apabila hal yang mereka tanyakan dilarang dalam Juknis BOS.
`;
try {
const apiKey = ""; // Canvas menyuntikkan API Key secara otomatis
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${apiKey}`;
const payload = {
contents: [
{ role: 'user', parts: [{ text: userMessage }] }
],
systemInstruction: {
parts: [{ text: systemPrompt }]
}
};
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const result = await response.json();
const answer = result?.candidates?.[0]?.content?.parts?.[0]?.text ||
"Mohon maaf, saya sedang mengalami kendala jaringan pendampingan di server Inspektorat NTB. Silakan coba ajukan pertanyaan Anda kembali.";
setAiChat((prev) => [...prev, { role: 'assistant', text: answer }]);
} catch (err) {
console.error(err);
setAiChat((prev) => [...prev, { role: 'assistant', text: "Terjadi kesalahan koneksi ke server e-Review Inspektorat NTB. Namun secara umum, harap pastikan belanja Anda tertera dalam rencana kerja sekolah dan didukung kwitansi serta nota yang sah." }]);
} finally {
setIsAiLoading(false);
}
};
const handleAddProposedItem = (e) => {
e.preventDefault();
if (!newActivity || !newCost) {
showToast("Mohon isi kegiatan dan estimasi anggaran", "error");
return;
}
const newItem = {
id: `PROP-${Math.floor(400 + Math.random() * 90)}`,
schoolId: selectedSchoolId,
activity: newActivity,
plannedCost: parseInt(newCost),
consultationStatus: "Draf Diajukan",
notes: "Menunggu penelaahan awal oleh Konsultan APIP NTB"
};
setProposedItems([...proposedItems, newItem]);
addLog(`Mengajukan draf anggaran baru: "${newActivity}" senilai Rp ${parseInt(newCost).toLocaleString()}`);
showToast("Draf berhasil diajukan! Auditor pendamping NTB Anda telah menerima notifikasi.", "success");
setNewActivity('');
setNewCost('');
};
const handleAddDraftSpj = (e) => {
e.preventDefault();
if (!newDraftDesc || !newDraftAmount) {
showToast("Mohon isi semua data deskripsi draf belanja", "error");
return;
}
const newDraft = {
id: `CONS-${Math.floor(700 + Math.random() * 90)}`,
schoolId: selectedSchoolId,
proposedCode: newDraftTarget,
description: newDraftDesc,
amount: parseInt(newDraftAmount),
date: new Date().toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' }),
file: newDraftFile ? newDraftFile.name : "Draf_Kwitansi_Belanja.pdf",
hasAdvice: false,
adviceText: "",
status: "Diproses"
};
setDraftSpjList([...draftSpjList, newDraft]);
addLog(`Mengajukan draf kwitansi: "${newDraftDesc}" sebesar Rp ${parseInt(newDraftAmount).toLocaleString()}`);
showToast("Berkas draf transaksi terkirim! Konsultan APIP NTB kini dapat langsung mengulasnya.", "success");
setNewDraftDesc('');
setNewDraftAmount('');
setNewDraftFile(null);
setActiveSpjTab('list');
};
const handleSendChat = (e, senderLabel) => {
e.preventDefault();
if (!chatMessage.trim()) return;
const newChat = {
schoolId: selectedSchoolId,
sender: senderLabel,
time: "Hari ini, Baru saja",
message: chatMessage
};
setChats([...chats, newChat]);
addLog(`Mengirim pesan bimbingan: "${chatMessage.substring(0, 30)}..."`);
setChatMessage('');
showToast("Pesan bimbingan terkirim!", "success");
};
const handleToggleQuestion = (qKey) => {
const currentSchoolAnswers = complianceAnswers[selectedSchoolId] || { q1: false, q2: false, q3: false, q4: false };
const updatedAnswers = {
...currentSchoolAnswers,
[qKey]: !currentSchoolAnswers[qKey]
};
let trueCount = 0;
if (updatedAnswers.q1) trueCount++;
if (updatedAnswers.q2) trueCount++;
if (updatedAnswers.q3) trueCount++;
if (updatedAnswers.q4) trueCount++;
const newScore = trueCount * 25;
setComplianceAnswers({
...complianceAnswers,
[selectedSchoolId]: updatedAnswers
});
setSchools(schools.map(sch => {
if (sch.id === selectedSchoolId) {
return {
...sch,
complianceScore: newScore,
status: newScore >= 75 ? "Aman" : newScore >= 50 ? "Konsultasi Aktif" : "Butuh Pendampingan"
};
}
return sch;
}));
showToast("Jawaban disimpan! Kepatuhan internal sekolah diperbarui.", "info");
};
const handleSignAndSubmit = (e) => {
e.preventDefault();
const signatureInput = activeSchool.signatureName;
if (!signatureInput || !signatureInput.trim()) {
showToast("Mohon ketik nama lengkap Kepala Sekolah sebagai tanda tangan virtual.", "error");
return;
}
setSchools(schools.map(sch => {
if (sch.id === selectedSchoolId) {
return {
...sch,
isSigned: true,
isReportSubmitted: true
};
}
return sch;
}));
addLog(`Kepala Sekolah (${signatureInput}) menandatangani draf laporan kepatuhan secara digital.`);
showToast("Laporan Berkala & Deklarasi Kepatuhan telah resmi terkirim ke e-Review APIP NTB!", "success");
};
const handleApplyCoaching = (e) => {
e.preventDefault();
if (!coachingText.trim()) {
showToast("Mohon tuliskan catatan bimbingan atau rekomendasi perbaikan.", "error");
return;
}
setDraftSpjList(draftSpjList.map(item => {
if (item.id === coachingTargetId) {
return {
...item,
hasAdvice: true,
adviceText: coachingText,
status: coachingStatusValue ? "Sesuai" : "Butuh Pendampingan"
};
}
return item;
}));
addLog(`[Auditor NTB] Menambahkan bimbingan preventif pada draf ${coachingTargetId}`);
setNotifications([
{
id: Date.now(),
schoolId: selectedSchoolId,
type: coachingStatusValue ? "success" : "warning",
message: `Inspektorat NTB memperbarui status draf ${coachingTargetId}.`,
date: "Baru saja",
read: false
},
...notifications
]);
setIsCoachingModalOpen(false);
setCoachingText('');
showToast("Rekomendasi preventif (Coaching Note) berhasil dikirimkan!", "success");
};
const handlePublishAdvisoryNote = (e) => {
e.preventDefault();
if (!advisoryText.trim()) {
showToast("Mohon tuliskan pokok saran rekomendasi", "error");
return;
}
setProposedItems(proposedItems.map(item => {
if (item.id === selectedDraftId) {
return {
...item,
consultationStatus: "Sesuai Juknis (Advisory Issued)",
notes: `Rekomendasi Resmi APIP NTB: "${advisoryText}"`
};
}
return item;
}));
addLog(`[APIP NTB] Menerbitkan Advisory Note Resmi untuk program ${selectedDraftId}`);
setIsAdvisoryModalOpen(false);
setAdvisoryText('');
showToast("Advisory Note Resmi diterbitkan! Lembar rekomendasi PDF siap diunduh sekolah.", "success");
};
const addLog = (action) => {
const newLog = {
id: Date.now(),
schoolId: selectedSchoolId,
time: new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' }) + " WITA, Hari ini",
user: role === 'sekolah' ? 'Sekolah' : 'Auditor APIP NTB',
action
};
setConsultingLogs([newLog, ...consultingLogs]);
};
const filteredSchools = schools.filter(sch => {
const matchesSearch = sch.name.toLowerCase().includes(searchQuery.toLowerCase()) || sch.npsn.includes(searchQuery);
const matchesStatus = filterStatus === 'Semua' || sch.status === filterStatus;
return matchesSearch && matchesStatus;
});
return (
{/* HEADER UTAMA */}
{/* TOAST NOTIFIKASI */}
{toast && (
{toast.type === 'success' &&
}
{toast.type === 'warning' &&
}
{toast.type === 'info' &&
}
{toast.message}
)}
{/* WORKSPACE AREA */}
{/* RUNNING BANNER UNTUK MEMBERI INSTRUKSI INTERAKSI LIVE */}
Provinsi NTB
Aplikasi ini berfokus pada e-Review Pre-Review Dokumen secara preventif. Anda melihat dashboard:
{role === 'sekolah' ? 'Sekolah Binaan NTB' : 'APIP Inspektorat NTB'} .
{ setRole(role === 'sekolah' ? 'auditor' : 'sekolah'); }}
className="text-[11px] font-bold text-emerald-600 hover:text-emerald-800 flex items-center gap-1.5 transition-colors self-end md:self-auto"
>
Ganti Peran Cepat
{/* ========================================================
PORTAL SEKOLAH (SMA/SMK DI NTB)
======================================================== */}
{role === 'sekolah' && (
{/* Main Area: 3 Steps of e-Review */}
{/* SELECTOR SEKOLAH AKTIF */}
🏫
Portal e-Review Sekolah
Ulas rencana belanja Anda bersama tim pendamping Inspektorat NTB
Nama Sekolah:
{
const newId = parseInt(e.target.value);
setSelectedSchoolId(newId);
showToast(`Pindah akun ke: ${schools.find(s => s.id === newId).name}`, "info");
}}
className="bg-slate-100 border border-slate-200 text-xs text-slate-700 rounded-xl px-3 py-2 font-bold focus:outline-none w-full sm:w-auto"
>
{schools.map(s => (
{s.name}
))}
{/* LANGKAH-LANGKAH PREVENTIF SEKOLAH */}
setSchoolStep(1)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${schoolStep === 1 ? 'bg-indigo-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
1. Klinik Perencanaan
setSchoolStep(2)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${schoolStep === 2 ? 'bg-indigo-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
2. Klinik SPJ & Kepatuhan
setSchoolStep(3)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${schoolStep === 3 ? 'bg-indigo-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
3. Chat & Advisory Note
{/* INFORMASI DETAIL SEKOLAH BINAAN */}
Identitas Sekolah:
{activeSchool.name}
NPSN: {activeSchool.npsn} • {activeSchool.address}
Status Bimbingan NTB:
{activeSchool.status}
{/* TAHAP 1 SEKOLAH: KLINIK PERENCANAAN */}
{schoolStep === 1 && (
💡
Klinik Perencanaan Preventif NTB: Sebelum rancangan program draf sekolah diajukan secara resmi, unggah rencana belanja Anda di bawah ini agar mendapatkan analisis kesesuaian dari tim auditor Inspektorat Provinsi NTB.
{/* DAFTAR DRAF KEGIATAN YANG SEDANG DIKONSULTASIKAN */}
Riwayat Konsultasi Rencana Belanja
{proposedItems.filter(p => p.schoolId === selectedSchoolId).length === 0 ? (
Belum ada usulan program yang didaftarkan. Gunakan form di atas untuk berkonsultasi.
) : (
proposedItems.filter(p => p.schoolId === selectedSchoolId).map((item) => (
{item.id}
{item.consultationStatus}
{item.activity}
💡 Saran Preventif APIP NTB: {item.notes}
Rencana Belanja: Rp {item.plannedCost.toLocaleString()}
))
)}
)}
{/* TAHAP 2 SEKOLAH: KLINIK SPJ & KEPATUHAN */}
{schoolStep === 2 && (
{/* KEPATUHAN MANDIRI */}
Kuesioner Kepatuhan Mandiri (Self-Assessment NTB)
{activeSchool.complianceScore}% Tertib
Evaluasi tingkat administrasi sekolah Anda secara teratur terhadap aturan Juknis BOS Nasional dan Petunjuk Teknis Daerah NTB.
{/* KLINIK DRAFT SPJ */}
setActiveSpjTab('list')}
className={`px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeSpjTab === 'list' ? 'bg-indigo-50 text-indigo-600 border border-indigo-100' : 'text-slate-500 hover:text-slate-800'}`}
>
Draf Kwitansi Aktif ({draftSpjList.filter(d => d.schoolId === selectedSchoolId).length})
setActiveSpjTab('add')}
className={`px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeSpjTab === 'add' ? 'bg-indigo-50 text-indigo-600 border border-indigo-100' : 'text-slate-500 hover:text-slate-800'}`}
>
+ Ajukan Draft Nota Baru
{activeSpjTab === 'list' ? (
{draftSpjList.filter(d => d.schoolId === selectedSchoolId).length === 0 ? (
Belum ada draf kwitansi yang diulas.
) : (
draftSpjList.filter(d => d.schoolId === selectedSchoolId).map((draft) => (
{draft.id}
Pagu: {draft.proposedCode}
{draft.status}
{draft.description}
File Draft SPJ: {draft.file}
{draft.hasAdvice && (
📑 Saran / Hasil Pre-Review APIP NTB:
"{draft.adviceText}"
)}
Estimasi Pengeluaran: Rp {draft.amount.toLocaleString()}
))
)}
) : (
)}
{/* DIGITAL SIGNATURE KEPALA SEKOLAH */}
Deklarasi & Persetujuan Kepala Sekolah
Sebelum draf diverifikasi secara formal oleh Inspektorat Provinsi NTB, Kepala Sekolah wajib menyetujui pernyataan mandiri kepatuhan ini secara virtual.
{activeSchool.isReportSubmitted ? (
Laporan Kepatuhan Mandiri Terkirim
Tanda Tangan Digital Sah: {activeSchool.signatureName || activeSchool.headmaster}
) : (
)}
)}
{/* TAHAP 3 SEKOLAH: CHAT & ADVISORY NOTE */}
{schoolStep === 3 && (
{/* CHAT PENDAMPINGAN */}
Obrolan Konsultasi Aktif (APIP NTB)
{chats.filter(c => c.schoolId === selectedSchoolId).length === 0 ? (
Ketik pesan untuk memulai konsultasi langsung dengan Auditor pendamping Anda.
) : (
chats.filter(c => c.schoolId === selectedSchoolId).map((chat, idx) => (
{chat.sender} • {chat.time}
{chat.message}
))
)}
{/* ADVISORY NOTE RESMI */}
🛡️ Advisory Note Resmi e-Review NTB
Lembar Advisory Note bertindak sebagai surat rekomendasi tertulis dari Inspektorat NTB yang menjadi jaminan preventif draf belanja sekolah Anda telah disetujui.
{proposedItems.filter(p => p.schoolId === selectedSchoolId && p.consultationStatus.includes("Advisory")).length === 0 ? (
Belum ada rekomendasi formal yang diterbitkan oleh APIP NTB.
) : (
proposedItems.filter(p => p.schoolId === selectedSchoolId && p.consultationStatus.includes("Advisory")).map((item) => (
RESMI APIP NTB
{item.activity}
{item.notes}
showToast(`Berkas Advisory Note ${item.id} berhasil diunduh sebagai PDF!`, "success")}
className="bg-emerald-600 hover:bg-emerald-700 text-white text-[10px] font-bold px-3 py-2 rounded-lg flex items-center gap-1 shrink-0 transition-all shadow-sm"
>
Cetak PDF
))
)}
)}
{/* Sidebar Kanan Sekolah: Asisten AI */}
{/* ASISTEN AI JUKNIS BOS */}
Asisten AI e-Review NTB
Kecerdasan Buatan Terbatas Konteks NTB
{aiChat.map((msg, idx) => (
{msg.text}
))}
{isAiLoading && (
Menganalisis draf dengan parameter Juknis BOS & NTB...
)}
setAiInput("Bolehkah dana BOS digunakan untuk menyewa kendaraan pariwisata di Sumbawa?")}
className="text-[10px] bg-slate-800 hover:bg-slate-700 text-slate-300 px-2 py-1 rounded-md text-left truncate max-w-full"
>
💡 Sewa Bus Pariwisata?
setAiInput("Bagaimana cara membuat sup iga sapi khas Lombok?")}
className="text-[10px] bg-slate-800 hover:bg-rose-950/40 text-rose-300 px-2 py-1 rounded-md text-left truncate max-w-full"
>
⚠️ Resep Masakan (Luar Konteks)?
{/* AUDIT TRAIL LOG */}
Log Aktivitas e-Review
{consultingLogs.filter(l => l.schoolId === selectedSchoolId).map((log) => (
{log.time}
{log.user}: {log.action}
))}
)}
{/* ========================================================
PORTAL INSPEKTORAT (APIP PROVINSI NTB)
======================================================== */}
{role === 'auditor' && (
{/* Main Area: 3 Steps for APIP NTB */}
🔍
Portal Inspektorat NTB (e-Review)
Evaluasi pre-review draf usulan preventif sekolah se-NTB
Wilayah NTB
{/* LANGKAH-LANGKAH PREVENTIF APIP */}
setAuditorStep(1)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${auditorStep === 1 ? 'bg-emerald-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
1. Peta Dampingan NTB
setAuditorStep(2)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${auditorStep === 2 ? 'bg-emerald-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
2. Telaah Kwitansi/SPJ
setAuditorStep(3)}
className={`py-2.5 px-2 rounded-xl text-xs font-bold transition-all ${auditorStep === 3 ? 'bg-emerald-600 text-white shadow-sm' : 'text-slate-600 hover:text-slate-800 hover:bg-slate-200/60'}`}
>
3. Otorisasi Advisory
{/* TAHAP 1 APIP: PETA KATEGORI KEAKTIFAN */}
{auditorStep === 1 && (
Daftar Sekolah Binaan Provinsi NTB
Pilih sekolah di Lombok / Sumbawa untuk melihat pre-review draf anggaran.
setFilterStatus(e.target.value)}
className="text-xs bg-white border border-slate-200 rounded-xl px-3 py-2 focus:outline-none font-bold text-slate-700"
>
Semua Tingkat Keaktifan
Sesuai Juknis / Aman
Konsultasi Aktif
Butuh Pendampingan
{filteredSchools.map((sch) => (
{ setSelectedSchoolId(sch.id); showToast(`Fokus ulasan dialihkan ke: ${sch.name}`, "info"); }}
className={`p-4 rounded-2xl border transition-all cursor-pointer relative flex flex-col justify-between h-[140px] ${
selectedSchoolId === sch.id ? 'ring-2 ring-emerald-500 bg-emerald-50/10 border-emerald-200 shadow-md shadow-emerald-500/5' : 'bg-white hover:shadow-md border-slate-200/70'
}`}
>
{sch.npsn}
{sch.name}
{sch.address}
Kepatuhan Mandiri: {sch.complianceScore}%
Pilih Sekolah →
{selectedSchoolId === sch.id && (
)}
))}
)}
{/* TAHAP 2 APIP: PENILAIAN PREVENTIF DRAFT KWITANSI */}
{auditorStep === 2 && (
SEKOLAH TERPILIH NTB
{activeSchool.name}
Hubungan Binaan: {activeSchool.status} • Kepatuhan: {activeSchool.complianceScore}%
Dokumen Draft SPJ Siap Ditelaah
{draftSpjList.filter(d => d.schoolId === selectedSchoolId).length === 0 ? (
Tidak ada draf kwitansi/SPJ yang dikirimkan oleh sekolah ini.
) : (
draftSpjList.filter(d => d.schoolId === selectedSchoolId).map((draft) => (
{draft.id}
{draft.status}
{draft.description}
Berkas: {draft.file} • Estimasi: Rp {draft.amount.toLocaleString()}
{
setCoachingTargetId(draft.id);
setCoachingStatusValue(true);
setCoachingText("Draf kwitansi sudah memenuhi Juknis BOS.");
setIsCoachingModalOpen(true);
}}
className="bg-emerald-50 hover:bg-emerald-100 text-emerald-700 text-[11px] font-bold px-3 py-1.5 rounded-lg border border-emerald-200 transition-all shadow-sm"
>
✓ Sesuai Juknis
{
setCoachingTargetId(draft.id);
setCoachingStatusValue(false);
setCoachingText("Mohon lampirkan...");
setIsCoachingModalOpen(true);
}}
className="bg-amber-50 hover:bg-amber-100 text-amber-700 text-[11px] font-bold px-3 py-1.5 rounded-lg border border-amber-200 transition-all shadow-sm"
>
⚠️ Perlu Perbaikan
{draft.hasAdvice && (
Catatan Bimbingan Anda (APIP NTB): "{draft.adviceText}"
)}
))
)}
)}
{/* TAHAP 3 APIP: BIMBINGAN CHAT & OTORISASI */}
{auditorStep === 3 && (
{/* CHAT PENDAMPINGAN SISI AUDITOR */}
Obrolan Pendampingan e-Review NTB
{chats.filter(c => c.schoolId === selectedSchoolId).length === 0 ? (
Ketik pesan pertama Anda untuk merespons sekolah.
) : (
chats.filter(c => c.schoolId === selectedSchoolId).map((chat, idx) => (
{chat.sender} • {chat.time}
{chat.message}
))
)}
{/* FORM PENERBITAN ADVISORY NOTE RESMI */}
Otorisasi Dokumen Advisory Note e-Review NTB
Rilis dokumen persetujuan final (Advisory Note) resmi dari Inspektorat NTB sebagai penutup hasil pre-review draf sekolah.
{proposedItems.filter(p => p.schoolId === selectedSchoolId).length === 0 ? (
Belum ada usulan program belanja dari sekolah ini.
) : (
proposedItems.filter(p => p.schoolId === selectedSchoolId).map((item) => (
{item.id}
{item.activity}
Rencana Pagu: Rp {item.plannedCost.toLocaleString()}
{ setSelectedDraftId(item.id); setAdvisoryText("Berdasarkan Juknis BOS Nasional dan koordinasi Inspektorat Provinsi NTB, program disetujui secara preventif."); setIsAdvisoryModalOpen(true); }}
className="bg-emerald-600 hover:bg-emerald-700 text-white text-[10px] font-bold px-3 py-2 rounded-xl transition-all shadow-sm"
>
Terbitkan Note
))
)}
)}
{/* Sidebar Kanan Inspektorat: Informasi & Log */}
{/* DETAIL SEKOLAH */}
Sekolah Terpilih:
{activeSchool.name}
Kepala Sekolah:
{activeSchool.headmaster}
Bendahara BOS:
{activeSchool.treasurer}
Status Binaan:
{activeSchool.status}
{/* NOTIFIKASI */}
Notifikasi Masuk
{notifications.filter(n => n.schoolId === selectedSchoolId).length === 0 ? (
Belum ada notifikasi baru untuk sekolah ini.
) : (
notifications.filter(n => n.schoolId === selectedSchoolId).map((notif) => (
{notif.date}
{notif.message}
))
)}
{/* AUDIT TRAIL LOG */}
Log Aktivitas APIP
{consultingLogs.filter(l => l.schoolId === selectedSchoolId).map((log) => (
{log.time}
{log.user}: {log.action}
))}
)}
{/* ========================================================
BUILDING INTERACTIVE CUSTOM MODALS
======================================================== */}
{/* COACHING NOTE */}
{isCoachingModalOpen && (
)}
{/* OTORISASI ADVISORY NOTE */}
{isAdvisoryModalOpen && (
Otorisasi Dokumen Advisory Note
setIsAdvisoryModalOpen(false)} className="text-slate-400 hover:text-slate-600">
Program Target: {selectedDraftId} - {proposedItems.find(p => p.id === selectedDraftId)?.activity}
Rekomendasi Hukum Preventif APIP NTB
setAdvisoryText(e.target.value)}
className="w-full bg-slate-50 border border-slate-200 rounded-xl px-3 py-2.5 text-xs focus:ring-1 focus:ring-indigo-500 focus:outline-none font-semibold"
/>
setIsAdvisoryModalOpen(false)}
className="bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-bold px-4 py-2.5 rounded-xl"
>
Batal
Terbitkan Rekomendasi
)}
{/* FOOTER */}
);
}