import React, { useState, useEffect, useMemo } from 'react'; import { Users, Briefcase, FileText, Calculator, MessageSquare, LayoutDashboard, LogOut, AlertCircle, CheckCircle, PieChart, Download, FileSpreadsheet, TrendingUp, ChevronRight } from 'lucide-react'; // --- KONFIGURASI TEMA & ROLE --- const ROLES = { DIREKTUR: { id: 'direktur', name: 'Yudis (Direktur)', pin: '1111' }, COO: { id: 'coo', name: 'Ramadhan (COO)', pin: '2222' }, FINANCE: { id: 'finance', name: 'Desi (Finance & Legal)', pin: '3333' }, HR: { id: 'hr', name: 'Irfan (HR Manager)', pin: '4444' }, INTERN: { id: 'intern', name: 'Intern / PKL', pin: '5555' } }; // --- KOMPONEN UTAMA (APP) --- export default function App() { const [user, setUser] = useState(null); const [activeTab, setActiveTab] = useState('dashboard'); useEffect(() => { const savedUser = localStorage.getItem('rcc_user'); if (savedUser) setUser(JSON.parse(savedUser)); }, []); const handleLogin = (roleKey, pin) => { const role = ROLES[roleKey]; if (pin === role.pin) { const userData = { role: role.id, name: role.name }; setUser(userData); localStorage.setItem('rcc_user', JSON.stringify(userData)); if (role.id === 'finance') setActiveTab('finance'); else if (role.id === 'intern') setActiveTab('intern'); else setActiveTab('dashboard'); } else { alert("PIN Salah! (Petunjuk: Coba 1111, 2222, 3333, 4444, 5555)"); } }; const handleLogout = () => { setUser(null); localStorage.removeItem('rcc_user'); setActiveTab('dashboard'); }; if (!user) return ; return (
{activeTab === 'dashboard' && } {activeTab === 'memo' && } {activeTab === 'finance' && } {activeTab === 'hpp' && } {activeTab === 'docs' && } {activeTab === 'intern' && }
); } // --- KOMPONEN: LOGIN --- function LoginScreen({ onLogin }) { const [selectedRole, setSelectedRole] = useState('DIREKTUR'); const [pin, setPin] = useState(''); return (
{/* Background Ornaments */}
RCC

Majukan Skill

PORTAL MANAJEMEN EKSEKUTIF

setPin(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && onLogin(selectedRole, pin)} />
); } // --- KOMPONEN: SIDEBAR & HEADER --- function Sidebar({ user, activeTab, setActiveTab, onLogout }) { const navItems = [ { id: 'dashboard', label: 'Overview', icon: LayoutDashboard, roles: ['direktur', 'coo'] }, { id: 'memo', label: 'Komunikasi Internal', icon: MessageSquare, roles: ['direktur', 'coo', 'finance', 'hr', 'intern'] }, { id: 'finance', label: 'Keuangan', icon: Briefcase, roles: ['direktur', 'coo', 'finance'] }, { id: 'hpp', label: 'Kalkulator HPP', icon: Calculator, roles: ['direktur', 'coo', 'finance'] }, { id: 'docs', label: 'Dokumen & SOP', icon: FileText, roles: ['direktur', 'coo', 'finance', 'hr'] }, { id: 'intern', label: 'Manajemen Intern', icon: Users, roles: ['direktur', 'coo', 'hr', 'intern'] }, ]; return (
RC

Workspace

PT Ranstra Creative

{user.name.charAt(0)}

{user.name}

{user.role}

); } function Header({ title, user }) { return (

{title}

Selamat datang kembali, mari capai target kita hari ini.

{user.name}

{user.role}
{user.name.charAt(0)}
); } function getTabTitle(tab) { const titles = { dashboard: 'Executive Overview', memo: 'Pusat Komunikasi', finance: 'Laporan Finansial', hpp: 'Simulasi HPP & Harga', docs: 'Arsip & Legalitas', intern: 'Portal SDM & Intern' }; return titles[tab] || 'Dashboard'; } // --- MODUL 1: DASHBOARD OVERVIEW --- function DashboardOverview({ user, setActiveTab }) { return (

Distribusi Revenue (KBLI)

