Tutorial #8: Halaman Login Nasabah dan Autentikasi dengan API
Halo para nasabah digital! 💻 Hari ini kita akan membuat halaman login yang sesungguhnya di React. Kita akan hubungkan ke API Laravel yang sudah kita buat, simpan token, dan redirect ke dashboard. Anggap saja kita membuat pintu masuk ke bank digital! 🚪
Yang akan kita lakukan:
- ✅ Membuat form login dengan state (email, password).
- ✅ Menangani submit form dan mengirim POST request ke API
/api/login. - ✅ Menyimpan token yang didapat ke localStorage.
- ✅ Redirect ke halaman dashboard setelah login sukses.
- ✅ Menampilkan notifikasi SweetAlert jika login gagal.
- ✅ Menambahkan proteksi route (hanya bisa akses dashboard jika sudah login).
Langkah 1: Install Axios (Opsional, tapi lebih enak)
Kita bisa pakai fetch bawaan JavaScript, tapi biar lebih mudah kita pakai Axios. Install axios di folder frontend:
npm install axios
Axios ini kayak kurir yang mengantar data kita ke backend dan membawa balasan. 📦
Langkah 2: Membuat Halaman Login yang Interaktif
Buka file src/pages/LoginPage.js. Kita akan ubah dari yang sebelumnya statis menjadi dinamis dengan state dan fungsi handle login.
Pertama, import yang dibutuhkan:
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom'; // untuk redirect
import axios from 'axios';
import Swal from 'sweetalert2';
Kemudian buat komponen LoginPage dengan state email dan password:
function LoginPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const response = await axios.post('http://127.0.0.1:8000/api/login', {
email: email,
password: password
});
// Jika sukses, simpan token dan data user
const { token, user } = response.data;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
// Tampilkan notifikasi sukses
Swal.fire({
icon: 'success',
title: 'Login Berhasil!',
text: `Selamat datang, ${user.name}!`,
timer: 1500,
showConfirmButton: false
});
// Redirect ke dashboard
navigate('/dashboard');
} catch (error) {
// Tangani error
const message = error.response?.data?.message || 'Login gagal. Periksa email dan password.';
Swal.fire({
icon: 'error',
title: 'Oops...',
text: message
});
} finally {
setLoading(false);
}
};
Jangan lupa bagian form di JSX diubah supaya terhubung ke state dan onSubmit:
return (
<div className="row justify-content-center">
<div className="col-md-6">
<div className="card">
<div className="card-header bg-primary text-white">
<h4 className="mb-0">Login Nasabah</h4>
</div>
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label className="form-label">Email</label>
<input
type="email"
className="form-control"
placeholder="masukkan email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div className="mb-3">
<label className="form-label">Password</label>
<input
type="password"
className="form-control"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<button
type="submit"
className="btn btn-primary w-100"
disabled={loading}
>
{loading ? 'Memproses...' : 'Login'}
</button>
</form>
</div>
</div>
</div>
</div>
);
Jangan lupa untuk mengekspor komponen ini.
Langkah 3: Menyimpan Token dan Proteksi Halaman
Setelah login sukses, token disimpan di localStorage. Sekarang kita perlu melindungi halaman dashboard agar tidak bisa diakses jika belum login.
Buat komponen PrivateRoute (atau langsung gunakan di App.js). Kita akan buat file baru src/components/PrivateRoute.js:
import React from 'react';
import { Navigate } from 'react-router-dom';
function PrivateRoute({ children }) {
const token = localStorage.getItem('token');
return token ? children : <Navigate to="/login" />;
}
export default PrivateRoute;
Kemudian di App.js, gunakan PrivateRoute untuk membungkus halaman dashboard:
import PrivateRoute from './components/PrivateRoute';
// ... di dalam Routes
<Route path="/dashboard" element={
<PrivateRoute>
<DashboardPage />
</PrivateRoute>
} />
Sekarang jika user mencoba akses /dashboard tanpa token, akan langsung diarahkan ke /login.
Langkah 4: Menambahkan Tombol Logout
Kita perlu tombol logout di dashboard. Di Navbar, kita bisa cek apakah user sudah login, jika ya tampilkan tombol logout.
Modifikasi src/components/Navbar.js:
import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import Swal from 'sweetalert2';
function Navbar() {
const navigate = useNavigate();
const token = localStorage.getItem('token');
const user = JSON.parse(localStorage.getItem('user') || '{}');
const handleLogout = () => {
Swal.fire({
title: 'Yakin mau logout?',
text: 'Kamu akan keluar dari aplikasi',
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Ya, logout',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
localStorage.removeItem('token');
localStorage.removeItem('user');
navigate('/login');
Swal.fire('Berhasil logout!', '', 'success');
}
});
};
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-primary">
<div className="container">
<Link className="navbar-brand" to="/">🏦 Bank Tabungan</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav ms-auto">
<li className="nav-item">
<Link className="nav-link" to="/">Home</Link>
</li>
{!token ? (
<li className="nav-item">
<Link className="nav-link" to="/login">Login Nasabah</Link>
</li>
) : (
<>
<li className="nav-item">
<Link className="nav-link" to="/dashboard">Dashboard</Link>
</li>
<li className="nav-item">
<span className="nav-link">Halo, {user.name}</span>
</li>
<li className="nav-item">
<button className="btn btn-outline-light btn-sm" onClick={handleLogout}>Logout</button>
</li>
</>
)}
</ul>
</div>
</div>
</nav>
);
}
export default Navbar;
Langkah 5: Menghubungkan Dashboard ke API Nyata
Dashboard kita masih pakai data dummy. Sekarang kita akan ambil data saldo dan mutasi dari API menggunakan token yang tersimpan.
Modifikasi DashboardPage.js:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Swal from 'sweetalert2';
function DashboardPage() {
const [saldo, setSaldo] = useState(null);
const [mutasi, setMutasi] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const token = localStorage.getItem('token');
if (!token) return;
try {
// Ambil saldo
const saldoRes = await axios.get('http://127.0.0.1:8000/api/nasabah/saldo', {
headers: { Authorization: `Bearer ${token}` }
});
setSaldo(saldoRes.data);
// Ambil mutasi
const mutasiRes = await axios.get('http://127.0.0.1:8000/api/nasabah/mutasi', {
headers: { Authorization: `Bearer ${token}` }
});
setMutasi(mutasiRes.data.mutasi);
} catch (error) {
Swal.fire('Gagal memuat data', error.response?.data?.message || 'Terjadi kesalahan', 'error');
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) {
return <div className="text-center">Loading...</div>;
}
return (
<div>
<h2>Dashboard Nasabah</h2>
<div className="card mb-4">
<div className="card-body">
<h5 className="card-title">Total Saldo</h5>
<p className="card-text display-6 text-success">
Rp {saldo?.saldo?.toLocaleString()}
</p>
<p>No. Rekening: {saldo?.no_rekening}</p>
</div>
</div>
<h4>Mutasi Terbaru</h4>
{mutasi.length === 0 ? (
<p>Belum ada transaksi.</p>
) : (
<table className="table table-striped">
<thead>
<tr>
<th>Tanggal</th>
<th>Jenis</th>
<th>Jumlah</th>
<th>Keterangan</th>
<th>Petugas</th>
</tr>
</thead>
<tbody>
{mutasi.map((trx) => (
<tr key={trx.id}>
<td>{trx.tanggal}</td>
<td>{trx.jenis}</td>
<td>Rp {trx.jumlah.toLocaleString()}</td>
<td>{trx.keterangan}</td>
<td>{trx.petugas}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
}
export default DashboardPage;
Langkah 6: Uji Coba Login
Pastikan backend Laravel berjalan (php artisan serve). Buka frontend (npm start). Coba login dengan email nasabah yang sudah terdaftar (misal budi@mail.com dengan password 123456).
Jika berhasil, akan diarahkan ke dashboard dan muncul data saldo dan mutasi dari database. Jika salah password, muncul SweetAlert error.
"proxy": "http://127.0.0.1:8000" di package.json frontend, lalu ubah axios panggil /api/login tanpa domain. Atau install middleware CORS di Laravel (lebih disarankan).
Kesimpulan
- ✅ Form login terhubung ke API dan menyimpan token.
- ✅ Redirect otomatis ke dashboard setelah login.
- ✅ Halaman dashboard dilindungi (tidak bisa diakses tanpa token).
- ✅ Data saldo dan mutasi diambil dari backend real.
- ✅ SweetAlert memberikan notifikasi manis.
Di tutorial selanjutnya (#9: Dashboard Nasabah – Menampilkan Total Saldo dan Mutasi) kita akan mempercantik dashboard, mungkin menambahkan grafik atau fitur lain. Tapi sebenarnya sudah kita lakukan di sini! Jadi tutorial #9 bisa fokus pada styling atau fitur tambahan. Sampai jumpa! 🚀