diff --git a/src/components/FloatingActionsButton.tsx b/src/components/FloatingActionsButton.tsx index 2e4eed07..974ca280 100644 --- a/src/components/FloatingActionsButton.tsx +++ b/src/components/FloatingActionsButton.tsx @@ -5,6 +5,8 @@ import Tooltip from '@/components/Tooltip'; import { cn } from '@/lib/helper'; import { Icon } from '@iconify/react'; +import { useAuth } from '@/services/hooks/useAuth'; + type FloatingActionsButtonProps = { actions: { action: 'DETAIL' | 'EDIT' | 'DELETE'; @@ -13,6 +15,7 @@ type FloatingActionsButtonProps = { onClick?: () => void; hidden?: boolean; disabled?: boolean; + permissions?: string | string[]; }[]; approvals: { action: 'APPROVED' | 'REJECTED'; @@ -20,6 +23,7 @@ type FloatingActionsButtonProps = { label?: string; onClick?: () => void; disabled?: boolean; + permissions?: string | string[]; }[]; selectedRowIds: number[]; onClose: () => void; @@ -31,6 +35,7 @@ const FloatingActionsButton = ({ selectedRowIds, onClose, }: FloatingActionsButtonProps) => { + const { permissionCheck } = useAuth(); // Jika tidak ada baris yang dipilih, jangan tampilkan FAB const positionStyles = selectedRowIds.length > 0 @@ -71,7 +76,18 @@ const FloatingActionsButton = ({
{/* Render Aksi dari props.actions */} {actions - .filter((action) => !action.hidden) + .filter((action) => { + if (action.hidden) return false; + if (action.permissions) { + if (typeof action.permissions === 'string') { + return permissionCheck(action.permissions); + } + return action.permissions.some((permission) => + permissionCheck(permission) + ); + } + return true; + }) .map((action, index) => { return ( - ))} + {approvals + .filter((approval) => { + if (approval.permissions) { + if (typeof approval.permissions === 'string') { + return permissionCheck(approval.permissions); + } + return approval.permissions.some((permission) => + permissionCheck(permission) + ); + } + return true; + }) + .map((approval, index) => ( + + ))}
diff --git a/src/components/MainDrawer.tsx b/src/components/MainDrawer.tsx index 3a09c0b1..fc8cbb18 100644 --- a/src/components/MainDrawer.tsx +++ b/src/components/MainDrawer.tsx @@ -9,10 +9,13 @@ import Drawer from '@/components/Drawer'; import Navbar from '@/components/Navbar'; import Button from '@/components/Button'; import SidebarMenu from '@/components/molecules/SidebarMenu'; +import PermissionNotFound from '@/components/helper/PermissionNotFound'; import { useUiStore } from '@/stores/ui/ui.store'; import { MAIN_DRAWER_LINKS } from '@/config/constant'; import { isPathActive } from '@/lib/helper'; +import { ROUTE_PERMISSIONS } from '@/config/route-permission'; +import { useAuth } from '@/services/hooks/useAuth'; const MainDrawerContent = () => { const pathname = usePathname(); @@ -62,6 +65,11 @@ const MainDrawer = ({ }>) => { const { mainDrawerOpen, setMainDrawerOpen } = useUiStore(); const pathname = usePathname(); + const { permissionCheck } = useAuth(); + + const isPermitted = ROUTE_PERMISSIONS[pathname]?.some((permission) => + permissionCheck(permission) + ); const getPageTitle = useCallback(() => { let title = ''; @@ -101,6 +109,10 @@ const MainDrawer = ({ setMainDrawerOpen(!mainDrawerOpen); }; + if (!isPermitted) { + return ; + } + return ( { + return ( +
+

Permission Not Found

+

+ You do not have permission to access this page. +

+
+ ); +}; + +export default PermissionNotFound; diff --git a/src/components/helper/RequirePermission.tsx b/src/components/helper/RequirePermission.tsx new file mode 100644 index 00000000..2a7061ed --- /dev/null +++ b/src/components/helper/RequirePermission.tsx @@ -0,0 +1,28 @@ +'use client'; + +import { useAuth } from '@/services/hooks/useAuth'; + +interface RequirePermissionProps { + children: React.ReactNode; + permissions: string | string[]; +} + +const RequirePermission = ({ + children, + permissions, +}: RequirePermissionProps) => { + const { permissionCheck } = useAuth(); + + const isPermitted = + typeof permissions === 'string' + ? permissionCheck(permissions) + : permissions.some((permission) => permissionCheck(permission)); + + if (!isPermitted) { + return null; + } + + return <>{children}; +}; + +export default RequirePermission; diff --git a/src/components/molecules/SidebarMenu.tsx b/src/components/molecules/SidebarMenu.tsx index 6a217dcc..4b85c2c8 100644 --- a/src/components/molecules/SidebarMenu.tsx +++ b/src/components/molecules/SidebarMenu.tsx @@ -2,6 +2,7 @@ import Link from 'next/link'; import Menu from '@/components/menu/Menu'; import { Icon } from '@iconify/react'; import { cn, isPathActive } from '@/lib/helper'; +import { useAuth } from '@/services/hooks/useAuth'; export interface SidebarMenuItem { type?: 'item' | 'title'; @@ -9,6 +10,7 @@ export interface SidebarMenuItem { link: string; icon?: string; submenu?: SidebarMenuItem[]; + permission?: string[]; } interface SidebarMenuItemProps { @@ -22,8 +24,17 @@ interface SidebarMenuProps { } const SidebarMenuItem = ({ item, activeLink }: SidebarMenuItemProps) => { + const { permissionCheck } = useAuth(); const isItemActive = isPathActive(activeLink, item.link); + const isUserPermitted = item.permission + ? item.permission?.some((permissionName) => permissionCheck(permissionName)) + : true; + + if (!isUserPermitted) { + return null; + } + const menuItemWithoutSubmenu = (
  • { const SidebarMenu = ({ menu, activeLink }: SidebarMenuProps) => { return ( - {menu.map((menuItem, menuIdx) => ( - - ))} + {menu.map((menuItem, menuIdx) => { + return ( + + ); + })} ); }; diff --git a/src/components/pages/closing/ClosingsTable.tsx b/src/components/pages/closing/ClosingsTable.tsx index 91e78c8c..e6574d4f 100644 --- a/src/components/pages/closing/ClosingsTable.tsx +++ b/src/components/pages/closing/ClosingsTable.tsx @@ -15,6 +15,8 @@ import SelectInput, { import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; + import { cn, formatCurrency, formatDate } from '@/lib/helper'; import { isResponseSuccess } from '@/lib/api-helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; @@ -43,17 +45,18 @@ const RowOptionsMenu = ({ }) => { return ( - {/* TODO: apply RBAC */}
    - + + +
    ); diff --git a/src/components/pages/expense/ExpenseRealizationContent.tsx b/src/components/pages/expense/ExpenseRealizationContent.tsx index 2b5b0a0a..c69f089f 100644 --- a/src/components/pages/expense/ExpenseRealizationContent.tsx +++ b/src/components/pages/expense/ExpenseRealizationContent.tsx @@ -4,6 +4,7 @@ import toast from 'react-hot-toast'; import Link from 'next/link'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; +import RequirePermission from '@/components/helper/RequirePermission'; import Card from '@/components/Card'; import DropFileInput from '@/components/input/DropFileInput'; @@ -62,16 +63,17 @@ const ExpenseRealizationContent = ({
    - {/* TODO: apply RBAC */} - + + +
    @@ -124,36 +126,38 @@ const ExpenseRealizationContent = ({ )}
    -
    - + +
    + - {formik.values.documents && - formik.values.documents.length > 0 && ( - - )} -
    + {formik.values.documents && + formik.values.documents.length > 0 && ( + + )} +
    + diff --git a/src/components/pages/expense/ExpenseRequestContent.tsx b/src/components/pages/expense/ExpenseRequestContent.tsx index 0d7d959d..b937c5bc 100644 --- a/src/components/pages/expense/ExpenseRequestContent.tsx +++ b/src/components/pages/expense/ExpenseRequestContent.tsx @@ -19,6 +19,7 @@ import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import ExpensePDFPreviewButton from '@/components/pages/expense//pdf/ExpensePDFButton'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Expense } from '@/types/api/expense'; import { formatCurrency, formatDate } from '@/lib/helper'; @@ -255,100 +256,119 @@ const ExpenseRequestContent = ({
    {isCurrentApprovalOnManager && ( - + + + )} {isCurrentApprovalOnFinance && ( - + + + )} {isCurrentApprovalOnRealization && ( - + + + )} {showRejectButton && ( - + + )} {isExpenseCanBeRealized && ( - + + + )}
    {showEditButton && ( - + + + )} - + + +
    @@ -485,36 +505,42 @@ const ExpenseRequestContent = ({ )} -
    - + +
    + - {formik.values.documents && - formik.values.documents.length > 0 && ( - - )} -
    + {formik.values.documents && + formik.values.documents.length > 0 && ( + + )} +
    + diff --git a/src/components/pages/expense/ExpensesTable.tsx b/src/components/pages/expense/ExpensesTable.tsx index bbcb6c4e..9ae3ed34 100644 --- a/src/components/pages/expense/ExpensesTable.tsx +++ b/src/components/pages/expense/ExpensesTable.tsx @@ -28,6 +28,7 @@ import ExpenseStatusBadge from '@/components/pages/expense/ExpenseStatusBadge'; import CheckboxInput from '@/components/input/CheckboxInput'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import DateInput from '@/components/input/DateInput'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Expense } from '@/types/api/expense'; import { ExpenseApi } from '@/services/api/expense'; @@ -67,58 +68,70 @@ const RowOptionsMenu = ({ return (
    - - - {showEditButton && ( + + + + {showEditButton && ( + + + )} {showRealizationButton && ( - + + + )} - + + +
    ); @@ -559,57 +572,70 @@ const ExpensesTable = () => {
    - + + + {selectedRowIds.length > 0 && ( <> - + + + - + + + - + + )}
    diff --git a/src/components/pages/expense/form/ExpenseRealizationForm.tsx b/src/components/pages/expense/form/ExpenseRealizationForm.tsx index a7ebdbca..d1c7c5f2 100644 --- a/src/components/pages/expense/form/ExpenseRealizationForm.tsx +++ b/src/components/pages/expense/form/ExpenseRealizationForm.tsx @@ -16,6 +16,7 @@ import DateInput from '@/components/input/DateInput'; import DropFileInput from '@/components/input/DropFileInput'; import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable'; import ExpenseRealizationKandangDetailExpense from '@/components/pages/expense/form/ExpenseRealizationKandangDetailExpense'; +import RequirePermission from '@/components/helper/RequirePermission'; import { CreateExpenseRealizationPayload, @@ -290,21 +291,23 @@ const ExpenseRealizationForm = ({ className={{ wrapper: 'col-span-12' }} /> - + + + {formik.values.existing_documents && formik.values.existing_documents.length > 0 && ( @@ -357,20 +360,22 @@ const ExpenseRealizationForm = ({ {type !== 'add' && (
    {type !== 'edit' && ( - + + + )}
    )} diff --git a/src/components/pages/expense/form/ExpenseRequestForm.tsx b/src/components/pages/expense/form/ExpenseRequestForm.tsx index d52bde0d..71160785 100644 --- a/src/components/pages/expense/form/ExpenseRequestForm.tsx +++ b/src/components/pages/expense/form/ExpenseRequestForm.tsx @@ -18,6 +18,7 @@ import DateInput from '@/components/input/DateInput'; import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable'; import DropFileInput from '@/components/input/DropFileInput'; import ExpenseRequestKandangDetailExpense from '@/components/pages/expense/form/ExpenseRequestKandangDetailExpense'; +import RequirePermission from '@/components/helper/RequirePermission'; import { ExpenseRequestFormSchema, @@ -385,21 +386,23 @@ const ExpenseRequestForm = ({ className={{ wrapper: 'col-span-12' }} /> - + + + {formik.values.existing_documents && formik.values.existing_documents.length > 0 && ( @@ -461,36 +464,40 @@ const ExpenseRequestForm = ({
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/inventory/adjustment/InventoryAdjustmentTable.tsx b/src/components/pages/inventory/adjustment/InventoryAdjustmentTable.tsx index a3de8a34..7612a081 100644 --- a/src/components/pages/inventory/adjustment/InventoryAdjustmentTable.tsx +++ b/src/components/pages/inventory/adjustment/InventoryAdjustmentTable.tsx @@ -4,6 +4,7 @@ import Badge from '@/components/Badge'; import Button from '@/components/Button'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; import Table from '@/components/Table'; +import RequirePermission from '@/components/helper/RequirePermission'; import { ROWS_OPTIONS } from '@/config/constant'; import { isResponseSuccess } from '@/lib/api-helper'; import { cn } from '@/lib/helper'; @@ -175,15 +176,17 @@ const InventoryAdjustmentTable = () => {
    - + + + {/* ; }) => ( - + + + ); @@ -145,15 +148,17 @@ const MovementTable = () => {
    - + + +
    ; }) => ( - + + + ); diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index d1d5940a..bb6c5569 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -26,6 +26,8 @@ import { useRouter } from 'next/navigation'; import { useCallback, useState } from 'react'; import toast from 'react-hot-toast'; import useSWR from 'swr'; +import RequirePermission from '@/components/helper/RequirePermission'; +import { useAuth } from '@/services/hooks/useAuth'; const RowsOptionsMenu = ({ type = 'dropdown', @@ -50,57 +52,71 @@ const RowsOptionsMenu = ({ )} >
    - - {props.row.original.latest_approval.step_number != 1 && ( + + + {props.row.original.latest_approval.step_number != 1 && ( + + + )} {props.row.original.latest_approval.step_number != 3 && ( - + + + )} - + + +
    ); @@ -116,6 +132,7 @@ const MarketingTable = () => { ); const [selectedItem, setSelectedItem] = useState(null); const [rowSelection, setRowSelection] = useState>({}); + const { permissionCheck } = useAuth(); const router = useRouter(); @@ -270,10 +287,14 @@ const MarketingTable = () => {
    { }} />
    - + + + - + + +
    {initialValues?.latest_approval?.step_number == 1 && ( <> - - + + + + + + + )} {initialValues?.latest_approval?.step_number != 1 && ( - + + )}
    @@ -413,19 +427,23 @@ const MarketingDetail = ({ )}
    {initialValues?.latest_approval?.step_number != 3 && ( - + + + )} - + + +
    - + + +
    )} diff --git a/src/components/pages/master-data/area/AreasTable.tsx b/src/components/pages/master-data/area/AreasTable.tsx index 207fb8a6..45c4fdff 100644 --- a/src/components/pages/master-data/area/AreasTable.tsx +++ b/src/components/pages/master-data/area/AreasTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Area } from '@/types/api/master-data/area'; import { AreaApi } from '@/services/api/master-data'; @@ -34,40 +35,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -192,15 +199,19 @@ const AreasTable = () => {
    - +
    + + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/bank/BanksTable.tsx b/src/components/pages/master-data/bank/BanksTable.tsx index 58b09ef8..f28f4bd0 100644 --- a/src/components/pages/master-data/bank/BanksTable.tsx +++ b/src/components/pages/master-data/bank/BanksTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Bank } from '@/types/api/master-data/bank'; import { BankApi } from '@/services/api/master-data'; @@ -34,40 +35,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -205,15 +212,17 @@ const BanksTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/customer/CustomersTable.tsx b/src/components/pages/master-data/customer/CustomersTable.tsx index 89401638..3e442620 100644 --- a/src/components/pages/master-data/customer/CustomersTable.tsx +++ b/src/components/pages/master-data/customer/CustomersTable.tsx @@ -9,6 +9,7 @@ import Table from '@/components/Table'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { ROWS_OPTIONS } from '@/config/constant'; import { isResponseSuccess } from '@/lib/api-helper'; import { cn } from '@/lib/helper'; @@ -32,38 +33,44 @@ const RowOptionsMenu = ({ }) => { return ( - - - + > + + Detail + + + + + + + + ); }; @@ -200,15 +207,17 @@ const CustomersTable = () => {
    - + + +
    {formType !== 'add' && (
    - - - {formType !== 'edit' && ( + + + + {formType !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/fcr/FcrsTable.tsx b/src/components/pages/master-data/fcr/FcrsTable.tsx index b582222e..2d65a406 100644 --- a/src/components/pages/master-data/fcr/FcrsTable.tsx +++ b/src/components/pages/master-data/fcr/FcrsTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Fcr } from '@/types/api/master-data/fcr'; import { FcrApi } from '@/services/api/master-data'; @@ -34,40 +35,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -192,15 +199,17 @@ const FcrsTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/flock/FlocksTable.tsx b/src/components/pages/master-data/flock/FlocksTable.tsx index 5350c518..ce8f701a 100644 --- a/src/components/pages/master-data/flock/FlocksTable.tsx +++ b/src/components/pages/master-data/flock/FlocksTable.tsx @@ -13,6 +13,7 @@ import { useModal } from '@/components/Modal'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import toast from 'react-hot-toast'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; @@ -32,48 +33,54 @@ const RowsOptions = ({ }) => { return ( - - + + + - + > + + Detail + + + + + ); }; @@ -196,15 +203,17 @@ const FlockTable = () => {
    - + + +
    {
    {formType !== 'add' && (
    - - {formType !== 'edit' && ( + + + {formType !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/kandang/KandangsTable.tsx b/src/components/pages/master-data/kandang/KandangsTable.tsx index eebc490a..1bd7badb 100644 --- a/src/components/pages/master-data/kandang/KandangsTable.tsx +++ b/src/components/pages/master-data/kandang/KandangsTable.tsx @@ -20,6 +20,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Kandang } from '@/types/api/master-data/kandang'; import { KandangApi } from '@/services/api/master-data'; @@ -39,40 +40,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -243,15 +250,19 @@ const KandangsTable = () => {
    - +
    + + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/location/LocationsTable.tsx b/src/components/pages/master-data/location/LocationsTable.tsx index 19f11298..10fe46c9 100644 --- a/src/components/pages/master-data/location/LocationsTable.tsx +++ b/src/components/pages/master-data/location/LocationsTable.tsx @@ -20,6 +20,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Location } from '@/types/api/master-data/location'; import { LocationApi } from '@/services/api/master-data'; @@ -39,40 +40,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -230,15 +237,19 @@ const LocationsTable = () => {
    - +
    + + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/nonstock/NonstocksTable.tsx b/src/components/pages/master-data/nonstock/NonstocksTable.tsx index ae38c573..7066c19a 100644 --- a/src/components/pages/master-data/nonstock/NonstocksTable.tsx +++ b/src/components/pages/master-data/nonstock/NonstocksTable.tsx @@ -20,6 +20,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Nonstock } from '@/types/api/master-data/nonstock'; import { NonstockApi } from '@/services/api/master-data'; @@ -39,40 +40,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -242,15 +249,17 @@ const NonstocksTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/product-category/ProductCategoryTable.tsx b/src/components/pages/master-data/product-category/ProductCategoryTable.tsx index 1a6e641c..a9b98bcb 100644 --- a/src/components/pages/master-data/product-category/ProductCategoryTable.tsx +++ b/src/components/pages/master-data/product-category/ProductCategoryTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { ProductCategory } from '@/types/api/master-data/product-category'; import { ProductCategoryApi } from '@/services/api/master-data'; @@ -34,38 +35,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - + > + + Detail + + + + + + + + + + ); }; @@ -193,15 +202,17 @@ const ProductCategoryTable = () => {
    - + + +
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/product/ProductTable.tsx b/src/components/pages/master-data/product/ProductTable.tsx index 2a94656c..957d0551 100644 --- a/src/components/pages/master-data/product/ProductTable.tsx +++ b/src/components/pages/master-data/product/ProductTable.tsx @@ -20,6 +20,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Product } from '@/types/api/master-data/product'; import { ProductApi } from '@/services/api/master-data'; @@ -38,38 +39,44 @@ const RowOptionsMenu = ({ deleteClickHandler: () => void; }) => ( - - - + > + + Detail + + + + + + + + ); @@ -273,15 +280,17 @@ const ProductsTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - {type !== 'edit' && ( + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/supplier/SupplierTable.tsx b/src/components/pages/master-data/supplier/SupplierTable.tsx index da84afc0..3e10c9c8 100644 --- a/src/components/pages/master-data/supplier/SupplierTable.tsx +++ b/src/components/pages/master-data/supplier/SupplierTable.tsx @@ -9,6 +9,7 @@ import Table from '@/components/Table'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { ROWS_OPTIONS } from '@/config/constant'; import { isResponseSuccess } from '@/lib/api-helper'; import { cn } from '@/lib/helper'; @@ -32,48 +33,54 @@ const RowOptions = ({ }) => { return ( - - + + + - + > + + Edit + + + + + ); }; @@ -219,15 +226,17 @@ const SuppliersTable = () => {
    - + + +
    {formType !== 'add' && (
    - - - {formType !== 'edit' && ( + + + + {formType !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/uom/UomsTable.tsx b/src/components/pages/master-data/uom/UomsTable.tsx index edf67f34..851647b9 100644 --- a/src/components/pages/master-data/uom/UomsTable.tsx +++ b/src/components/pages/master-data/uom/UomsTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Uom } from '@/types/api/master-data/uom'; import { UomApi } from '@/services/api/master-data'; @@ -34,40 +35,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -192,15 +199,17 @@ const UomsTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/master-data/warehouse/WarehousesTable.tsx b/src/components/pages/master-data/warehouse/WarehousesTable.tsx index a61f6f5b..fe694322 100644 --- a/src/components/pages/master-data/warehouse/WarehousesTable.tsx +++ b/src/components/pages/master-data/warehouse/WarehousesTable.tsx @@ -20,6 +20,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { Warehouse } from '@/types/api/master-data/warehouse'; import { WarehouseApi } from '@/services/api/master-data'; @@ -39,40 +40,46 @@ const RowOptionsMenu = ({ }) => { return ( - - - - - + > + + Detail + + + + + + + + + + ); }; @@ -270,15 +277,17 @@ const WarehousesTable = () => {
    - + + +
    {
    {type !== 'add' && (
    - - - {type !== 'edit' && ( + + + + {type !== 'edit' && ( + + + )}
    )} diff --git a/src/components/pages/production/project-flock/ProjectFlockTable.tsx b/src/components/pages/production/project-flock/ProjectFlockTable.tsx index 4be30f7a..7f8ee104 100644 --- a/src/components/pages/production/project-flock/ProjectFlockTable.tsx +++ b/src/components/pages/production/project-flock/ProjectFlockTable.tsx @@ -25,6 +25,8 @@ import { ChangeEventHandler, useEffect, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import useSWR from 'swr'; +import RequirePermission from '@/components/helper/RequirePermission'; + const RowOptionsMenu = ({ type = 'dropdown', props, @@ -46,50 +48,58 @@ const RowOptionsMenu = ({ )} >
    - - {props.row.original.approval.step_name === 'Aktif' && ( + + + {props.row.original.approval.step_name === 'Aktif' && ( + + + )} {props.row.original.approval.step_name === 'Pengajuan' && ( - + + + )} - + + +
    ); @@ -287,14 +297,16 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
    - + + + {/*
    - + + +
    ))}
    diff --git a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx index 41b511c9..0ee3ae32 100644 --- a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx +++ b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx @@ -29,6 +29,7 @@ import { } from '@/config/approval-line'; import useSWR from 'swr'; import { ProjectFlockKandangApi } from '@/services/api/production'; +import RequirePermission from '@/components/helper/RequirePermission'; const ProjectFlockDetail = ({ projectFlock, @@ -110,27 +111,31 @@ const ProjectFlockDetail = ({ leftIconHref='/production/project-flock' subtitle={`Created On ${formatDate(projectFlock.created_at, 'MMM DD, YYYY')}`} > - - - - - - + + + + + + + + + + {/* Informasi Umum */} @@ -418,38 +423,42 @@ const ProjectFlockDetail = ({
    - - - - - + + + + - Close - - + + +
    diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx index 5ce62733..46830879 100644 --- a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx @@ -47,6 +47,7 @@ import Card from '@/components/Card'; import ProjectFlockKandangTable from '@/components/pages/production/project-flock/form/ProjectFlockKandangTable'; import { Nonstock } from '@/types/api/master-data/nonstock'; import { useUiStore } from '@/stores/ui/ui.store'; +import RequirePermission from '@/components/helper/RequirePermission'; import DrawerHeader from '@/components/helper/drawer/DrawerHeader'; interface ProjectFlockFormProps { @@ -734,36 +735,40 @@ const ProjectFlockForm = ({ )} {formType == 'detail' && (
    - - + + + + + +
    )}
    */} {formType !== 'detail' && ( - + + )}
    diff --git a/src/components/pages/production/recording/RecordingTable.tsx b/src/components/pages/production/recording/RecordingTable.tsx index 65cead2a..e5bd30cb 100644 --- a/src/components/pages/production/recording/RecordingTable.tsx +++ b/src/components/pages/production/recording/RecordingTable.tsx @@ -6,6 +6,7 @@ import useSWR from 'swr'; import { Icon } from '@iconify/react'; import { SortingState, CellContext } from '@tanstack/react-table'; import { cn, formatDate } from '@/lib/helper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { useModal } from '@/components/Modal'; import Modal from '@/components/Modal'; import Button from '@/components/Button'; @@ -59,60 +60,70 @@ const RowOptionsMenu = ({ return ( - - - {!isApproved && !isRejected && ( + + + + + + {!isApproved && !isRejected && ( + + + )} {!isApproved && !isRejected && ( + + + + )} + - )} - + ); }; @@ -514,49 +525,63 @@ const RecordingTable = () => {
    - + + + {selectedRowIds.length > 0 && ( <> - + + + - + + + )}
    diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx index 4dca38dc..c8fa3ca0 100644 --- a/src/components/pages/production/recording/form/RecordingForm.tsx +++ b/src/components/pages/production/recording/form/RecordingForm.tsx @@ -8,6 +8,7 @@ import useSWR from 'swr'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; +import RequirePermission from '@/components/helper/RequirePermission'; import Card from '@/components/Card'; import Badge from '@/components/Badge'; import NumberInput from '@/components/input/NumberInput'; @@ -1492,41 +1493,45 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { !isRecordingApproved(initialValues) && !isRecordingRejected(initialValues) && (
    - + + + - + + +
    )}
    @@ -2696,36 +2701,40 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { {/* Left side - Detail & Edit actions */}
    {type === 'detail' && deleteRecordingClickHandler && ( - + + + )} {type === 'detail' && initialValues && ( - + + + )}
    {/* Right side actions */} diff --git a/src/components/pages/production/transfer-to-laying/TransferToLayingsTable.tsx b/src/components/pages/production/transfer-to-laying/TransferToLayingsTable.tsx index 424cc3c2..18ce404d 100644 --- a/src/components/pages/production/transfer-to-laying/TransferToLayingsTable.tsx +++ b/src/components/pages/production/transfer-to-laying/TransferToLayingsTable.tsx @@ -26,6 +26,7 @@ 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 { TransferToLaying } from '@/types/api/production/transfer-to-laying'; import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying'; @@ -56,72 +57,81 @@ const RowOptionsMenu = ({ const showDeleteButton = showEditButton; - // TODO: apply RBAC const showApproveButton = showEditButton; const showRejectButton = showEditButton; return ( - - - {showEditButton && ( + + + + {showEditButton && ( + + + )} {/* TODO: apply RBAC */} {showApproveButton && ( - + + + )} {showRejectButton && ( - + + + )} {showDeleteButton && ( - + + + )} ); @@ -502,47 +512,53 @@ const TransferToLayingsTable = () => {
    - + + + {selectedRowIds.length > 0 && ( <> - + + + - + + + )}
    diff --git a/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx b/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx index 16885062..4d60f69a 100644 --- a/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx +++ b/src/components/pages/production/transfer-to-laying/form/TransferToLayingForm.tsx @@ -8,6 +8,7 @@ import useSWR from 'swr'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; +import RequirePermission from '@/components/helper/RequirePermission'; import SelectInput, { OptionType, useSelect, @@ -500,34 +501,37 @@ const TransferToLayingForm = ({ <> {isShowApproveRejectButton && (
    - {/* TODO: apply RBAC */} - + + + - + + +
    )} @@ -788,37 +792,41 @@ const TransferToLayingForm = ({ {type !== 'add' && (
    {isShowDeleteButton && ( - + + + )} {type !== 'edit' && isShowEditButton && ( - + + + )}
    )} @@ -833,15 +841,23 @@ const TransferToLayingForm = ({ Reset - + +
    )}
    diff --git a/src/components/pages/purchase/PurchaseTable.tsx b/src/components/pages/purchase/PurchaseTable.tsx index a77e1158..81f45cc9 100644 --- a/src/components/pages/purchase/PurchaseTable.tsx +++ b/src/components/pages/purchase/PurchaseTable.tsx @@ -15,6 +15,7 @@ import SelectInput, { OptionType } from '@/components/input/SelectInput'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; +import RequirePermission from '@/components/helper/RequirePermission'; import { cn, formatDate } from '@/lib/helper'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -38,15 +39,17 @@ const RowOptionsMenu = ({ }: RowOptionsMenuProps) => { return ( - + + + {/**/} - + + + ); }; @@ -227,15 +232,17 @@ const PurchaseTable = () => {
    - + + +
    {canUpdatePurchaseItems && canShowDeleteAddButtons && ( - + + + )}
    diff --git a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx index 35d9e104..de07ee52 100644 --- a/src/components/pages/purchase/order/PurchaseOrderDetail.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderDetail.tsx @@ -39,19 +39,22 @@ import { toast } from 'react-hot-toast'; import { useSearchParams } from 'next/navigation'; import { formatCurrency, formatNumber, formatDate } from '@/lib/helper'; import { PURCHASE_ORDER_APPROVAL_LINE } from '@/config/approval-line'; +import RequirePermission from '@/components/helper/RequirePermission'; const ItemPembelianDropdown = ({ onEdit }: { onEdit: () => void }) => { return ( - + + + ); }; @@ -59,15 +62,17 @@ const ItemPembelianDropdown = ({ onEdit }: { onEdit: () => void }) => { const PenerimaanBarangDropdown = ({ onEdit }: { onEdit: () => void }) => { return ( - + + + ); }; @@ -496,14 +501,16 @@ const PurchaseOrderDetail = ({ }; return ( - + + + ); }, }, @@ -632,25 +639,45 @@ const PurchaseOrderDetail = ({ {showApprovalButton && (
    - + + - + +
    )}
    diff --git a/src/config/constant.ts b/src/config/constant.ts index 954d21a4..fb293c52 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -10,14 +10,20 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ text: 'Produksi', link: '/production', icon: 'heroicons-outline:wrench-screwdriver', + permission: [ + 'lti.production.project_flocks.list', + 'lti.production.recording.list', + ], submenu: [ { text: 'Daftar Flock', link: '/production/project-flock', + permission: ['lti.production.project_flocks.list'], }, { text: 'Recording', link: '/production/recording', + permission: ['lti.production.recording.list'], }, { text: 'Transfer to Laying', @@ -29,6 +35,7 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ text: 'Pembelian', link: '/purchase', icon: 'heroicons-outline:shopping-cart', + permission: ['lti.purchase.list'], }, { text: 'Penjualan', @@ -41,14 +48,16 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ icon: 'heroicons-outline:scale', }, { - text: 'Biaya Operasional', + text: 'Biaya', link: '/expense', icon: 'heroicons:wallet', + permission: ['lti.expense.list'], }, { text: 'Closing', link: '/closing', icon: 'heroicons-outline:presentation-chart-bar', + permission: ['lti.closing.list'], }, { text: 'Laporan', @@ -73,18 +82,26 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ text: 'Persediaan', link: '/inventory', icon: 'heroicons-outline:folder', + permission: [ + 'lti.inventory.product_stock.list', + 'lti.inventory.product_warehouses.list', + 'lti.inventory.transfer.list', + ], submenu: [ { text: 'Stok Produk', link: '/inventory/product', + permission: ['lti.inventory.product_stock.list'], }, { text: 'Penyesuaian Stok', link: '/inventory/adjustment', + permission: ['lti.inventory.product_stock.list'], }, { text: 'Transfer Stok', link: '/inventory/movement', + permission: ['lti.inventory.transfer.list'], }, ], }, @@ -92,58 +109,86 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [ text: 'Master Data', link: '/master-data', icon: 'heroicons-outline:circle-stack', + permission: [ + 'lti.master.area.list', + 'lti.master.banks.list', + 'lti.master.customer.list', + 'lti.master.fcr.list', + 'lti.master.flocks.list', + 'lti.master.kandangs.list', + 'lti.master.locations.list', + 'lti.master.nonstocks.list', + 'lti.master.product_categories.list', + 'lti.master.products.list', + 'lti.master.suppliers.list', + 'lti.master.uoms.list', + 'lti.master.warehouses.list', + ], submenu: [ { text: 'Produk', link: '/master-data/product', + permission: ['lti.master.products.list'], }, { text: 'Kategori Produk', link: '/master-data/product-category', + permission: ['lti.master.product_categories.list'], }, { text: 'Bank', link: '/master-data/bank', + permission: ['lti.master.banks.list'], }, { text: 'Area', link: '/master-data/area', + permission: ['lti.master.area.list'], }, { text: 'Lokasi', link: '/master-data/location', + permission: ['lti.master.locations.list'], }, { text: 'Kandang', link: '/master-data/kandang', + permission: ['lti.master.kandangs.list'], }, { text: 'Warehouse', link: '/master-data/warehouse', + permission: ['lti.master.warehouses.list'], }, { text: 'Customer', link: '/master-data/customer', + permission: ['lti.master.customer.list'], }, { text: 'UOM', link: '/master-data/uom', + permission: ['lti.master.uoms.list'], }, { text: 'Non-Stock', link: '/master-data/nonstock', + permission: ['lti.master.nonstocks.list'], }, { text: 'FCR', link: '/master-data/fcr', + permission: ['lti.master.fcr.list'], }, { text: 'Supplier', link: '/master-data/supplier', + permission: ['lti.master.suppliers.list'], }, { text: 'Flock', link: '/master-data/flock', + permission: ['lti.master.flocks.list'], }, ], }, diff --git a/src/config/route-permission.ts b/src/config/route-permission.ts new file mode 100644 index 00000000..ed6d4771 --- /dev/null +++ b/src/config/route-permission.ts @@ -0,0 +1,155 @@ +export const ROUTE_PERMISSIONS: Record = { + '/': ['lti.dashboard.list'], + + // Dashboard + '/dashboard/': ['lti.dashboard.list'], + + // Production + // Production - Project Flock + '/production/project-flock/': ['lti.production.project_flocks.list'], + '/production/project-flock/add/': ['lti.production.project_flocks.create'], + '/production/project-flock/detail/': ['lti.production.project_flocks.detail'], + '/production/project-flock/detail/edit/': [ + 'lti.production.project_flocks.update', + ], + '/production/project-flock/chickin/add/kandang/': [ + 'lti.production.chickins.create', + ], + '/production/project-flock/closing/': [ + 'lti.production.project_flock_kandangs.closing', + ], + + // Production - Recording + '/production/recording/': ['lti.production.recording.list'], + '/production/recording/add/': ['lti.production.recording.create'], + '/production/recording/detail/': ['lti.production.recording.detail'], + '/production/recording/detail/edit/': ['lti.production.recording.update'], + + // Production - Transfer to Laying + '/production/transfer-to-laying/': ['lti.production.transfer_to_laying.list'], + '/production/transfer-to-laying/add/': [ + 'lti.production.transfer_to_laying.create', + ], + '/production/transfer-to-laying/detail/': [ + 'lti.production.transfer_to_laying.detail', + ], + '/production/transfer-to-laying/detail/edit/': [ + 'lti.production.transfer_to_laying.update', + ], + + // Purchase + '/purchase/': ['lti.purchase.list'], + '/purchase/add/': ['lti.purchase.create'], + '/purchase/detail/': ['lti.purchase.detail'], + '/purchase/detail/edit/': ['lti.purchase.update'], + + // Marketing + '/marketing/': ['lti.marketing.delivery_order.list'], + '/marketing/add/delivery-orders/': ['lti.marketing.delivery_order.create'], + '/marketing/add/sales-orders/': ['lti.marketing.sales_order.create'], + '/marketing/detail/': ['lti.marketing.delivery_order.detail'], + '/marketing/detail/delivery-orders/edit/': [ + 'lti.marketing.delivery_order.update', + ], + '/marketing/detail/sales-orders/edit/': ['lti.marketing.sales_order.update'], + + // Expense + '/expense/': ['lti.expense.list'], + '/expense/add/': ['lti.expense.create'], + '/expense/detail/': ['lti.expense.detail'], + '/expense/detail/edit/': ['lti.expense.update'], + '/expense/realization/': ['lti.expense.create.realization'], + '/expense/realization/edit/': ['lti.expense.update.realization'], + + // Closing + '/closing/': ['lti.closing.list'], + '/closing/detail/': ['lti.closing.detail'], + + // Report + '/report/logistic-stock/': ['lti.repport.purchasesupplier.list'], + '/report/expense/': ['lti.repport.expense.list'], + '/report/marketing/': ['lti.repport.delivery.list'], + + // Inventory + '/inventory/adjustment/': ['lti.inventory.list'], + '/inventory/adjustment/add/': ['lti.inventory.create'], + '/inventory/adjustment/detail/': ['lti.inventory.detail'], + '/inventory/movement/': ['lti.inventory.transfer.list'], + '/inventory/movement/add/': ['lti.inventory.transfer.create'], + '/inventory/movement/detail/': ['lti.inventory.transfer.detail'], + '/inventory/movement/detail/edit/': ['lti.inventory.transfer.update'], + '/inventory/product/': ['lti.inventory.product_stock.list'], + '/inventory/product/detail/': ['lti.inventory.product_stock.detail'], + + // Master Data + '/master-data/product/': ['lti.master.products.list'], + '/master-data/product/add/': ['lti.master.products.create'], + '/master-data/product/detail/': ['lti.master.products.detail'], + '/master-data/product/detail/edit/': ['lti.master.products.update'], + + '/master-data/product-category/': ['lti.master.product_categories.list'], + '/master-data/product-category/add/': [ + 'lti.master.product_categories.create', + ], + '/master-data/product-category/detail/': [ + 'lti.master.product_categories.detail', + ], + '/master-data/product-category/detail/edit/': [ + 'lti.master.product_categories.update', + ], + + '/master-data/bank/': ['lti.master.banks.list'], + '/master-data/bank/add/': ['lti.master.banks.create'], + '/master-data/bank/detail/': ['lti.master.banks.detail'], + '/master-data/bank/detail/edit/': ['lti.master.banks.update'], + + '/master-data/area/': ['lti.master.area.list'], + '/master-data/area/add/': ['lti.master.area.create'], + '/master-data/area/detail/': ['lti.master.area.detail'], + '/master-data/area/detail/edit/': ['lti.master.area.update'], + + '/master-data/location/': ['lti.master.locations.list'], + '/master-data/location/add/': ['lti.master.locations.create'], + '/master-data/location/detail/': ['lti.master.locations.detail'], + '/master-data/location/detail/edit/': ['lti.master.locations.update'], + + '/master-data/kandang/': ['lti.master.kandangs.list'], + '/master-data/kandang/add/': ['lti.master.kandangs.create'], + '/master-data/kandang/detail/': ['lti.master.kandangs.detail'], + '/master-data/kandang/detail/edit/': ['lti.master.kandangs.update'], + + '/master-data/warehouse/': ['lti.master.warehouses.list'], + '/master-data/warehouse/add/': ['lti.master.warehouses.create'], + '/master-data/warehouse/detail/': ['lti.master.warehouses.detail'], + '/master-data/warehouse/detail/edit/': ['lti.master.warehouses.update'], + + '/master-data/customer/': ['lti.master.customer.list'], + '/master-data/customer/add/': ['lti.master.customer.create'], + '/master-data/customer/detail/': ['lti.master.customer.detail'], + '/master-data/customer/detail/edit/': ['lti.master.customer.update'], + + '/master-data/uom/': ['lti.master.uoms.list'], + '/master-data/uom/add/': ['lti.master.uoms.create'], + '/master-data/uom/detail/': ['lti.master.uoms.detail'], + '/master-data/uom/detail/edit/': ['lti.master.uoms.update'], + + '/master-data/nonstock/': ['lti.master.nonstocks.list'], + '/master-data/nonstock/add/': ['lti.master.nonstocks.create'], + '/master-data/nonstock/detail/': ['lti.master.nonstocks.detail'], + '/master-data/nonstock/detail/edit/': ['lti.master.nonstocks.update'], + + '/master-data/fcr/': ['lti.master.fcr.list'], + '/master-data/fcr/add/': ['lti.master.fcr.create'], + '/master-data/fcr/detail/': ['lti.master.fcr.detail'], + '/master-data/fcr/detail/edit/': ['lti.master.fcr.update'], + + '/master-data/supplier/': ['lti.master.suppliers.list'], + '/master-data/supplier/add/': ['lti.master.suppliers.create'], + '/master-data/supplier/detail/': ['lti.master.suppliers.detail'], + '/master-data/supplier/detail/edit/': ['lti.master.suppliers.update'], + + '/master-data/flock/': ['lti.master.flocks.list'], + '/master-data/flock/add/': ['lti.master.flocks.create'], + '/master-data/flock/detail/': ['lti.master.flocks.detail'], + '/master-data/flock/detail/edit/': ['lti.master.flocks.update'], +};