refactor: implement server-side pagination across admin modules and update corresponding frontend components and tests

This commit is contained in:
Yoga Pangestu 2026-04-30 22:41:43 +07:00
parent f5698ee47f
commit dc68c73c2a
27 changed files with 67 additions and 42 deletions

View File

@ -15,7 +15,7 @@ class ExpenseController extends Controller
public function index(): Response
{
return Inertia::render('admin/finance/expense/index', [
'expenses' => Expense::with(['media', 'user'])->latest()->get(),
'expenses' => Expense::with(['media', 'user'])->latest()->paginate(10),
]);
}

View File

@ -28,7 +28,7 @@ public function index(): Response
$query->where('user_id', auth()->id());
})
->latest()
->get(),
->paginate(10),
'currentMonthPayrolls' => Payroll::with(['user.profile', 'adjustments'])
->where('period_month', $currentMonth)
->when(auth()->user()->hasRole('Admin'), function ($query) {

View File

@ -23,7 +23,7 @@ class OrderController extends Controller
public function index(): Response
{
return Inertia::render('admin/manage/order/index', [
'orders' => Order::with(['items.product', 'user'])->latest()->get(),
'orders' => Order::with(['items.product', 'user'])->latest()->paginate(10),
]);
}

View File

@ -19,7 +19,7 @@ class PurchaseController extends Controller
public function index(): Response
{
return Inertia::render('admin/manage/purchase/index', [
'purchases' => Purchase::with(['items.product'])->latest()->get(),
'purchases' => Purchase::with(['items.product'])->latest()->paginate(10),
]);
}

View File

@ -15,7 +15,7 @@ class CategoryController extends Controller
public function index(): Response
{
return Inertia::render('admin/master/category/index', [
'categories' => Category::latest()->get(),
'categories' => Category::latest()->paginate(10),
]);
}

View File

@ -20,7 +20,7 @@ class ProductController extends Controller
public function index(): Response
{
return Inertia::render('admin/master/product/index', [
'products' => Product::with(['prices', 'categories', 'media'])->latest()->get(),
'products' => Product::with(['prices', 'categories', 'media'])->latest()->paginate(10),
'categories' => Category::active()->get(),
]);
}

View File

@ -19,7 +19,7 @@ class UserController extends Controller
public function index(): Response
{
return Inertia::render('admin/master/user/index', [
'users' => User::with(['profile', 'roles'])->latest()->get(),
'users' => User::with(['profile', 'roles'])->latest()->paginate(10),
'roles' => Role::all(),
'defaultPassword' => config('auth.password_default', 'password'),
]);

View File

@ -13,9 +13,8 @@ public function index(): Response
{
$activities = Activity::with('causer')
->latest()
->limit(500)
->get()
->map(fn ($activity) => [
->paginate(10)
->through(fn ($activity) => [
'id' => $activity->id,
'description' => $activity->description,
'module' => $activity->log_name,

View File

@ -18,7 +18,7 @@ class RoleController extends Controller
public function index(): Response
{
return Inertia::render('admin/system/role/index', [
'roles' => Role::with('permissions')->latest()->get(),
'roles' => Role::with('permissions')->latest()->paginate(10),
]);
}

View File

@ -6,13 +6,14 @@ import { ImagePreviewDialog } from '@/components/modal/image-preview';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import type { Expense } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { useExpenseIndex } from './hooks/use-expense-index';
import { getColumns } from './partials/columns';
import { ExpenseFormModal } from './partials/expense-form-modal';
import { usePermission } from '@/hooks/use-permission';
export default function ExpenseIndex({ expenses }: { expenses: Expense[] }) {
export default function ExpenseIndex({ expenses }: { expenses: PaginatedData<Expense> }) {
const { hasPermission } = usePermission();
const {
selectedProof,
@ -67,7 +68,8 @@ export default function ExpenseIndex({ expenses }: { expenses: Expense[] }) {
<CardContent className="p-0">
<DataTable
columns={columns}
data={expenses}
data={expenses.data}
meta={expenses}
showSelection={hasPermission('DeleteAny:Expense')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -6,6 +6,7 @@ import { DeleteConfirmation } from '@/components/modal/delete-confirmation';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import type { Payroll } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { PayrollCard } from '@/components/cards/payroll-card';
import { usePermission } from '@/hooks/use-permission';
@ -17,7 +18,7 @@ export default function PayrollIndex({
payrolls,
currentMonthPayrolls,
}: {
payrolls: Payroll[];
payrolls: PaginatedData<Payroll>;
currentMonthPayrolls: Payroll[];
}) {
const { hasPermission } = usePermission();
@ -106,7 +107,8 @@ export default function PayrollIndex({
<CardContent className="p-0">
<DataTable
columns={columns}
data={payrolls}
data={payrolls.data}
meta={payrolls}
showSelection={hasPermission('DeleteAny:Payroll')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -8,12 +8,13 @@ import { Plus, Trash2 } from 'lucide-react';
import { usePermission } from '@/hooks/use-permission';
import * as orderRoutes from '@/routes/order';
import type { Order } from '@/types/order';
import type { PaginatedData } from '@/types/pagination';
import { useOrderIndex } from './hooks/use-order-index';
import { useOrderPrint } from './hooks/use-order-print';
import { getColumns } from './partials/columns';
import { PrinterSettings } from './partials/printer-settings';
export default function OrderIndex({ orders }: { orders: Order[] }) {
export default function OrderIndex({ orders }: { orders: PaginatedData<Order> }) {
const { hasPermission } = usePermission();
const {
isDeleteDialogOpen,
@ -84,7 +85,8 @@ export default function OrderIndex({ orders }: { orders: Order[] }) {
<CardContent className="p-0">
<DataTable
columns={columns}
data={orders}
data={orders.data}
meta={orders}
showSelection={hasPermission('DeleteAny:Order')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -10,11 +10,12 @@ import { Card, CardContent } from '@/components/ui/card';
import { formatDate } from '@/lib/formatters';
import purchaseRoutes from '@/routes/purchase';
import type { Purchase } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { usePurchaseIndex } from './hooks/use-purchase-index';
import { getColumns } from './partials/columns';
import { usePermission } from '@/hooks/use-permission';
export default function PurchaseIndex({ purchases }: { purchases: Purchase[] }) {
export default function PurchaseIndex({ purchases }: { purchases: PaginatedData<Purchase> }) {
const { hasPermission } = usePermission();
const {
isDeleteDialogOpen,
@ -57,7 +58,8 @@ export default function PurchaseIndex({ purchases }: { purchases: Purchase[] })
<CardContent className="p-0">
<DataTable
columns={columns}
data={purchases}
data={purchases.data}
meta={purchases}
showSelection={hasPermission('DeleteAny:Purchase')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -4,14 +4,14 @@ import { DataTable } from '@/components/data-table';
import { DeleteConfirmation } from '@/components/modal/delete-confirmation';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import type { Category } from '@/types';
import type { Category, PaginatedData } from '@/types';
import { useCategoryIndex } from './hooks/use-category-index';
import { CategoryFormModal } from './partials/category-form-modal';
import { getColumns } from './partials/columns';
import { usePermission } from '@/hooks/use-permission';
export default function CategoryIndex({ categories }: { categories: Category[] }) {
export default function CategoryIndex({ categories }: { categories: PaginatedData<Category> }) {
const { hasPermission } = usePermission();
const {
isFormOpen,
@ -64,7 +64,8 @@ export default function CategoryIndex({ categories }: { categories: Category[] }
<CardContent className="p-0">
<DataTable
columns={columns}
data={categories}
data={categories.data}
meta={categories}
showSelection={hasPermission('DeleteAny:Category')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -6,13 +6,14 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import productRoutes from '@/routes/product';
import type { Product, Category } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { ImagePreviewDialog } from '../../../../components/modal/image-preview';
import { useProductIndex } from './hooks/use-product-index';
import { getColumns } from './partials/columns';
import { usePermission } from '@/hooks/use-permission';
export default function ProductIndex({ products, categories }: { products: Product[], categories: Category[] }) {
export default function ProductIndex({ products, categories }: { products: PaginatedData<Product>, categories: Category[] }) {
const { hasPermission } = usePermission();
const {
selectedImage,
@ -59,7 +60,8 @@ export default function ProductIndex({ products, categories }: { products: Produ
<CardContent className="p-0">
<DataTable
columns={columns}
data={products}
data={products.data}
meta={products}
showSelection={hasPermission('DeleteAny:Product')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -15,6 +15,7 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import userRoutes from '@/routes/user';
import type { User } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { Head, Link } from '@inertiajs/react';
import { KeyRound, Plus, Trash2, X } from 'lucide-react';
@ -22,7 +23,7 @@ import { usePermission } from '@/hooks/use-permission';
import { useUserIndex } from './hooks/use-user-index';
import { getColumns } from './partials/columns';
export default function UserIndex({ users, defaultPassword }: { users: User[], defaultPassword: string }) {
export default function UserIndex({ users, defaultPassword }: { users: PaginatedData<User>, defaultPassword: string }) {
const { hasPermission } = usePermission();
const {
isDeleteDialogOpen,
@ -71,7 +72,8 @@ export default function UserIndex({ users, defaultPassword }: { users: User[], d
<CardContent className="p-0">
<DataTable
columns={columns}
data={users}
data={users.data}
meta={users}
showSelection={hasPermission('DeleteAny:User')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -2,10 +2,11 @@ import { Head } from '@inertiajs/react';
import { DataTable } from '@/components/data-table';
import { Card, CardContent } from '@/components/ui/card';
import type { Activity } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { getColumns } from './partials/columns';
interface Props {
activities: Activity[];
activities: PaginatedData<Activity>;
}
export default function ActivityLogIndex({ activities }: Props) {
@ -25,7 +26,8 @@ export default function ActivityLogIndex({ activities }: Props) {
<CardContent className="p-0">
<DataTable
columns={columns}
data={activities}
data={activities.data}
meta={activities}
filters={[
{
columnId: 'description',

View File

@ -6,11 +6,12 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import roleRoutes from '@/routes/system/role';
import type { Role } from '@/types';
import type { PaginatedData } from '@/types/pagination';
import { useRoleIndex } from './hooks/use-role-index';
import { getColumns } from './partials/columns';
import { usePermission } from '@/hooks/use-permission';
export default function RoleIndex({ roles }: { roles: Role[] }) {
export default function RoleIndex({ roles }: { roles: PaginatedData<Role> }) {
const { hasPermission } = usePermission();
const {
isDeleteDialogOpen,
@ -53,7 +54,8 @@ export default function RoleIndex({ roles }: { roles: Role[] }) {
<CardContent className="p-0">
<DataTable
columns={columns}
data={roles}
data={roles.data}
meta={roles}
showSelection={hasPermission('DeleteAny:Role')}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}

View File

@ -51,7 +51,7 @@
->assertInertia(fn ($page) => $page
->component('admin/finance/expense/index')
->has('expenses', fn ($page) => $page
->has('0.user')
->has('data.0.user')
->etc()
)
);

View File

@ -51,7 +51,7 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/finance/payroll/index')
->has('payrolls')
->has('payrolls', fn ($page) => $page->has('data')->etc())
->has('currentMonthPayrolls')
);
});

View File

@ -55,10 +55,10 @@
->assertInertia(fn ($page) => $page
->component('admin/manage/order/index')
->has('orders', fn ($page) => $page
->has('0.user')
->has('0.cogs_formatted')
->has('0.payment_formatted')
->has('0.created_at_formatted')
->has('data.0.user')
->has('data.0.cogs_formatted')
->has('data.0.payment_formatted')
->has('data.0.created_at_formatted')
->etc()
)
);

View File

@ -48,7 +48,10 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/manage/purchase/index')
->has('purchases')
->has('purchases', fn ($page) => $page
->has('data')
->etc()
)
);
});

View File

@ -47,7 +47,10 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/master/category/index')
->has('categories')
->has('categories', fn ($page) => $page
->has('data')
->etc()
)
);
});

View File

@ -51,7 +51,10 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/master/product/index')
->has('products')
->has('products', fn ($page) => $page
->has('data')
->etc()
)
->has('categories')
);
});

View File

@ -49,7 +49,7 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/master/user/index')
->has('users')
->has('users', fn ($page) => $page->has('data')->etc())
->has('roles')
->has('defaultPassword')
);

View File

@ -42,7 +42,7 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/system/activity-log/index')
->has('activities')
->has('activities', fn ($page) => $page->has('data')->etc())
);
});
});

View File

@ -47,7 +47,7 @@
->assertOk()
->assertInertia(fn ($page) => $page
->component('admin/system/role/index')
->has('roles')
->has('roles', fn ($page) => $page->has('data')->etc())
);
});