/* ════════════════════════════════════════════════ Dashboard — Kelola Pengguna, Role & Kewenangan (dinamis) ════════════════════════════════════════════════ */ const PERM_LIST = [ ['articles', 'Kelola Artikel'], ['registrations', 'Lihat Pendaftar'], ['donasi', 'Kelola Donasi'], ['content', 'Edit Konten Halaman'], ['users', 'Kelola Pengguna'], ['settings', 'Pengaturan Situs'], ]; function UsersModule({ user, toast }) { const [users, setUsers] = useState([]); const [roles, setRoles] = useState([]); const [perms, setPerms] = useState({}); const [loading, setLoading] = useState(true); const [modal, setModal] = useState(null); // form pengguna const [roleModal, setRoleModal] = useState(null); // form role baru const [form, setForm] = useState({}); const [roleForm, setRoleForm] = useState({ label: '', permissions: {} }); const [saving, setSaving] = useState(false); const roleLabel = (id) => (roles.find(r => r.id === id) || {}).label || id; const load = () => { setLoading(true); Promise.all([ api.get('auth.php?action=users'), api.get('auth.php?action=get_permissions'), api.get('auth.php?action=get_roles'), ]).then(([u, p, r]) => { if (u.ok && u.users) setUsers(u.users); if (p.ok && p.permissions) setPerms(p.permissions); if (r.ok && r.roles) setRoles(r.roles); }).finally(() => setLoading(false)); }; useEffect(load, []); const firstRole = roles[0] ? roles[0].id : 'writer'; const openAdd = () => { setForm({ name: '', email: '', role: roles.find(r => !r.system)?.id || firstRole, password: '' }); setModal({}); }; const openEdit = (u) => { setForm({ ...u, password: '' }); setModal({ id: u.id }); }; const save = async () => { if (!form.name || !form.email) return; setSaving(true); const action = modal.id ? 'update_user' : 'create_user'; const r = await api.post(`auth.php?action=${action}`, modal.id ? { ...form, id: modal.id } : form); setSaving(false); if (r.ok) { toast(modal.id ? '✅ Pengguna diperbarui' : '✅ Pengguna ditambahkan'); setModal(null); load(); } else toast('⚠️ ' + (r.error || 'Gagal menyimpan')); }; const del = async (u) => { if (u.id === user.id) { toast('⚠️ Tidak bisa menghapus akun sendiri'); return; } if (!window.confirm(`Hapus pengguna "${u.name}"?`)) return; const r = await api.post('auth.php?action=delete_user', { id: u.id }); if (r.ok) { toast('Pengguna dihapus'); load(); } else toast('⚠️ Gagal menghapus'); }; const togglePerm = (role, key) => setPerms(p => ({ ...p, [role]: { ...p[role], [key]: !p[role]?.[key] } })); const savePerms = async () => { const r = await api.post('auth.php?action=save_permissions', { permissions: perms }); if (r.ok) toast('✅ Kewenangan role disimpan'); else toast('⚠️ Gagal'); }; const saveRole = async () => { if (!roleForm.label.trim()) return; setSaving(true); const r = await api.post('auth.php?action=create_role', { label: roleForm.label.trim(), permissions: roleForm.permissions }); setSaving(false); if (r.ok) { toast('✅ Role baru dibuat'); setRoleModal(null); setRoleForm({ label: '', permissions: {} }); load(); } else toast('⚠️ ' + (r.error || 'Gagal')); }; const delRole = async (role) => { if (!window.confirm(`Hapus role "${role.label}"?`)) return; const r = await api.post('auth.php?action=delete_role', { id: role.id }); if (r.ok) { toast('Role dihapus'); load(); } else toast('⚠️ ' + (r.error || 'Gagal menghapus')); }; const accent = (id, i) => id === 'admin' ? 'var(--navy)' : ['var(--sage)', 'var(--orange)', '#7A4E8C', '#0E7C86'][i % 4]; return (
{/* Daftar pengguna */}
Pengguna ({users.length})
+ Tambah Pengguna
{loading ?
Memuat…
: ( {users.map((u, i) => (
{(u.name || '?')[0]}
{u.name}{u.id === user.id ? ' (Anda)' : ''}
{u.email}
{roleLabel(u.role)}
openEdit(u)}>Edit del(u)}>Hapus
))}
)}
{/* Kewenangan role (dinamis) */}
Role & Kewenangan
{ setRoleForm({ label: '', permissions: {} }); setRoleModal({}); }}>+ Role Baru

Centang akses tiap role. Administrator selalu penuh & tak bisa diubah.

{roles.map((role, i) => ( ))} {PERM_LIST.map(([key, label]) => ( {roles.map(role => { const isAdmin = role.id === 'admin'; return ( ); })} ))}
Kewenangan {role.label} {!role.system && }
{label} togglePerm(role.id, key)} style={{ width: 17, height: 17, accentColor: 'var(--sage)', cursor: isAdmin ? 'not-allowed' : 'pointer' }} />
Simpan Kewenangan
{/* Modal pengguna */} setModal(null)} title={modal && modal.id ? 'Edit Pengguna' : 'Tambah Pengguna'} width="440px"> {modal && ( <> setForm(f => ({ ...f, name: e.target.value }))} style={dInp} /> setForm(f => ({ ...f, email: e.target.value }))} style={dInp} /> setForm(f => ({ ...f, password: e.target.value }))} style={dInp} placeholder="••••••••" />
{saving ? 'Menyimpan…' : 'Simpan'} setModal(null)}>Batal
)}
{/* Modal role baru */} setRoleModal(null)} title="Buat Role Baru" width="440px"> {roleModal && ( <> setRoleForm(f => ({ ...f, label: e.target.value }))} style={dInp} placeholder="mis. Editor, Bendahara, Humas" />
Kewenangan
{PERM_LIST.map(([key, label]) => ( ))}
{saving ? 'Menyimpan…' : 'Buat Role'} setRoleModal(null)}>Batal
)}
); } window.UsersModule = UsersModule; /* ── Profil Saya: semua pengguna isi foto, bio, gelar ── */ function ProfileModule({ user, toast, onUpdated }) { const [f, setF] = useState({ name: user.name || '', title: '', bio: '', photo: '' }); const [saving, setSaving] = useState(false); useEffect(() => { api.get('auth.php?action=me').then(r => { if (r.ok && r.user) setF(s => ({ ...s, name: r.user.name || '', title: r.user.title || '', bio: r.user.bio || '', photo: r.user.photo || '' })); }); }, []); const save = async () => { setSaving(true); const r = await api.post('auth.php?action=update_profile', f); setSaving(false); if (r.ok) { toast('✅ Profil disimpan'); if (onUpdated) onUpdated(); } else toast('⚠️ ' + (r.error || 'Gagal')); }; return (
Profil Saya

Foto, gelar, dan bio ini tampil saat pengunjung mengeklik nama Anda di artikel.

{f.photo ? : (f.name[0] || '?')}
setF(s => ({ ...s, photo: v }))} ratio="1/1" />
setF(s => ({ ...s, name: e.target.value }))} style={dInp} /> setF(s => ({ ...s, title: e.target.value }))} style={dInp} placeholder="Pengajar / Penulis" />