mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-331): implement permission guard in expense
This commit is contained in:
@@ -4,6 +4,7 @@ import toast from 'react-hot-toast';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
import DropFileInput from '@/components/input/DropFileInput';
|
import DropFileInput from '@/components/input/DropFileInput';
|
||||||
|
|
||||||
@@ -62,16 +63,17 @@ const ExpenseRealizationContent = ({
|
|||||||
<div>
|
<div>
|
||||||
<div className='w-full max-w-5xl mx-auto flex flex-col sm:flex-row justify-end gap-2'>
|
<div className='w-full max-w-5xl mx-auto flex flex-col sm:flex-row justify-end gap-2'>
|
||||||
<div className='w-full sm:w-fit sm:ml-2 flex flex-row gap-2 items-center'>
|
<div className='w-full sm:w-fit sm:ml-2 flex flex-row gap-2 items-center'>
|
||||||
{/* TODO: apply RBAC */}
|
<RequirePermission permissions='lti.expense.update.realization'>
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type='button'
|
||||||
color='warning'
|
color='warning'
|
||||||
href={`/expense/realization/edit/?expenseId=${initialValues?.id}`}
|
href={`/expense/realization/edit/?expenseId=${initialValues?.id}`}
|
||||||
className='px-4 grow sm:grow-0'
|
className='px-4 grow sm:grow-0'
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:pencil-outline' width={24} height={24} />
|
<Icon icon='mdi:pencil-outline' width={24} height={24} />
|
||||||
Edit Realisasi
|
Edit Realisasi
|
||||||
</Button>
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -124,36 +126,38 @@ const ExpenseRealizationContent = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col gap-2'>
|
<RequirePermission permissions='lti.expense.document.realization'>
|
||||||
<DropFileInput
|
<div className='flex flex-col gap-2'>
|
||||||
name='documents'
|
<DropFileInput
|
||||||
values={formik.values.documents}
|
name='documents'
|
||||||
onChange={realizationDocumentsChangeHandler}
|
values={formik.values.documents}
|
||||||
onDelete={realizationDocumentsDeleteHandler}
|
onChange={realizationDocumentsChangeHandler}
|
||||||
accept={{
|
onDelete={realizationDocumentsDeleteHandler}
|
||||||
...ACCEPTED_FILE_TYPE.PDF,
|
accept={{
|
||||||
...ACCEPTED_FILE_TYPE.IMAGE,
|
...ACCEPTED_FILE_TYPE.PDF,
|
||||||
}}
|
...ACCEPTED_FILE_TYPE.IMAGE,
|
||||||
maxFiles={10}
|
}}
|
||||||
className={{
|
maxFiles={10}
|
||||||
wrapper: 'mt-2',
|
className={{
|
||||||
inputWrapper: 'flex items-center',
|
wrapper: 'mt-2',
|
||||||
}}
|
inputWrapper: 'flex items-center',
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
{formik.values.documents &&
|
{formik.values.documents &&
|
||||||
formik.values.documents.length > 0 && (
|
formik.values.documents.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
onClick={formik.submitForm}
|
onClick={formik.submitForm}
|
||||||
disabled={formik.isSubmitting}
|
disabled={formik.isSubmitting}
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
className='w-fit self-end'
|
className='w-fit self-end'
|
||||||
>
|
>
|
||||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
<Icon icon='ic:round-plus' width={24} height={24} />
|
||||||
Tambah
|
Tambah
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</RequirePermission>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useModal } from '@/components/Modal';
|
|||||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||||
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
||||||
import ExpensePDFPreviewButton from '@/components/pages/expense//pdf/ExpensePDFButton';
|
import ExpensePDFPreviewButton from '@/components/pages/expense//pdf/ExpensePDFButton';
|
||||||
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
|
|
||||||
import { Expense } from '@/types/api/expense';
|
import { Expense } from '@/types/api/expense';
|
||||||
import { formatCurrency, formatDate } from '@/lib/helper';
|
import { formatCurrency, formatDate } from '@/lib/helper';
|
||||||
@@ -255,100 +256,119 @@ const ExpenseRequestContent = ({
|
|||||||
|
|
||||||
<div className='w-full max-w-5xl mx-auto flex flex-col sm:flex-row justify-end gap-2'>
|
<div className='w-full max-w-5xl mx-auto flex flex-col sm:flex-row justify-end gap-2'>
|
||||||
{isCurrentApprovalOnManager && (
|
{isCurrentApprovalOnManager && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.approve.manager'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='info'
|
variant='outline'
|
||||||
onClick={approveClickHandler}
|
color='info'
|
||||||
className='w-full sm:w-fit'
|
onClick={approveClickHandler}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon icon='lucide-lab:farm' width={24} height={24} />
|
>
|
||||||
Approve Manager
|
<Icon icon='lucide-lab:farm' width={24} height={24} />
|
||||||
</Button>
|
Approve Manager
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isCurrentApprovalOnFinance && (
|
{isCurrentApprovalOnFinance && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.approve.finance'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='success'
|
variant='outline'
|
||||||
onClick={approveClickHandler}
|
color='success'
|
||||||
className='w-full sm:w-fit'
|
onClick={approveClickHandler}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon icon='tdesign:money' width={24} height={24} />
|
>
|
||||||
Approve Finance
|
<Icon icon='tdesign:money' width={24} height={24} />
|
||||||
</Button>
|
Approve Finance
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isCurrentApprovalOnRealization && (
|
{isCurrentApprovalOnRealization && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.complete.expense'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='success'
|
variant='outline'
|
||||||
onClick={completeExpenseClickHandler}
|
color='success'
|
||||||
className='w-full sm:w-fit'
|
onClick={completeExpenseClickHandler}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon
|
>
|
||||||
icon='material-symbols:done-all-rounded'
|
<Icon
|
||||||
width={24}
|
icon='material-symbols:done-all-rounded'
|
||||||
height={24}
|
width={24}
|
||||||
/>
|
height={24}
|
||||||
Selesai
|
/>
|
||||||
</Button>
|
Selesai
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showRejectButton && (
|
{showRejectButton && (
|
||||||
<Button
|
<RequirePermission
|
||||||
variant='outline'
|
permissions={[
|
||||||
color='error'
|
'lti.expense.approve.manager',
|
||||||
onClick={rejectClickHandler}
|
'lti.expense.approve.finance',
|
||||||
className='w-full:w-fit'
|
]}
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:close' width={24} height={24} />
|
<Button
|
||||||
Reject
|
variant='outline'
|
||||||
</Button>
|
color='error'
|
||||||
|
onClick={rejectClickHandler}
|
||||||
|
className='w-full:w-fit'
|
||||||
|
>
|
||||||
|
<Icon icon='material-symbols:close' width={24} height={24} />
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isExpenseCanBeRealized && (
|
{isExpenseCanBeRealized && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.create.realization'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='info'
|
variant='outline'
|
||||||
href={`/expense/realization/?expenseId=${initialValues?.id}`}
|
color='info'
|
||||||
className='w-full sm:w-fit'
|
href={`/expense/realization/?expenseId=${initialValues?.id}`}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon
|
>
|
||||||
icon='material-symbols:money-bag-rounded'
|
<Icon
|
||||||
width={24}
|
icon='material-symbols:money-bag-rounded'
|
||||||
height={24}
|
width={24}
|
||||||
/>
|
height={24}
|
||||||
Realisasi
|
/>
|
||||||
</Button>
|
Realisasi
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='w-full sm:w-fit sm:ml-2 flex flex-row gap-2 items-center'>
|
<div className='w-full sm:w-fit sm:ml-2 flex flex-row gap-2 items-center'>
|
||||||
{showEditButton && (
|
{showEditButton && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.update'>
|
||||||
type='button'
|
<Button
|
||||||
color='warning'
|
type='button'
|
||||||
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
color='warning'
|
||||||
className='px-4 grow sm:grow-0'
|
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
||||||
>
|
className='px-4 grow sm:grow-0'
|
||||||
<Icon icon='mdi:pencil-outline' width={24} height={24} />
|
>
|
||||||
Edit
|
<Icon icon='mdi:pencil-outline' width={24} height={24} />
|
||||||
</Button>
|
Edit
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.delete'>
|
||||||
type='button'
|
<Button
|
||||||
color='error'
|
type='button'
|
||||||
onClick={deleteExpenseClickHandler}
|
color='error'
|
||||||
className='px-4 grow sm:grow-0'
|
onClick={deleteExpenseClickHandler}
|
||||||
>
|
className='px-4 grow sm:grow-0'
|
||||||
<Icon
|
>
|
||||||
icon='material-symbols:delete-outline-rounded'
|
<Icon
|
||||||
width={24}
|
icon='material-symbols:delete-outline-rounded'
|
||||||
height={24}
|
width={24}
|
||||||
className='justify-start text-sm'
|
height={24}
|
||||||
/>
|
className='justify-start text-sm'
|
||||||
Delete
|
/>
|
||||||
</Button>
|
Delete
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -485,36 +505,42 @@ const ExpenseRequestContent = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col gap-2'>
|
<RequirePermission permissions='lti.expense.document'>
|
||||||
<DropFileInput
|
<div className='flex flex-col gap-2'>
|
||||||
name='documents'
|
<DropFileInput
|
||||||
values={formik.values.documents}
|
name='documents'
|
||||||
onChange={requestDocumentsChangeHandler}
|
values={formik.values.documents}
|
||||||
onDelete={requestDocumentsDeleteHandler}
|
onChange={requestDocumentsChangeHandler}
|
||||||
accept={{
|
onDelete={requestDocumentsDeleteHandler}
|
||||||
...ACCEPTED_FILE_TYPE.PDF,
|
accept={{
|
||||||
...ACCEPTED_FILE_TYPE.IMAGE,
|
...ACCEPTED_FILE_TYPE.PDF,
|
||||||
}}
|
...ACCEPTED_FILE_TYPE.IMAGE,
|
||||||
maxFiles={10}
|
}}
|
||||||
className={{
|
maxFiles={10}
|
||||||
wrapper: 'mt-2',
|
className={{
|
||||||
inputWrapper: 'flex items-center',
|
wrapper: 'mt-2',
|
||||||
}}
|
inputWrapper: 'flex items-center',
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
{formik.values.documents &&
|
{formik.values.documents &&
|
||||||
formik.values.documents.length > 0 && (
|
formik.values.documents.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
onClick={formik.submitForm}
|
onClick={formik.submitForm}
|
||||||
disabled={formik.isSubmitting}
|
disabled={formik.isSubmitting}
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
className='w-fit self-end'
|
className='w-fit self-end'
|
||||||
>
|
>
|
||||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
<Icon
|
||||||
Tambah
|
icon='ic:round-plus'
|
||||||
</Button>
|
width={24}
|
||||||
)}
|
height={24}
|
||||||
</div>
|
/>
|
||||||
|
Tambah
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</RequirePermission>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import ExpenseStatusBadge from '@/components/pages/expense/ExpenseStatusBadge';
|
|||||||
import CheckboxInput from '@/components/input/CheckboxInput';
|
import CheckboxInput from '@/components/input/CheckboxInput';
|
||||||
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
||||||
import DateInput from '@/components/input/DateInput';
|
import DateInput from '@/components/input/DateInput';
|
||||||
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
|
|
||||||
import { Expense } from '@/types/api/expense';
|
import { Expense } from '@/types/api/expense';
|
||||||
import { ExpenseApi } from '@/services/api/expense';
|
import { ExpenseApi } from '@/services/api/expense';
|
||||||
@@ -67,58 +68,70 @@ const RowOptionsMenu = ({
|
|||||||
return (
|
return (
|
||||||
<RowOptionsMenuWrapper type={type}>
|
<RowOptionsMenuWrapper type={type}>
|
||||||
<div className='w-full max-h-40 overflow-auto flex flex-col gap-1'>
|
<div className='w-full max-h-40 overflow-auto flex flex-col gap-1'>
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.detail'>
|
||||||
href={`/expense/detail/?expenseId=${props.row.original.id}`}
|
|
||||||
variant='ghost'
|
|
||||||
color='primary'
|
|
||||||
className='justify-start text-sm'
|
|
||||||
>
|
|
||||||
<Icon icon='mdi:eye-outline' width={16} height={16} />
|
|
||||||
Detail
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{showEditButton && (
|
|
||||||
<Button
|
<Button
|
||||||
href={`/expense/detail/edit/?expenseId=${props.row.original.id}`}
|
href={`/expense/detail/?expenseId=${props.row.original.id}`}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='warning'
|
color='primary'
|
||||||
className='justify-start text-sm'
|
className='justify-start text-sm'
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:edit-outline' width={16} height={16} />
|
<Icon icon='mdi:eye-outline' width={16} height={16} />
|
||||||
Edit
|
Detail
|
||||||
</Button>
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
|
{showEditButton && (
|
||||||
|
<RequirePermission permissions='lti.expense.update'>
|
||||||
|
<Button
|
||||||
|
href={`/expense/detail/edit/?expenseId=${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>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showRealizationButton && (
|
{showRealizationButton && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.create.realization'>
|
||||||
href={`/expense/realization/?expenseId=${props.row.original.id}`}
|
<Button
|
||||||
variant='ghost'
|
href={`/expense/realization/?expenseId=${props.row.original.id}`}
|
||||||
color='info'
|
variant='ghost'
|
||||||
className='justify-start text-sm text-info focus-visible:text-info-content hover:text-info-content'
|
color='info'
|
||||||
>
|
className='justify-start text-sm text-info focus-visible:text-info-content hover:text-info-content'
|
||||||
<Icon
|
>
|
||||||
icon='material-symbols:money-bag-rounded'
|
<Icon
|
||||||
width={16}
|
icon='material-symbols:money-bag-rounded'
|
||||||
height={16}
|
width={16}
|
||||||
/>
|
height={16}
|
||||||
Realisasi
|
/>
|
||||||
</Button>
|
Realisasi
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.delete'>
|
||||||
onClick={deleteClickHandler}
|
<Button
|
||||||
variant='ghost'
|
onClick={deleteClickHandler}
|
||||||
color='error'
|
variant='ghost'
|
||||||
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
|
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'
|
<Icon
|
||||||
width={16}
|
icon='material-symbols:delete-outline-rounded'
|
||||||
height={16}
|
width={16}
|
||||||
className='justify-start text-sm'
|
height={16}
|
||||||
/>
|
className='justify-start text-sm'
|
||||||
Delete
|
/>
|
||||||
</Button>
|
Delete
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
</div>
|
</div>
|
||||||
</RowOptionsMenuWrapper>
|
</RowOptionsMenuWrapper>
|
||||||
);
|
);
|
||||||
@@ -559,57 +572,70 @@ const ExpensesTable = () => {
|
|||||||
<div className='flex flex-col gap-2 mb-4'>
|
<div className='flex flex-col gap-2 mb-4'>
|
||||||
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-4'>
|
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-4'>
|
||||||
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
|
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.create'>
|
||||||
href='/expense/add'
|
<Button
|
||||||
variant='outline'
|
href='/expense/add'
|
||||||
color='primary'
|
variant='outline'
|
||||||
className='w-full sm:w-fit'
|
color='primary'
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon icon='ic:round-plus' width={24} height={24} />
|
>
|
||||||
Tambah
|
<Icon icon='ic:round-plus' width={24} height={24} />
|
||||||
</Button>
|
Tambah
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
{selectedRowIds.length > 0 && (
|
{selectedRowIds.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.approve.manager'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='info'
|
variant='outline'
|
||||||
onClick={bulkApproveClickHandler}
|
color='info'
|
||||||
disabled={!isAllSelectedRowLatestApprovalOnManager}
|
onClick={bulkApproveClickHandler}
|
||||||
className='w-full sm:w-fit'
|
disabled={!isAllSelectedRowLatestApprovalOnManager}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon icon='lucide-lab:farm' width={24} height={24} />
|
>
|
||||||
Approve Manager
|
<Icon icon='lucide-lab:farm' width={24} height={24} />
|
||||||
</Button>
|
Approve Manager
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.approve.finance'>
|
||||||
variant='outline'
|
<Button
|
||||||
color='success'
|
variant='outline'
|
||||||
onClick={bulkApproveClickHandler}
|
color='success'
|
||||||
disabled={!isAllSelectedRowLatestApprovalOnFinance}
|
onClick={bulkApproveClickHandler}
|
||||||
className='w-full sm:w-fit'
|
disabled={!isAllSelectedRowLatestApprovalOnFinance}
|
||||||
>
|
className='w-full sm:w-fit'
|
||||||
<Icon icon='tdesign:money' width={24} height={24} />
|
>
|
||||||
Approve Finance
|
<Icon icon='tdesign:money' width={24} height={24} />
|
||||||
</Button>
|
Approve Finance
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
<Button
|
<RequirePermission
|
||||||
variant='outline'
|
permissions={[
|
||||||
color='error'
|
'lti.expense.approve.manager',
|
||||||
onClick={bulkRejectClickHandler}
|
'lti.expense.approve.finance',
|
||||||
disabled={
|
]}
|
||||||
!isAllSelectedRowLatestApprovalOnManager &&
|
|
||||||
!isAllSelectedRowLatestApprovalOnFinance
|
|
||||||
}
|
|
||||||
className='w-full sm:w-fit'
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Button
|
||||||
icon='material-symbols:close'
|
variant='outline'
|
||||||
width={24}
|
color='error'
|
||||||
height={24}
|
onClick={bulkRejectClickHandler}
|
||||||
/>
|
disabled={
|
||||||
Reject
|
!isAllSelectedRowLatestApprovalOnManager &&
|
||||||
</Button>
|
!isAllSelectedRowLatestApprovalOnFinance
|
||||||
|
}
|
||||||
|
className='w-full sm:w-fit'
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:close'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import DateInput from '@/components/input/DateInput';
|
|||||||
import DropFileInput from '@/components/input/DropFileInput';
|
import DropFileInput from '@/components/input/DropFileInput';
|
||||||
import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable';
|
import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable';
|
||||||
import ExpenseRealizationKandangDetailExpense from '@/components/pages/expense/form/ExpenseRealizationKandangDetailExpense';
|
import ExpenseRealizationKandangDetailExpense from '@/components/pages/expense/form/ExpenseRealizationKandangDetailExpense';
|
||||||
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CreateExpenseRealizationPayload,
|
CreateExpenseRealizationPayload,
|
||||||
@@ -290,21 +291,23 @@ const ExpenseRealizationForm = ({
|
|||||||
className={{ wrapper: 'col-span-12' }}
|
className={{ wrapper: 'col-span-12' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DropFileInput
|
<RequirePermission permissions='lti.expense.document.realization'>
|
||||||
label='Dokumen Realisasi'
|
<DropFileInput
|
||||||
name='documents'
|
label='Dokumen Realisasi'
|
||||||
values={formik.values.documents}
|
name='documents'
|
||||||
onChange={realizationDocumentsChangeHandler}
|
values={formik.values.documents}
|
||||||
onDelete={realizationDocumentsDeleteHandler}
|
onChange={realizationDocumentsChangeHandler}
|
||||||
accept={{
|
onDelete={realizationDocumentsDeleteHandler}
|
||||||
...ACCEPTED_FILE_TYPE.PDF,
|
accept={{
|
||||||
...ACCEPTED_FILE_TYPE.IMAGE,
|
...ACCEPTED_FILE_TYPE.PDF,
|
||||||
}}
|
...ACCEPTED_FILE_TYPE.IMAGE,
|
||||||
className={{
|
}}
|
||||||
wrapper: 'col-span-12',
|
className={{
|
||||||
inputWrapper: 'h-12 flex items-center',
|
wrapper: 'col-span-12',
|
||||||
}}
|
inputWrapper: 'h-12 flex items-center',
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
{formik.values.existing_documents &&
|
{formik.values.existing_documents &&
|
||||||
formik.values.existing_documents.length > 0 && (
|
formik.values.existing_documents.length > 0 && (
|
||||||
@@ -357,20 +360,22 @@ const ExpenseRealizationForm = ({
|
|||||||
{type !== 'add' && (
|
{type !== 'add' && (
|
||||||
<div className='flex flex-row justify-start gap-2'>
|
<div className='flex flex-row justify-start gap-2'>
|
||||||
{type !== 'edit' && (
|
{type !== 'edit' && (
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.update'>
|
||||||
type='button'
|
<Button
|
||||||
color='warning'
|
type='button'
|
||||||
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
color='warning'
|
||||||
className='px-4'
|
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
||||||
>
|
className='px-4'
|
||||||
<Icon
|
>
|
||||||
icon='material-symbols:edit-outline'
|
<Icon
|
||||||
width={24}
|
icon='material-symbols:edit-outline'
|
||||||
height={24}
|
width={24}
|
||||||
className='justify-start text-sm'
|
height={24}
|
||||||
/>
|
className='justify-start text-sm'
|
||||||
Edit
|
/>
|
||||||
</Button>
|
Edit
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import DateInput from '@/components/input/DateInput';
|
|||||||
import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable';
|
import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable';
|
||||||
import DropFileInput from '@/components/input/DropFileInput';
|
import DropFileInput from '@/components/input/DropFileInput';
|
||||||
import ExpenseRequestKandangDetailExpense from '@/components/pages/expense/form/ExpenseRequestKandangDetailExpense';
|
import ExpenseRequestKandangDetailExpense from '@/components/pages/expense/form/ExpenseRequestKandangDetailExpense';
|
||||||
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExpenseRequestFormSchema,
|
ExpenseRequestFormSchema,
|
||||||
@@ -385,21 +386,23 @@ const ExpenseRequestForm = ({
|
|||||||
className={{ wrapper: 'col-span-12' }}
|
className={{ wrapper: 'col-span-12' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DropFileInput
|
<RequirePermission permissions='lti.expense.document'>
|
||||||
label='Dokumen Pengajuan'
|
<DropFileInput
|
||||||
name='documents'
|
label='Dokumen Pengajuan'
|
||||||
values={formik.values.documents}
|
name='documents'
|
||||||
onChange={requestDocumentsChangeHandler}
|
values={formik.values.documents}
|
||||||
onDelete={requestDocumentsDeleteHandler}
|
onChange={requestDocumentsChangeHandler}
|
||||||
accept={{
|
onDelete={requestDocumentsDeleteHandler}
|
||||||
...ACCEPTED_FILE_TYPE.PDF,
|
accept={{
|
||||||
...ACCEPTED_FILE_TYPE.IMAGE,
|
...ACCEPTED_FILE_TYPE.PDF,
|
||||||
}}
|
...ACCEPTED_FILE_TYPE.IMAGE,
|
||||||
className={{
|
}}
|
||||||
wrapper: 'col-span-12',
|
className={{
|
||||||
inputWrapper: 'h-12 flex items-center',
|
wrapper: 'col-span-12',
|
||||||
}}
|
inputWrapper: 'h-12 flex items-center',
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
{formik.values.existing_documents &&
|
{formik.values.existing_documents &&
|
||||||
formik.values.existing_documents.length > 0 && (
|
formik.values.existing_documents.length > 0 && (
|
||||||
@@ -461,36 +464,40 @@ const ExpenseRequestForm = ({
|
|||||||
<div className='flex flex-row justify-between gap-2 flex-wrap'>
|
<div className='flex flex-row justify-between gap-2 flex-wrap'>
|
||||||
{type !== 'add' && (
|
{type !== 'add' && (
|
||||||
<div className='flex flex-row justify-start gap-2'>
|
<div className='flex flex-row justify-start gap-2'>
|
||||||
<Button
|
<RequirePermission permissions='lti.expense.delete'>
|
||||||
type='button'
|
|
||||||
color='error'
|
|
||||||
onClick={deleteExpenseClickHandler}
|
|
||||||
className='px-4'
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:delete-outline-rounded'
|
|
||||||
width={24}
|
|
||||||
height={24}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Delete
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{type !== 'edit' && (
|
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type='button'
|
||||||
color='warning'
|
color='error'
|
||||||
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
onClick={deleteExpenseClickHandler}
|
||||||
className='px-4'
|
className='px-4'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon='material-symbols:edit-outline'
|
icon='material-symbols:delete-outline-rounded'
|
||||||
width={24}
|
width={24}
|
||||||
height={24}
|
height={24}
|
||||||
className='justify-start text-sm'
|
className='justify-start text-sm'
|
||||||
/>
|
/>
|
||||||
Edit
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
|
|
||||||
|
{type !== 'edit' && (
|
||||||
|
<RequirePermission permissions='lti.expense.update'>
|
||||||
|
<Button
|
||||||
|
type='button'
|
||||||
|
color='warning'
|
||||||
|
href={`/expense/detail/edit/?expenseId=${initialValues?.id}`}
|
||||||
|
className='px-4'
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon='material-symbols:edit-outline'
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
className='justify-start text-sm'
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user