466 lines
20 KiB
PHP
466 lines
20 KiB
PHP
@extends('admin.layouts.app')
|
|
|
|
@section('title', 'Profil Admin')
|
|
|
|
@section('content')
|
|
<div class="p-6 bg-white rounded-lg shadow-md">
|
|
<!-- Header with Profile Info -->
|
|
<div class="flex flex-col md:flex-row items-start md:items-center gap-6 mb-8">
|
|
<div class="relative group">
|
|
<div id="profile-photo" class="w-24 h-24 rounded-full bg-blue-600 flex items-center justify-center text-white text-3xl font-bold overflow-hidden">
|
|
<span id="admin-initials">A</span>
|
|
<!-- Profile photo will be loaded here -->
|
|
</div>
|
|
<button onclick="document.getElementById('photo-upload-form').style.display='flex'" class="absolute inset-0 w-24 h-24 rounded-full bg-black bg-opacity-50 text-white text-sm font-medium hidden group-hover:flex items-center justify-center cursor-pointer">
|
|
Ubah Foto
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<h2 id="admin-name" class="text-2xl font-bold text-gray-800">Loading...</h2>
|
|
<p id="admin-email" class="text-gray-600">Loading...</p>
|
|
<p class="mt-2 inline-flex items-center bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm font-medium">
|
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
|
|
</svg>
|
|
Administrator
|
|
</p>
|
|
<button onclick="showEditProfileModal()" class="mt-3 flex items-center text-blue-600 hover:text-blue-800">
|
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"></path>
|
|
</svg>
|
|
Edit Profil
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Admin Information -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
<!-- Contact Information -->
|
|
<div>
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-4 pb-2 border-b">Informasi Kontak</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<p class="text-sm text-gray-500">Nomor Telepon</p>
|
|
<p id="admin-phone" class="text-gray-800 font-medium">Loading...</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-500">Alamat</p>
|
|
<p id="admin-address" class="text-gray-800 font-medium">Loading...</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-500">Terdaftar Sejak</p>
|
|
<p id="admin-created" class="text-gray-800 font-medium">Loading...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Account Information -->
|
|
<div>
|
|
<h3 class="text-lg font-semibold text-gray-800 mb-4 pb-2 border-b">Informasi Akun</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<p class="text-sm text-gray-500">ID Admin</p>
|
|
<p id="admin-id" class="text-gray-800 font-medium">Loading...</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-500">Role</p>
|
|
<p id="admin-role" class="bg-green-100 text-green-800 inline-block px-2 py-1 rounded text-sm font-medium">Loading...</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-500">Terakhir Diperbarui</p>
|
|
<p id="admin-updated" class="text-gray-800 font-medium">Loading...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Photo Upload Modal (Hidden by default) -->
|
|
<div id="photo-upload-form" class="hidden fixed inset-0 items-center justify-center z-50 bg-black bg-opacity-50">
|
|
<div class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-medium">Upload Foto Profil</h3>
|
|
<button onclick="document.getElementById('photo-upload-form').style.display='none'" class="text-gray-400 hover:text-gray-500">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<form id="photoForm" onsubmit="uploadPhoto(event)">
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Pilih Foto</label>
|
|
<input type="file" name="profile_photo" id="profile-photo-input" accept="image/*" required
|
|
class="w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
|
<div id="photo-preview" class="mt-3 hidden">
|
|
<img id="preview-image" class="w-32 h-32 object-cover rounded-full mx-auto" src="" alt="Preview">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end space-x-3">
|
|
<button type="button" onclick="document.getElementById('photo-upload-form').style.display='none'"
|
|
class="px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-800 rounded-md">
|
|
Batal
|
|
</button>
|
|
<button type="submit"
|
|
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md">
|
|
Upload Foto
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Profile Modal (Hidden by default) -->
|
|
<div id="edit-profile-modal" class="hidden fixed inset-0 items-center justify-center z-50 bg-black bg-opacity-50">
|
|
<div class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-medium">Edit Informasi Profil</h3>
|
|
<button onclick="closeEditProfileModal()" class="text-gray-400 hover:text-gray-500">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<form id="editProfileForm" onsubmit="updateProfile(event)">
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label for="edit-name" class="block text-sm font-medium text-gray-700">Nama</label>
|
|
<input type="text" id="edit-name" name="name" required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
|
|
</div>
|
|
<div>
|
|
<label for="edit-email" class="block text-sm font-medium text-gray-700">Email</label>
|
|
<input type="email" id="edit-email" name="email" required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
|
|
</div>
|
|
<div>
|
|
<label for="edit-phone" class="block text-sm font-medium text-gray-700">Nomor Telepon</label>
|
|
<input type="text" id="edit-phone" name="phone_number"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm">
|
|
</div>
|
|
<div>
|
|
<label for="edit-address" class="block text-sm font-medium text-gray-700">Alamat</label>
|
|
<textarea id="edit-address" name="address" rows="3"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"></textarea>
|
|
</div>
|
|
<div>
|
|
<label for="edit-profile-photo" class="block text-sm font-medium text-gray-700">Foto Profil</label>
|
|
<div class="mt-1 flex items-center space-x-5">
|
|
<div id="edit-current-photo" class="h-20 w-20 rounded-full bg-gray-200 flex items-center justify-center overflow-hidden">
|
|
<!-- Current photo will be displayed here -->
|
|
</div>
|
|
<div class="flex-1">
|
|
<input type="file" name="profile_photo" id="edit-profile-photo" accept="image/*"
|
|
class="w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
|
<p class="mt-1 text-xs text-gray-500">Pilih foto baru untuk mengubah foto profil</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-5 flex justify-end space-x-3">
|
|
<button type="button" onclick="closeEditProfileModal()"
|
|
class="px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-800 rounded-md">
|
|
Batal
|
|
</button>
|
|
<button type="submit"
|
|
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md">
|
|
Simpan Perubahan
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
@endsection
|
|
|
|
@push('styles')
|
|
<link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
|
|
@endpush
|
|
|
|
@push('scripts')
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<script>
|
|
let adminData = null;
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadAdminProfile();
|
|
|
|
// Preview image when selected
|
|
document.getElementById('profile-photo-input').addEventListener('change', function(e) {
|
|
const file = e.target.files[0];
|
|
if (file) {
|
|
const reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
document.getElementById('preview-image').src = e.target.result;
|
|
document.getElementById('photo-preview').classList.remove('hidden');
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
});
|
|
});
|
|
|
|
async function loadAdminProfile() {
|
|
try {
|
|
const response = await fetch(window.apiUrl('api/admin/profile'), {
|
|
headers: {
|
|
'Authorization': 'Bearer {{ session('api_token') }}',
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch admin profile');
|
|
}
|
|
|
|
const responseData = await response.json();
|
|
console.log('Admin Profile:', responseData);
|
|
|
|
if (responseData.success) {
|
|
adminData = responseData.data;
|
|
|
|
// Update profile info with null checks
|
|
const nameEl = document.getElementById('admin-name');
|
|
if (nameEl) nameEl.textContent = adminData.name;
|
|
|
|
const emailEl = document.getElementById('admin-email');
|
|
if (emailEl) emailEl.textContent = adminData.email;
|
|
|
|
const phoneEl = document.getElementById('admin-phone');
|
|
if (phoneEl) phoneEl.textContent = adminData.phone_number || 'Tidak ada';
|
|
|
|
const addressEl = document.getElementById('admin-address');
|
|
if (addressEl) addressEl.textContent = adminData.address || 'Tidak ada';
|
|
|
|
const idEl = document.getElementById('admin-id');
|
|
if (idEl) idEl.textContent = adminData.id;
|
|
|
|
const roleEl = document.getElementById('admin-role');
|
|
if (roleEl) roleEl.textContent = adminData.role;
|
|
|
|
// Format dates
|
|
const createdDate = new Date(adminData.created_at);
|
|
const updatedDate = new Date(adminData.updated_at);
|
|
|
|
const createdEl = document.getElementById('admin-created');
|
|
if (createdEl) createdEl.textContent = createdDate.toLocaleDateString('id-ID', {
|
|
day: 'numeric', month: 'long', year: 'numeric'
|
|
});
|
|
|
|
const updatedEl = document.getElementById('admin-updated');
|
|
if (updatedEl) updatedEl.textContent = updatedDate.toLocaleDateString('id-ID', {
|
|
day: 'numeric', month: 'long', year: 'numeric'
|
|
});
|
|
|
|
// Set initials
|
|
const initials = adminData.name.split(' ').map(name => name[0]).join('');
|
|
const initialsEl = document.getElementById('admin-initials');
|
|
if (initialsEl) initialsEl.textContent = initials;
|
|
|
|
// Check if profile photo exists
|
|
if (adminData.profile_photo) {
|
|
const photoContainer = document.getElementById('profile-photo');
|
|
if (photoContainer) {
|
|
photoContainer.innerHTML = `<img src="${window.assetUrl(adminData.profile_photo)}" alt="${adminData.name}" class="w-full h-full object-cover">`;
|
|
}
|
|
|
|
// Also update in edit modal
|
|
const editPhotoContainer = document.getElementById('edit-current-photo');
|
|
if (editPhotoContainer) {
|
|
editPhotoContainer.innerHTML = `<img src="${window.assetUrl(adminData.profile_photo)}" alt="${adminData.name}" class="w-full h-full object-cover">`;
|
|
}
|
|
} else {
|
|
// If no photo, show initials in edit modal too
|
|
const editPhotoContainer = document.getElementById('edit-current-photo');
|
|
if (editPhotoContainer) {
|
|
editPhotoContainer.innerHTML = `<span class="text-xl font-bold text-white">${initials}</span>`;
|
|
editPhotoContainer.classList.add('bg-blue-600');
|
|
}
|
|
}
|
|
|
|
// Pre-fill edit form
|
|
const editNameEl = document.getElementById('edit-name');
|
|
if (editNameEl) editNameEl.value = adminData.name;
|
|
|
|
const editEmailEl = document.getElementById('edit-email');
|
|
if (editEmailEl) editEmailEl.value = adminData.email;
|
|
|
|
const editPhoneEl = document.getElementById('edit-phone');
|
|
if (editPhoneEl) editPhoneEl.value = adminData.phone_number || '';
|
|
|
|
const editAddressEl = document.getElementById('edit-address');
|
|
if (editAddressEl) editAddressEl.value = adminData.address || '';
|
|
} else {
|
|
throw new Error(responseData.message || 'Gagal memuat profil admin');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
title: 'Error!',
|
|
text: error.message || 'Gagal memuat data profil admin',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK',
|
|
confirmButtonColor: '#4F46E5'
|
|
});
|
|
}
|
|
}
|
|
|
|
function showEditProfileModal() {
|
|
document.getElementById('edit-profile-modal').style.display = 'flex';
|
|
}
|
|
|
|
function closeEditProfileModal() {
|
|
document.getElementById('edit-profile-modal').style.display = 'none';
|
|
}
|
|
|
|
async function updateProfile(event) {
|
|
event.preventDefault();
|
|
|
|
const form = event.target;
|
|
const formData = new FormData(form);
|
|
const hasPhoto = document.getElementById('edit-profile-photo') && document.getElementById('edit-profile-photo').files.length > 0;
|
|
|
|
try {
|
|
// Show loading
|
|
Swal.fire({
|
|
title: 'Memperbarui...',
|
|
text: 'Mohon tunggu',
|
|
allowOutsideClick: false,
|
|
didOpen: () => {
|
|
Swal.showLoading();
|
|
}
|
|
});
|
|
|
|
// Update profile data
|
|
const response = await fetch(window.apiUrl('api/admin/profile'), {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': 'Bearer {{ session('api_token') }}',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: formData
|
|
});
|
|
|
|
const responseData = await response.json();
|
|
console.log('Update Profile Response:', responseData);
|
|
|
|
// If there's a photo, upload it separately
|
|
if (hasPhoto) {
|
|
const photoFormData = new FormData();
|
|
const fileInput = document.getElementById('edit-profile-photo');
|
|
if (fileInput && fileInput.files[0]) {
|
|
photoFormData.append('profile_photo', fileInput.files[0]);
|
|
|
|
const photoResponse = await fetch(window.apiUrl('api/admin/profile/photo'), {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': 'Bearer {{ session('api_token') }}',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: photoFormData
|
|
});
|
|
|
|
const photoResponseData = await photoResponse.json();
|
|
console.log('Upload Photo Response:', photoResponseData);
|
|
}
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'Berhasil!',
|
|
text: 'Profil berhasil diperbarui',
|
|
icon: 'success',
|
|
confirmButtonText: 'OK',
|
|
confirmButtonColor: '#4F46E5'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
closeEditProfileModal();
|
|
|
|
// Small delay before reloading profile to ensure DOM is ready
|
|
setTimeout(() => {
|
|
loadAdminProfile();
|
|
}, 300);
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
title: 'Gagal!',
|
|
text: error.message || 'Gagal memperbarui profil. Silakan coba lagi nanti.',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK',
|
|
confirmButtonColor: '#4F46E5'
|
|
});
|
|
}
|
|
}
|
|
|
|
async function uploadPhoto(event) {
|
|
event.preventDefault();
|
|
|
|
const form = event.target;
|
|
const formData = new FormData(form);
|
|
|
|
try {
|
|
// Show loading
|
|
Swal.fire({
|
|
title: 'Mengupload...',
|
|
text: 'Mohon tunggu',
|
|
allowOutsideClick: false,
|
|
didOpen: () => {
|
|
Swal.showLoading();
|
|
}
|
|
});
|
|
|
|
const response = await fetch(window.apiUrl('api/admin/profile/photo'), {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': 'Bearer {{ session('api_token') }}',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: formData
|
|
});
|
|
|
|
const responseData = await response.json();
|
|
console.log('Upload Photo Response:', responseData);
|
|
|
|
if (responseData.success) {
|
|
Swal.fire({
|
|
title: 'Berhasil!',
|
|
text: responseData.message || 'Foto profil berhasil diupload',
|
|
icon: 'success',
|
|
confirmButtonText: 'OK',
|
|
confirmButtonColor: '#4F46E5'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const photoUploadForm = document.getElementById('photo-upload-form');
|
|
if (photoUploadForm) photoUploadForm.style.display = 'none';
|
|
|
|
const photoPreview = document.getElementById('photo-preview');
|
|
if (photoPreview) photoPreview.classList.add('hidden');
|
|
|
|
if (form) form.reset();
|
|
|
|
// Small delay before reloading profile to ensure DOM is ready
|
|
setTimeout(() => {
|
|
loadAdminProfile();
|
|
}, 300);
|
|
}
|
|
});
|
|
} else {
|
|
throw new Error(responseData.message || 'Gagal mengupload foto profil');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
Swal.fire({
|
|
title: 'Gagal!',
|
|
text: error.message || 'Gagal mengupload foto profil. Silakan coba lagi nanti.',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK',
|
|
confirmButtonColor: '#4F46E5'
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
@endpush
|