Tutorial Laravel & ReactJS #17: Fitur Ubah Password untuk Semua Level Pengguna

Tutorial #17: Fitur Ubah Password untuk Semua Level Pengguna

Halo para penjaga keamanan! Hari ini kita akan menambahkan fitur ubah password yang bisa digunakan oleh semua pengguna: Nasabah, Petugas, maupun Admin. Dengan fitur ini, pengguna bisa mengganti password mereka kapan saja demi keamanan. Siap jadi satpam digital? 

😂 Joke keamanan: "Kenapa password harus sering diganti? Soalnya kalau jarang diganti, bisa basi kayak makanan!" 🍲

Yang akan kita lakukan:

  • ✅ Membuat endpoint API baru di Laravel untuk ubah password.
  • ✅ Membuat halaman/form ubah password di React.
  • ✅ Validasi input di sisi klien (React) dan server (Laravel).
  • ✅ Menambahkan proteksi route (hanya bisa diakses jika sudah login).
  • ✅ Menampilkan notifikasi SweetAlert untuk sukses/gagal.
  • ✅ Mengintegrasikan fitur ini ke semua dashboard (nasabah, petugas, admin).

Langkah 1: Membuat Endpoint Ubah Password di Laravel

Pertama, kita perlu endpoint API untuk mengubah password. Buka routes/api.php dan tambahkan route baru di dalam group auth:sanctum (agar hanya user yang login yang bisa mengakses):

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/change-password', [App\Http\Controllers\Api\AuthController::class, 'changePassword']);
    // route lainnya...
});

Kemudian di app/Http/Controllers/Api/AuthController.php, tambahkan method changePassword:

public function changePassword(Request $request)
{
    $request->validate([
        'current_password' => 'required|string',
        'new_password' => 'required|string|min:6|confirmed',
    ]);

    $user = $request->user();

    // Cek apakah password lama cocok
    if (!Hash::check($request->current_password, $user->password)) {
        return response()->json([
            'message' => 'Password lama tidak sesuai'
        ], 400);
    }

    // Update password baru
    $user->password = Hash::make($request->new_password);
    $user->save();

    return response()->json([
        'message' => 'Password berhasil diubah'
    ], 200);
}

Penjelasan:

  • current_password: password yang sedang digunakan.
  • new_password: password baru, minimal 6 karakter, dan harus ada new_password_confirmation (karena pakai confirmed).
  • Kita cek kecocokan password lama dengan Hash::check().
  • Jika semua ok, password baru di-hash dan disimpan.
💡 Catatan: Pastikan di form nanti kita mengirim new_password_confirmation agar validasi confirmed berfungsi.

Langkah 2: Membuat Halaman Ubah Password di React

Buat file baru src/pages/ChangePassword.js dengan komponen berikut:

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
import Swal from 'sweetalert2';

