chore: adjust TransferToLayingsTable styling

This commit is contained in:
ValdiANS
2026-01-20 17:07:24 +07:00
parent 7a45926c49
commit 26d89c35a5
@@ -1,6 +1,6 @@
'use client';
import { ChangeEventHandler, useState } from 'react';
import { ChangeEventHandler, useEffect, useState } from 'react';
import useSWR from 'swr';
import {
CellContext,
@@ -20,33 +20,32 @@ import SelectInput, {
OptionType,
useSelect,
} from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import TextInput from '@/components/input/TextInput';
import CheckboxInput from '@/components/input/CheckboxInput';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import RequirePermission from '@/components/helper/RequirePermission';
import DateInput from '@/components/input/DateInput';
import PopoverButton from '@/components/popover/PopoverButton';
import { TransferToLaying } from '@/types/api/production/transfer-to-laying';
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
import { cn, formatDate } from '@/lib/helper';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { ROWS_OPTIONS } from '@/config/constant';
import { Flock } from '@/types/api/master-data/flock';
import { FlockApi } from '@/services/api/master-data';
import PillBadge from '@/components/PillBadge';
import { ProjectFlockApi } from '@/services/api/production';
import Badge from '@/components/Badge';
import { Color } from '@/types/theme';
import PopoverContent from '@/components/popover/PopoverContent';
const RowOptionsMenu = ({
type = 'dropdown',
props,
popoverPosition = 'bottom',
approveClickHandler,
rejectClickHandler,
deleteClickHandler,
}: {
type: 'dropdown' | 'collapse';
props: CellContext<TransferToLaying, unknown>;
popoverPosition: 'bottom' | 'top';
approveClickHandler: () => void;
rejectClickHandler: () => void;
deleteClickHandler: () => void;
@@ -60,80 +59,99 @@ const RowOptionsMenu = ({
const showApproveButton = showEditButton;
const showRejectButton = showEditButton;
const popoverId = `transferToLaying#${props.row.original.id}`;
const popoverAnchorName = `--anchor-transferToLaying#${props.row.original.id}`;
return (
<RowOptionsMenuWrapper type={type}>
<RequirePermission permissions='lti.production.transfer_to_laying.detail'>
<Button
href={`/production/transfer-to-laying/detail/?transferToLayingId=${props.row.original.id}`}
variant='ghost'
color='primary'
className='justify-start text-sm'
>
<Icon icon='mdi:eye-outline' width={16} height={16} />
Detail
</Button>
</RequirePermission>
<div className='relative'>
<PopoverButton
tabIndex={0}
variant='ghost'
color='none'
popoverTarget={popoverId}
anchorName={popoverAnchorName}
>
<Icon icon='material-symbols:more-vert' width={16} height={16} />
</PopoverButton>
{showEditButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.update'>
<Button
href={`/production/transfer-to-laying/detail/edit/?transferToLayingId=${props.row.original.id}`}
variant='ghost'
color='warning'
className='justify-start text-sm'
>
<Icon icon='material-symbols:edit-outline' width={16} height={16} />
Edit
</Button>
</RequirePermission>
)}
<PopoverContent
id={popoverId}
anchorName={popoverAnchorName}
position={popoverPosition === 'bottom' ? 'bottom-start' : 'left'}
className='rounded-xl border border-base-content/5 shadow-sm'
>
<div className='flex flex-col bg-base-100 rounded-xl'>
<RequirePermission permissions='lti.production.transfer_to_laying.detail'>
<Button
href={`/production/transfer-to-laying/detail/?transferToLayingId=${props.row.original.id}`}
variant='ghost'
color='none'
className='p-3 justify-start text-sm font-semibold w-full'
>
<Icon icon='heroicons:eye' width={20} height={20} />
View Details
</Button>
</RequirePermission>
{/* TODO: apply RBAC */}
{showApproveButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
<Button
variant='ghost'
color='success'
onClick={approveClickHandler}
className='justify-start text-sm'
>
<Icon icon='material-symbols:check' width={24} height={24} />
Approve
</Button>
</RequirePermission>
)}
{showRejectButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
<Button
variant='ghost'
color='error'
onClick={rejectClickHandler}
className='justify-start text-sm'
>
<Icon icon='material-symbols:close' width={24} height={24} />
Reject
</Button>
</RequirePermission>
)}
{showDeleteButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.delete'>
<Button
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={16}
height={16}
className='justify-start text-sm'
/>
Delete
</Button>
</RequirePermission>
)}
</RowOptionsMenuWrapper>
{showEditButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.update'>
<Button
href={`/production/transfer-to-laying/detail/edit/?transferToLayingId=${props.row.original.id}`}
variant='ghost'
color='none'
className='p-3 justify-start text-sm font-semibold w-full'
>
<Icon icon='heroicons:pencil-square' width={20} height={20} />
Edit
</Button>
</RequirePermission>
)}
{showApproveButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
<Button
variant='ghost'
color='success'
onClick={approveClickHandler}
className='p-3 justify-start text-sm font-semibold w-full'
>
<Icon icon='heroicons:check' width={20} height={20} />
Approve
</Button>
</RequirePermission>
)}
{showRejectButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
<Button
variant='ghost'
color='error'
onClick={rejectClickHandler}
className='p-3 justify-start text-sm font-semibold w-full'
>
<Icon icon='heroicons:x-mark' width={20} height={20} />
Reject
</Button>
</RequirePermission>
)}
{showDeleteButton && (
<RequirePermission permissions='lti.production.transfer_to_laying.delete'>
<hr className='mx-3 border-base-content/10 h-px' />
<Button
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='p-3 justify-start text-sm font-semibold w-full'
>
<Icon icon='heroicons:trash' width={20} height={20} />
Delete
</Button>
</RequirePermission>
)}
</div>
</PopoverContent>
</div>
);
};
@@ -150,6 +168,8 @@ const TransferToLayingsTable = () => {
transferDate: '',
flockSource: '',
flockDestination: '',
filter_by: '',
sort_by: '',
},
paramMap: {
page: 'page',
@@ -157,6 +177,8 @@ const TransferToLayingsTable = () => {
transferDate: 'transfer_date',
flockSource: 'flock_source',
flockDestination: 'flock_destination',
filter_by: 'filter_by',
sort_by: 'sort_by',
},
});
@@ -181,7 +203,7 @@ const TransferToLayingsTable = () => {
isLoadingOptions: isLoadingFlockSourceOptions,
loadMore: loadMoreFlockSource,
hasMore: hasMoreFlockSource,
} = useSelect<Flock>(FlockApi.basePath, 'id', 'name');
} = useSelect<Flock>(ProjectFlockApi.basePath, 'id', 'flock_name');
const {
setInputValue: setFlockDestinationInputValue,
@@ -189,7 +211,7 @@ const TransferToLayingsTable = () => {
isLoadingOptions: isLoadingFlockDestinationOptions,
loadMore: loadMoreFlockDestination,
hasMore: hasMoreFlockDestination,
} = useSelect<Flock>(FlockApi.basePath, 'id', 'name');
} = useSelect<Flock>(ProjectFlockApi.basePath, 'id', 'flock_name');
// Flocks value
const [selectedFlockSource, setSelectedFlockSource] =
@@ -244,13 +266,6 @@ const TransferToLayingsTable = () => {
);
},
},
{
header: '#',
cell: (props) =>
tableFilterState.pageSize * (tableFilterState.page - 1) +
props.row.index +
1,
},
{
accessorKey: 'transfer_date',
header: 'Tanggal Transfer',
@@ -274,6 +289,7 @@ const TransferToLayingsTable = () => {
{
accessorKey: 'notes',
header: 'Alasan Transfer',
enableSorting: false,
},
{
header: 'Status',
@@ -282,34 +298,39 @@ const TransferToLayingsTable = () => {
props.row.original.approval.action === 'REJECTED';
let latestApprovalStepName = props.row.original.approval.step_name;
let pillBadgeColor: 'yellow' | 'green' | 'gray' | 'red' = 'gray';
let badgeColor: Color = 'neutral';
switch (latestApprovalStepName.toLowerCase()) {
case 'pengajuan':
pillBadgeColor = 'yellow';
badgeColor = 'neutral';
break;
case 'disetujui':
pillBadgeColor = 'green';
badgeColor = 'success';
break;
}
if (isLatestApprovalRejected) {
pillBadgeColor = 'red';
badgeColor = 'error';
latestApprovalStepName = 'Ditolak';
}
return (
<PillBadge
content={latestApprovalStepName}
color={pillBadgeColor}
className='text-sm'
/>
<Badge
variant='soft'
className={{
badge: 'rounded-lg px-2 w-full flex flex-row justify-start',
}}
color={badgeColor}
>
<Icon icon='mdi:circle' width={12} height={12} color={badgeColor} />
{latestApprovalStepName}
</Badge>
);
},
},
{
header: 'Aksi',
id: 'actions',
cell: (props) => {
const currentPageSize = props.table.getPaginationRowModel().rows.length;
const currentPageRows = props.table.getPaginationRowModel().flatRows;
@@ -346,31 +367,13 @@ const TransferToLayingsTable = () => {
};
return (
<>
{currentPageSize > 3 && (
<RowDropdownOptions isLast2Rows={isLast2Rows}>
<RowOptionsMenu
type='dropdown'
props={props}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
deleteClickHandler={deleteClickHandler}
/>
</RowDropdownOptions>
)}
{currentPageSize <= 3 && (
<RowCollapseOptions>
<RowOptionsMenu
type='collapse'
props={props}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
deleteClickHandler={deleteClickHandler}
/>
</RowCollapseOptions>
)}
</>
<RowOptionsMenu
props={props}
approveClickHandler={approveClickHandler}
rejectClickHandler={rejectClickHandler}
deleteClickHandler={deleteClickHandler}
popoverPosition={isLast2Rows ? 'top' : 'bottom'}
/>
);
},
},
@@ -503,20 +506,19 @@ const TransferToLayingsTable = () => {
);
};
// track sorting
// useEffect(() => {
// const isNameSorted = sorting.find((sortItem) => sortItem.id === 'name');
// if (!isNameSorted) {
// updateFilter('nameSort', '');
// } else {
// updateFilter('nameSort', isNameSorted.desc ? 'desc' : 'asc');
// }
// }, [sorting, updateFilter]);
useEffect(() => {
if (sorting.length === 1) {
updateFilter('filter_by', sorting[0].id);
updateFilter('sort_by', sorting[0].desc ? 'desc' : 'asc');
} else {
updateFilter('filter_by', '');
updateFilter('sort_by', '');
}
}, [sorting]);
return (
<>
<div className='w-full p-0 sm:p-4'>
<div className='w-full p-0'>
<div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col xl:flex-row justify-between items-end xl:items-center gap-2'>
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
@@ -583,12 +585,10 @@ const TransferToLayingsTable = () => {
</div>
<div className='grid grid-cols-12 justify-end gap-4'>
<TextInput
required
type='date'
label='Tanggal Transfer'
<DateInput
name='transfer_date'
placeholder='Masukkan tanggal transfer'
label='Tanggal Transfer'
placeholder='Tanggal Transfer'
value={tableFilterState.transferDate}
onChange={transferDateChangeHandler}
className={{
@@ -623,20 +623,6 @@ const TransferToLayingsTable = () => {
wrapper: 'col-span-12 sm:col-span-3',
}}
/>
<SelectInput
label='Baris'
options={ROWS_OPTIONS}
value={{
label: String(tableFilterState.pageSize),
value: tableFilterState.pageSize,
}}
onChange={pageSizeChangeHandler}
className={{
wrapper:
'col-span-6 sm:col-span-3 max-w-28 sm:justify-self-end',
}}
/>
</div>
</div>
@@ -657,26 +643,21 @@ const TransferToLayingsTable = () => {
: 0
}
onPageChange={setPage}
onPageSizeChange={setPageSize}
isLoading={isLoading}
sorting={sorting}
setSorting={setSorting}
rowSelection={rowSelection}
setRowSelection={setRowSelection}
enableRowSelection={tableEnableRowSelectionHandler}
withCheckbox
className={{
containerClassName: cn({
'mb-20':
'w-full mb-20':
isResponseSuccess(transferToLayings) &&
transferToLayings?.data?.length === 0,
}),
tableWrapperClassName: 'overflow-x-auto min-h-full!',
tableClassName: 'font-inter w-full table-auto min-h-full!',
headerRowClassName: 'border-b border-b-gray-200',
headerColumnClassName:
'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
bodyRowClassName: 'border-b border-b-gray-200',
bodyColumnClassName:
'px-6 py-3 last:flex last:flex-row last:justify-end',
headerColumnClassName: 'text-nowrap',
}}
/>
</div>