Version: 1.0
Last updated: December 10, 2025
HR Approver Management is a module within the HR System for managing approval workflows in the DTR System. HR managers and administrators can:
Key files involved:
resources/views/users/hr/approver/
index.blade.php — List approverscreate.blade.php — Create approveredit.blade.php — Edit approverApp\Http\Controllers\Web\HR\ApproverController.php (expected)App\Models\Approver, App\Models\Userapprovers tablePurpose:
Scope:
Out of scope:
Required permissions:
view_approvers — view approver list and detailscreate_approvers — create new approver assignmentsedit_approvers — modify existing approver assignmentsdelete_approvers — remove approver assignmentsview_hr_dashboard — access HR module (includes approver management)Recommended roles:
Implementation note:
authorize() in controller methodsHR URLs:
/hr/approvers/hr/approvers?type=leave or /hr/approvers?type=overtime/hr/approvers?department={id}/hr/approvers/create/hr/approvers/{id} (optional detail view)/hr/approvers/{id}/edit/hr/approvers/{id}/delete (POST with confirmation)/hr/approvers?search={query}Navigation path:
Browser requirements: Modern browsers (Chrome, Firefox, Safari, Edge). Mobile responsive design.
Purpose: Display all approvers with filtering, search, and management actions.
View file: resources/views/users/hr/approver/index.blade.php
Top section - Filters & Search:
Department filter (dropdown):
Type filter (dropdown):
Search bar:
Quick actions:
Approvers table - Columns:
| Column | Content | Notes |
|---|---|---|
| Approver Name | First + Last name | Linked to user profile |
| User email address | Linked to send email | |
| Department | Department name | Shows approver's department |
| Approval Type | Leave / Overtime / Both | Badge styled |
| Delegate Approver | Backup approver name | Shows if assigned |
| Pending Requests | Number count | (Optional) Shows pending requests |
| Status | Active / Inactive | Green/Gray badge |
| Created By | Admin user name | Who created assignment |
| Created At | Date/Time | Timestamp |
| Actions | Edit, Delete | Buttons/Links |
Table features:
Empty state:
Controller method: ApproverController::index(Request $request) (in HR namespace)
public function index(Request $request)
{
$department = $request->get('department');
$type = $request->get('type', 'all');
$search = $request->get('search');
$query = Approver::with(['user.profile', 'department', 'delegateApprover.profile'])
->when(auth()->user()->cannot('view_all_approvers'), function ($query) {
// Filter by user's departments only
$query->whereIn('department_id', auth()->user()->departments()->pluck('id'));
})
->when($department, function ($query) use ($department) {
$query->where('department_id', $department);
})
->when($type !== 'all', function ($query) use ($type) {
$query->where('approver_for', $type);
})
->when($search, function ($query) use ($search) {
$query->whereHas('user.profile', function ($q) use ($search) {
$q->where('first_name', 'like', "%{$search}%")
->orWhere('last_name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
})
->orderBy('department_id')
->orderBy('approver_for')
->orderBy('created_at', 'desc');
$approvers = $query->paginate(10);
$departments = Department::all(); // For filter dropdown
return view('users.hr.approver.index', compact('approvers', 'departments'));
}
Purpose: Create a new approver assignment for leave or overtime requests.
Trigger: "Create Approver" button on index view.
View file: resources/views/users/hr/approver/create.blade.php
Form fields:
User (required, dropdown/searchable):
Department (required, dropdown):
Approval Type (required, radio buttons or dropdown):
leave or overtimeDelegate Approver (optional, dropdown/searchable):
Active (optional, checkbox):
Notes (optional, text area):
Form submission (POST /hr/approvers):
hr, admin, tl, or approver role)Validation rules:
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:user_id',
'notes' => 'nullable|string|max:500'
]);
// Check delegate approver has appropriate role
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'The delegate approver must have appropriate permissions.'
])->withInput();
}
}
// Check for duplicate assignment
$exists = Approver::where('user_id', $request->user_id)
->where('department_id', $request->department_id)
->where('approver_for', $request->approver_for)
->exists();
if ($exists) {
return back()->withErrors([
'user_id' => 'This user is already an approver for this type in this department.'
])->withInput();
}
Controller method:
public function store(Request $request)
{
// Authorization check
$this->authorize('create_approvers');
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:user_id',
'notes' => 'nullable|string|max:500'
]);
// Verify delegate has appropriate role
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'Delegate must have appropriate role.'
])->withInput();
}
}
// Check duplicate
$exists = Approver::where('user_id', $request->user_id)
->where('department_id', $request->department_id)
->where('approver_for', $request->approver_for)
->exists();
if ($exists) {
return back()->withErrors([
'user_id' => 'Already assigned this role in this department.'
])->withInput();
}
$approver = Approver::create([
...$validated,
'created_by' => auth()->id(),
]);
// Audit log
activity()
->causedBy(auth()->user())
->performedOn($approver)
->withProperties([
'user_name' => User::find($validated['user_id'])->name,
'department_id' => $validated['department_id'],
'type' => $validated['approver_for']
])
->log('approver_created');
// Notification
// Notification::send($approver->user, new ApproverAssigned($approver));
return redirect()->route('hr.approvers.index')
->with('success', 'Approver assigned successfully');
}
Purpose: Modify existing approver assignment (change department, type, delegate, or status).
Trigger: Click "Edit" button next to approver in index view.
View file: resources/views/users/hr/approver/edit.blade.php
Form fields:
Same as create form, except:
User (read-only or disabled):
Department (required, dropdown):
Approval Type (required, radio buttons or dropdown):
leave or overtimeDelegate Approver (optional, dropdown):
Active (optional, checkbox):
Notes (optional, text area):
Confirmation details (if applicable):
Form submission (PUT /hr/approvers/{id}):
Validation rules:
$validated = $request->validate([
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:approver.user_id',
'notes' => 'nullable|string|max:500'
]);
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'Delegate must have appropriate role.'
])->withInput();
}
}
Controller method:
public function update(Request $request, Approver $approver)
{
// Authorization check
$this->authorize('edit_approvers');
$validated = $request->validate([
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:' . $approver->user_id,
'notes' => 'nullable|string|max:500'
]);
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'Delegate must have appropriate role.'
])->withInput();
}
}
$oldValues = $approver->only(array_keys($validated));
$approver->update($validated);
// Audit log with changes
activity()
->causedBy(auth()->user())
->performedOn($approver)
->withProperties([
'old' => $oldValues,
'new' => $validated
])
->log('approver_updated');
return redirect()->route('hr.approvers.index')
->with('success', 'Approver assignment updated successfully');
}
Delete Approver:
Trigger: Click "Delete" button or link on index view.
Confirmation modal:
Are you sure you want to remove this approver?
User: [Name]
Type: [Leave / Overtime]
Department: [Department]
Pending Requests: X
Options:
[ Cancel ] [ Confirm Delete ]
Flow:
Controller method:
public function destroy(Approver $approver)
{
// Authorization check
$this->authorize('delete_approvers');
// Check for pending requests
$pendingCount = LeaveRequest::where('approver_id', $approver->user_id)
->where('status', 'pending')
->count();
if ($pendingCount > 0) {
// Handle pending requests
// Option 1: Auto-reassign to delegate
if ($approver->delegate_approver_id) {
LeaveRequest::where('approver_id', $approver->user_id)
->where('status', 'pending')
->update(['approver_id' => $approver->delegate_approver_id]);
}
}
// Audit log
activity()
->causedBy(auth()->user())
->performedOn($approver)
->withProperties([
'user_name' => $approver->user->name,
'pending_requests' => $pendingCount
])
->log('approver_deleted');
$approver->delete();
return redirect()->route('hr.approvers.index')
->with('success', 'Approver assignment removed successfully');
}
Approver table fields:
id — Primary key
user_id — Foreign key to users (primary approver)
department_id — Foreign key to departments
approver_for — Enum: 'leave' or 'overtime'
delegate_approver_id — Foreign key to users (nullable, backup)
active — Boolean (default true)
notes — Text (nullable, max 500 chars)
created_by — Foreign key to users (who created)
created_at — Timestamp
updated_at — Timestamp
deleted_at — Timestamp (soft delete, nullable)
Sample records:
Approver 1:
├─ id: 1
├─ user_id: 5 (Jane Doe)
├─ department_id: 1 (HR Department)
├─ approver_for: 'leave'
├─ delegate_approver_id: 8 (John Smith)
├─ active: true
├─ notes: "Primary leave approver for HR"
├─ created_by: 1 (Admin ID)
└─ created_at: 2025-01-01 09:00:00
Approver 2:
├─ id: 2
├─ user_id: 6 (Alice Johnson)
├─ department_id: 2 (Operations)
├─ approver_for: 'overtime'
├─ delegate_approver_id: null
├─ active: true
├─ notes: null
├─ created_by: 1
└─ created_at: 2025-01-05 10:30:00
Relationships:
Approver belongsTo User (primary approver)Approver belongsTo User as delegateApprover (backup)Approver belongsTo DepartmentApprover belongsTo User as createdBy (who created)User hasMany Approver (user can be approver in multiple departments)Department hasMany ApproverApproval Type: leave
├─ Responsibility: Review & approve employee leave requests
├─ Approval Authority: Accept/Reject leave requests
├─ Scope: Specific department
└─ Typical Users: HR Manager, HR Specialist, Team Lead
Example:
Jane Doe (HR Manager) approves leave for HR Department
- Handles all leave requests from HR employees
- Can delegate to John Smith (HR Backup)
- Can approve or reject requests
Approval Type: overtime
├─ Responsibility: Review & approve overtime requests
├─ Approval Authority: Accept/Reject overtime requests
├─ Scope: Specific department
└─ Typical Users: Department Manager, Operations Manager
Example:
Alice Johnson (Operations Manager) approves overtime for Operations
- Handles overtime requests from Operations team
- Ensures budget compliance
- Can delegate to backup manager
HR Department:
├─ Leave Approver: Jane Doe (HR Manager)
│ └─ Delegate: John Smith (HR Specialist)
└─ Overtime Approver: Jane Doe (HR Manager)
└─ No delegate
Operations Department:
├─ Leave Approver: Alice Johnson (Ops Manager)
│ └─ No delegate
└─ Overtime Approver: David Lee (Ops Director)
└─ Delegate: Emma Brown (Ops Manager)
Finance Department:
├─ Leave Approver: Frank Martinez (Finance Manager)
│ └─ Delegate: Grace Kim (Finance Specialist)
└─ Overtime Approver: Frank Martinez (Finance Manager)
└─ Delegate: Grace Kim
Task 1: Create Leave Approver for Department
Task 2: Assign Approver for Multiple Types
Task 3: Update Delegate Approver
Task 4: Deactivate Approver (Temporary)
Task 5: Remove Approver
Task 6: View All Approvers by Type
Task 7: Search for Specific Approver
Task 8: Filter by Department
Leave Request Integration:
Overtime Request Integration:
Auto-routing logic:
// Find approver for request
$approver = Approver::where('department_id', $request->department_id)
->where('approver_for', 'leave') // or 'overtime'
->where('active', true)
->with('delegateApprover')
->first();
if (!$approver && isset($approver)) {
// Primary not active, check delegate
if ($approver->delegateApprover && $approver->delegateApprover->active) {
$approver = $approver->delegateApprover;
} else {
// No active approver found
$request->status = 'no_approver';
// Log warning or notify admin
}
}
$request->approver_id = $approver->user_id ?? null;
$request->save();
Quick filters:
Search functionality:
Advanced filters (optional):
Reports:
Export formats: CSV, Excel, PDF
GET /hr/approvers
type (leave, overtime, all), department, search, pagepublic function index(Request $request)
{
$type = $request->get('type', 'all');
$department = $request->get('department');
$search = $request->get('search');
$query = Approver::with(['user.profile', 'department', 'delegateApprover.profile'])
// ... filtering logic ...
->paginate(10);
return view('users.hr.approver.index', compact('approvers', 'departments'));
}
GET /hr/approvers/create
$users — eligible users$departments — accessible departmentspublic function create()
{
$users = User::role(['hr', 'admin', 'tl', 'approver'])->get();
$departments = auth()->user()->departments ?? Department::all();
return view('users.hr.approver.create', compact('users', 'departments'));
}
POST /hr/approvers
{ user_id, department_id, approver_for, delegate_approver_id, active, notes }GET /hr/approvers/{id}/edit
public function edit(Approver $approver)
{
$this->authorize('edit_approvers');
$users = User::role(['hr', 'admin', 'tl', 'approver'])->get();
$departments = auth()->user()->departments ?? Department::all();
return view('users.hr.approver.edit', compact('approver', 'users', 'departments'));
}
PUT /hr/approvers/{id}
{ department_id, approver_for, active, delegate_approver_id, notes }DELETE /hr/approvers/{id}
GET /api/hr/approvers
type, department_id, search, page{
"data": [
{
"id": 1,
"user": {
"id": 5,
"name": "Jane Doe",
"email": "jane@company.com"
},
"department": { "id": 1, "name": "HR Department" },
"approver_for": "leave",
"delegate_approver": { "id": 8, "name": "John Smith" },
"active": true,
"created_at": "2025-01-01T09:00:00Z"
}
],
"pagination": { "total": 10, "per_page": 25 }
}
GET /api/hr/approvers/for-request
type, department_id{
"approver": { "id": 5, "name": "Jane Doe" },
"delegate": { "id": 8, "name": "John Smith" }
}
Location: app/Http/Controllers/Web/HR/ApproverController.php (expected)
index() method:
public function index(Request $request)
{
// Authorization
$this->authorize('view_approvers');
$type = $request->get('type', 'all');
$department = $request->get('department');
$search = $request->get('search');
// Base query with relationships
$query = Approver::with(['user.profile', 'department', 'delegateApprover.profile'])
// Department scope (only accessible departments)
->when(auth()->user()->cannot('view_all_approvers'), function ($query) {
$query->whereIn('department_id', auth()->user()->departments()->pluck('id'));
})
// Filters
->when($department, function ($query) use ($department) {
$query->where('department_id', $department);
})
->when($type !== 'all', function ($query) use ($type) {
$query->where('approver_for', $type);
})
->when($search, function ($query) use ($search) {
$query->whereHas('user.profile', function ($q) use ($search) {
$q->where('first_name', 'like', "%{$search}%")
->orWhere('last_name', 'like', "%{$search}%");
})->orWhereHas('user', function ($q) use ($search) {
$q->where('email', 'like', "%{$search}%");
});
})
// Sorting
->orderBy('department_id')
->orderBy('approver_for')
->orderBy('created_at', 'desc');
$approvers = $query->paginate(10);
$departments = auth()->user()->departments ?? Department::all();
return view('users.hr.approver.index', compact('approvers', 'departments'));
}
create() method:
public function create()
{
$this->authorize('create_approvers');
$users = User::whereHas('roles', function ($query) {
$query->whereIn('name', ['hr', 'admin', 'tl', 'approver']);
})->get();
$departments = auth()->user()->departments ?? Department::all();
return view('users.hr.approver.create', compact('users', 'departments'));
}
store() method:
public function store(Request $request)
{
$this->authorize('create_approvers');
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:user_id',
'notes' => 'nullable|string|max:500'
]);
// Verify delegate role
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'Delegate must have appropriate permissions.'
])->withInput();
}
}
// Check duplicate
$exists = Approver::where('user_id', $request->user_id)
->where('department_id', $request->department_id)
->where('approver_for', $request->approver_for)
->exists();
if ($exists) {
return back()->withErrors([
'user_id' => 'Already assigned this role in this department.'
])->withInput();
}
$approver = Approver::create([
...$validated,
'created_by' => auth()->id(),
]);
activity()
->causedBy(auth()->user())
->performedOn($approver)
->log('approver_created');
return redirect()->route('hr.approvers.index')
->with('success', 'Approver assigned successfully');
}
edit() method:
public function edit(Approver $approver)
{
$this->authorize('edit_approvers');
$users = User::whereHas('roles', function ($query) {
$query->whereIn('name', ['hr', 'admin', 'tl', 'approver']);
})->get();
$departments = auth()->user()->departments ?? Department::all();
return view('users.hr.approver.edit', compact('approver', 'users', 'departments'));
}
update() method:
public function update(Request $request, Approver $approver)
{
$this->authorize('edit_approvers');
$validated = $request->validate([
'department_id' => 'required|exists:departments,id',
'approver_for' => 'required|in:leave,overtime',
'active' => 'boolean|default:true',
'delegate_approver_id' => 'nullable|exists:users,id|different:' . $approver->user_id,
'notes' => 'nullable|string|max:500'
]);
if ($request->delegate_approver_id) {
$delegateUser = User::find($request->delegate_approver_id);
if (!$delegateUser->hasAnyRole(['hr', 'admin', 'tl', 'approver'])) {
return back()->withErrors([
'delegate_approver_id' => 'Delegate must have appropriate permissions.'
])->withInput();
}
}
$approver->update($validated);
activity()
->causedBy(auth()->user())
->performedOn($approver)
->log('approver_updated');
return redirect()->route('hr.approvers.index')
->with('success', 'Approver updated successfully');
}
destroy() method:
public function destroy(Approver $approver)
{
$this->authorize('delete_approvers');
activity()
->causedBy(auth()->user())
->performedOn($approver)
->log('approver_deleted');
$approver->delete();
return redirect()->route('hr.approvers.index')
->with('success', 'Approver removed successfully');
}
Audit logging:
Notifications:
Compliance:
Example 1: Single Department Setup
HR Department Structure:
Primary Approvers:
├─ Jane Doe (HR Manager)
│ ├─ Approves: Leave, Overtime
│ ├─ Pending: 5 requests
│ └─ Delegate: John Smith
├─ John Smith (HR Specialist)
│ ├─ Approves: Backup for Leave
│ ├─ Pending: 0 requests
│ └─ No delegate
Secondary Approvers:
└─ Carol White (HR Assistant)
├─ Approves: Internal use
└─ Pending: 2 requests
Example 2: Multi-Department Setup
Organization Structure:
HR Department:
├─ Leave: Jane Doe (Delegate: John Smith)
└─ Overtime: Jane Doe (Delegate: Carol White)
Operations Department:
├─ Leave: Alice Johnson (No delegate)
└─ Overtime: David Lee (Delegate: Emma Brown)
Finance Department:
├─ Leave: Frank Martinez (Delegate: Grace Kim)
└─ Overtime: Frank Martinez (Delegate: Grace Kim)
Support Department:
├─ Leave: Helen Davis (No delegate)
└─ Overtime: Ian Brown (No delegate)
Example 3: Approver Transition
Scenario: Jane retiring, transition to Alice
Action Plan:
1. Create: Alice → HR → Leave (Delegate: Jane)
2. Notify: Employees of new approver
3. Training: Jane trains Alice on processes
4. Approval: Alice approves with Jane's guidance
5. Period: 2-week overlap
6. Final: Remove Jane as approver
7. Confirm: Alice is sole approver
Timeline:
├─ Week 1-2: Both active, Alice learning
├─ Week 3: Jane inactive, Alice handling all
└─ Week 4: Jane removed from system
Unit tests:
Integration tests:
E2E tests (manual):
Permission tests:
Q: "Cannot create approver - user doesn't have role"
hr, admin, tl, approverQ: "Approver not found for leave request"
Q: "Cannot edit approver - changes not saving"
edit_approvers permissionQ: "Delegate not receiving requests"
Q: "See approvers from other departments"
view_all_approvers permissionQ: "Approver appears twice in list"
Q: "Cannot delete approver - pending requests"
Model: Approver with relationships
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Approver extends Model
{
protected $fillable = [
'user_id', 'department_id', 'approver_for',
'delegate_approver_id', 'active', 'notes', 'created_by'
];
protected $casts = [
'active' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function department(): BelongsTo
{
return $this->belongsTo(Department::class);
}
public function delegateApprover(): BelongsTo
{
return $this->belongsTo(User::class, 'delegate_approver_id');
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
// Scopes
public function scopeActive($query)
{
return $query->where('active', true);
}
public function scopeForLeave($query)
{
return $query->where('approver_for', 'leave');
}
public function scopeForOvertime($query)
{
return $query->where('approver_for', 'overtime');
}
public function scopeForDepartment($query, $departmentId)
{
return $query->where('department_id', $departmentId);
}
}
SQL: Find approvers for department
SELECT a.*, u.first_name, u.last_name, u.email, d.name as department_name
FROM approvers a
JOIN users u ON a.user_id = u.id
JOIN departments d ON a.department_id = d.id
WHERE a.department_id = 1 AND a.active = 1
ORDER BY a.approver_for;
SQL: Find approver with delegate
SELECT a.id, u.name as approver, da.name as delegate, d.name as department, a.approver_for
FROM approvers a
JOIN users u ON a.user_id = u.id
LEFT JOIN users da ON a.delegate_approver_id = da.id
JOIN departments d ON a.department_id = d.id
WHERE a.delegate_approver_id IS NOT NULL
ORDER BY d.name;
SQL: Count pending requests per approver
SELECT a.user_id, u.name, COUNT(lr.id) as pending_count
FROM approvers a
JOIN users u ON a.user_id = u.id
LEFT JOIN leave_requests lr ON a.user_id = lr.approver_id
AND lr.status = 'pending'
WHERE a.approver_for = 'leave' AND a.active = 1
GROUP BY a.user_id
ORDER BY pending_count DESC;
Blade template: Index table
<table class="table">
<thead>
<tr>
<th>Approver</th>
<th>Email</th>
<th>Department</th>
<th>Type</th>
<th>Delegate</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach($approvers as $approver)
<tr>
<td>{{ $approver->user->profile->first_name }} {{ $approver->user->profile->last_name }}</td>
<td>{{ $approver->user->email }}</td>
<td>{{ $approver->department->name }}</td>
<td>
<span class="badge badge-{{ $approver->approver_for === 'leave' ? 'info' : 'warning' }}">
{{ ucfirst($approver->approver_for) }}
</span>
</td>
<td>{{ $approver->delegateApprover->name ?? '—' }}</td>
<td>
<span class="badge badge-{{ $approver->active ? 'success' : 'secondary' }}">
{{ $approver->active ? 'Active' : 'Inactive' }}
</span>
</td>
<td>
<a href="{{ route('hr.approvers.edit', $approver) }}" class="btn btn-sm btn-primary">Edit</a>
<form action="{{ route('hr.approvers.destroy', $approver) }}" method="POST" style="display:inline;">
@csrf @method('DELETE')
<button class="btn btn-sm btn-danger" onclick="return confirm('Delete?')">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
Blade template: Create form
<form action="{{ route('hr.approvers.store') }}" method="POST">
@csrf
<div class="form-group">
<label for="user_id">Approver *</label>
<select name="user_id" id="user_id" class="form-control" required>
<option value="">— Select Approver —</option>
@foreach($users as $user)
<option value="{{ $user->id }}" {{ old('user_id') == $user->id ? 'selected' : '' }}>
{{ $user->profile->first_name }} {{ $user->profile->last_name }} ({{ $user->email }})
</option>
@endforeach
</select>
@error('user_id') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label for="department_id">Department *</label>
<select name="department_id" id="department_id" class="form-control" required>
<option value="">— Select Department —</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id') == $dept->id ? 'selected' : '' }}>
{{ $dept->name }}
</option>
@endforeach
</select>
@error('department_id') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label for="approver_for">Type *</label>
<select name="approver_for" id="approver_for" class="form-control" required>
<option value="">— Select Type —</option>
<option value="leave" {{ old('approver_for') === 'leave' ? 'selected' : '' }}>Leave</option>
<option value="overtime" {{ old('approver_for') === 'overtime' ? 'selected' : '' }}>Overtime</option>
</select>
@error('approver_for') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label for="delegate_approver_id">Delegate Approver (Optional)</label>
<select name="delegate_approver_id" id="delegate_approver_id" class="form-control">
<option value="">— None —</option>
@foreach($users as $user)
<option value="{{ $user->id }}" {{ old('delegate_approver_id') == $user->id ? 'selected' : '' }}>
{{ $user->profile->first_name }} {{ $user->profile->last_name }}
</option>
@endforeach
</select>
@error('delegate_approver_id') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label for="notes">Notes (Optional)</label>
<textarea name="notes" id="notes" class="form-control" rows="3" maxlength="500">{{ old('notes') }}</textarea>
@error('notes') <span class="text-danger">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label>
<input type="checkbox" name="active" value="1" {{ old('active', true) ? 'checked' : '' }}>
Active
</label>
</div>
<button type="submit" class="btn btn-primary">Create Approver</button>
<a href="{{ route('hr.approvers.index') }}" class="btn btn-secondary">Cancel</a>
</form>
Document version: 1.0
Maintainers: HR / Operations / Engineering
Last updated: December 10, 2025