import React, { useState, useEffect } from 'react'; import { Users, School, FileText, LogOut, CheckCircle, XCircle, Menu, X, Trash2, Printer, Settings, PlusCircle, Edit, Save, Heading, ArrowUp, ArrowDown, Link, Eye, EyeOff, Lock, Mail, Search, Upload, File, Image as ImageIcon, Layout // Icon untuk Branding } from 'lucide-react'; // --- DATA MOCKUP & KONFIGURASI --- const JENJANG_LIST = ['KB', 'RA', 'MI', 'MTs', 'MA']; // Konfigurasi Default Aplikasi (Bisa diedit Superadmin) const INITIAL_APP_CONFIG = { ppdbName: 'PPDB Online', foundationName: 'Yayasan Hidayatun Najah Tuban', logoUrl: null, // Jika null, pakai icon default themeColor: 'emerald' // Bisa dikembangkan untuk tema warna }; // Konfigurasi Awal Formulir const INITIAL_FORM_CONFIG = [ // Bagian 1 { id: 'h1', label: 'Data Pribadi Calon Siswa', type: 'header', key: 'sec_pribadi' }, { id: 'f1', label: 'Nama Lengkap', type: 'text', key: 'namaLengkap', required: true }, { id: 'f2', label: 'NIK', type: 'number', key: 'nik', required: true }, { id: 'f3', label: 'Pilih Jenjang', type: 'select', key: 'jenjang', options: JENJANG_LIST, required: true, allowCustom: false }, { id: 'f_prog', label: 'Program / Peminatan', type: 'select', key: 'program', required: true, dependsOn: 'jenjang', visibleForJenjang: ['MA', 'MTs'], optionsMapping: { 'MA': ['IPA', 'IPS', 'Bahasa', 'Keagamaan'], 'MTs': ['Reguler', 'Tahfidz', 'Bilingual'] } }, { id: 'f4', label: 'Tempat Lahir', type: 'text', key: 'tempatLahir', required: true }, { id: 'f5', label: 'Tanggal Lahir', type: 'date', key: 'tanggalLahir', required: true }, // Bagian 2 { id: 'h2', label: 'Data Sekolah Sebelumnya', type: 'header', key: 'sec_sekolah' }, { id: 'f6', label: 'Asal Sekolah', type: 'text', key: 'asalSekolah', required: true }, // Bagian 3 { id: 'h3', label: 'Data Orang Tua / Wali', type: 'header', key: 'sec_ortu' }, { id: 'f7', label: 'Nama Ayah Kandung', type: 'text', key: 'namaAyah', required: true }, { id: 'f8', label: 'No. HP / WhatsApp', type: 'text', key: 'noHp', required: true }, // Bagian 4: Upload Berkas { id: 'h4', label: 'Berkas Persyaratan', type: 'header', key: 'sec_berkas' }, { id: 'f9', label: 'Scan Kartu Keluarga (KK)', type: 'file', key: 'file_kk', required: false }, { id: 'f10', label: 'Pas Foto (3x4)', type: 'file', key: 'file_foto', required: false }, ]; const INITIAL_USERS = [ { id: 1, name: 'Ketua Yayasan', email: 'super@yayasan.com', role: 'superadmin', password: '123' }, { id: 2, name: 'Admin MI', email: 'admin.mi@yayasan.com', role: 'admin_jenjang', jenjang: 'MI', password: '123' }, { id: 3, name: 'Admin MTs', email: 'admin.mts@yayasan.com', role: 'admin_jenjang', jenjang: 'MTs', password: '123' }, { id: 4, name: 'Budi Santoso', email: 'siswa@test.com', role: 'pendaftar', password: '123' } ]; const INITIAL_REGISTRATIONS = [ { id: 'REG-001', userId: 4, namaLengkap: 'Budi Santoso', nik: '3523000000000001', jenjang: 'MI', program: 'Tahfidz', asalSekolah: 'TK Pertiwi', namaAyah: 'Slamet', noHp: '081234567890', tempatLahir: 'Tuban', tanggalLahir: '2015-05-20', status: 'Diterima', tanggalDaftar: '2023-05-20' } ]; // --- KOMPONEN UTAMA --- export default function App() { const [currentUser, setCurrentUser] = useState(null); const [users, setUsers] = useState(INITIAL_USERS); const [registrations, setRegistrations] = useState(INITIAL_REGISTRATIONS); const [formConfig, setFormConfig] = useState(INITIAL_FORM_CONFIG); const [appConfig, setAppConfig] = useState(INITIAL_APP_CONFIG); // State Global App Config const [currentView, setCurrentView] = useState('login'); const handleLogin = (email, password) => { const user = users.find(u => u.email === email && u.password === password); if (user) { setCurrentUser(user); setCurrentView('dashboard'); } else { alert('Email atau password salah!'); } }; const handleLogout = () => { setCurrentUser(null); setCurrentView('login'); }; const handleRegister = (name, email, password) => { const newUser = { id: users.length + 1, name, email, password, role: 'pendaftar' }; setUsers([...users, newUser]); alert('Pendaftaran akun berhasil! Silakan login.'); setCurrentView('login'); }; if (currentView === 'login') { return setCurrentView('register')} />; } if (currentView === 'register') { return setCurrentView('login')} />; } return ( {currentUser.role === 'superadmin' && ( )} {currentUser.role === 'admin_jenjang' && ( )} {currentUser.role === 'pendaftar' && ( )} ); } // --- SCREEN COMPONENTS --- function LoginScreen({ appConfig, onLogin, onGoToRegister }) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); return (
{appConfig.logoUrl ? ( Logo ) : ( )}

{appConfig.ppdbName}

{appConfig.foundationName}

{ e.preventDefault(); onLogin(email, password); }}>
setEmail(e.target.value)} placeholder="contoh: super@yayasan.com" required />
setPassword(e.target.value)} placeholder="******" required />