Pintasan Tindakan Cepat

); } function StatCard({ title, value, sub, color, icon: Icon }) { const styles = { green: 'from-emerald-400 to-green-500 shadow-green-500/20 text-green-700 bg-green-50', blue: 'from-[#1A237E] to-blue-600 shadow-blue-500/20 text-blue-700 bg-blue-50', yellow: 'from-[#FFD700] to-orange-400 shadow-orange-500/20 text-orange-800 bg-orange-50', purple: 'from-purple-500 to-indigo-500 shadow-purple-500/20 text-purple-700 bg-purple-50' }[color]; const [gradient, shadow, textColor, bgColor] = styles.split(' '); return (

{title}

{value}
{sub}
); } function ProgressBar({ label, percent, color }) { return (
{label} {percent}%
); } // --- MODUL 2: HPP CALCULATOR (FITUR UTAMA) --- function HPPCalculator({ user }) { const [data, setData] = useState({ gajiOwner: 5000000, gajiTim: 10000000, sewa: 2000000, listrik: 500000, ads: 1500000, software: 500000, lisensiTahun: 3600000, hargaAset: 12000000, umurAset: 2, material: 200000, feeFreelance: 500000, transport: 100000, buffer: 10, targetProyek: 10, kapasitasMaks: 15, targetMargin: 50, jenisKeuntungan: 'margin', pajak: 11 }); const [skenario, setSkenario] = useState(1); const handleChange = (e) => { const { name, value } = e.target; setData(prev => ({ ...prev, [name]: parseFloat(value) || 0 })); }; const calc = useMemo(() => { const targetProyekReal = Math.max(1, Math.round(data.targetProyek * skenario)); const fixedTotal = data.gajiOwner + data.gajiTim + data.sewa + data.listrik + data.ads + data.software; const depTotal = (data.lisensiTahun / 12) + (data.umurAset > 0 ? (data.hargaAset / data.umurAset) / 12 : 0); const varDasar = data.material + data.feeFreelance + data.transport; const varTotal = varDasar + (varDasar * (data.buffer / 100)); const bebanTetapPerProyek = (fixedTotal + depTotal) / targetProyekReal; const hppPerProyek = bebanTetapPerProyek + varTotal; let hargaDasar = data.jenisKeuntungan === 'margin' ? hppPerProyek / (1 - (data.targetMargin / 100)) : hppPerProyek * (1 + (data.targetMargin / 100)); const pajakNominal = hargaDasar * (data.pajak / 100); const hargaJualRekomendasi = hargaDasar + pajakNominal; const profitPerProyek = hargaDasar - hppPerProyek; const netProfitBulan = profitPerProyek * targetProyekReal; const marginKontribusi = hargaDasar - varTotal; const bepUnit = marginKontribusi > 0 ? Math.ceil((fixedTotal + depTotal) / marginKontribusi) : 0; return { targetProyekReal, fixedTotal, depTotal, varTotal, hppPerProyek, hargaJualRekomendasi, bepUnit, netProfitBulan, pajakNominal, profitPerProyek, hargaDasar }; }, [data, skenario]); const formatRp = (num) => new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(num); // Perhitungan Data Donut Chart const totalBiaya = calc.hargaJualRekomendasi; const pctFixed = (((calc.fixedTotal + calc.depTotal) / calc.targetProyekReal) / totalBiaya) * 100; const pctVar = (calc.varTotal / totalBiaya) * 100; const pctTax = (calc.pajakNominal / totalBiaya) * 100; if (!['direktur', 'coo', 'finance'].includes(user.role)) { return
Akses Ditolak. Anda tidak memiliki izin melihat modul keuangan.
; } return (
{/* FORM INPUT AREA */}
{/* SECTION 1 */}

1. Biaya Tetap & Operasional (Bulanan)

Beban yang harus dibayar ada/tidak ada proyek

{/* SECTION 2 & 3 */}

2. Penyusutan Tahunan

Dibagi otomatis per bulan

3. Biaya Variabel

Keluar untuk setiap 1 proyek baru

{/* SECTION 4 */}

4. Parameter Bisnis & Target

DARI
{data.targetProyek > data.kapasitasMaks && (
Target melebihi kapasitas!
)}
PPN %
{/* DASHBOARD OUTPUT AREA (Kanan - STICKY) */}

Harga Jual Rekomendasi

{formatRp(calc.hargaJualRekomendasi)}

Per 1 Proyek (Termasuk Pajak {data.pajak}%)

{/* SVG Donut Chart Pure CSS/SVG */}
{/* Modal Background */} {/* Fixed Cost (Blue) */} {/* Variable Cost (Yellow) */} {/* Tax (Gray) */} {/* Profit (Green) */}
Margin {data.targetMargin}%

Target Balik Modal (BEP)

Wajib Closing {calc.bepUnit} Proyek/Bln

); } function InputRp({ label, name, value, onChange }) { return (
Rp
); } function LegendItem({ color, label, value }) { return (
{label}
{value}
) } // --- MODUL LENGKAP LAINNYA (UI Placeholder) --- function MemoModule({ user }) { return (

Pusat Komunikasi

{['direktur', 'coo', 'hr'].includes(user.role) && }
Urgent

Update Harga Paket Majukan Skill

Dari: Direktur • 10 Apr 2026

); } function FinanceModule({ user }) { if (!['direktur', 'coo', 'finance'].includes(user.role)) return
Akses Ditolak
; return (

Buku Kas Digital

Modul pencatatan transaksi sedang dalam antrean pengembangan fase 2 (Integrasi Google Sheets).

); } function DocumentModule({ user }) { if (user.role === 'intern') return
Akses Ditolak
; return (

Arsip & Legalitas

Nama Dokumen Status Aksi
SOP Pembuatan Reels Instagram Aktif
); } function InternModule({ user }) { if (user.role === 'finance') return
Akses Ditolak
; return (

Portal SDM & Intern

Absensi Hari Ini

); }