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
{/* Distribusi Risiko */}
);
}
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 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;