feat: prevent duplicate pending leave requests and restrict submission UI when a pending request exists

This commit is contained in:
Yoga Pangestu 2026-06-14 14:58:25 +07:00
parent 46cb2c3588
commit c140192453
4 changed files with 26 additions and 4 deletions

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Hr; namespace App\Http\Controllers\Admin\Hr;
use App\Enums\LeaveRequestStatus;
use App\Enums\Permission; use App\Enums\Permission;
use App\Http\Controllers\Concerns\FlashesEntityMessage; use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
@ -29,12 +30,21 @@ public function index(Request $request): Response
$tableQuery = $this->parseDataTableQuery($request); $tableQuery = $this->parseDataTableQuery($request);
$user = $request->user(); $user = $request->user();
$hasPending = false;
if ($user?->employee !== null) {
$hasPending = LeaveRequest::query()
->where('employee_id', $user->employee->id)
->where('status', LeaveRequestStatus::PENDING)
->exists();
}
return Inertia::render('admin/hr/leave-requests/Index', [ return Inertia::render('admin/hr/leave-requests/Index', [
'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery), 'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery),
'authEmployeeId' => $user?->employee?->id, 'authEmployeeId' => $user?->employee?->id,
'canSubmit' => $user?->can(Permission::LEAVE_REQUESTS_CREATE->value) 'canSubmit' => $user?->can(Permission::LEAVE_REQUESTS_CREATE->value)
&& ! $user->can(Permission::LEAVE_REQUESTS_VERIFY->value) && ! $user->can(Permission::LEAVE_REQUESTS_VERIFY->value)
&& $user->employee !== null, && $user->employee !== null,
'hasPending' => $hasPending,
'filters' => $this->dataTableFilters($tableQuery), 'filters' => $this->dataTableFilters($tableQuery),
]); ]);
} }

View File

@ -51,6 +51,17 @@ public function create(array $validated, User $user): void
{ {
$employee = $this->resolveAuthEmployee($user); $employee = $this->resolveAuthEmployee($user);
$hasPending = LeaveRequest::query()
->where('employee_id', $employee->id)
->where('status', LeaveRequestStatus::PENDING)
->exists();
if ($hasPending) {
throw ValidationException::withMessages([
'start_date' => 'Anda masih memiliki pengajuan cuti yang aktif (menunggu persetujuan).',
]);
}
$startDate = Carbon::parse($validated['start_date'])->startOfDay(); $startDate = Carbon::parse($validated['start_date'])->startOfDay();
$endDate = Carbon::parse($validated['end_date'])->startOfDay(); $endDate = Carbon::parse($validated['end_date'])->startOfDay();
@ -107,7 +118,7 @@ public function approve(LeaveRequest $leaveRequest, User $user): void
DB::transaction(function () use ($leaveRequest, $user): void { DB::transaction(function () use ($leaveRequest, $user): void {
$leaveRequest->status = LeaveRequestStatus::APPROVED; $leaveRequest->status = LeaveRequestStatus::APPROVED;
$leaveRequest->verified_at = now(); $leaveRequest->verified_at = Carbon::now();
$leaveRequest->verified_by_id = $user->id; $leaveRequest->verified_by_id = $user->id;
$leaveRequest->save(); $leaveRequest->save();
}); });
@ -129,7 +140,7 @@ public function reject(LeaveRequest $leaveRequest, string $reason, User $user):
DB::transaction(function () use ($leaveRequest, $user, $reason): void { DB::transaction(function () use ($leaveRequest, $user, $reason): void {
$leaveRequest->status = LeaveRequestStatus::REJECTED; $leaveRequest->status = LeaveRequestStatus::REJECTED;
$leaveRequest->verified_at = now(); $leaveRequest->verified_at = Carbon::now();
$leaveRequest->verified_by_id = $user->id; $leaveRequest->verified_by_id = $user->id;
$leaveRequest->save(); $leaveRequest->save();
@ -157,7 +168,7 @@ private function calculateTotalDays(Carbon $startDate, Carbon $endDate): int
private function ensureMinimumLeadTime(Carbon $startDate): void private function ensureMinimumLeadTime(Carbon $startDate): void
{ {
$minimumStartDate = now()->startOfDay()->addDay(); $minimumStartDate = Carbon::now()->startOfDay()->addDay();
if ($startDate->lt($minimumStartDate)) { if ($startDate->lt($minimumStartDate)) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([

View File

@ -93,7 +93,7 @@ watch(
</h2> </h2>
</div> </div>
<Button v-if="canSubmit" class="shrink-0 self-start sm:self-center" @click="openCreateModal"> <Button v-if="canSubmit && !hasPending" class="shrink-0 self-start sm:self-center" @click="openCreateModal">
<Plus class="size-4" /> <Plus class="size-4" />
Ajukan Ajukan
</Button> </Button>

View File

@ -37,6 +37,7 @@ export type LeaveRequestPageProps = {
leaveRequests: PaginatedLeaveRequests; leaveRequests: PaginatedLeaveRequests;
authEmployeeId: number | null; authEmployeeId: number | null;
canSubmit: boolean; canSubmit: boolean;
hasPending: boolean;
filters: { filters: {
search: string; search: string;
sort?: string; sort?: string;