feat: add employee management features including create, edit, and list functionalities

- Implemented employee columns for data table with sorting and action buttons.
- Created employee creation form with validation and default password information.
- Developed employee editing form pre-filled with existing data.
- Added employee listing page with delete and reset password functionalities.
- Introduced leave request management with columns for status and actions.
- Created leave request form for adding and editing requests with date pickers.
- Implemented confirmation dialogs for delete, approve, and reject actions.
This commit is contained in:
Yoga Pangestu 2026-07-29 22:33:55 +07:00
parent 887526bd18
commit da30f12fc2
14 changed files with 39 additions and 39 deletions

View File

@ -1,11 +1,11 @@
<?php
namespace App\Http\Controllers\Admin\SDM;
namespace App\Http\Controllers\Admin\HR;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\SDM\EmployeeRequest;
use App\Http\Requests\Admin\HR\EmployeeRequest;
use App\Models\User;
use App\Services\Admin\SDM\EmployeeService;
use App\Services\Admin\HR\EmployeeService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
@ -19,14 +19,14 @@ public function __construct(
public function index(): Response
{
return Inertia::render('admin/sdm/employee/index', [
return Inertia::render('admin/hr/employee/index', [
'employees' => $this->service->getAll(),
]);
}
public function create(): Response
{
return Inertia::render('admin/sdm/employee/create');
return Inertia::render('admin/hr/employee/create');
}
public function store(EmployeeRequest $request): RedirectResponse
@ -42,12 +42,12 @@ public function store(EmployeeRequest $request): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.employees.index');
return to_route('admin.hr.employees.index');
}
public function edit(User $employee): Response
{
return Inertia::render('admin/sdm/employee/edit', [
return Inertia::render('admin/hr/employee/edit', [
'employee' => $this->service->getById($employee->id),
]);
}
@ -65,7 +65,7 @@ public function update(EmployeeRequest $request, User $employee): RedirectRespon
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.employees.index');
return to_route('admin.hr.employees.index');
}
public function destroy(User $employee): RedirectResponse
@ -81,7 +81,7 @@ public function destroy(User $employee): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.employees.index');
return to_route('admin.hr.employees.index');
}
public function toggleActive(User $employee): RedirectResponse
@ -98,7 +98,7 @@ public function toggleActive(User $employee): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.employees.index');
return to_route('admin.hr.employees.index');
}
public function resetPassword(User $employee): RedirectResponse
@ -114,6 +114,6 @@ public function resetPassword(User $employee): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.employees.index');
return to_route('admin.hr.employees.index');
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace App\Http\Controllers\Admin\SDM;
namespace App\Http\Controllers\Admin\HR;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\SDM\LeaveRequestRequest;
use App\Http\Requests\Admin\HR\LeaveRequestRequest;
use App\Models\LeaveRequest;
use App\Services\Admin\SDM\LeaveRequestService;
use App\Services\Admin\HR\LeaveRequestService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
@ -19,7 +19,7 @@ public function __construct(
public function index(): Response
{
return Inertia::render('admin/sdm/leave-request/index', [
return Inertia::render('admin/hr/leave-request/index', [
'leaveRequests' => $this->service->getAll(),
]);
}
@ -37,7 +37,7 @@ public function store(LeaveRequestRequest $request): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.leave-requests.index');
return to_route('admin.hr.leave-requests.index');
}
public function update(LeaveRequestRequest $request, LeaveRequest $leaveRequest): RedirectResponse
@ -53,7 +53,7 @@ public function update(LeaveRequestRequest $request, LeaveRequest $leaveRequest)
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.leave-requests.index');
return to_route('admin.hr.leave-requests.index');
}
public function destroy(LeaveRequest $leaveRequest): RedirectResponse
@ -66,7 +66,7 @@ public function destroy(LeaveRequest $leaveRequest): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.leave-requests.index');
return to_route('admin.hr.leave-requests.index');
}
public function approve(LeaveRequest $leaveRequest): RedirectResponse
@ -79,7 +79,7 @@ public function approve(LeaveRequest $leaveRequest): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.leave-requests.index');
return to_route('admin.hr.leave-requests.index');
}
public function reject(LeaveRequest $leaveRequest): RedirectResponse
@ -92,6 +92,6 @@ public function reject(LeaveRequest $leaveRequest): RedirectResponse
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.sdm.leave-requests.index');
return to_route('admin.hr.leave-requests.index');
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Requests\Admin\SDM;
namespace App\Http\Requests\Admin\HR;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

View File

@ -1,6 +1,6 @@
<?php
namespace App\Http\Requests\Admin\SDM;
namespace App\Http\Requests\Admin\HR;
use Illuminate\Foundation\Http\FormRequest;

View File

@ -1,6 +1,6 @@
<?php
namespace App\Services\Admin\SDM;
namespace App\Services\Admin\HR;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;

View File

@ -1,6 +1,6 @@
<?php
namespace App\Services\Admin\SDM;
namespace App\Services\Admin\HR;
use App\Enums\LeaveRequestStatus;
use App\Models\LeaveRequest;

View File

