From 2a3e70b78d8a4eea3f609e8e5c8364422569ceda Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sat, 1 Aug 2026 02:54:24 +0700 Subject: [PATCH] Refactor role management and pagination in admin panel - Updated RoleIndex component to handle pagination, sorting, and searching for roles. - Adjusted data structure for roles to include pagination details. - Enhanced tests for various admin features (Finance, HR, Master) to validate pagination and data structure. - Ensured all relevant tests check for data structure consistency, including total counts and pagination details. --- .../Admin/Finance/CashAccountController.php | 9 +- .../Finance/EmployeeAdvanceController.php | 5 +- .../Admin/Finance/ExpenseController.php | 5 +- .../Admin/Finance/PayrollPeriodController.php | 5 +- .../Admin/HR/EmployeeController.php | 9 +- .../Admin/HR/LeaveRequestController.php | 9 +- .../Admin/Master/CategoryController.php | 5 +- .../Admin/Master/CustomerController.php | 5 +- .../Admin/Master/ProductController.php | 11 +- .../Admin/Master/SupplierController.php | 5 +- app/Http/Controllers/Admin/RoleController.php | 5 +- app/Http/Requests/PaginatedRequest.php | 35 +++ .../Admin/Finance/CashAccountService.php | 24 ++ .../Admin/Finance/EmployeeAdvanceService.php | 11 + app/Services/Admin/Finance/ExpenseService.php | 15 + .../Admin/Finance/PayrollPeriodService.php | 20 ++ app/Services/Admin/HR/EmployeeService.php | 18 ++ app/Services/Admin/HR/LeaveRequestService.php | 14 + app/Services/Admin/Master/CategoryService.php | 10 + app/Services/Admin/Master/CustomerService.php | 10 + app/Services/Admin/Master/ProductService.php | 27 ++ app/Services/Admin/Master/SupplierService.php | 10 + app/Services/Admin/Settings/RoleService.php | 10 + resources/js/components/data-table.tsx | 262 +++++++++++++----- resources/js/layouts/settings/layout.tsx | 4 +- .../admin/finance/cash-account/index.tsx | 101 ++++++- .../admin/finance/employee-advance/index.tsx | 78 +++++- .../js/pages/admin/finance/expense/index.tsx | 71 ++++- .../admin/finance/payroll-period/index.tsx | 87 +++++- .../js/pages/admin/hr/employee/index.tsx | 102 ++++++- .../js/pages/admin/hr/leave-request/index.tsx | 103 ++++++- .../js/pages/admin/master/category/index.tsx | 87 +++++- .../js/pages/admin/master/customer/index.tsx | 87 +++++- .../js/pages/admin/master/product/index.tsx | 90 +++++- .../js/pages/admin/master/supplier/index.tsx | 87 +++++- resources/js/pages/admin/roles/index.tsx | 82 +++++- .../Feature/Admin/Finance/CashAccountTest.php | 39 ++- tests/Feature/Admin/Finance/ExpenseTest.php | 4 +- tests/Feature/Admin/HR/AttendanceTest.php | 30 +- tests/Feature/Admin/HR/EmployeeTest.php | 81 ++++-- tests/Feature/Admin/HR/LeaveRequestTest.php | 65 ++++- tests/Feature/Admin/Master/CategoryTest.php | 51 +++- tests/Feature/Admin/Master/CustomerTest.php | 51 +++- tests/Feature/Admin/Master/ProductTest.php | 33 ++- tests/Feature/Admin/Master/SupplierTest.php | 51 +++- tests/Feature/Admin/Settings/RoleTest.php | 20 +- 46 files changed, 1659 insertions(+), 284 deletions(-) create mode 100644 app/Http/Requests/PaginatedRequest.php diff --git a/app/Http/Controllers/Admin/Finance/CashAccountController.php b/app/Http/Controllers/Admin/Finance/CashAccountController.php index 020cdcc..35391ab 100644 --- a/app/Http/Controllers/Admin/Finance/CashAccountController.php +++ b/app/Http/Controllers/Admin/Finance/CashAccountController.php @@ -3,11 +3,11 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\CashTransactionRequest; use App\Models\CashTransaction; use App\Services\Admin\Finance\CashAccountService; use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -17,14 +17,15 @@ public function __construct( private CashAccountService $service ) {} - public function index(Request $request): Response + public function index(PaginatedRequest $request): Response { $cashAccount = $this->service->get(); return Inertia::render('admin/finance/cash-account/index', [ 'cashAccount' => $cashAccount, - 'transactions' => $this->service->getAllTransactions( - $request->only(['type']) + 'transactions' => $this->service->paginatedTransactions( + ...$request->validatedWithDefaults(), + filters: $request->only(['type']), ), 'filters' => $request->only(['type']), ]); diff --git a/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php b/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php index c7ce4a7..75ad0a7 100644 --- a/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php +++ b/app/Http/Controllers/Admin/Finance/EmployeeAdvanceController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\EmployeeAdvanceRequest; use App\Models\EmployeeAdvance; use App\Services\Admin\Finance\EmployeeAdvanceService; @@ -16,10 +17,10 @@ public function __construct( private EmployeeAdvanceService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/finance/employee-advance/index', [ - 'employeeAdvances' => $this->service->getAll(), + 'employeeAdvances' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/Finance/ExpenseController.php b/app/Http/Controllers/Admin/Finance/ExpenseController.php index 64f8ff4..478634c 100644 --- a/app/Http/Controllers/Admin/Finance/ExpenseController.php +++ b/app/Http/Controllers/Admin/Finance/ExpenseController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin\Finance; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Finance\ExpenseRequest; use App\Models\Expense; use App\Services\Admin\Finance\ExpenseService; @@ -16,10 +17,10 @@ public function __construct( private ExpenseService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/finance/expense/index', [ - 'expenses' => $this->service->getAll(), + 'expenses' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/Finance/PayrollPeriodController.php b/app/Http/Controllers/Admin/Finance/PayrollPeriodController.php index 90f581b..4e00b67 100644 --- a/app/Http/Controllers/Admin/Finance/PayrollPeriodController.php +++ b/app/Http/Controllers/Admin/Finance/PayrollPeriodController.php @@ -4,6 +4,7 @@ use App\Enums\PayrollPeriodStatus; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Models\PayrollPeriod; use App\Services\Admin\Finance\PayrollPeriodService; use Illuminate\Http\RedirectResponse; @@ -16,10 +17,10 @@ public function __construct( private PayrollPeriodService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/finance/payroll-period/index', [ - 'payrollPeriods' => $this->service->getAll(), + 'payrollPeriods' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/HR/EmployeeController.php b/app/Http/Controllers/Admin/HR/EmployeeController.php index 2744d1a..6b64a86 100644 --- a/app/Http/Controllers/Admin/HR/EmployeeController.php +++ b/app/Http/Controllers/Admin/HR/EmployeeController.php @@ -3,11 +3,11 @@ namespace App\Http\Controllers\Admin\HR; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\HR\EmployeeRequest; use App\Models\User; use App\Services\Admin\HR\EmployeeService; use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -17,10 +17,13 @@ public function __construct( private EmployeeService $service ) {} - public function index(Request $request): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/hr/employee/index', [ - 'employees' => $this->service->getAll($request->only(['employment_status', 'is_active', 'gender'])), + 'employees' => $this->service->paginated( + ...$request->validatedWithDefaults(), + filters: $request->only(['employment_status', 'is_active', 'gender']), + ), 'filters' => $request->only(['employment_status', 'is_active', 'gender']), ]); } diff --git a/app/Http/Controllers/Admin/HR/LeaveRequestController.php b/app/Http/Controllers/Admin/HR/LeaveRequestController.php index ebab12a..5fcb915 100644 --- a/app/Http/Controllers/Admin/HR/LeaveRequestController.php +++ b/app/Http/Controllers/Admin/HR/LeaveRequestController.php @@ -3,11 +3,11 @@ namespace App\Http\Controllers\Admin\HR; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\HR\LeaveRequestRequest; use App\Models\LeaveRequest; use App\Services\Admin\HR\LeaveRequestService; use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -17,11 +17,12 @@ public function __construct( private LeaveRequestService $service ) {} - public function index(Request $request): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/hr/leave-request/index', [ - 'leaveRequests' => $this->service->getAll( - $request->only(['status']) + 'leaveRequests' => $this->service->paginated( + ...$request->validatedWithDefaults(), + filters: $request->only(['status']), ), 'filters' => $request->only(['status']), ]); diff --git a/app/Http/Controllers/Admin/Master/CategoryController.php b/app/Http/Controllers/Admin/Master/CategoryController.php index 2d59475..bafb34a 100644 --- a/app/Http/Controllers/Admin/Master/CategoryController.php +++ b/app/Http/Controllers/Admin/Master/CategoryController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\CategoryRequest; use App\Models\Category; use App\Services\Admin\Master\CategoryService; @@ -16,10 +17,10 @@ public function __construct( private CategoryService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/master/category/index', [ - 'categories' => $this->service->getAll(), + 'categories' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/Master/CustomerController.php b/app/Http/Controllers/Admin/Master/CustomerController.php index d66ab79..bdb1576 100644 --- a/app/Http/Controllers/Admin/Master/CustomerController.php +++ b/app/Http/Controllers/Admin/Master/CustomerController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\CustomerRequest; use App\Models\Customer; use App\Services\Admin\Master\CustomerService; @@ -16,10 +17,10 @@ public function __construct( private CustomerService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/master/customer/index', [ - 'customers' => $this->service->getAll(), + 'customers' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/Master/ProductController.php b/app/Http/Controllers/Admin/Master/ProductController.php index 4cb86b5..f4d89d8 100644 --- a/app/Http/Controllers/Admin/Master/ProductController.php +++ b/app/Http/Controllers/Admin/Master/ProductController.php @@ -4,12 +4,12 @@ use App\Enums\ProductStatus; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\ProductRequest; use App\Models\Product; use App\Services\Admin\Master\CategoryService; use App\Services\Admin\Master\ProductService; use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -20,11 +20,14 @@ public function __construct( private CategoryService $categoryService, ) {} - public function index(Request $request): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/master/product/index', [ - 'products' => $this->service->getAll($request->only(['status', 'name'])), - 'filters' => $request->only(['status', 'name']), + 'products' => $this->service->paginated( + ...$request->validatedWithDefaults(), + filters: $request->only(['status']), + ), + 'filters' => $request->only(['status']), ]); } diff --git a/app/Http/Controllers/Admin/Master/SupplierController.php b/app/Http/Controllers/Admin/Master/SupplierController.php index 9f70e26..b638c4a 100644 --- a/app/Http/Controllers/Admin/Master/SupplierController.php +++ b/app/Http/Controllers/Admin/Master/SupplierController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin\Master; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\Master\SupplierRequest; use App\Models\Supplier; use App\Services\Admin\Master\SupplierService; @@ -16,10 +17,10 @@ public function __construct( private SupplierService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/master/supplier/index', [ - 'suppliers' => $this->service->getAll(), + 'suppliers' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Controllers/Admin/RoleController.php b/app/Http/Controllers/Admin/RoleController.php index a4fe56c..bf57541 100644 --- a/app/Http/Controllers/Admin/RoleController.php +++ b/app/Http/Controllers/Admin/RoleController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; +use App\Http\Requests\PaginatedRequest; use App\Http\Requests\Admin\RoleRequest; use App\Services\Admin\Settings\RoleService; use Illuminate\Http\RedirectResponse; @@ -16,10 +17,10 @@ public function __construct( private RoleService $service ) {} - public function index(): Response + public function index(PaginatedRequest $request): Response { return Inertia::render('admin/roles/index', [ - 'roles' => $this->service->getAll(), + 'roles' => $this->service->paginated(...$request->validatedWithDefaults()), ]); } diff --git a/app/Http/Requests/PaginatedRequest.php b/app/Http/Requests/PaginatedRequest.php new file mode 100644 index 0000000..931d442 --- /dev/null +++ b/app/Http/Requests/PaginatedRequest.php @@ -0,0 +1,35 @@ + 'nullable|integer|in:25,50,100,999999', + 'search' => 'nullable|string|max:255', + 'sort' => 'nullable|string', + 'direction' => 'nullable|string|in:asc,desc', + ]; + } + + public function validatedWithDefaults(): array + { + $validated = $this->validated(); + + return [ + 'perPage' => $validated['per_page'] ?? 25, + 'search' => $validated['search'] ?? '', + 'sort' => $validated['sort'] ?? 'created_at', + 'direction' => $validated['direction'] ?? 'desc', + ]; + } +} diff --git a/app/Services/Admin/Finance/CashAccountService.php b/app/Services/Admin/Finance/CashAccountService.php index c7c7107..2e64a6d 100644 --- a/app/Services/Admin/Finance/CashAccountService.php +++ b/app/Services/Admin/Finance/CashAccountService.php @@ -6,6 +6,7 @@ use App\Models\CashAccount; use App\Models\CashTransaction; use App\Services\S3PresignedService; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; @@ -42,6 +43,29 @@ public function getAllTransactions(array $filters = []): Collection ->map(fn (CashTransaction $transaction) => $this->formatTransaction($transaction)); } + public function paginatedTransactions(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator + { + $cashAccount = $this->get(); + + if (! $cashAccount) { + return new \Illuminate\Pagination\LengthAwarePaginator(collect(), 0, $perPage); + } + + $paginator = $cashAccount->cashTransactions() + ->select('id', 'created_by_id', 'reference_type', 'reference_id', 'amount', 'balance_after', 'type', 'description', 'created_at') + ->with('createdBy.userProfile', 'media') + ->when($search, fn ($q) => $q->where('description', 'like', "%{$search}%")) + ->when($filters['type'] ?? null, function ($query, $type) { + $query->where('type', $type); + }) + ->orderBy($sort, $direction) + ->paginate($perPage); + + $paginator->getCollection()->map(fn (CashTransaction $transaction) => $this->formatTransaction($transaction)); + + return $paginator; + } + private function formatTransaction(CashTransaction $transaction): array { $media = $transaction->getFirstMedia('receipts'); diff --git a/app/Services/Admin/Finance/EmployeeAdvanceService.php b/app/Services/Admin/Finance/EmployeeAdvanceService.php index df8906a..9c786c0 100644 --- a/app/Services/Admin/Finance/EmployeeAdvanceService.php +++ b/app/Services/Admin/Finance/EmployeeAdvanceService.php @@ -7,6 +7,7 @@ use App\Models\CashAccount; use App\Models\CashTransaction; use App\Models\EmployeeAdvance; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Validation\ValidationException; @@ -21,6 +22,16 @@ public function getAll(): Collection ->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return EmployeeAdvance::query() + ->select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at') + ->with(['employee.user.userProfile']) + ->when($search, fn ($q) => $q->where('description', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function create(array $data): EmployeeAdvance { return DB::transaction(function () use ($data) { diff --git a/app/Services/Admin/Finance/ExpenseService.php b/app/Services/Admin/Finance/ExpenseService.php index 132a678..0d2004b 100644 --- a/app/Services/Admin/Finance/ExpenseService.php +++ b/app/Services/Admin/Finance/ExpenseService.php @@ -7,6 +7,7 @@ use App\Models\CashTransaction; use App\Models\Expense; use App\Services\S3PresignedService; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; @@ -29,6 +30,20 @@ public function getAll(): Collection ->map(fn (Expense $expense) => $this->formatExpense($expense)); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + $paginator = Expense::query() + ->select('id', 'created_by_id', 'amount', 'description', 'created_at') + ->with('createdBy.userProfile', 'media') + ->when($search, fn ($q) => $q->where('description', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + + $paginator->getCollection()->map(fn (Expense $expense) => $this->formatExpense($expense)); + + return $paginator; + } + private function formatExpense(Expense $expense): array { $media = $expense->getFirstMedia('receipts'); diff --git a/app/Services/Admin/Finance/PayrollPeriodService.php b/app/Services/Admin/Finance/PayrollPeriodService.php index 6fdf247..2507ca6 100644 --- a/app/Services/Admin/Finance/PayrollPeriodService.php +++ b/app/Services/Admin/Finance/PayrollPeriodService.php @@ -9,6 +9,7 @@ use App\Models\CashTransaction; use App\Models\Payroll; use App\Models\PayrollPeriod; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Validation\ValidationException; @@ -33,6 +34,25 @@ public function getAll(): Collection ->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return PayrollPeriod::query() + ->select('id', 'year', 'month', 'status', 'closed_at', 'created_at') + ->withCount('payrolls') + ->withSum('payrolls', 'total_amount') + ->withSum('payrolls', 'bonus_amount') + ->withSum('payrolls', 'deduction_amount') + ->withCount(['payrolls as paid_count' => function ($q) { + $q->paid(); + }]) + ->withCount(['payrolls as cancelled_count' => function ($q) { + $q->cancelled(); + }]) + ->when($search, fn ($q) => $q->where('year', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function getDetail(PayrollPeriod $period): PayrollPeriod { return $period->load([ diff --git a/app/Services/Admin/HR/EmployeeService.php b/app/Services/Admin/HR/EmployeeService.php index f48c2d5..8151307 100644 --- a/app/Services/Admin/HR/EmployeeService.php +++ b/app/Services/Admin/HR/EmployeeService.php @@ -3,6 +3,7 @@ namespace App\Services\Admin\HR; use App\Models\User; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\DB; @@ -23,6 +24,23 @@ public function getAll(array $filters = []): Collection ->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator + { + return User::query() + ->select('id', 'email', 'username', 'is_active') + ->whereHas('employee') + ->with([ + 'userProfile' => fn ($q) => $q->select('id', 'user_id', 'full_name', 'phone_number', 'gender'), + 'employee' => fn ($q) => $q->select('id', 'user_id', 'join_date', 'employment_status', 'base_salary'), + ]) + ->when($search, fn ($q) => $q->whereHas('userProfile', fn ($uq) => $uq->where('full_name', 'like', "%{$search}%"))) + ->when($filters['employment_status'] ?? null, fn ($q, $status) => $q->whereHas('employee', fn ($eq) => $eq->where('employment_status', $status))) + ->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn ($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN))) + ->when($filters['gender'] ?? null, fn ($q, $gender) => $q->whereHas('userProfile', fn ($uq) => $uq->where('gender', $gender))) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function getById(int $id): User { return User::with(['userProfile', 'employee'])->findOrFail($id); diff --git a/app/Services/Admin/HR/LeaveRequestService.php b/app/Services/Admin/HR/LeaveRequestService.php index b731f58..6f8bb27 100644 --- a/app/Services/Admin/HR/LeaveRequestService.php +++ b/app/Services/Admin/HR/LeaveRequestService.php @@ -5,6 +5,7 @@ use App\Enums\LeaveRequestStatus; use App\Models\LeaveRequest; use Carbon\Carbon; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; @@ -21,6 +22,19 @@ public function getAll(array $filters = []): Collection ->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator + { + return LeaveRequest::query() + ->select('id', 'employee_id', 'start_date', 'end_date', 'total_days', 'status', 'created_at') + ->with(['employee.user.userProfile']) + ->when($search, fn ($q) => $q->whereHas('employee.user.userProfile', fn ($uq) => $uq->where('full_name', 'like', "%{$search}%"))) + ->when($filters['status'] ?? null, function ($query, $status) { + $query->where('status', $status); + }) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function create(array $data): LeaveRequest { return DB::transaction(function () use ($data) { diff --git a/app/Services/Admin/Master/CategoryService.php b/app/Services/Admin/Master/CategoryService.php index eea4da3..b6af156 100644 --- a/app/Services/Admin/Master/CategoryService.php +++ b/app/Services/Admin/Master/CategoryService.php @@ -3,6 +3,7 @@ namespace App\Services\Admin\Master; use App\Models\Category; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; class CategoryService @@ -12,6 +13,15 @@ public function getAll(): Collection return Category::select('id', 'name')->latest()->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return Category::query() + ->select('id', 'name') + ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function create(array $data): Category { return Category::create($data); diff --git a/app/Services/Admin/Master/CustomerService.php b/app/Services/Admin/Master/CustomerService.php index 4b5fa95..f66db3f 100644 --- a/app/Services/Admin/Master/CustomerService.php +++ b/app/Services/Admin/Master/CustomerService.php @@ -3,6 +3,7 @@ namespace App\Services\Admin\Master; use App\Models\Customer; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; class CustomerService @@ -12,6 +13,15 @@ public function getAll(): Collection return Customer::select('id', 'name', 'phone_number', 'address')->latest()->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return Customer::query() + ->select('id', 'name', 'phone_number', 'address') + ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function create(array $data): Customer { return Customer::create($data); diff --git a/app/Services/Admin/Master/ProductService.php b/app/Services/Admin/Master/ProductService.php index 2459f58..47d5616 100644 --- a/app/Services/Admin/Master/ProductService.php +++ b/app/Services/Admin/Master/ProductService.php @@ -7,6 +7,7 @@ use App\Models\ProductVariant; use App\Models\ProductPrice; use App\Services\S3PresignedService; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; @@ -44,6 +45,32 @@ public function getAll(array $filters = []): Collection return $products; } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator + { + $paginator = Product::query() + ->select('id', 'name', 'slug', 'description', 'status') + ->with([ + 'categories:id,name', + 'productVariants:id,product_id,name,stock,reject_stock,retail_stock', + 'productVariants.productPrices:id,variant_id,type,price', + ]) + ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->when($filters['status'] ?? null, fn ($q, $status) => $q->where('status', $status)) + ->orderBy($sort, $direction) + ->paginate($perPage); + + $paginator->getCollection()->each(function ($product) { + $product->productVariants->each(function ($variant) { + $media = $variant->getMedia('photos')->first(); + $variant->photo_url = $media + ? $this->s3Service->getTemporaryUrl($media->file_name) + : null; + }); + }); + + return $paginator; + } + public function create(array $data): Product { return DB::transaction(function () use ($data) { diff --git a/app/Services/Admin/Master/SupplierService.php b/app/Services/Admin/Master/SupplierService.php index 492b2bb..0dc2f3f 100644 --- a/app/Services/Admin/Master/SupplierService.php +++ b/app/Services/Admin/Master/SupplierService.php @@ -3,6 +3,7 @@ namespace App\Services\Admin\Master; use App\Models\Supplier; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; class SupplierService @@ -12,6 +13,15 @@ public function getAll(): Collection return Supplier::select('id', 'name', 'phone_number', 'address')->latest()->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return Supplier::query() + ->select('id', 'name', 'phone_number', 'address') + ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function create(array $data): Supplier { return Supplier::create($data); diff --git a/app/Services/Admin/Settings/RoleService.php b/app/Services/Admin/Settings/RoleService.php index 57bf0b9..f074430 100644 --- a/app/Services/Admin/Settings/RoleService.php +++ b/app/Services/Admin/Settings/RoleService.php @@ -2,6 +2,7 @@ namespace App\Services\Admin\Settings; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Spatie\Permission\Models\Permission; @@ -14,6 +15,15 @@ public function getAll(): Collection return Role::withCount('permissions')->get(); } + public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator + { + return Role::query() + ->withCount('permissions') + ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->orderBy($sort, $direction) + ->paginate($perPage); + } + public function getById(int $id): Role { return Role::with('permissions')->findOrFail($id); diff --git a/resources/js/components/data-table.tsx b/resources/js/components/data-table.tsx index 825ef69..76c73f4 100644 --- a/resources/js/components/data-table.tsx +++ b/resources/js/components/data-table.tsx @@ -1,35 +1,37 @@ +import type { DragEndEvent } from '@dnd-kit/core'; import { DndContext, - KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; -import type { DragEndEvent } from '@dnd-kit/core'; import { SortableContext, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; +import type { ColumnDef, ExpandedState, Row } from '@tanstack/react-table'; import { flexRender, getCoreRowModel, getExpandedRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, useReactTable } from '@tanstack/react-table'; -import type { ColumnDef, ColumnFiltersState, ExpandedState, SortingState, Row } from '@tanstack/react-table'; -import { GripVertical } from 'lucide-react'; -import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react'; +import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, GripVertical } from 'lucide-react'; import * as React from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; import { Table, TableBody, @@ -39,6 +41,18 @@ import { TableRow, } from '@/components/ui/table'; +export interface PaginationState { + current_page: number; + last_page: number; + per_page: number; + total: number; +} + +export interface SortState { + column: string; + direction: 'asc' | 'desc'; +} + interface DataTableProps { columns: ColumnDef[]; data: TData[]; @@ -50,6 +64,13 @@ interface DataTableProps { toolbar?: React.ReactNode; renderSubRow?: (row: Row, searchValue?: string) => React.ReactNode; defaultExpanded?: boolean; + pagination?: PaginationState; + onPageChange?: (page: number) => void; + onPerPageChange?: (perPage: number) => void; + onSearchChange?: (search: string) => void; + onSortChange?: (column: string, direction: 'asc' | 'desc') => void; + currentSort?: SortState; + searchValue?: string; } const DragHandleContext = React.createContext<{ @@ -108,6 +129,23 @@ function SortableTableRow({ ); } +function useDebounce(callback: (value: string) => void, delay: number) { + const timeoutRef = React.useRef | null>(null); + + return React.useCallback( + (value: string) => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + timeoutRef.current = setTimeout(() => { + callback(value); + }, delay); + }, + [callback, delay], + ); +} + export function DataTable({ columns, data, @@ -119,21 +157,41 @@ export function DataTable({ toolbar, renderSubRow, defaultExpanded = false, + pagination, + onPageChange, + onPerPageChange, + onSearchChange, + onSortChange, + currentSort, + searchValue, }: DataTableProps) { - const [sorting, setSorting] = React.useState([]); - const [columnFilters, setColumnFilters] = - React.useState([]); const [expanded, setExpanded] = React.useState(() => { - if (!defaultExpanded || !data.length) return {}; + if (!defaultExpanded || !data.length) { +return {}; +} + const initial: Record = {}; data.forEach((item, index) => { initial[String(index)] = true; }); + return initial; }); + const [localSearch, setLocalSearch] = React.useState(searchValue ?? ''); + + React.useEffect(() => { + setLocalSearch(searchValue ?? ''); + }, [searchValue]); + + const isServerMode = !!pagination && !!onPageChange; const isSortable = !!onReorder && !!getRowId; + const handleSearchDebounced = useDebounce( + (value: string) => onSearchChange?.(value), + 300, + ); + const visibleColumns = isSortable ? [ { @@ -160,16 +218,9 @@ export function DataTable({ data, columns: visibleColumns, getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), getExpandedRowModel: renderSubRow ? getExpandedRowModel() : undefined, onExpandedChange: setExpanded, - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), state: { - sorting, - columnFilters, expanded, }, }); @@ -200,27 +251,60 @@ export function DataTable({ onReorder?.(reordered); } + function handleSearchChange(value: string) { + setLocalSearch(value); + + if (isServerMode) { + handleSearchDebounced(value); + } + } + + function handleSort(columnId: string) { + if (!onSortChange) { +return; +} + + const newDirection = + currentSort?.column === columnId && currentSort?.direction === 'asc' + ? 'desc' + : 'asc'; + onSortChange(columnId, newDirection); + } + + const totalPages = pagination?.last_page ?? 1; + const currentPage = pagination?.current_page ?? 1; + return ( <> - {(searchKey || toolbar) && ( + {(searchKey || toolbar || isServerMode) && (
{searchKey && ( - table - .getColumn(searchKey) - ?.setFilterValue(event.target.value) - } + value={localSearch} + onChange={(event) => handleSearchChange(event.target.value)} className="max-w-sm" /> )} {toolbar} +
+ {isServerMode && onPerPageChange && ( + + )} +
)} @@ -352,7 +436,7 @@ export function DataTable({ className="bg-muted/50 p-0" >
- {renderSubRow(row, (table.getColumn(searchKey ?? '')?.getFilterValue() as string) ?? '')} + {renderSubRow(row, localSearch)}
@@ -375,44 +459,84 @@ export function DataTable({
-
-
- Halaman {table.getState().pagination.pageIndex + 1} dari{' '} - {table.getPageCount()} -
-
- - - - +
+ + {isServerMode + ? `Halaman ${currentPage} dari ${totalPages}` + : `Halaman ${table.getState().pagination.pageIndex + 1} dari ${table.getPageCount()}`} + +
+ {isServerMode ? ( + <> + + + + + + ) : ( + <> + + + + + + )}
diff --git a/resources/js/layouts/settings/layout.tsx b/resources/js/layouts/settings/layout.tsx index db3d07c..aaa93ae 100644 --- a/resources/js/layouts/settings/layout.tsx +++ b/resources/js/layouts/settings/layout.tsx @@ -1,3 +1,5 @@ +import { Link } from '@inertiajs/react'; +import type { PropsWithChildren } from 'react'; import Heading from '@/components/heading'; import { Button } from '@/components/ui/button'; import { Separator } from '@/components/ui/separator'; @@ -8,8 +10,6 @@ import { edit as editPermissions } from '@/routes/permissions'; import { edit } from '@/routes/profile'; import { edit as editSecurity } from '@/routes/security'; import type { NavItem } from '@/types'; -import { Link } from '@inertiajs/react'; -import type { PropsWithChildren } from 'react'; const sidebarNavItems: NavItem[] = [ { diff --git a/resources/js/pages/admin/finance/cash-account/index.tsx b/resources/js/pages/admin/finance/cash-account/index.tsx index 53dd897..7e943ac 100644 --- a/resources/js/pages/admin/finance/cash-account/index.tsx +++ b/resources/js/pages/admin/finance/cash-account/index.tsx @@ -1,8 +1,9 @@ import { Form, Head, router } from '@inertiajs/react'; import { ArrowDownToLine, ArrowUpFromLine, Filter, Wallet, X } from 'lucide-react'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; import { FileUpload } from '@/components/file-upload'; import InputError from '@/components/input-error'; import { RupiahInput } from '@/components/rupiah-input'; @@ -33,7 +34,13 @@ type CashAccount = { type Props = { cashAccount: CashAccount | null; - transactions: CashTransaction[]; + transactions: { + data: CashTransaction[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; filters: { type?: string; }; @@ -58,6 +65,16 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: const [editUploading, setEditUploading] = useState(false); const [editFileMeta, setEditFileMeta] = useState<{ size: number; type: string } | null>(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: transactions.current_page, + last_page: transactions.last_page, + per_page: transactions.per_page, + total: transactions.total, + }; + const hasActiveFilters = filters.type; function applyFilter(key: string, value: string) { @@ -69,17 +86,24 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: newFilters[key as keyof typeof newFilters] = value; } - router.get(cashAccountIndex(), newFilters, { - preserveState: true, - replace: true, - }); + router.get(cashAccountIndex(), { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); } function clearFilters() { - router.get(cashAccountIndex(), {}, { - preserveState: true, - replace: true, - }); + router.get(cashAccountIndex(), { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); setFilterOpen(false); } @@ -93,6 +117,52 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: }); } + function handlePageChange(page: number) { + router.get(cashAccountIndex(), { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(cashAccountIndex(), { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(cashAccountIndex(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort, filters]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(cashAccountIndex(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } + const columns = createTransactionColumns({ handleEdit: (transaction) => { setEditing(transaction); @@ -195,15 +265,23 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: { setDepositOpen(open); + if (!open) { setDepositReceiptKey(null); setDepositFileMeta(null); @@ -273,6 +351,7 @@ export default function CashAccountIndex({ cashAccount, transactions, filters }: { setWithdrawalOpen(open); + if (!open) { setWithdrawalReceiptKey(null); setWithdrawalFileMeta(null); diff --git a/resources/js/pages/admin/finance/employee-advance/index.tsx b/resources/js/pages/admin/finance/employee-advance/index.tsx index 4b57af0..5ea28a7 100644 --- a/resources/js/pages/admin/finance/employee-advance/index.tsx +++ b/resources/js/pages/admin/finance/employee-advance/index.tsx @@ -1,9 +1,12 @@ import { Form, Head, router } from '@inertiajs/react'; import { Plus } from 'lucide-react'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { ConfirmDialog } from '@/components/confirm-dialog'; +import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; +import { DatePicker } from '@/components/date-picker'; import InputError from '@/components/input-error'; import { RupiahInput } from '@/components/rupiah-input'; -import { DatePicker } from '@/components/date-picker'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -17,11 +20,15 @@ import { Label } from '@/components/ui/label'; import { destroy, index as employeeAdvanceIndex, store, update, approve, pay } from '@/routes/admin/finance/employee-advances'; import { createEmployeeAdvanceColumns } from './columns'; import type { EmployeeAdvance } from './columns'; -import { ConfirmDialog } from '@/components/confirm-dialog'; -import { DataTable } from '@/components/data-table'; type Props = { - employeeAdvances: EmployeeAdvance[]; + employeeAdvances: { + data: EmployeeAdvance[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; }; export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { @@ -32,6 +39,15 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { const [paying, setPaying] = useState(null); const [dueDate, setDueDate] = useState(undefined); const [editingDueDate, setEditingDueDate] = useState(undefined); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: employeeAdvances.current_page, + last_page: employeeAdvances.last_page, + per_page: employeeAdvances.per_page, + total: employeeAdvances.total, + }; useEffect(() => { if (editing) { @@ -71,6 +87,48 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { }); } + function handlePageChange(page: number) { + router.get(employeeAdvanceIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(employeeAdvanceIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(employeeAdvanceIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(employeeAdvanceIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } + const columns = createEmployeeAdvanceColumns({ handleEdit: (employeeAdvance) => setEditing(employeeAdvance), handleDeleteClick: (employeeAdvance) => setDeleting(employeeAdvance), @@ -91,6 +149,7 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) {
{ setCreateOpen(open); + if (!open) { setDueDate(undefined); } @@ -173,10 +232,17 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) { (null); const [editFileMeta, setEditFileMeta] = useState<{ size: number; type: string } | null>(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: expenses.current_page, + last_page: expenses.last_page, + per_page: expenses.per_page, + total: expenses.total, + }; + + function handlePageChange(page: number) { + router.get(expenseIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(expenseIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(expenseIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(expenseIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } function handleDelete() { if (!deleting) { @@ -157,10 +215,17 @@ export default function ExpenseIndex({ expenses }: Props) { (null); const [reopening, setReopening] = useState(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: payrollPeriods.current_page, + last_page: payrollPeriods.last_page, + per_page: payrollPeriods.per_page, + total: payrollPeriods.total, + }; function handleClose() { - if (!closing) return; + if (!closing) { +return; +} router.post(close(closing.id), {}, { onSuccess: () => setClosing(null), @@ -38,13 +56,57 @@ export default function PayrollPeriodIndex({ payrollPeriods }: Props) { } function handleReopen() { - if (!reopening) return; + if (!reopening) { +return; +} router.post(reopen(reopening.id), {}, { onSuccess: () => setReopening(null), }); } + function handlePageChange(page: number) { + router.get(payrollPeriodsIndex(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(payrollPeriodsIndex(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(payrollPeriodsIndex(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(payrollPeriodsIndex(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } + const columns = createPayrollPeriodColumns({ showUrl: (id) => payrollPeriodShow(id).url, handleClose: (period) => setClosing(period), @@ -66,16 +128,25 @@ export default function PayrollPeriodIndex({ payrollPeriods }: Props) { { - if (!open) setClosing(null); + if (!open) { +setClosing(null); +} }} title="Tutup Periode Gaji" description={`Apakah Anda yakin ingin menutup periode gaji ${closing ? `${MONTH_NAMES[closing.month]} ${closing.year}` : ''}? Semua gaji harus sudah dibayar sebelum periode ditutup.`} @@ -86,7 +157,9 @@ export default function PayrollPeriodIndex({ payrollPeriods }: Props) { { - if (!open) setReopening(null); + if (!open) { +setReopening(null); +} }} title="Buka Periode Gaji" description={`Apakah Anda yakin ingin membuka kembali periode gaji ${reopening ? `${MONTH_NAMES[reopening.month]} ${reopening.year}` : ''}?`} diff --git a/resources/js/pages/admin/hr/employee/index.tsx b/resources/js/pages/admin/hr/employee/index.tsx index f5b98d3..25402ea 100644 --- a/resources/js/pages/admin/hr/employee/index.tsx +++ b/resources/js/pages/admin/hr/employee/index.tsx @@ -1,17 +1,24 @@ +import { Head, router } from '@inertiajs/react'; +import { Filter, Plus, X } from 'lucide-react'; +import { useCallback, useState } from 'react'; import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; import { Button } from '@/components/ui/button'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; 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 { Filter, Plus, X } from 'lucide-react'; -import { useState } from 'react'; import type { Employee } from './columns'; import { createEmployeeColumns } from './columns'; type Props = { - employees: Employee[]; + employees: { + data: Employee[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; filters: { employment_status?: string; is_active?: string; @@ -23,6 +30,15 @@ export default function EmployeeIndex({ employees, filters }: Props) { const [deleting, setDeleting] = useState(null); const [resetPasswordTarget, setResetPasswordTarget] = useState(null); const [filterOpen, setFilterOpen] = useState(false); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: employees.current_page, + last_page: employees.last_page, + per_page: employees.per_page, + total: employees.total, + }; const hasActiveFilters = filters.employment_status || filters.is_active; @@ -35,20 +51,73 @@ export default function EmployeeIndex({ employees, filters }: Props) { newFilters[key as keyof typeof newFilters] = value; } - router.get(employeeIndex.url(), newFilters, { - preserveState: true, - replace: true, - }); + router.get(employeeIndex.url(), { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); } function clearFilters() { - router.get(employeeIndex.url(), {}, { - preserveState: true, - replace: true, - }); + router.get(employeeIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); setFilterOpen(false); } + function handlePageChange(page: number) { + router.get(employeeIndex.url(), { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(employeeIndex.url(), { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(employeeIndex.url(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort, filters]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(employeeIndex.url(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } + function handleDelete() { if (!deleting) { return; @@ -193,10 +262,17 @@ export default function EmployeeIndex({ employees, filters }: Props) { diff --git a/resources/js/pages/admin/hr/leave-request/index.tsx b/resources/js/pages/admin/hr/leave-request/index.tsx index 26ced49..1bccb5c 100644 --- a/resources/js/pages/admin/hr/leave-request/index.tsx +++ b/resources/js/pages/admin/hr/leave-request/index.tsx @@ -1,5 +1,9 @@ +import { Form, Head, router } from '@inertiajs/react'; +import { Filter, Plus, X } from 'lucide-react'; +import { useCallback, useEffect, useState } from 'react'; import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; import { DatePicker } from '@/components/date-picker'; import InputError from '@/components/input-error'; import { Button } from '@/components/ui/button'; @@ -14,14 +18,17 @@ import { Label } from '@/components/ui/label'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { approve, destroy, index as leaveRequestIndex, reject, store, update } from '@/routes/admin/hr/leave-requests'; -import { Form, Head, router } from '@inertiajs/react'; -import { Filter, Plus, X } from 'lucide-react'; -import { useEffect, useState } from 'react'; import type { LeaveRequest } from './columns'; import { createLeaveRequestColumns } from './columns'; type Props = { - leaveRequests: LeaveRequest[]; + leaveRequests: { + data: LeaveRequest[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; filters: { status?: string; }; @@ -38,6 +45,15 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { const [editingStartDate, setEditingStartDate] = useState(undefined); const [editingEndDate, setEditingEndDate] = useState(undefined); const [filterOpen, setFilterOpen] = useState(false); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: leaveRequests.current_page, + last_page: leaveRequests.last_page, + per_page: leaveRequests.per_page, + total: leaveRequests.total, + }; const hasActiveFilters = filters.status; @@ -60,17 +76,24 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { newFilters[key as keyof typeof newFilters] = value; } - router.get(leaveRequestIndex(), newFilters, { - preserveState: true, - replace: true, - }); + router.get(leaveRequestIndex(), { + ...newFilters, + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); } function clearFilters() { - router.get(leaveRequestIndex(), {}, { - preserveState: true, - replace: true, - }); + router.get(leaveRequestIndex(), { + page: 1, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); setFilterOpen(false); } @@ -104,6 +127,52 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { }); } + function handlePageChange(page: number) { + router.get(leaveRequestIndex(), { + ...filters, + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(leaveRequestIndex(), { + ...filters, + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(leaveRequestIndex(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort, filters]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(leaveRequestIndex(), { + ...filters, + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } + const columns = createLeaveRequestColumns({ handleEdit: (leaveRequest) => setEditing(leaveRequest), handleDeleteClick: (leaveRequest) => setDeleting(leaveRequest), @@ -179,6 +248,7 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) {
{ setCreateOpen(open); + if (!open) { setStartDate(undefined); setEndDate(undefined); @@ -257,10 +327,17 @@ export default function LeaveRequestIndex({ leaveRequests, filters }: Props) { diff --git a/resources/js/pages/admin/master/category/index.tsx b/resources/js/pages/admin/master/category/index.tsx index 925331a..28ff069 100644 --- a/resources/js/pages/admin/master/category/index.tsx +++ b/resources/js/pages/admin/master/category/index.tsx @@ -1,6 +1,9 @@ import { Form, Head, router } from '@inertiajs/react'; import { Plus } from 'lucide-react'; -import { useState } from 'react'; +import { useCallback, useState } from 'react'; +import { ConfirmDialog } from '@/components/confirm-dialog'; +import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; import InputError from '@/components/input-error'; import { Button } from '@/components/ui/button'; import { @@ -15,17 +18,84 @@ import { Label } from '@/components/ui/label'; import { destroy, index as categoryIndex, store, update } from '@/routes/admin/master/categories'; import { createCategoryColumns } from './columns'; import type { Category } from './columns'; -import { ConfirmDialog } from '@/components/confirm-dialog'; -import { DataTable } from '@/components/data-table'; type Props = { - categories: Category[]; + categories: { + data: Category[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; }; export default function CategoryIndex({ categories }: Props) { const [createOpen, setCreateOpen] = useState(false); const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: categories.current_page, + last_page: categories.last_page, + per_page: categories.per_page, + total: categories.total, + }; + + function handlePageChange(page: number) { + router.get(categoryIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + function handlePerPageChange(perPage: number) { + router.get(categoryIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(categoryIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(categoryIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { + preserveState: true, + replace: true, + }); + } function handleDelete() { if (!deleting) { @@ -112,10 +182,17 @@ export default function CategoryIndex({ categories }: Props) { (null); const [deleting, setDeleting] = useState(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: customers.current_page, + last_page: customers.last_page, + per_page: customers.per_page, + total: customers.total, + }; + + function handlePageChange(page: number) { + router.get(customerIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + function handlePerPageChange(perPage: number) { + router.get(customerIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(customerIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(customerIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { + preserveState: true, + replace: true, + }); + } function handleDelete() { if (!deleting) { @@ -131,10 +201,17 @@ export default function CustomerIndex({ customers }: Props) { ; searchValue?: export default function ProductIndex({ products, filters }: Props) { const [deleting, setDeleting] = useState(null); const [filterOpen, setFilterOpen] = useState(false); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); const hasActiveFilters = filters.status || filters.name; + const pagination: PaginationState = { + current_page: products.current_page, + last_page: products.last_page, + per_page: products.per_page, + total: products.total, + }; + const productNames = useMemo(() => { - const names = products.map((p) => p.name); + const names = products.data.map((p) => p.name); + return [...new Set(names)].sort(); - }, [products]); + }, [products.data]); function applyFilter(key: string, value: string) { const newFilters = { ...filters }; @@ -165,6 +182,52 @@ export default function ProductIndex({ products, filters }: Props) { setFilterOpen(false); } + function handlePageChange(page: number) { + router.get(productIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + ...filters, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(productIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + ...filters, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(productIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + ...filters, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort, filters]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(productIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + ...filters, + }, { preserveState: true, replace: true }); + } + function handleDelete() { if (!deleting) { return; @@ -280,10 +343,17 @@ export default function ProductIndex({ products, filters }: Props) { } defaultExpanded toolbar={filterToolbar} diff --git a/resources/js/pages/admin/master/supplier/index.tsx b/resources/js/pages/admin/master/supplier/index.tsx index ab25dd9..3b86a44 100644 --- a/resources/js/pages/admin/master/supplier/index.tsx +++ b/resources/js/pages/admin/master/supplier/index.tsx @@ -1,5 +1,9 @@ +import { Form, Head, router } from '@inertiajs/react'; +import { Plus } from 'lucide-react'; +import { useCallback, useState } from 'react'; import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; +import type { PaginationState, SortState } from '@/components/data-table'; import InputError from '@/components/input-error'; import { PhoneNumberInput } from '@/components/phone-number-input'; import { Button } from '@/components/ui/button'; @@ -13,20 +17,86 @@ import { import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { destroy, store, index as supplierIndex, update } from '@/routes/admin/master/suppliers'; -import { Form, Head, router } from '@inertiajs/react'; -import { Plus } from 'lucide-react'; -import { useState } from 'react'; import type { Supplier } from './columns'; import { createSupplierColumns } from './columns'; type Props = { - suppliers: Supplier[]; + suppliers: { + data: Supplier[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + }; }; export default function SupplierIndex({ suppliers }: Props) { const [createOpen, setCreateOpen] = useState(false); const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: suppliers.current_page, + last_page: suppliers.last_page, + per_page: suppliers.per_page, + total: suppliers.total, + }; + + function handlePageChange(page: number) { + router.get(supplierIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + function handlePerPageChange(perPage: number) { + router.get(supplierIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(supplierIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { + preserveState: true, + replace: true, + }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(supplierIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { + preserveState: true, + replace: true, + }); + } function handleDelete() { if (!deleting) { @@ -131,10 +201,17 @@ export default function SupplierIndex({ suppliers }: Props) { (null); + const [search, setSearch] = useState(''); + const [sort, setSort] = useState({ column: 'created_at', direction: 'desc' }); + + const pagination: PaginationState = { + current_page: roles.current_page, + last_page: roles.last_page, + per_page: roles.per_page, + total: roles.total, + }; + + function handlePageChange(page: number) { + router.get(rolesIndex.url(), { + page, + per_page: pagination.per_page, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + function handlePerPageChange(perPage: number) { + router.get(rolesIndex.url(), { + page: 1, + per_page: perPage, + search, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + } + + const handleSearchChange = useCallback((value: string) => { + setSearch(value); + router.get(rolesIndex.url(), { + page: 1, + per_page: pagination.per_page, + search: value, + sort: sort.column, + direction: sort.direction, + }, { preserveState: true, replace: true }); + }, [pagination.per_page, sort]); + + function handleSortChange(column: string, direction: 'asc' | 'desc') { + setSort({ column, direction }); + router.get(rolesIndex.url(), { + page: 1, + per_page: pagination.per_page, + search, + sort: column, + direction, + }, { preserveState: true, replace: true }); + } function handleDelete() { if (!deleting) { @@ -52,10 +111,17 @@ export default function RoleIndex({ roles }: Props) { assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') ->has('cashAccount') - ->has('transactions') + ->has('transactions.data') + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -57,7 +59,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 0) + ->has('transactions.data', 0) + ->where('transactions.total', 0) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -118,7 +123,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 2) + ->has('transactions.data', 2) + ->where('transactions.total', 2) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -159,7 +167,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 2) + ->has('transactions.data', 2) + ->where('transactions.total', 2) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -191,7 +202,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 1) + ->has('transactions.data', 1) + ->where('transactions.total', 1) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -223,7 +237,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 1) + ->has('transactions.data', 1) + ->where('transactions.total', 1) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -264,7 +281,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 3) + ->has('transactions.data', 3) + ->where('transactions.total', 3) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); @@ -309,7 +329,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/cash-account/index') - ->has('transactions', 0) + ->has('transactions.data', 0) + ->where('transactions.total', 0) + ->where('transactions.current_page', 1) + ->where('transactions.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Finance/ExpenseTest.php b/tests/Feature/Admin/Finance/ExpenseTest.php index 6214e48..889fde5 100644 --- a/tests/Feature/Admin/Finance/ExpenseTest.php +++ b/tests/Feature/Admin/Finance/ExpenseTest.php @@ -39,7 +39,9 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/finance/expense/index') - ->has('expenses') + ->has('expenses.data') + ->where('expenses.current_page', 1) + ->where('expenses.per_page', 25) ); }); diff --git a/tests/Feature/Admin/HR/AttendanceTest.php b/tests/Feature/Admin/HR/AttendanceTest.php index 36e811d..ede485f 100644 --- a/tests/Feature/Admin/HR/AttendanceTest.php +++ b/tests/Feature/Admin/HR/AttendanceTest.php @@ -55,7 +55,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/attendance/index') - ->has('attendances', 1) + ->has('attendances.data', 1) + ->where('attendances.total', 1) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); @@ -67,7 +70,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/attendance/index') - ->has('attendances', 0) + ->has('attendances.data', 0) + ->where('attendances.total', 0) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); @@ -106,7 +112,10 @@ $response->assertInertia(fn (Assert $page) => $page ->where('currentYear', 2024) ->where('currentMonth', 3) - ->has('attendances', 1) + ->has('attendances.data', 1) + ->where('attendances.total', 1) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); @@ -130,7 +139,10 @@ $response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 4])); $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page - ->has('attendances', 0) + ->has('attendances.data', 0) + ->where('attendances.total', 0) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); @@ -620,7 +632,10 @@ $response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1])); $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page - ->has('attendances', 2) + ->has('attendances.data', 2) + ->where('attendances.total', 2) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); @@ -656,7 +671,10 @@ $response = $this->get(route('admin.hr.attendances.index', ['year' => 2024, 'month' => 1])); $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page - ->has('attendances', 3) + ->has('attendances.data', 3) + ->where('attendances.total', 3) + ->where('attendances.current_page', 1) + ->where('attendances.per_page', 25) ); }); diff --git a/tests/Feature/Admin/HR/EmployeeTest.php b/tests/Feature/Admin/HR/EmployeeTest.php index 0f0a59c..ffdaa5d 100644 --- a/tests/Feature/Admin/HR/EmployeeTest.php +++ b/tests/Feature/Admin/HR/EmployeeTest.php @@ -51,7 +51,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) ); }); @@ -63,7 +66,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 0) + ->has('employees.data', 0) + ->where('employees.total', 0) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) ); }); @@ -77,7 +83,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 0) + ->has('employees.data', 0) + ->where('employees.total', 0) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) ); }); @@ -99,7 +108,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) ); }); @@ -125,8 +137,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Full Time Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Full Time Employee') ); }); @@ -146,8 +161,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Contract Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Contract Employee') ); }); @@ -167,8 +185,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Resigned Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Resigned Employee') ); }); @@ -194,8 +215,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Active Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Active Employee') ); }); @@ -215,8 +239,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Inactive Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Inactive Employee') ); }); @@ -242,8 +269,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Male Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Male Employee') ); }); @@ -263,8 +293,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Female Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Female Employee') ); }); @@ -302,8 +335,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) - ->where('employees.0.user_profile.full_name', 'Match Employee') + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) + ->where('employees.data.0.user_profile.full_name', 'Match Employee') ); }); @@ -1018,7 +1054,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/employee/index') - ->has('employees', 1) + ->has('employees.data', 1) + ->where('employees.total', 1) + ->where('employees.current_page', 1) + ->where('employees.per_page', 25) ); }); diff --git a/tests/Feature/Admin/HR/LeaveRequestTest.php b/tests/Feature/Admin/HR/LeaveRequestTest.php index 2934b27..623e8ef 100644 --- a/tests/Feature/Admin/HR/LeaveRequestTest.php +++ b/tests/Feature/Admin/HR/LeaveRequestTest.php @@ -44,7 +44,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 3) + ->has('leaveRequests.data', 3) + ->where('leaveRequests.total', 3) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -56,7 +59,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 0) + ->has('leaveRequests.data', 0) + ->where('leaveRequests.total', 0) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -73,7 +79,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 1) + ->has('leaveRequests.data', 1) + ->where('leaveRequests.total', 1) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -95,7 +104,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -111,7 +123,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -127,7 +142,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -143,7 +161,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -160,7 +181,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 4) + ->has('leaveRequests.data', 4) + ->where('leaveRequests.total', 4) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -196,7 +220,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 0) + ->has('leaveRequests.data', 0) + ->where('leaveRequests.total', 0) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -795,7 +822,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/hr/leave-request/index') - ->has('leaveRequests', 1) + ->has('leaveRequests.data', 1) + ->where('leaveRequests.total', 1) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); @@ -827,7 +857,10 @@ $response = $this->get(route('admin.hr.leave-requests.index', ['status' => 'pending'])); $response->assertInertia(fn (Assert $page) => $page - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); $leaveRequest = LeaveRequest::where('status', LeaveRequestStatus::PENDING)->first(); @@ -835,11 +868,17 @@ $response = $this->get(route('admin.hr.leave-requests.index', ['status' => 'pending'])); $response->assertInertia(fn (Assert $page) => $page - ->has('leaveRequests', 1) + ->has('leaveRequests.data', 1) + ->where('leaveRequests.total', 1) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); $response = $this->get(route('admin.hr.leave-requests.index', ['status' => 'approved'])); $response->assertInertia(fn (Assert $page) => $page - ->has('leaveRequests', 2) + ->has('leaveRequests.data', 2) + ->where('leaveRequests.total', 2) + ->where('leaveRequests.current_page', 1) + ->where('leaveRequests.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Master/CategoryTest.php b/tests/Feature/Admin/Master/CategoryTest.php index d1a51a0..94d9145 100644 --- a/tests/Feature/Admin/Master/CategoryTest.php +++ b/tests/Feature/Admin/Master/CategoryTest.php @@ -45,7 +45,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 3) + ->has('categories.data', 3) + ->where('categories.total', 3) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); }); @@ -57,7 +60,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 0) + ->has('categories.data', 0) + ->where('categories.total', 0) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); }); @@ -72,8 +78,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 1) - ->where('categories.0.name', 'Active Category') + ->has('categories.data', 1) + ->where('categories.total', 1) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) + ->where('categories.data.0.name', 'Active Category') ); }); @@ -90,7 +99,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 4) + ->has('categories.data', 4) + ->where('categories.total', 4) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); }); @@ -690,8 +702,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 1) - ->where('categories.0.name', 'Active') + ->has('categories.data', 1) + ->where('categories.total', 1) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) + ->where('categories.data.0.name', 'Active') ); }); @@ -820,7 +835,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 1) + ->has('categories.data', 1) + ->where('categories.total', 1) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); }); @@ -1267,7 +1285,10 @@ $response = $this->get(route('admin.master.categories.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 0) + ->has('categories.data', 0) + ->where('categories.total', 0) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); $category->restore(); @@ -1275,8 +1296,11 @@ $response = $this->get(route('admin.master.categories.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 1) - ->where('categories.0.name', 'Restored Category') + ->has('categories.data', 1) + ->where('categories.total', 1) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) + ->where('categories.data.0.name', 'Restored Category') ); }); @@ -1333,7 +1357,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/category/index') - ->has('categories', 2) + ->has('categories.data', 2) + ->where('categories.total', 2) + ->where('categories.current_page', 1) + ->where('categories.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Master/CustomerTest.php b/tests/Feature/Admin/Master/CustomerTest.php index 6f2f5ea..36de4f2 100644 --- a/tests/Feature/Admin/Master/CustomerTest.php +++ b/tests/Feature/Admin/Master/CustomerTest.php @@ -43,7 +43,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 3) + ->has('customers.data', 3) + ->where('customers.total', 3) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); }); @@ -55,7 +58,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 0) + ->has('customers.data', 0) + ->where('customers.total', 0) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); }); @@ -70,8 +76,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 1) - ->where('customers.0.name', 'Active Customer') + ->has('customers.data', 1) + ->where('customers.total', 1) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) + ->where('customers.data.0.name', 'Active Customer') ); }); @@ -88,7 +97,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 4) + ->has('customers.data', 4) + ->where('customers.total', 4) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); }); @@ -1078,8 +1090,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 1) - ->where('customers.0.name', 'Active') + ->has('customers.data', 1) + ->where('customers.total', 1) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) + ->where('customers.data.0.name', 'Active') ); }); @@ -1174,7 +1189,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 1) + ->has('customers.data', 1) + ->where('customers.total', 1) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); }); @@ -1305,7 +1323,10 @@ $response = $this->get(route('admin.master.customers.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 0) + ->has('customers.data', 0) + ->where('customers.total', 0) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); $customer->restore(); @@ -1313,8 +1334,11 @@ $response = $this->get(route('admin.master.customers.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 1) - ->where('customers.0.name', 'Restored Customer') + ->has('customers.data', 1) + ->where('customers.total', 1) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) + ->where('customers.data.0.name', 'Restored Customer') ); }); @@ -1370,7 +1394,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/customer/index') - ->has('customers', 2) + ->has('customers.data', 2) + ->where('customers.total', 2) + ->where('customers.current_page', 1) + ->where('customers.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Master/ProductTest.php b/tests/Feature/Admin/Master/ProductTest.php index 44d72c9..c0ffd43 100644 --- a/tests/Feature/Admin/Master/ProductTest.php +++ b/tests/Feature/Admin/Master/ProductTest.php @@ -190,7 +190,10 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products', 3) + ->has('products.data', 3) + ->where('products.total', 3) + ->where('products.current_page', 1) + ->where('products.per_page', 25) ); }); @@ -202,7 +205,10 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products', 0) + ->has('products.data', 0) + ->where('products.total', 0) + ->where('products.current_page', 1) + ->where('products.per_page', 25) ); }); @@ -217,8 +223,11 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products', 1) - ->where('products.0.name', 'Active Product') + ->has('products.data', 1) + ->where('products.total', 1) + ->where('products.current_page', 1) + ->where('products.per_page', 25) + ->where('products.data.0.name', 'Active Product') ); }); @@ -235,7 +244,10 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products', 4) + ->has('products.data', 4) + ->where('products.total', 4) + ->where('products.current_page', 1) + ->where('products.per_page', 25) ); }); @@ -254,7 +266,7 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products.0.categories', 1) + ->has('products.data.0.categories', 1) ); }); @@ -269,7 +281,7 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products.0.product_variants', 1) + ->has('products.data.0.product_variants', 1) ); }); @@ -285,7 +297,7 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products.0.product_variants.0.product_prices', 1) + ->has('products.data.0.product_variants.0.product_prices', 1) ); }); @@ -1775,7 +1787,10 @@ function allPriceTypes(): array $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/product/index') - ->has('products', 2) + ->has('products.data', 2) + ->where('products.total', 2) + ->where('products.current_page', 1) + ->where('products.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Master/SupplierTest.php b/tests/Feature/Admin/Master/SupplierTest.php index 0b8d131..0812fba 100644 --- a/tests/Feature/Admin/Master/SupplierTest.php +++ b/tests/Feature/Admin/Master/SupplierTest.php @@ -43,7 +43,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 3) + ->has('suppliers.data', 3) + ->where('suppliers.total', 3) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); }); @@ -55,7 +58,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 0) + ->has('suppliers.data', 0) + ->where('suppliers.total', 0) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); }); @@ -70,8 +76,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 1) - ->where('suppliers.0.name', 'Active Supplier') + ->has('suppliers.data', 1) + ->where('suppliers.total', 1) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) + ->where('suppliers.data.0.name', 'Active Supplier') ); }); @@ -88,7 +97,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 4) + ->has('suppliers.data', 4) + ->where('suppliers.total', 4) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); }); @@ -1078,8 +1090,11 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 1) - ->where('suppliers.0.name', 'Active') + ->has('suppliers.data', 1) + ->where('suppliers.total', 1) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) + ->where('suppliers.data.0.name', 'Active') ); }); @@ -1174,7 +1189,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 1) + ->has('suppliers.data', 1) + ->where('suppliers.total', 1) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); }); @@ -1305,7 +1323,10 @@ $response = $this->get(route('admin.master.suppliers.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 0) + ->has('suppliers.data', 0) + ->where('suppliers.total', 0) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); $supplier->restore(); @@ -1313,8 +1334,11 @@ $response = $this->get(route('admin.master.suppliers.index')); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 1) - ->where('suppliers.0.name', 'Restored Supplier') + ->has('suppliers.data', 1) + ->where('suppliers.total', 1) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) + ->where('suppliers.data.0.name', 'Restored Supplier') ); }); @@ -1370,7 +1394,10 @@ $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/master/supplier/index') - ->has('suppliers', 2) + ->has('suppliers.data', 2) + ->where('suppliers.total', 2) + ->where('suppliers.current_page', 1) + ->where('suppliers.per_page', 25) ); }); diff --git a/tests/Feature/Admin/Settings/RoleTest.php b/tests/Feature/Admin/Settings/RoleTest.php index 0dda9bb..b918565 100644 --- a/tests/Feature/Admin/Settings/RoleTest.php +++ b/tests/Feature/Admin/Settings/RoleTest.php @@ -90,7 +90,10 @@ function createUserWithRole(string $roleName = 'Developer'): User $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/roles/index') - ->has('roles', 3) + ->has('roles.data', 3) + ->where('roles.total', 3) + ->where('roles.current_page', 1) + ->where('roles.per_page', 25) ); }); @@ -101,7 +104,10 @@ function createUserWithRole(string $roleName = 'Developer'): User $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/roles/index') - ->has('roles', 1) + ->has('roles.data', 1) + ->where('roles.total', 1) + ->where('roles.current_page', 1) + ->where('roles.per_page', 25) ); }); @@ -116,7 +122,10 @@ function createUserWithRole(string $roleName = 'Developer'): User $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/roles/index') - ->has('roles', 1) + ->has('roles.data', 1) + ->where('roles.total', 1) + ->where('roles.current_page', 1) + ->where('roles.per_page', 25) ); }); @@ -736,7 +745,10 @@ function createUserWithRole(string $roleName = 'Developer'): User $response->assertOk(); $response->assertInertia(fn (Assert $page) => $page ->component('admin/roles/index') - ->has('roles', 3) + ->has('roles.data', 3) + ->where('roles.total', 3) + ->where('roles.current_page', 1) + ->where('roles.per_page', 25) ); });