Belum punya akun?

Akun Demo (Klik untuk menyalin):

{setEmail('super@yayasan.com'); setPassword('123')}}>👑 Superadmin: super@yayasan.com / 123
{setEmail('admin.mi@yayasan.com'); setPassword('123')}}>🏫 Admin MI: admin.mi@yayasan.com / 123
{setEmail('siswa@test.com'); setPassword('123')}}>👤 Pendaftar: siswa@test.com / 123
); } function RegisterScreen({ appConfig, onRegister, onBack }) { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); return (
{appConfig.logoUrl && ( Logo )}

Pendaftaran Akun

{appConfig.foundationName}

{ e.preventDefault(); onRegister(name, email, password); }}>
setName(e.target.value)} required />
setEmail(e.target.value)} required />
setPassword(e.target.value)} required />
); } function DashboardLayout({ user, onLogout, children, appConfig }) { const [isSidebarOpen, setSidebarOpen] = useState(false); return (
{appConfig.ppdbName}
{user.name.charAt(0)}

{user.name}

{user.role.replace('_', ' ')}

{appConfig.foundationName}

Selamat Datang, {user.name}

Panel Kontrol {appConfig.ppdbName}

{new Date().toLocaleDateString('id-ID', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}

{children}
); } // 1. SUPERADMIN VIEW function SuperAdminView({ users, setUsers, registrations, setRegistrations, formConfig, setFormConfig, appConfig, setAppConfig }) { const [tab, setTab] = useState('pendaftar'); // pendaftar | users | form | settings return (
} color="bg-blue-500" /> } color="bg-purple-500" /> } color="bg-orange-500" /> r.status === 'Menunggu').length} icon={} color="bg-yellow-500" />
{tab === 'pendaftar' ? ( ) : tab === 'users' ? ( ) : tab === 'form' ? ( ) : ( )}
); } // APP SETTINGS EDITOR (NEW COMPONENT) function AppSettingsEditor({ appConfig, setAppConfig }) { const [formData, setFormData] = useState({ ...appConfig }); const handleLogoUpload = (e) => { const file = e.target.files[0]; if (file) { if (file.size > 2 * 1024 * 1024) { alert("Ukuran logo terlalu besar! Maksimal 2MB."); return; } const reader = new FileReader(); reader.onloadend = () => { setFormData(prev => ({ ...prev, logoUrl: reader.result })); }; reader.readAsDataURL(file); } }; const handleSave = (e) => { e.preventDefault(); setAppConfig(formData); alert('Pengaturan aplikasi berhasil disimpan!'); }; return (

Identitas Aplikasi & Yayasan

Sesuaikan nama aplikasi, yayasan, dan logo yang tampil di halaman login/daftar.

