mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix(FE): fixing floating action button project flock and change page size
This commit is contained in:
@@ -39,8 +39,8 @@ const FloatingActionsButton = ({
|
||||
// Jika tidak ada baris yang dipilih, jangan tampilkan FAB
|
||||
const positionStyles =
|
||||
selectedRowIds.length > 0
|
||||
? 'bottom-[10%] opacity-100'
|
||||
: 'bottom-[-10%] opacity-0';
|
||||
? 'bottom-[5%] opacity-100'
|
||||
: 'bottom-[-5%] opacity-0';
|
||||
|
||||
// Helper untuk menentukan gaya warna tombol approval
|
||||
const getApprovalColor = (action: 'APPROVED' | 'REJECTED') => {
|
||||
@@ -60,7 +60,7 @@ const FloatingActionsButton = ({
|
||||
// Container utama FAB
|
||||
<div
|
||||
className={cn(
|
||||
`absolute ${positionStyles} inset-x-1/2 -translate-x-1/2 z-50`,
|
||||
`fixed ${positionStyles} inset-x-1/2 -translate-x-1/2 z-50`,
|
||||
'mx-auto w-full max-w-sm sm:mx-0 bg-base-300 p-4 rounded-xl shadow-md transition-all duration-300 transform',
|
||||
'bg-slate-950 backdrop-blur-md'
|
||||
)}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { CellContext, SortingState } from '@tanstack/react-table';
|
||||
import { CellContext, ColumnDef, SortingState } from '@tanstack/react-table';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
@@ -27,84 +27,6 @@ import useSWR from 'swr';
|
||||
|
||||
import RequirePermission from '@/components/helper/RequirePermission';
|
||||
|
||||
const RowOptionsMenu = ({
|
||||
type = 'dropdown',
|
||||
props,
|
||||
deleteClickHandler,
|
||||
}: {
|
||||
type: 'dropdown' | 'collapse';
|
||||
props: CellContext<ProjectFlock, unknown>;
|
||||
deleteClickHandler: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
tabIndex={type == 'dropdown' ? 0 : undefined}
|
||||
className={cn(
|
||||
{
|
||||
'dropdown-content': type === 'dropdown',
|
||||
'mt-2': type === 'collapse',
|
||||
},
|
||||
'p-2.5 mr-2 bg-base-100 rounded-box z-10 border border-black/10 shadow'
|
||||
)}
|
||||
>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<RequirePermission permissions='lti.production.project_flocks.detail'>
|
||||
<Button
|
||||
href={`/production/project-flock/detail?projectFlockId=${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>
|
||||
{props.row.original.approval.step_name === 'Aktif' && (
|
||||
<RequirePermission permissions='lti.production.chickins.create'>
|
||||
<Button
|
||||
href={`/production/project-flock/chickin/add?projectFlockId=${props.row.original.id}`}
|
||||
variant='ghost'
|
||||
color='success'
|
||||
className='justify-start text-sm'
|
||||
>
|
||||
<Icon icon='mdi:home-import-outline' width={16} height={16} />
|
||||
Chickin
|
||||
</Button>
|
||||
</RequirePermission>
|
||||
)}
|
||||
{props.row.original.approval.step_name === 'Pengajuan' && (
|
||||
<RequirePermission permissions='lti.production.project_flocks.update'>
|
||||
<Button
|
||||
href={`/production/project-flock/detail/edit?projectFlockId=${props.row.original.id}`}
|
||||
variant='ghost'
|
||||
color='warning'
|
||||
className='justify-start text-sm'
|
||||
>
|
||||
<Icon icon='mdi:pencil-outline' width={16} height={16} />
|
||||
Edit
|
||||
</Button>
|
||||
</RequirePermission>
|
||||
)}
|
||||
<RequirePermission permissions='lti.production.project_flocks.delete'>
|
||||
<Button
|
||||
onClick={deleteClickHandler}
|
||||
variant='ghost'
|
||||
color='error'
|
||||
className='text-error hover:text-inherit justify-start text-sm'
|
||||
>
|
||||
<Icon
|
||||
icon='material-symbols:delete-outline-rounded'
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Delete
|
||||
</Button>
|
||||
</RequirePermission>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
const {
|
||||
state: tableFilterState,
|
||||
@@ -149,8 +71,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
);
|
||||
const [periodInputValue, setPeriodInputValue] = useState<number | null>(null);
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [selectedProjectFlock, setSelectedProjectFlock] =
|
||||
useState<ProjectFlock>();
|
||||
const deleteModal = useModal();
|
||||
const confirmModal = useModal();
|
||||
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
|
||||
@@ -221,10 +141,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
: [];
|
||||
|
||||
// ====== HANDLER ======
|
||||
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
const newVal = val as OptionType;
|
||||
setPageSize(newVal.value as number);
|
||||
};
|
||||
const confirmationModalDeleteClickHandler = async () => {
|
||||
setIsDeleteLoading(true);
|
||||
|
||||
@@ -292,12 +208,146 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
const canApprove = useMemo(() => {
|
||||
if (!selectedSingleRow || isApproveLoading) return false;
|
||||
|
||||
const isPengajuan = selectedSingleRow.approval.step_number == 1;
|
||||
const isNotRejected = selectedSingleRow.approval.action != 'REJECTED';
|
||||
const isPengajuan = selectedSingleRow.approval?.step_number == 1;
|
||||
const isNotRejected = selectedSingleRow.approval?.action != 'REJECTED';
|
||||
|
||||
return isPengajuan && isNotRejected;
|
||||
}, [selectedSingleRow, isApproveLoading]);
|
||||
|
||||
// ====== COLUMNS ======
|
||||
const columns = useMemo<ColumnDef<ProjectFlock>[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'select',
|
||||
header: ({ table }) => {
|
||||
const allRows = table.getRowModel().rows;
|
||||
const selectableRows = allRows;
|
||||
|
||||
const allSelected =
|
||||
selectableRows.every((row) => row.getIsSelected()) &&
|
||||
selectableRows.length != 0;
|
||||
|
||||
const someSelected =
|
||||
selectableRows.some((row) => row.getIsSelected()) && !allSelected;
|
||||
|
||||
const toggleSelectableRows = () => {
|
||||
const shouldSelect = !allSelected;
|
||||
selectableRows.forEach((row) => row.toggleSelected(shouldSelect));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-row justify-center'>
|
||||
<CheckboxInput
|
||||
name='allRow'
|
||||
checked={allSelected}
|
||||
indeterminate={someSelected}
|
||||
onChange={toggleSelectableRows}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<CheckboxInput
|
||||
name='row'
|
||||
checked={row.getIsSelected()}
|
||||
disabled={!row.getCanSelect()}
|
||||
indeterminate={row.getIsSomeSelected()}
|
||||
onChange={row.getToggleSelectedHandler()}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: 'flock_name',
|
||||
header: 'Flock',
|
||||
},
|
||||
{
|
||||
accessorKey: 'area.name',
|
||||
header: 'Area',
|
||||
},
|
||||
{
|
||||
accessorKey: 'location.name',
|
||||
header: 'Lokasi',
|
||||
},
|
||||
{
|
||||
accessorKey: 'fcr.name',
|
||||
header: 'FCR',
|
||||
},
|
||||
{
|
||||
accessorKey: 'category',
|
||||
header: 'Kategori',
|
||||
},
|
||||
{
|
||||
accessorKey: 'approval.step_name',
|
||||
header: 'Status',
|
||||
cell: (props) => {
|
||||
const approval = props.row.original.approval;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
variant='soft'
|
||||
className={{
|
||||
badge: 'rounded-lg px-2 w-full flex flex-row justify-start',
|
||||
}}
|
||||
color={
|
||||
approval?.step_number == 1
|
||||
? 'neutral'
|
||||
: approval?.step_number == 2
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:circle'
|
||||
width={12}
|
||||
height={12}
|
||||
color={
|
||||
approval?.step_number == 1
|
||||
? 'neutral'
|
||||
: approval?.step_number == 2
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
/>
|
||||
{approval?.step_name}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Kandang',
|
||||
cell: (props) => {
|
||||
const kandang = props.row.original.kandangs;
|
||||
if (kandang) {
|
||||
const kandangNames = kandang.map((k: Kandang) => k.name);
|
||||
return (
|
||||
<div>
|
||||
{kandangNames.length > 0
|
||||
? kandangNames.join(', ')
|
||||
: 'Tidak ada'}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'period',
|
||||
header: 'Periode',
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: 'Dibuat pada',
|
||||
cell: (props) =>
|
||||
formatDate(props.row.original.created_at, 'MMM DD, YYYY'),
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='min-h-screen w-full p-4'>
|
||||
@@ -320,7 +370,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
<div className='ms-auto w-full sm:w-auto'>
|
||||
<DebouncedTextInput
|
||||
name='search'
|
||||
placeholder='Cari Area'
|
||||
placeholder='Cari Project Flock'
|
||||
value={tableFilterState.search}
|
||||
onChange={searchChangeHandler}
|
||||
className={{
|
||||
@@ -382,160 +432,18 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
type='number'
|
||||
label='Periode'
|
||||
placeholder='Masukan periode'
|
||||
value={periodInputValue ?? ''}
|
||||
value={periodInputValue?.toString() ?? ''}
|
||||
onChange={(e) => {
|
||||
setPeriodInputValue(parseInt(e.target.value));
|
||||
updateFilter('periodFilter', e.target.value);
|
||||
}}
|
||||
/>
|
||||
<SelectInput
|
||||
label='Baris'
|
||||
options={ROWS_OPTIONS}
|
||||
value={{
|
||||
label: String(tableFilterState.pageSize),
|
||||
value: tableFilterState.pageSize,
|
||||
}}
|
||||
onChange={pageSizeChangeHandler}
|
||||
className={{ wrapper: 'max-w-28' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table<ProjectFlock>
|
||||
data={isResponseSuccess(projectFlocks) ? projectFlocks?.data : []}
|
||||
columns={[
|
||||
{
|
||||
id: 'select',
|
||||
header: ({ table }) => {
|
||||
const allRows = table.getRowModel().rows;
|
||||
const selectableRows = allRows;
|
||||
|
||||
const allSelected =
|
||||
selectableRows.every((row) => row.getIsSelected()) &&
|
||||
selectableRows.length != 0;
|
||||
|
||||
const someSelected =
|
||||
selectableRows.some((row) => row.getIsSelected()) &&
|
||||
!allSelected;
|
||||
|
||||
const toggleSelectableRows = () => {
|
||||
const shouldSelect = !allSelected;
|
||||
selectableRows.forEach((row) =>
|
||||
row.toggleSelected(shouldSelect)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-row justify-center'>
|
||||
<CheckboxInput
|
||||
name='allRow'
|
||||
checked={allSelected}
|
||||
indeterminate={someSelected}
|
||||
onChange={toggleSelectableRows}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<CheckboxInput
|
||||
name='row'
|
||||
checked={row.getIsSelected()}
|
||||
disabled={!row.getCanSelect()}
|
||||
indeterminate={row.getIsSomeSelected()}
|
||||
onChange={row.getToggleSelectedHandler()}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: 'flock_name',
|
||||
header: 'Flock',
|
||||
},
|
||||
{
|
||||
accessorKey: 'area.name',
|
||||
header: 'Area',
|
||||
},
|
||||
{
|
||||
accessorKey: 'location.name',
|
||||
header: 'Lokasi',
|
||||
},
|
||||
{
|
||||
accessorKey: 'fcr.name',
|
||||
header: 'FCR',
|
||||
},
|
||||
{
|
||||
accessorKey: 'category',
|
||||
header: 'Kategori',
|
||||
},
|
||||
{
|
||||
accessorKey: 'approval.step_name',
|
||||
header: 'Status',
|
||||
cell: (props) => {
|
||||
const approval = props.row.original.approval;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
variant='soft'
|
||||
className={{
|
||||
badge:
|
||||
'rounded-lg px-2 w-full flex flex-row justify-start',
|
||||
}}
|
||||
color={
|
||||
approval.step_number == 1
|
||||
? 'neutral'
|
||||
: approval.step_number == 2
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:circle'
|
||||
width={12}
|
||||
height={12}
|
||||
color={
|
||||
approval.step_number == 1
|
||||
? 'neutral'
|
||||
: approval.step_number == 2
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
/>
|
||||
{approval.step_name}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Kandang',
|
||||
cell: (props) => {
|
||||
const kandang = props.row.original.kandangs;
|
||||
if (kandang) {
|
||||
const kandangNames = kandang.map((k: Kandang) => k.name);
|
||||
return (
|
||||
<div>
|
||||
{kandangNames.length > 0
|
||||
? kandangNames.join(', ')
|
||||
: 'Tidak ada'}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'period',
|
||||
header: 'Periode',
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: 'Dibuat pada',
|
||||
cell: (props) =>
|
||||
formatDate(props.row.original.created_at, 'MMM DD, YYYY'),
|
||||
},
|
||||
]}
|
||||
columns={columns}
|
||||
pageSize={tableFilterState.pageSize}
|
||||
page={
|
||||
isResponseSuccess(projectFlocks) ? projectFlocks?.meta?.page : 0
|
||||
@@ -545,7 +453,12 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
? projectFlocks?.meta?.total_results
|
||||
: 0
|
||||
}
|
||||
onPageChange={setPage}
|
||||
onPageChange={(page) => {
|
||||
setPage(page);
|
||||
}}
|
||||
onPageSizeChange={(pageSize) => {
|
||||
setPageSize(pageSize);
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
sorting={sorting}
|
||||
setSorting={setSorting}
|
||||
@@ -553,9 +466,9 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||
setRowSelection={setRowSelection}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20':
|
||||
'mb-40':
|
||||
isResponseSuccess(projectFlocks) &&
|
||||
projectFlocks?.data?.length === 0,
|
||||
projectFlocks?.data?.length > 0,
|
||||
}),
|
||||
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
||||
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
||||
|
||||
@@ -289,4 +289,4 @@
|
||||
"debt_price": -181845000
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user