// cluster.jsx — Cluster hub (Izin Renovasi + Cluster OS stubs). Exported to window. const PERMIT_STATUS = { diajukan: { label: 'DIAJUKAN', color: 'var(--s-500)', soft: 'var(--s-100)' }, ditinjau: { label: 'DITINJAU', color: 'var(--blue)', soft: 'var(--blue-50)' }, revisi: { label: 'REVISI', color: 'var(--amber)', soft: 'var(--amber-50)' }, disetujui: { label: 'DISETUJUI', color: 'var(--lime)', soft: 'var(--lime-50)' }, ditolak: { label: 'DITOLAK', color: 'var(--coral)', soft: 'var(--coral-50)' }, selesai: { label: 'SELESAI', color: 'var(--violet)', soft: 'var(--violet-50)' }, }; function PermitStatusChip({ status }) { const s = PERMIT_STATUS[status] || PERMIT_STATUS.diajukan; return ( {s.label} ); } const RENO_TYPES = [ ['ringan', 'Ringan', 'Cat, perbaikan kecil'], ['sedang', 'Sedang', 'Tambah / ubah ruang'], ['berat', 'Berat', 'Struktur, tambah lantai'], ['bongkar_bangun', 'Bongkar Bangun', 'Bongkar total & bangun ulang'], ]; function fmtDate(d) { if (!d) return '-'; try { return new Date(d).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); } catch (e) { return d; } } function fmtRp(n) { if (n == null) return '-'; return 'Rp' + Number(n).toLocaleString('id-ID'); } const fieldStyle = { width: '100%', padding: '13px 14px', borderRadius: 'var(--r-md)', border: '1px solid var(--border)', background: 'var(--surface-2)', fontFamily: 'var(--font)', fontSize: 14.5, fontWeight: 500, color: 'var(--text-1)', outline: 'none' }; function Label({ children, opt }) { return ; } function PermitFlow({ clusters = [], profile, onClose, onDone }) { const [clusterId, setClusterId] = React.useState(profile && profile.home_cluster_id ? profile.home_cluster_id : ''); const [unit, setUnit] = React.useState(''); const [addr, setAddr] = React.useState(''); const [renoType, setRenoType] = React.useState(''); const [startD, setStartD] = React.useState(''); const [endD, setEndD] = React.useState(''); const [cName, setCName] = React.useState(''); const [cPhone, setCPhone] = React.useState(''); const [workers, setWorkers] = React.useState(''); const [desc, setDesc] = React.useState(''); const [files, setFiles] = React.useState([]); const [err, setErr] = React.useState(''); const [busy, setBusy] = React.useState(false); const [sent, setSent] = React.useState(false); const fileRef = React.useRef(null); const onPick = (e) => { const list = Array.from(e.target.files || []); setFiles(f => f.concat(list)); if (fileRef.current) fileRef.current.value = ''; }; const removeFile = (i) => setFiles(f => f.filter((_, j) => j !== i)); const submit = async () => { setErr(''); if (!clusterId) return setErr('Pilih cluster dulu'); if (!renoType) return setErr('Pilih jenis renovasi'); if (!startD) return setErr('Isi tanggal mulai'); setBusy(true); const res = await gsData.submitPermit({ cluster_id: clusterId, unit_number: unit.trim() || null, unit_address: addr.trim() || null, reno_type: renoType, description: desc.trim() || null, contractor_name: cName.trim() || null, contractor_phone: cPhone.trim() || null, worker_count: workers ? parseInt(workers, 10) : null, start_date: startD || null, end_date: endD || null, files, }); setBusy(false); if (res.error) return setErr('Gagal mengirim: ' + res.error); setSent(true); setTimeout(onDone, 1500); }; if (sent) { return (

Pengajuan terkirim!

Estate manager akan meninjau pengajuan renovasimu. Pantau statusnya di halaman Cluster.

); } return (

Ajukan Izin Renovasi

setUnit(e.target.value)} placeholder="cth. C12 No. 7" style={fieldStyle} />
setAddr(e.target.value)} placeholder="Jalan / blok" style={fieldStyle} />
{RENO_TYPES.map(([k, lbl, sub]) => { const on = renoType === k; return ( ); })}
setStartD(e.target.value)} style={fieldStyle} />
setEndD(e.target.value)} style={fieldStyle} />
setCName(e.target.value)} placeholder="Nama" style={fieldStyle} />
setWorkers(e.target.value)} placeholder="0" style={fieldStyle} />
setCPhone(e.target.value)} placeholder="08xxxx" style={{ ...fieldStyle, fontFamily: 'var(--mono)' }} />