Sesi 8: Frontend Core Pages - BPRS Baktimakmur

Sesi 8: Frontend Core Pages

Dashboard, Input Nasabah, & Analisa AI (Frontend Integration)

1. Halaman Dashboard (Monitoring Portfolio)

Halaman ini menampilkan statistik utama yang diambil dari API `/monitoring/dashboard`. Ini adalah tampilan pertama setelah user login.

File: frontend/src/pages/Dashboard.tsx

import React, { useEffect, useState } from 'react'; import apiClient from '../api/client'; import { AlertCircle, TrendingUp, Users, AlertTriangle } from 'lucide-react'; export default function Dashboard() { const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchStats = async () => { try { const response = await apiClient.get('/monitoring/dashboard'); setStats(response.data); } catch (error) { console.error("Gagal mengambil data dashboard", error); } finally { setLoading(false); } }; fetchStats(); }, []); if (loading) return
Memuat Data...
; return (

Dashboard Portofolio

{/* Kartu Statistik Utama */}

Total Pembiayaan

{stats?.total_active_loans || 0}
Plafond: Rp {stats?.total_principal ? new Intl.NumberFormat('id-ID').format(stats.total_principal) : 0}

Rasio Kelalaian (NPL)

{stats?.delinquency_rate || 0}%
5 ? 'text-red-500' : 'text-green-600'}`}> {stats?.delinquency_rate > 5 ? 'Perlu Perhatian' : 'Sehat'}

Total Nasabah Risiko

{stats?.risk_distribution?.high || 0}
Kategori High Risk
{/* Distribusi Risiko */}

Distribusi Risiko Portofolio

Low Risk
{stats?.risk_distribution?.low || 0}
Medium Risk
{stats?.risk_distribution?.medium || 0}
High Risk
{stats?.risk_distribution?.high || 0}
); }

2. Halaman Input Nasabah

Formulir untuk mendaftarkan nasabah baru. Menggunakan state React untuk menampung input.

File: frontend/src/pages/CreateCustomer.tsx

import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import apiClient from '../api/client'; export default function CreateCustomer() { const navigate = useNavigate(); const [formData, setFormData] = useState({ name: '', phone: '', national_id: '', business_type: '', monthly_income: '', assets_value: '' }); const handleChange = (e: React.ChangeEvent) => { setFormData({ ...formData, [e.target.name]: e.target.value }); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await apiClient.post('/customers/', { ...formData, monthly_income: parseFloat(formData.monthly_income), assets_value: parseFloat(formData.assets_value) }); alert('Nasabah berhasil ditambahkan!'); navigate('/dashboard'); } catch (error) { alert('Gagal menambah nasabah. Cek input kembali.'); } }; return (

Tambah Data Nasabah

); }

3. Halaman Input Pembiayaan & Analisa AI

Halaman ini menerima ID nasabah (bisa input manual nanti dibuat dropdown), data pinjaman, dan menampilkan hasil Skor AI setelah submit.

File: frontend/src/pages/CreateLoan.tsx

import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import apiClient from '../api/client'; export default function CreateLoan() { const navigate = useNavigate(); const [formData, setFormData] = useState({ customer_id: '', branch_id: 1, // Default branch KPO product_name: '', principal_amount: '', profit_rate: 15, // Default 15% tenor_months: 12, start_date: new Date().toISOString().split('T')[0] }); const [result, setResult] = useState(null); const handleChange = (e: React.ChangeEvent) => { setFormData({ ...formData, [e.target.name]: e.target.value }); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setResult(null); try { // Submit ke Backend. Backend akan otomatis menjalankan AI Scoring (Sesi 5). const response = await apiClient.post('/loans/submit', { ...formData, principal_amount: parseFloat(formData.principal_amount), profit_rate: parseFloat(formData.profit_rate), tenor_months: parseInt(formData.tenor_months) }); setResult(response.data); // Simpan hasil (termasuk score & segment) } catch (error: any) { alert(error.response?.data?.detail || 'Gagal membuat pembiayaan'); } }; // Helper warna untuk segment const getSegmentColor = (segment: string) => { if (segment === 'low') return 'bg-green-100 text-green-800 border-green-200'; if (segment === 'medium') return 'bg-yellow-100 text-yellow-800 border-yellow-200'; return 'bg-red-100 text-red-800 border-red-200'; }; return (

Pengajuan Pembiayaan Baru

{/* TAMPILKAN HASIL AI */} {result && (

Hasil Analisa Sistem

Skor Kredit
{result.credit_score}
{result.segment.toUpperCase()} RISK
Probabilitas Gagal Bayar
{(result.default_probability * 100).toFixed(1)}%
Angsuran/Bulan
Rp {new Intl.NumberFormat('id-ID').format(result.monthly_installment || 0)}
{result.segment === 'high' ?

⚠️ Perhatian: Risiko Tinggi. Pertimbangkan survei ulang.

:

✅ Pengajuan Memenuhi Kriteria.

}
)}
); }

4. Konfigurasi Routing (App.tsx)

Sekarang kita hubungkan semua halaman tersebut ke dalam file induk aplikasi agar bisa dinavigasi.

File: frontend/src/App.tsx

import React from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import Login from './pages/Login'; import Dashboard from './pages/Dashboard'; import CreateCustomer from './pages/CreateCustomer'; import CreateLoan from './pages/CreateLoan'; import apiClient from './api/client'; // Protected Route Component const ProtectedRoute = ({ children }: { children: React.ReactNode }) => { const token = localStorage.getItem('access_token'); if (!token) { return ; } return <>{children}; }; function App() { return ( } /> } /> } /> } /> ); } export default App;