@ -41,8 +41,8 @@ import { index as suppliersIndex } from '@/routes/admin/master/suppliers';
import { index as cashAccountsIndex } from '@/routes/admin/finance/cash-accounts';
import { index as expensesIndex } from '@/routes/admin/finance/expenses';
import { index as employeeAdvancesIndex } from '@/routes/admin/finance/employee-advances';
import { index as employeesIndex } from '@/routes/admin/sdm/employees';
import { index as leaveRequestsIndex } from '@/routes/admin/sdm/leave-requests';
import { index as employeesIndex } from '@/routes/admin/hr/employees';
import { index as leaveRequestsIndex } from '@/routes/admin/hr/leave-requests';
type NavMenuItem = { title: string; href: string; icon: LucideIcon };
@ -80,7 +80,7 @@ const keuanganItems: NavMenuItem[] = [
{ title: 'Gaji', href: '#', icon: DollarSign },
];
const sdmItems: NavMenuItem[] = [
const hrItems: NavMenuItem[] = [
{ title: 'Pegawai', href: employeesIndex.url(), icon: UserCircle },
{ title: 'Presensi', href: '#', icon: CalendarCheck },
{ title: 'Cuti', href: leaveRequestsIndex.url(), icon: CalendarDays },
@ -158,7 +158,7 @@ export function AppSidebar() {
<MenuGroup label="Master" items={masterItems} />
<MenuGroup label="Kelola" items={kelolaItems} />
<MenuGroup label="Keuangan" items={keuanganItems} />
<MenuGroup label="SDM" items={sdmItems} />
<MenuGroup label="HR" items={hrItems} />
<MenuGroup label="Sistem" items={sistemItems} />
</SidebarContent>
</Sidebar>

View File

@ -15,7 +15,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { index as employeeIndex, store } from '@/routes/admin/sdm/employees';
import { index as employeeIndex, store } from '@/routes/admin/hr/employees';
import { Form, Head } from '@inertiajs/react';
import { AlertCircle, ArrowLeft } from 'lucide-react';
import { useState } from 'react';
@ -222,7 +222,7 @@ export default function EmployeeCreate() {
EmployeeCreate.layout = {
breadcrumbs: [
{
title: 'SDM',
title: 'HR',
href: employeeIndex.url(),
},
{

View File

@ -14,7 +14,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { index as employeeIndex, update } from '@/routes/admin/sdm/employees';
import { index as employeeIndex, update } from '@/routes/admin/hr/employees';
import { Form, Head } from '@inertiajs/react';
import { ArrowLeft } from 'lucide-react';
import { useState } from 'react';
@ -249,7 +249,7 @@ export default function EmployeeEdit({ employee }: Props) {
EmployeeEdit.layout = {
breadcrumbs: [
{
title: 'SDM',
title: 'HR',
href: employeeIndex.url(),
},
{

View File

@ -1,7 +1,7 @@
import { ConfirmDialog } from '@/components/confirm-dialog';
import { DataTable } from '@/components/data-table';
import { Button } from '@/components/ui/button';
import { destroy, create as employeeCreate, edit as employeeEdit, index as employeeIndex, toggleActive, resetPassword as resetPasswordRoute } from '@/routes/admin/sdm/employees';
import { destroy, create as employeeCreate, edit as employeeEdit, index as employeeIndex, toggleActive, resetPassword as resetPasswordRoute } from '@/routes/admin/hr/employees';
import { Head, router } from '@inertiajs/react';
import { Plus } from 'lucide-react';
import { useState } from 'react';
@ -106,7 +106,7 @@ export default function EmployeeIndex({ employees }: Props) {
EmployeeIndex.layout = {
breadcrumbs: [
{
title: 'SDM',
title: 'HR',
href: employeeIndex.url(),
},
{

View File

@ -11,7 +11,7 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { Label } from '@/components/ui/label';
import { approve, destroy, index as leaveRequestIndex, reject, store, update } from '@/routes/admin/sdm/leave-requests';
import { approve, destroy, index as leaveRequestIndex, reject, store, update } from '@/routes/admin/hr/leave-requests';
import { Form, Head, router } from '@inertiajs/react';
import { Plus } from 'lucide-react';
import { useEffect, useState } from 'react';
@ -298,7 +298,7 @@ export default function LeaveRequestIndex({ leaveRequests }: Props) {
LeaveRequestIndex.layout = {
breadcrumbs: [
{
title: 'SDM',
title: 'HR',
href: leaveRequestIndex(),
},
{

View File

@ -6,8 +6,8 @@
use App\Http\Controllers\Admin\Master\CategoryController;
use App\Http\Controllers\Admin\Master\CustomerController;
use App\Http\Controllers\Admin\Master\SupplierController;
use App\Http\Controllers\Admin\SDM\EmployeeController;
use App\Http\Controllers\Admin\SDM\LeaveRequestController;
use App\Http\Controllers\Admin\HR\EmployeeController;
use App\Http\Controllers\Admin\HR\LeaveRequestController;
use Illuminate\Support\Facades\Route;
Route::inertia('/', 'welcome')->name('home');
@ -35,7 +35,7 @@
Route::post('employee-advances/{employeeAdvance}/pay', [EmployeeAdvanceController::class, 'pay'])->name('employee-advances.pay');
});
Route::prefix('admin/sdm')->name('admin.sdm.')->group(function () {
Route::prefix('admin/hr')->name('admin.hr.')->group(function () {
Route::resource('employees', EmployeeController::class)->except(['show']);
Route::post('employees/{employee}/toggle-active', [EmployeeController::class, 'toggleActive'])->name('employees.toggle-active');
Route::post('employees/{employee}/reset-password', [EmployeeController::class, 'resetPassword'])->name('employees.reset-password');