feat: enhance order management with additional filters and pagination support
- Added channel, status, and payment type filters to the order index functionality. - Updated OrderService to handle new filter parameters in pagination queries. - Introduced filter definitions and values in the OrderGroupedTable component for improved data filtering. - Enhanced the frontend to support dynamic filtering options for orders based on the new criteria.
This commit is contained in:
parent
7dec701770
commit
1f9aba6ba5
@ -30,9 +30,17 @@ public function index(Request $request): Response
|
||||
{
|
||||
$tableQuery = $this->parseDataTableQuery($request);
|
||||
|
||||
$tableQuery['channel'] = $request->string('channel')->toString();
|
||||
$tableQuery['status'] = $request->string('status')->toString();
|
||||
$tableQuery['payment_type'] = $request->string('payment_type')->toString();
|
||||
|
||||
return Inertia::render('admin/manage/orders/Index', [
|
||||
'orders' => $this->orderService->paginateForIndex($tableQuery, $request->user()),
|
||||
'filters' => $this->dataTableFilters($tableQuery),
|
||||
'filters' => $this->dataTableFilters($tableQuery, [
|
||||
'channel' => $tableQuery['channel'],
|
||||
'status' => $tableQuery['status'],
|
||||
'payment_type' => $tableQuery['payment_type'],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,10 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi
|
||||
->orWhereHas('product', fn (Builder $query) => $query->where('name', 'like', "%{$search}%"));
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
->when(($tableQuery['channel'] ?? '') !== '', fn (Builder $query) => $query->where('channel', $tableQuery['channel']))
|
||||
->when(($tableQuery['status'] ?? '') !== '', fn (Builder $query) => $query->where('status', $tableQuery['status']))
|
||||
->when(($tableQuery['payment_type'] ?? '') !== '', fn (Builder $query) => $query->where('payment_type', $tableQuery['payment_type']));
|
||||
|
||||
$this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']);
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export const OrderChannel = {
|
||||
STORE: 'store',
|
||||
TIKTOK: 'tiktok',
|
||||
SHOPEE: 'shopee',
|
||||
} as const;
|
||||
|
||||
@ -14,9 +14,13 @@ import {
|
||||
getPaperSizeLabel,
|
||||
useThermalPrinter,
|
||||
} from '@/composables/useThermalPrinter';
|
||||
import { OrderChannel } from '@/constants/order-channel';
|
||||
import { OrderPaymentType } from '@/constants/order-payment-type';
|
||||
import { OrderStatus } from '@/constants/order-status';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { PaperSize } from '@/lib/thermal-printer/types';
|
||||
import { index, create } from '@/routes/admin/manage/orders';
|
||||
import type { DataTableFilterDef } from '@/types/data-table';
|
||||
import type { PaginatedOrders } from '@/types/order';
|
||||
import OrderGroupedTable from './table/OrderGroupedTable.vue';
|
||||
|
||||
@ -26,6 +30,9 @@ const props = defineProps<{
|
||||
search: string;
|
||||
sort?: string;
|
||||
direction?: 'asc' | 'desc';
|
||||
channel?: string;
|
||||
status?: string;
|
||||
payment_type?: string;
|
||||
};
|
||||
}>();
|
||||
|
||||
@ -34,13 +41,55 @@ const page = usePage();
|
||||
const { isConnected, printOrderReceipt, tryReconnect } = useThermalPrinter();
|
||||
const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { setSearch, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
const { query, setSearch, setFilter, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['channel', 'status', 'payment_type'],
|
||||
});
|
||||
|
||||
useDataTableQuerySync(() => props.filters, syncFromServer);
|
||||
|
||||
const filterDefs = computed<DataTableFilterDef[]>(() => [
|
||||
{
|
||||
key: 'channel',
|
||||
label: 'Channel',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: OrderChannel.STORE, label: 'Toko' },
|
||||
{ value: OrderChannel.SHOPEE, label: 'Shopee' },
|
||||
{ value: OrderChannel.TIKTOK, label: 'TikTok' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
label: 'Status',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: OrderStatus.PENDING, label: 'Menunggu' },
|
||||
{ value: OrderStatus.PROCESSING, label: 'Diproses' },
|
||||
{ value: OrderStatus.COMPLETED, label: 'Selesai' },
|
||||
{ value: OrderStatus.CANCELLED, label: 'Dibatalkan' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'payment_type',
|
||||
label: 'Tipe Pembayaran',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: OrderPaymentType.CASH, label: 'Cash' },
|
||||
{ value: OrderPaymentType.TRANSFER, label: 'Transfer' },
|
||||
{ value: OrderPaymentType.QRIS, label: 'QRIS' },
|
||||
{ value: OrderPaymentType.MARKETPLACE, label: 'Marketplace' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const filterValues = computed(() => ({
|
||||
channel: query.value.channel ?? '',
|
||||
status: query.value.status ?? '',
|
||||
payment_type: query.value.payment_type ?? '',
|
||||
}));
|
||||
|
||||
const tablePagination = computed(() => ({
|
||||
currentPage: props.orders.current_page,
|
||||
perPage: props.orders.per_page,
|
||||
@ -138,6 +187,9 @@ onMounted(async () => {
|
||||
:first-item="firstItem"
|
||||
:pagination="tablePagination"
|
||||
:pagination-links="orders.links"
|
||||
:filter-defs="filterDefs"
|
||||
:filter-values="filterValues"
|
||||
@filter-change="setFilter"
|
||||
@filters-reset="resetFilters"
|
||||
/>
|
||||
</CardContent>
|
||||
|
||||
@ -21,6 +21,7 @@ import { usePaginationSummary } from '@/composables/usePaginationSummary';
|
||||
import { orderStatusBadgeVariant } from '@/constants/order-status';
|
||||
import { groupedTableRowNumber } from '@/lib/grouped-table';
|
||||
import type {
|
||||
DataTableFilterDef,
|
||||
DataTablePagination,
|
||||
DataTablePaginationLink,
|
||||
} from '@/types/data-table';
|
||||
@ -32,11 +33,14 @@ const props = defineProps<{
|
||||
firstItem?: number;
|
||||
pagination?: DataTablePagination;
|
||||
paginationLinks?: DataTablePaginationLink[];
|
||||
filterDefs?: DataTableFilterDef[];
|
||||
filterValues?: Record<string, string>;
|
||||
}>();
|
||||
|
||||
const search = defineModel<string>('search', { default: '' });
|
||||
|
||||
const emit = defineEmits<{
|
||||
'filter-change': [key: string, value: string];
|
||||
'filters-reset': [];
|
||||
}>();
|
||||
|
||||
@ -50,7 +54,8 @@ function rowNumber(index: number): number {
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<DataTableToolbar v-model:search="search" @filters-reset="emit('filters-reset')" />
|
||||
<DataTableToolbar v-model:search="search" :filter-defs="filterDefs" :filter-values="filterValues"
|
||||
@filter-change="(key, value) => emit('filter-change', key, value)" @filters-reset="emit('filters-reset')" />
|
||||
|
||||
<div v-if="orders.length" class="space-y-4">
|
||||
<div v-for="(order, index) in orders" :key="order.id" class="overflow-hidden rounded-md border">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user