setFormData({...formData, ppdbName: e.target.value})} placeholder="Contoh: PPDB Online 2024" required />
setFormData({...formData, foundationName: e.target.value})} placeholder="Contoh: Yayasan Pendidikan Maju Jaya" required />
{formData.logoUrl ? ( Preview Logo ) : (
)} {formData.logoUrl ? 'Ganti Logo' : 'Upload Logo'}

Format: PNG, JPG (Transparan disarankan)

); } // EDITOR FORMULIR function FormEditor({ formConfig, setFormConfig }) { const [isEditing, setIsEditing] = useState(false); const [editId, setEditId] = useState(null); const [formData, setFormData] = useState({ label: '', type: 'text', key: '', options: '', required: true, allowCustom: false, dependsOn: '', visibleForJenjang: [] }); const resetForm = () => { setFormData({ label: '', type: 'text', key: '', options: '', required: true, allowCustom: false, dependsOn: '', visibleForJenjang: [] }); setEditId(null); setIsEditing(false); }; const handleDelete = (id) => { if (confirm('Yakin ingin menghapus field ini? PERINGATAN: Menghapus field sistem dapat mengganggu tampilan tabel data.')) { setFormConfig(formConfig.filter(f => f.id !== id)); } }; const handleMoveUp = (index) => { if (index === 0) return; const newConfig = [...formConfig]; const temp = newConfig[index]; newConfig[index] = newConfig[index - 1]; newConfig[index - 1] = temp; setFormConfig(newConfig); }; const handleMoveDown = (index) => { if (index === formConfig.length - 1) return; const newConfig = [...formConfig]; const temp = newConfig[index]; newConfig[index] = newConfig[index + 1]; newConfig[index + 1] = temp; setFormConfig(newConfig); }; const handleEditClick = (field) => { setEditId(field.id); let optionsString = ''; if (field.dependsOn && field.optionsMapping) { optionsString = Object.entries(field.optionsMapping) .map(([key, opts]) => `${key} : ${opts.join(', ')}`) .join(' | '); } else { optionsString = field.options ? field.options.join(', ') : ''; } setFormData({ label: field.label, type: field.type, key: field.key, options: optionsString, required: field.required, allowCustom: field.allowCustom || false, dependsOn: field.dependsOn || '', visibleForJenjang: field.visibleForJenjang || [] }); setIsEditing(true); }; const handleSave = (e) => { e.preventDefault(); let optionsArray = undefined; let optionsMapping = undefined; if (formData.type === 'select') { if (formData.dependsOn) { optionsMapping = {}; const groups = formData.options.split('|'); groups.forEach(group => { const [parentKey, opts] = group.split(':'); if (parentKey && opts) { optionsMapping[parentKey.trim()] = opts.split(',').map(o => o.trim()); } }); } else { optionsArray = formData.options.split(',').map(o => o.trim()); } } let key = formData.key; if (!key && !editId) { key = formData.label.toLowerCase().replace(/[^a-zA-Z0-9]/g, ''); } const newFieldData = { label: formData.label, type: formData.type, key: key, required: formData.type === 'header' ? false : formData.required, options: optionsArray, optionsMapping: optionsMapping, allowCustom: formData.type === 'select' ? formData.allowCustom : false, dependsOn: formData.type === 'select' ? formData.dependsOn : undefined, visibleForJenjang: formData.visibleForJenjang }; if (editId) { const updatedConfig = formConfig.map(f => { if (f.id === editId) { return { ...f, ...newFieldData }; } return f; }); setFormConfig(updatedConfig); } else { const id = `f${Date.now()}`; setFormConfig([...formConfig, { id, ...newFieldData }]); } resetForm(); }; const toggleJenjang = (jenjang) => { const current = formData.visibleForJenjang || []; if (current.includes(jenjang)) { setFormData({ ...formData, visibleForJenjang: current.filter(j => j !== jenjang) }); } else { setFormData({ ...formData, visibleForJenjang: [...current, jenjang] }); } }; const availableParents = formConfig.filter(f => f.type === 'select' && f.id !== editId); return (

Editor Formulir Pendaftaran

Atur pertanyaan, urutan, dan visibilitas per jenjang.

{!isEditing && ( )}
{isEditing && (

{editId ? : } {editId ? 'Edit Item' : 'Tambah Item Baru'}

setFormData({...formData, label: e.target.value})} required />
setFormData({...formData, key: e.target.value})} />

Jika tidak ada yang dipilih, pertanyaan akan muncul untuk SEMUA jenjang.

{JENJANG_LIST.map(j => ( ))}
{formData.type === 'select' && (