added leave request, profile and staff members controllers

This commit is contained in:
Kwesi Banson Jnr
2026-08-20 09:30:43 +00:00
parent 1c4d32833a
commit 81d26dc138
152 changed files with 1627 additions and 152101 deletions

View File

@@ -1,66 +1,28 @@
@extends('layouts.masterbeta')
@section('title', 'CML ERP - Staff Directory')
@section('title', 'Click ERP - Staff Directory')
@push('styles')
<!-- Select2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
/* Staff Card Specific Styling */
.staff-card {
background: #fff;
border: 1px solid #eaedf1;
border-radius: 12px;
transition: all 0.2s ease-in-out;
position: relative;
overflow: hidden;
}
.staff-card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 15px rgba(0,0,0,0.05);
border-color: #d1d5db;
}
.staff-card { background: #fff; border: 1px solid #eaedf1; border-radius: 12px; transition: all 0.2s ease-in-out; position: relative; overflow: hidden; }
.staff-card:hover { transform: translateY(-3px); box-shadow: 0 8px 15px rgba(0,0,0,0.05); border-color: #d1d5db; }
.card-top-bar { height: 4px; width: 100%; position: absolute; top: 0; left: 0; }
/* The decorative colored top border */
.card-top-bar {
height: 4px;
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.dept-engineering { background-color: #5c4df0; }
.dept-sales { background-color: #10b981; }
.dept-support { background-color: #f59e0b; }
.staff-avatar { width: 64px; height: 64px; border-radius: 12px; object-fit: cover; background-color: #f8f9fc; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-weight: bold; color: #5c4df0; }
.contact-row { font-size: 0.85rem; padding: 0.4rem 0; border-bottom: 1px solid #f8f9fc; }
.contact-row:last-child { border-bottom: none; }
.staff-avatar {
width: 64px;
height: 64px;
border-radius: 12px;
object-fit: cover;
background-color: #f8f9fc;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
font-weight: bold;
color: #5c4df0;
}
.contact-row {
font-size: 0.85rem;
padding: 0.4rem 0;
border-bottom: 1px solid #f8f9fc;
}
.contact-row:last-child {
border-bottom: none;
}
/* Select2 Bootstrap 5 tweaks */
.select2-container .select2-selection--single { height: 38px; border: 1px solid #dee2e6; border-radius: 0.375rem; display: flex; align-items: center; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 36px; }
</style>
@endpush
@section('breadcrumbs')
<a href="{{ url('/') }}" class="text-secondary text-decoration-none"><i class="bi bi-house me-2"></i></a>
<i class="bi bi-chevron-right text-secondary me-2" style="font-size: 0.8rem;"></i>
<a href="#" class="text-secondary text-decoration-none me-2" style="font-size: 0.95rem;">Core Entities</a>
<i class="bi bi-chevron-right text-secondary me-2" style="font-size: 0.8rem;"></i>
<span class="fw-bold" style="font-size: 0.95rem;">Staff Directory</span>
@endsection
@@ -71,164 +33,139 @@
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Manage employee profiles, department roles, and system access.</p>
</div>
<div class="d-flex gap-2">
<button class="btn btn-outline-secondary d-flex align-items-center" style="border-radius: 8px;">
<i class="bi bi-diagram-3 me-2"></i> Org Chart
</button>
<button class="btn text-white fw-bold d-flex align-items-center" style="background-color: #5c4df0; border-radius: 8px;" id="btnOpenStaffModal">
<i class="bi bi-person-plus me-2"></i> Add Employee
</button>
</div>
</div>
<!-- Filters -->
<div class="content-card p-3 mb-4">
<div class="row g-3">
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text bg-transparent border-end-0 text-secondary"><i class="bi bi-search"></i></span>
<input type="text" class="form-control border-start-0 ps-0" placeholder="Search by name, role, or extension...">
<form action="{{ route('staff.index') }}" method="GET">
<div class="row g-3">
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text bg-transparent border-end-0 text-secondary"><i class="bi bi-search"></i></span>
<input type="text" name="search" value="{{ request('search') }}" class="form-control border-start-0 ps-0" placeholder="Search by name, role, or phone...">
</div>
</div>
<div class="col-md-3">
<select class="form-select" name="department_id" onchange="this.form.submit()">
<option value="">All Departments</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ request('department_id') == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<select class="form-select" name="status" onchange="this.form.submit()">
<option value="">Status: All</option>
<option value="ACTIVE" {{ request('status') == 'ACTIVE' ? 'selected' : '' }}>Active</option>
<option value="ON-LEAVE" {{ request('status') == 'ON-LEAVE' ? 'selected' : '' }}>On Leave</option>
<option value="INACTIVE" {{ request('status') == 'INACTIVE' ? 'selected' : '' }}>Inactive</option>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-secondary w-100" style="border-radius: 8px;">Filter</button>
</div>
</div>
<div class="col-md-3">
<select class="form-select">
<option value="">All Departments</option>
<option value="engineering">Engineering & IT</option>
<option value="sales">Sales & Accounts</option>
<option value="support">Technical Support</option>
</select>
</div>
<div class="col-md-2">
<select class="form-select">
<option value="active">Active</option>
<option value="on-leave">On Leave</option>
<option value="inactive">Inactive</option>
</select>
</div>
<div class="col-md-2">
<button class="btn btn-secondary w-100" style="border-radius: 8px;">Filter</button>
</div>
</div>
</form>
</div>
<!-- Staff Grid -->
<div class="row g-4">
<div class="col-xl-3 col-lg-4 col-md-6">
<div class="staff-card p-4 h-100">
<div class="card-top-bar dept-engineering"></div>
@php
// Define an array of Bootstrap background classes for the card top bars
$colors = ['bg-primary', 'bg-success', 'bg-warning', 'bg-danger', 'bg-info'];
@endphp
@forelse($staffMembers as $staff)
@php
// Generate Initials
$words = explode(' ', $staff->name);
$initials = strtoupper(substr($words[0], 0, 1) . (isset($words[1]) ? substr($words[1], 0, 1) : ''));
<div class="d-flex align-items-center mb-3">
<div class="staff-avatar bg-primary bg-opacity-10 me-3">AD</div>
<div>
<h6 class="fw-bold mb-1 text-dark">Admin Desk</h6>
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary-subtle px-2 py-1" style="font-size: 0.7rem;">Systems Admin</span>
</div>
</div>
// Match the department ID to the collection
$deptName = $departments->firstWhere('id', $staff->department_id)->name ?? 'Unassigned';
// Cycle through colors based on the loop index
$topBarColor = $colors[$loop->index % count($colors)];
@endphp
<div class="mb-3">
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary"><i class="bi bi-buildings me-2"></i>Engineering</span>
<span class="badge bg-success bg-opacity-10 text-success" style="font-size: 0.65rem;">ACTIVE</span>
<div class="col-xl-3 col-lg-4 col-md-6">
<div class="staff-card p-4 h-100 d-flex flex-column">
<div class="card-top-bar {{ $topBarColor }}"></div>
<div class="d-flex align-items-center mb-3">
@if($staff->profile_pic)
<img src="{{ asset('public/storage/' . $staff->profile_pic) }}" class="staff-avatar me-3" alt="{{ $staff->name }}">
@else
<div class="staff-avatar bg-primary bg-opacity-10 text-primary me-3">{{ $initials }}</div>
@endif
<div>
<h6 class="fw-bold mb-1 text-dark">{{ $staff->name }}</h6>
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary-subtle px-2 py-1" style="font-size: 0.7rem;">
{{ $staff->designation ?? 'N/A' }}
</span>
</div>
</div>
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary"><i class="bi bi-envelope me-2"></i>admin@nexus.io</span>
<a href="mailto:admin@nexus.io" class="text-secondary hover-primary"><i class="bi bi-box-arrow-up-right" style="font-size: 0.7rem;"></i></a>
</div>
<div class="contact-row d-flex align-items-center">
<span class="text-secondary"><i class="bi bi-telephone me-2"></i>Ext: 1001</span>
</div>
</div>
<div class="d-flex gap-2 mt-auto pt-2 border-top">
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold btn-edit-staff"
data-id="1" data-name="Admin Desk" data-email="admin@nexus.io" data-ext="1001" data-role="Systems Admin" data-dept="engineering" data-status="active">
<i class="bi bi-pencil me-1"></i> Edit
</button>
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold">
<i class="bi bi-shield-lock me-1"></i> Access
</button>
<div class="mb-3">
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary text-truncate" style="max-width: 140px;"><i class="bi bi-buildings me-2"></i>{{ $deptName }}</span>
<span class="badge {{ $staff->status == 'ACTIVE' ? 'bg-success text-success' : 'bg-warning text-warning' }} bg-opacity-10" style="font-size: 0.65rem;">
{{ $staff->status }}
</span>
</div>
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary text-truncate" style="max-width: 180px;"><i class="bi bi-envelope me-2"></i>{{ $staff->email }}</span>
<a href="mailto:{{ $staff->email }}" class="text-secondary"><i class="bi bi-box-arrow-up-right" style="font-size: 0.7rem;"></i></a>
</div>
<div class="contact-row d-flex align-items-center">
<span class="text-secondary"><i class="bi bi-geo-alt me-2"></i>{{ $staff->location_country ?? 'Not Specified' }}</span>
</div>
</div>
<div class="d-flex gap-2 mt-auto pt-2 border-top">
<button class="btn btn-sm btn-light text-primary flex-grow-1 fw-semibold btn-edit-staff"
data-id="{{ $staff->id }}"
data-name="{{ $staff->name }}"
data-email="{{ $staff->email }}"
data-phone="{{ $staff->phone }}"
data-designation="{{ $staff->designation }}"
data-department_id="{{ $staff->department_id }}"
data-location_country="{{ $staff->location_country }}"
data-status="{{ $staff->status }}"
data-pic="{{ $staff->profile_pic ? asset('public/storage/' . $staff->profile_pic) : '' }}">
<i class="bi bi-pencil me-1"></i> Edit
</button>
<form action="{{ route('staff.destroy', $staff->id) }}" method="POST" class="flex-grow-1 m-0">
@csrf
@method('DELETE')
<button type="button" class="btn btn-sm btn-light text-danger w-100 fw-semibold btn-delete-staff">
<i class="bi bi-trash me-1"></i> Delete
</button>
</form>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-4 col-md-6">
<div class="staff-card p-4 h-100">
<div class="card-top-bar dept-sales"></div>
<div class="d-flex align-items-center mb-3">
<div class="staff-avatar bg-success bg-opacity-10 text-success me-3">MO</div>
<div>
<h6 class="fw-bold mb-1 text-dark">Mansa Olympio</h6>
<span class="badge bg-success bg-opacity-10 text-success border border-success-subtle px-2 py-1" style="font-size: 0.7rem;">Account Executive</span>
</div>
</div>
<div class="mb-3">
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary"><i class="bi bi-buildings me-2"></i>Sales</span>
<span class="badge bg-success bg-opacity-10 text-success" style="font-size: 0.65rem;">ACTIVE</span>
</div>
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary text-truncate" style="max-width: 150px;"><i class="bi bi-envelope me-2"></i>m.osei@nexus.io</span>
<a href="mailto:m.osei@nexus.io" class="text-secondary hover-primary"><i class="bi bi-box-arrow-up-right" style="font-size: 0.7rem;"></i></a>
</div>
<div class="contact-row d-flex align-items-center">
<span class="text-secondary"><i class="bi bi-telephone me-2"></i>Ext: 1045</span>
</div>
</div>
<div class="d-flex gap-2 mt-auto pt-2 border-top">
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold btn-edit-staff"
data-id="2" data-name="Michael Osei" data-email="m.osei@nexus.io" data-ext="1045" data-role="Account Executive" data-dept="sales" data-status="active">
<i class="bi bi-pencil me-1"></i> Edit
</button>
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold">
<i class="bi bi-shield-lock me-1"></i> Access
</button>
</div>
@empty
<div class="col-12 text-center py-5 text-secondary">
<i class="bi bi-people mb-3 d-block" style="font-size: 3rem;"></i>
No staff members found.
</div>
</div>
<div class="col-xl-3 col-lg-4 col-md-6">
<div class="staff-card p-4 h-100">
<div class="card-top-bar dept-support"></div>
<div class="d-flex align-items-center mb-3">
<img src="https://ui-avatars.com/api/?name=David+Kumwenda&background=f59e0b&color=fff" class="staff-avatar me-3" alt="David Kumwenda">
<div>
<h6 class="fw-bold mb-1 text-dark">David Kumwenda</h6>
<span class="badge bg-warning bg-opacity-10 text-dark border border-warning-subtle px-2 py-1" style="font-size: 0.7rem;">Software Developer</span>
</div>
</div>
<div class="mb-3">
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary"><i class="bi bi-buildings me-2"></i>Tech</span>
<span class="badge bg-secondary bg-opacity-10 text-secondary" style="font-size: 0.65rem;">ON LEAVE</span>
</div>
<div class="contact-row d-flex justify-content-between align-items-center">
<span class="text-secondary text-truncate" style="max-width: 150px;"><i class="bi bi-envelope me-2"></i>s.mensah@nexus.io</span>
<a href="mailto:s.mensah@nexus.io" class="text-secondary hover-primary"><i class="bi bi-box-arrow-up-right" style="font-size: 0.7rem;"></i></a>
</div>
<div class="contact-row d-flex align-items-center">
<span class="text-secondary"><i class="bi bi-telephone me-2"></i>Ext: 1022</span>
</div>
</div>
<div class="d-flex gap-2 mt-auto pt-2 border-top">
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold btn-edit-staff"
data-id="3" data-name="Sarah Mensah" data-email="s.mensah@nexus.io" data-ext="1022" data-role="VoIP Specialist" data-dept="support" data-status="on-leave">
<i class="bi bi-pencil me-1"></i> Edit
</button>
<button class="btn btn-sm btn-light text-secondary flex-grow-1 fw-semibold">
<i class="bi bi-shield-lock me-1"></i> Access
</button>
</div>
</div>
</div>
@endforelse
</div>
<div class="mt-4">
{{ $staffMembers->links('pagination::bootstrap-5') }}
</div>
@endsection
@push('modals')
<!-- ADD / EDIT MODAL -->
<div class="modal fade" id="staffModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content" style="border-radius: 12px; border: none;">
@@ -239,36 +176,39 @@
<form id="staffForm" enctype="multipart/form-data">
<div class="modal-body p-4">
<div id="staffModalAlert"></div>
<input type="hidden" id="staffId" name="id">
<input type="hidden" id="staffMethod" name="_method" value="POST">
<div class="row mb-4">
<!-- Avatar Column -->
<div class="col-md-3 text-center border-end pe-4">
<div class="staff-avatar mx-auto mb-3" style="width: 100px; height: 100px; font-size: 2rem;" id="avatarPreview">
<i class="bi bi-person text-secondary"></i>
</div>
<label for="staffPhoto" class="btn btn-sm btn-outline-secondary w-100">Upload Photo</label>
<input type="file" id="staffPhoto" name="photo" class="d-none" accept="image/*">
<input type="file" id="staffPhoto" name="photo" class="d-none" accept=".jpg,.jpeg,.png">
<div class="form-text mt-1" style="font-size: 0.7rem;">Max size: 2MB</div>
</div>
<!-- Identity Column -->
<div class="col-md-9 ps-4">
<h6 class="fw-bold mb-3 text-secondary text-uppercase" style="font-size: 0.75rem;">Identity</h6>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Full Name *</label>
<label class="form-label text-secondary fw-semibold small">Full Name *</label>
<input type="text" class="form-control" id="staffName" name="name" required placeholder="Jane Doe">
</div>
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Job Title *</label>
<input type="text" class="form-control" id="staffRole" name="role" required placeholder="e.g. Network Engineer">
<label class="form-label text-secondary fw-semibold small">Job Title *</label>
<input type="text" class="form-control" id="staffDesignation" name="designation" required placeholder="e.g. Network Engineer">
</div>
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Email Address *</label>
<input type="email" class="form-control" id="staffEmail" name="email" required placeholder="jane@nexus.io">
<label class="form-label text-secondary fw-semibold small">Email Address *</label>
<input type="email" class="form-control" id="staffEmail" name="email" required placeholder="jane@company.com">
</div>
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">PBX Extension</label>
<input type="text" class="form-control" id="staffExt" name="extension" placeholder="e.g. 1010">
<label class="form-label text-secondary fw-semibold small">Phone / Extension</label>
<input type="text" class="form-control" id="staffPhone" name="phone" placeholder="e.g. +233 55 123 4567">
</div>
</div>
</div>
@@ -278,20 +218,30 @@
<h6 class="fw-bold mb-3 text-secondary text-uppercase" style="font-size: 0.75rem;">Organizational Assignment</h6>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Department</label>
<select class="form-select" id="staffDept" name="department_id">
<option value="engineering">Engineering & IT</option>
<option value="sales">Sales & Accounts</option>
<option value="support">Technical Support</option>
<div class="col-md-4">
<label class="form-label text-secondary fw-semibold small">Department *</label>
<select class="form-select" id="staffDept" name="department_id" required>
<option value="">Select Department...</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}">{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-6">
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Status</label>
<div class="col-md-4">
<label class="form-label text-secondary fw-semibold small">Location / Country</label>
<select class="form-select select2-field" id="staffCountry" name="location_country">
<option value="">Select Country</option>
@foreach($countries as $country)
<option value="{{ $country->en_short_name }}">{{ $country->en_short_name }}</option>
@endforeach
</select>
</div>
<div class="col-md-4">
<label class="form-label text-secondary fw-semibold small">Status</label>
<select class="form-select" id="staffStatus" name="status">
<option value="active">Active</option>
<option value="on-leave">On Leave</option>
<option value="inactive">Inactive</option>
<option value="ACTIVE">Active</option>
<option value="ON-LEAVE">On Leave</option>
<option value="INACTIVE">Inactive</option>
</select>
</div>
</div>
@@ -309,19 +259,41 @@
@endpush
@push('scripts')
<!-- Select2 JS -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
const staffModal = new bootstrap.Modal(document.getElementById('staffModal'));
const $form = $('#staffForm');
// Initialize Select2 inside the modal for Country
$('#staffCountry').select2({
placeholder: "Select Country",
allowClear: true,
width: '100%',
dropdownParent: $('#staffModal')
});
// Handle Photo Preview
$('#staffPhoto').on('change', function(e) {
if(e.target.files && e.target.files[0]) {
let reader = new FileReader();
reader.onload = function(e) {
$('#avatarPreview').html(`<img src="${e.target.result}" style="width:100%; height:100%; object-fit:cover; border-radius:12px;">`);
}
reader.readAsDataURL(e.target.files[0]);
}
});
// --- OPEN MODAL FOR CREATE ---
$('#btnOpenStaffModal').on('click', function() {
$form[0].reset();
$('#staffId').val('');
$('#staffMethod').val('POST');
$('#avatarPreview').html('<i class="bi bi-person text-secondary"></i>');
$('#staffCountry').val(null).trigger('change');
$('#staffModalTitle').text('Add New Employee');
$('#btnSubmitStaff').html('<i class="bi bi-save me-2"></i>Save Employee');
$('#avatarPreview').html('<i class="bi bi-person text-secondary"></i>');
staffModal.show();
});
@@ -331,44 +303,93 @@
$form[0].reset();
$('#staffId').val(data.id);
$('#staffMethod').val('PUT');
$('#staffName').val(data.name);
$('#staffRole').val(data.role);
$('#staffDesignation').val(data.designation);
$('#staffEmail').val(data.email);
$('#staffExt').val(data.ext);
$('#staffDept').val(data.dept);
$('#staffPhone').val(data.phone);
$('#staffDept').val(data.department_id);
$('#staffCountry').val(data.location_country).trigger('change');
$('#staffStatus').val(data.status);
// Show initials in preview for demo purposes
const initials = data.name.split(' ').map(n => n[0]).join('').substring(0,2);
$('#avatarPreview').html(initials).addClass('bg-primary bg-opacity-10 text-primary');
if (data.pic) {
$('#avatarPreview').html(`<img src="${data.pic}" style="width:100%; height:100%; object-fit:cover; border-radius:12px;">`);
} else {
$('#avatarPreview').html('<i class="bi bi-person text-secondary"></i>');
}
$('#staffModalTitle').text('Edit Employee: ' + data.name);
$('#btnSubmitStaff').html('<i class="bi bi-check-circle me-2"></i>Update Employee');
staffModal.show();
});
// --- HANDLE FORM SUBMISSION ---
// --- HANDLE FORM SUBMISSION (AJAX) ---
$form.on('submit', function(e) {
e.preventDefault();
const $btn = $('#btnSubmitStaff');
const originalText = $btn.html();
const $alertBox = $('#staffModalAlert');
$btn.html('<span class="spinner-border spinner-border-sm me-2"></span> Saving...');
$btn.prop('disabled', true);
$alertBox.html('');
$form.find('.is-invalid').removeClass('is-invalid');
// Use FormData to allow file uploads (profile picture)
let formData = new FormData(this);
const recordId = $('#staffId').val();
const submitUrl = recordId ? "{{ url('staff') }}/" + recordId : "{{ url('staff') }}";
// Simulate AJAX Request
setTimeout(() => {
console.log('Staff Data Saved');
$btn.html(originalText).prop('disabled', false);
staffModal.hide();
alert('Employee record saved successfully!');
}, 800);
if (recordId) formData.append('_method', 'PUT');
$.ajax({
url: submitUrl,
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
staffModal.hide();
Swal.fire({
icon: 'success',
title: 'Success!',
text: response.message,
confirmButtonColor: '#5c4df0'
}).then(() => location.reload());
}
},
error: function(xhr) {
if (xhr.status === 422) {
let errors = xhr.responseJSON.errors;
$alertBox.html('<div class="alert alert-danger py-2 px-3 small"><i class="bi bi-exclamation-triangle-fill me-2"></i>Please check the highlighted fields below.</div>');
$.each(errors, function(key, value) {
let $input = $form.find('[name="' + key + '"]');
$input.addClass('is-invalid');
});
} else {
$alertBox.html('<div class="alert alert-danger py-2 px-3 small"><i class="bi bi-x-circle-fill me-2"></i>An unexpected error occurred.</div>');
}
},
complete: function() {
$btn.html(originalText).prop('disabled', false);
}
});
});
// --- SWEETALERT FOR DELETE ---
$('.btn-delete-staff').on('click', function() {
const $form = $(this).closest('form');
Swal.fire({
title: 'Remove Staff Member?',
text: "You are about to delete this employee's profile. This cannot be undone.",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#ef4444',
cancelButtonColor: '#6c757d',
confirmButtonText: '<i class="bi bi-trash me-1"></i> Yes, remove them!'
}).then((result) => {
if (result.isConfirmed) $form.submit();
});
});
});
</script>