MIF_E31230745/resources/views/admin/profil/index.blade.php

274 lines
16 KiB
PHP

@extends('admin.layouts.app')
@section('title', 'Profil Admin')
@section('content')
<div class="mb-6">
<h2 class="text-2xl font-bold text-maroon">⚙️ Profil Admin</h2>
<p class="text-sm text-gray-500 mt-1">Kelola informasi akun administrator</p>
</div>
<!-- Success Alert -->
@if(session('success'))
<div class="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg flex items-center gap-3">
<span class="text-green-600 text-xl"></span>
<span class="text-green-700 font-medium">{{ session('success') }}</span>
</div>
@endif
<!-- Error Summary Alert -->
@if($errors->any())
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
<div class="flex items-center gap-2 mb-2">
<span class="text-red-600 text-xl">⚠️</span>
<span class="text-red-700 font-bold">Terjadi Kesalahan</span>
</div>
<ul class="text-red-600 text-sm space-y-1 ml-8">
@foreach($errors->all() as $error)
<li> {{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Update Profile -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-bold text-maroon mb-4">👤 Informasi Akun</h3>
<form action="{{ route('admin.profil.update') }}" method="POST" class="space-y-4" id="profileForm">
@csrf
@method('PUT')
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
<input type="text" name="name" required value="{{ old('name', $admin->name) }}" minlength="3" maxlength="100" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('name') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror" placeholder="Nama lengkap" oninput="validateName(this)">
<div class="flex justify-between items-center mt-1">
<span id="nameError" class="text-red-500 text-xs hidden">⚠️ Nama harus minimal 3 karakter</span>
<span id="nameValid" class="text-green-500 text-xs hidden"> Nama valid</span>
</div>
@error('name') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Email * <span class="text-gray-400 text-xs">(format email valid)</span></label>
<input type="email" name="email" required value="{{ old('email', $admin->email) }}" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('email') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror" placeholder="email@example.com" oninput="validateEmail(this)">
<div class="flex justify-between items-center mt-1">
<span id="emailError" class="text-red-500 text-xs hidden">⚠️ Format email tidak valid</span>
<span id="emailValid" class="text-green-500 text-xs hidden"> Email valid</span>
</div>
@error('email') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Role</label>
<input type="text" value="Administrator" readonly class="w-full px-4 py-2 border border-gray-200 rounded-lg bg-gray-100 text-gray-500 cursor-not-allowed">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Terdaftar Sejak</label>
<input type="text" value="{{ $admin->created_at->format('d M Y H:i') }}" readonly class="w-full px-4 py-2 border border-gray-200 rounded-lg bg-gray-100 text-gray-500 cursor-not-allowed">
</div>
<button type="submit" class="w-full gradient-maroon text-white font-bold py-3 px-4 rounded-lg hover:opacity-90 transition" id="profileSubmit">
💾 Update Profil
</button>
</form>
</div>
<!-- Change Password -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-bold text-maroon mb-4">🔒 Ubah Password</h3>
<form action="{{ route('admin.profil.password') }}" method="POST" class="space-y-4" id="passwordForm">
@csrf
@method('PUT')
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Password Lama * <span class="text-gray-400 text-xs">(harus benar)</span></label>
<div style="position: relative; display: flex; align-items: center;">
<input type="password" id="currentPass" name="current_password" required class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('current_password') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-blue-400 @enderror" placeholder="Masukkan password lama" style="padding-right: 45px;" oninput="validatePasswordForm()">
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('currentPass', this)">👁️</button>
</div>
@error('current_password') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Password Baru * <span class="text-gray-400 text-xs">(minimal 8 karakter)</span></label>
<div style="position: relative; display: flex; align-items: center;">
<input type="password" id="newPass" name="password" required minlength="8" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('password') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-blue-400 @enderror" placeholder="Minimal 8 karakter" style="padding-right: 45px;" oninput="validatePasswordForm()">
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('newPass', this)">👁️</button>
</div>
<div id="passwordStrength" class="text-xs mt-1 font-medium hidden">
<span id="passwordStrengthText"></span>
</div>
@error('password') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Konfirmasi Password Baru * <span class="text-gray-400 text-xs">(harus sama)</span></label>
<div style="position: relative; display: flex; align-items: center;">
<input type="password" id="newPassConfirm" name="password_confirmation" required class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition border-gray-300 focus:ring-blue-400" placeholder="Ulangi password baru" style="padding-right: 45px;" oninput="validatePasswordForm()">
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('newPassConfirm', this)">👁️</button>
</div>
<div id="confirmError" class="text-red-500 text-xs hidden mt-1">⚠️ Password konfirmasi tidak cocok</div>
<div id="confirmValid" class="text-green-500 text-xs hidden mt-1"> Password cocok</div>
</div>
<button type="submit" class="w-full bg-blue-600 text-white font-bold py-3 px-4 rounded-lg hover:bg-blue-700 transition disabled:opacity-50 disabled:cursor-not-allowed" id="passwordSubmit">
🔑 Ubah Password
</button>
</form>
</div>
</div>
@endsection
@section('scripts')
<script>
// Toggle password visibility
function togglePasswordVisibility(inputId, buttonElement) {
const input = document.getElementById(inputId);
const isPassword = input.type === 'password';
input.type = isPassword ? 'text' : 'password';
}
// Validate name
function validateName(input) {
const nameError = document.getElementById('nameError');
const nameValid = document.getElementById('nameValid');
const value = input.value.trim();
if (value.length === 0) {
nameError.classList.add('hidden');
nameValid.classList.add('hidden');
} else if (value.length < 3) {
input.classList.remove('focus:ring-maroon');
input.classList.add('border-red-500', 'focus:ring-red-400');
nameError.classList.remove('hidden');
nameValid.classList.add('hidden');
} else {
input.classList.remove('border-red-500', 'focus:ring-red-400');
input.classList.add('border-gray-300', 'focus:ring-maroon');
nameError.classList.add('hidden');
nameValid.classList.remove('hidden');
}
}
// Validate email
function validateEmail(input) {
const emailError = document.getElementById('emailError');
const emailValid = document.getElementById('emailValid');
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const value = input.value.trim();
if (value.length === 0) {
emailError.classList.add('hidden');
emailValid.classList.add('hidden');
} else if (!emailRegex.test(value)) {
input.classList.remove('focus:ring-maroon');
input.classList.add('border-red-500', 'focus:ring-red-400');
emailError.classList.remove('hidden');
emailValid.classList.add('hidden');
} else {
input.classList.remove('border-red-500', 'focus:ring-red-400');
input.classList.add('border-gray-300', 'focus:ring-maroon');
emailError.classList.add('hidden');
emailValid.classList.remove('hidden');
}
}
// Check password strength
function getPasswordStrength(password) {
let strength = 0;
if (password.length >= 8) strength++;
if (password.length >= 12) strength++;
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength++;
if (/\d/.test(password)) strength++;
if (/[^a-zA-Z\d]/.test(password)) strength++;
if (strength <= 1) return { level: 'Lemah', color: 'text-red-500' };
if (strength <= 2) return { level: 'Sedang', color: 'text-yellow-500' };
if (strength <= 3) return { level: 'Baik', color: 'text-blue-500' };
return { level: 'Kuat', color: 'text-green-500' };
}
// Validate password form
function validatePasswordForm() {
const currentPass = document.getElementById('currentPass').value;
const newPass = document.getElementById('newPass').value;
const confirmPass = document.getElementById('newPassConfirm').value;
const passwordStrength = document.getElementById('passwordStrength');
const passwordStrengthText = document.getElementById('passwordStrengthText');
const confirmError = document.getElementById('confirmError');
const confirmValid = document.getElementById('confirmValid');
const passwordSubmit = document.getElementById('passwordSubmit');
// Show password strength if new password is entered
if (newPass.length > 0) {
const strength = getPasswordStrength(newPass);
passwordStrengthText.textContent = `Kekuatan: ${strength.level}`;
passwordStrengthText.className = `${strength.color}`;
passwordStrength.classList.remove('hidden');
} else {
passwordStrength.classList.add('hidden');
}
// Check password confirmation
if (confirmPass.length > 0) {
if (newPass !== confirmPass) {
confirmError.classList.remove('hidden');
confirmValid.classList.add('hidden');
} else if (newPass.length >= 8) {
confirmError.classList.add('hidden');
confirmValid.classList.remove('hidden');
} else {
confirmError.classList.add('hidden');
confirmValid.classList.add('hidden');
}
} else {
confirmError.classList.add('hidden');
confirmValid.classList.add('hidden');
}
// Enable/disable submit button
const isValid = currentPass.length > 0 && newPass.length >= 8 && newPass === confirmPass;
passwordSubmit.disabled = !isValid;
}
// Validate profile form on submit
document.getElementById('profileForm')?.addEventListener('submit', function(e) {
const name = document.querySelector('input[name="name"]').value.trim();
const email = document.querySelector('input[name="email"]').value.trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
let errors = [];
if (name.length < 3) {
errors.push('Nama harus minimal 3 karakter');
}
if (!emailRegex.test(email)) {
errors.push('Format email tidak valid');
}
if (errors.length > 0) {
e.preventDefault();
alert('Perbaiki kesalahan berikut:\n• ' + errors.join('\n• '));
}
});
// Validate password form on submit
document.getElementById('passwordForm')?.addEventListener('submit', function(e) {
const currentPass = document.getElementById('currentPass').value;
const newPass = document.getElementById('newPass').value;
const confirmPass = document.getElementById('newPassConfirm').value;
let errors = [];
if (currentPass.length === 0) {
errors.push('Password lama harus diisi');
}
if (newPass.length < 8) {
errors.push('Password baru harus minimal 8 karakter');
}
if (newPass !== confirmPass) {
errors.push('Password konfirmasi tidak cocok dengan password baru');
}
if (errors.length > 0) {
e.preventDefault();
alert('Perbaiki kesalahan berikut:\n• ' + errors.join('\n• '));
}
});
</script>
@endsection