function ChangePassword() {
  const [formData, setFormData] = useState({
    current_password: '',
    new_password: '',
    new_password_confirmation: ''
  });
  const [loading, setLoading] = useState(false);
  const navigate = useNavigate();

  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    // Validasi client-side
    if (!formData.current_password || !formData.new_password || !formData.new_password_confirmation) {
      Swal.fire('Peringatan', 'Semua field harus diisi', 'warning');
      return;
    }
    if (formData.new_password.length < 6) {
      Swal.fire('Peringatan', 'Password baru minimal 6 karakter', 'warning');
      return;
    }
    if (formData.new_password !== formData.new_password_confirmation) {
      Swal.fire('Peringatan', 'Konfirmasi password tidak cocok', 'warning');
      return;
    }

    setLoading(true);
    const token = localStorage.getItem('token');

    try {
      await axios.post('http://127.0.0.1:8000/api/change-password', formData, {
        headers: { Authorization: `Bearer ${token}` }
      });

      Swal.fire({
        icon: 'success',
        title: 'Berhasil!',
        text: 'Password telah diubah. Silakan login ulang.',
        timer: 2000,
        showConfirmButton: false
      });

      // Logout otomatis setelah ubah password (opsional)
      localStorage.removeItem('token');
      localStorage.removeItem('user');
      navigate('/login');
    } catch (error) {
      const message = error.response?.data?.message || 'Terjadi kesalahan';
      Swal.fire('Gagal', message, 'error');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="container mt-5">
      <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">🔐 Ubah Password</h4>
            </div>
            <div className="card-body">
              <form onSubmit={handleSubmit}>
                <div className="mb-3">
                  <label className="form-label">Password Lama</label>
                  <input
                    type="password"
                    className="form-control"
                    name="current_password"
                    value={formData.current_password}
                    onChange={handleChange}
                    required
                  />
                </div>
                <div className="mb-3">
                  <label className="form-label">Password Baru</label>
                  <input
                    type="password"
                    className="form-control"
                    name="new_password"
                    value={formData.new_password}
                    onChange={handleChange}
                    required
                  />
                  <div className="password-requirements text-muted">
                    Minimal 6 karakter
                  </div>
                </div>
                <div className="mb-3">
                  <label className="form-label">Konfirmasi Password Baru</label>
                  <input
                    type="password"
                    className="form-control"
                    name="new_password_confirmation"
                    value={formData.new_password_confirmation}
                    onChange={handleChange}
                    required
                  />
                </div>
                <button
                  type="submit"
                  className="btn btn-primary w-100"
                  disabled={loading}
                >
                  {loading ? 'Memproses...' : 'Ubah Password'}
                </button>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default ChangePassword;

Langkah 3: Menambahkan Route dengan Proteksi

Buka src/App.js dan tambahkan route baru untuk halaman ubah password. Pastikan hanya user yang sudah login yang bisa mengakses.

import ChangePassword from './pages/ChangePassword';

// ... di dalam Routes
<Route path="/change-password" element={
  <PrivateRoute>
    <ChangePassword />
  </PrivateRoute>
} />

Modifikasi PrivateRoute agar bisa menerima semua role (tanpa allowedRoles) atau buat versi khusus. Kita bisa gunakan PrivateRoute yang sudah ada tanpa allowedRoles.

Langkah 4: Menambahkan Link Ubah Password di Navbar

Update src/components/Navbar.js untuk menambahkan dropdown atau link ke halaman ubah password.

// Di dalam bagian user sudah login, tambahkan menu dropdown
<li className="nav-item dropdown">
  <button
    className="nav-link dropdown-toggle btn btn-link text-white"
    id="navbarDropdown"
    data-bs-toggle="dropdown"
    aria-expanded="false"
  >
    {user.name}
  </button>
  <ul className="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
    <li>
      <Link className="dropdown-item" to="/change-password">
        Ubah Password
      </Link>
    </li>
    <li><hr className="dropdown-divider" /></li>
    <li>
      <button className="dropdown-item text-danger" onClick={handleLogout}>
        Logout
      </button>
    </li>
  </ul>
</li>

Jangan lupa import Link dari react-router-dom jika belum.

Langkah 5: Uji Coba Fitur Ubah Password

  1. Login sebagai nasabah, petugas, atau admin.
  2. Klik menu dropdown nama user, pilih "Ubah Password".
  3. Isi form dengan password lama yang benar, password baru minimal 6 karakter, dan konfirmasi yang sama.
  4. Submit. Jika berhasil, muncul notifikasi sukses dan logout otomatis (sesuai kode).
  5. Coba login dengan password baru, harus berhasil.
  6. Uji validasi: password lama salah, password baru < 6 karakter, konfirmasi tidak cocok. Semua harus ditolak dengan notifikasi.
😆 "Dengan fitur ini, password jadi seperti baju: bisa diganti kapan saja biar tetap segar!" 👕

Langkah 6: Penanganan Error dan Validasi Tambahan

Di backend, kita sudah menambahkan validasi. Tapi kita juga bisa menambahkan validasi tambahan di frontend, misalnya:

  • Password baru tidak boleh sama dengan password lama (opsional).
  • Menampilkan kekuatan password (lemah/sedang/kuat).

Contoh validasi password baru != password lama (tambahkan di frontend):

if (formData.current_password === formData.new_password) {
  Swal.fire('Peringatan', 'Password baru tidak boleh sama dengan password lama', 'warning');
  return;
}

Bonus: Logout Otomatis Setelah Ubah Password

Dalam kode di atas, kita sudah melakukan logout otomatis setelah ubah password. Ini untuk keamanan, karena biasanya setelah ganti password, pengguna harus login ulang. Jika ingin tetap login, cukup hapus baris localStorage.removeItem dan navigasi ke halaman sebelumnya.

💡 Catatan Penting: Fitur ini bisa diakses oleh semua role karena kita menggunakan middleware auth:sanctum di backend dan PrivateRoute tanpa filter role di frontend. Pastikan di PrivateRoute Anda tidak mengecek role (atau terima semua role).

Kesimpulan

  • ✅ Endpoint ubah password berhasil dibuat di Laravel.
  • ✅ Halaman ubah password di React sudah berfungsi dengan validasi.
  • ✅ Link ubah password tersedia di semua dashboard melalui navbar.
  • ✅ Notifikasi SweetAlert memberikan feedback yang jelas.

Di tutorial selanjutnya (#18: Menambahkan Fitur Profil dan Edit Profil) kita akan membuat halaman profil di mana pengguna bisa melihat dan mengupdate data diri mereka (nama, email, dll). Sampai jumpa!


Daftar Tutorial Lanjutan

  • Tutorial #18: Menambahkan Fitur Profil dan Edit Profil
  • Tutorial #19: Laporan Transaksi (Admin) – Filter dan Export ke Excel/PDF
  • Tutorial #20: Finalisasi dan Penyempurnaan Aplikasi
Lebih baru Lebih lama

نموذج الاتصال