mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'fix/transfer-to-laying' into 'development'
[FIX/FE] Transfer to Laying See merge request mbugroup/lti-web-client!219
This commit is contained in:
Generated
+4
-4
@@ -52,7 +52,7 @@
|
|||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"daisyui": "^5.5.8",
|
"daisyui": "^5.5.14",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "^15.5.7",
|
"eslint-config-next": "^15.5.7",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
@@ -5855,9 +5855,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
"node_modules/daisyui": {
|
||||||
"version": "5.5.8",
|
"version": "5.5.14",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.14.tgz",
|
||||||
"integrity": "sha512-6psL9jIEOFOw68V10j/BKCWcRgx8dh81mmNxShr+g7HDM6UHNoPharlp9zq/PQkHNuGU1ZQsajR3HgpvavbRKQ==",
|
"integrity": "sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@
|
|||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"daisyui": "^5.5.8",
|
"daisyui": "^5.5.14",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "^15.5.7",
|
"eslint-config-next": "^15.5.7",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--font-inter: var(--font-inter);
|
--font-inter: var(--font-inter);
|
||||||
|
--font-roboto: var(--font-roboto);
|
||||||
|
|
||||||
--container-sm: 40rem;
|
--container-sm: 40rem;
|
||||||
--container-md: 48rem;
|
--container-md: 48rem;
|
||||||
|
|||||||
+10
-2
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata, Viewport } from 'next';
|
import type { Metadata, Viewport } from 'next';
|
||||||
import { Inter } from 'next/font/google';
|
import { Inter, Roboto } from 'next/font/google';
|
||||||
import '@/app/globals.css';
|
import '@/app/globals.css';
|
||||||
|
|
||||||
import { Toaster } from 'react-hot-toast';
|
import { Toaster } from 'react-hot-toast';
|
||||||
@@ -12,6 +12,12 @@ const inter = Inter({
|
|||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const roboto = Roboto({
|
||||||
|
variable: '--font-roboto',
|
||||||
|
subsets: ['latin'],
|
||||||
|
weight: ['200', '300', '400', '500', '600', '700', '900'],
|
||||||
|
});
|
||||||
|
|
||||||
export const viewport: Viewport = {
|
export const viewport: Viewport = {
|
||||||
themeColor: '#1f74bf',
|
themeColor: '#1f74bf',
|
||||||
colorScheme: 'light',
|
colorScheme: 'light',
|
||||||
@@ -30,7 +36,9 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang='en' data-theme='lti'>
|
<html lang='en' data-theme='lti'>
|
||||||
<body className={`${inter.variable} antialiased font-inter`}>
|
<body
|
||||||
|
className={`${inter.variable} ${roboto.variable} antialiased font-inter`}
|
||||||
|
>
|
||||||
<RequireAuth>
|
<RequireAuth>
|
||||||
<MainDrawer>{children}</MainDrawer>
|
<MainDrawer>{children}</MainDrawer>
|
||||||
</RequireAuth>
|
</RequireAuth>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ const Drawer = ({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
varianClassName?.drawerSidebarContent,
|
varianClassName?.drawerSidebarContent,
|
||||||
className?.drawerContent,
|
className?.drawerSidebarContent,
|
||||||
'overflow-y-auto'
|
'overflow-y-auto'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -26,29 +26,34 @@ const MainDrawerContent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full p-4 flex flex-col gap-4'>
|
<div className='w-full flex flex-col'>
|
||||||
<div className='flex flex-row items-center gap-4'>
|
<div className='p-3 flex flex-row items-center gap-4 border-b border-base-content/10'>
|
||||||
|
<div className='flex flex-row items-center gap-2'>
|
||||||
<Image
|
<Image
|
||||||
src='/assets/img/lti-logo.png'
|
src='/assets/img/lti-logo.png'
|
||||||
alt='MBU Logo'
|
alt='LTI Logo'
|
||||||
width={256}
|
width={40}
|
||||||
height={256}
|
height={40}
|
||||||
className='w-full max-w-16 h-auto'
|
className='w-full max-w-10 h-auto'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h1 className='text-xl font-bold'>LTI ERP</h1>
|
<div className='font-roboto'>
|
||||||
|
<h1 className='text-sm font-semibold'>LTI ERP</h1>
|
||||||
|
<p className='text-sm text-black/50'>Lumbung Telur Indonesia</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='grow flex flex-row justify-end sm:hidden'>
|
<div className='grow flex flex-row justify-end sm:hidden'>
|
||||||
<Button
|
<Button
|
||||||
variant='soft'
|
variant='soft'
|
||||||
color='error'
|
color='error'
|
||||||
onClick={closeMainDrawerHandler}
|
onClick={closeMainDrawerHandler}
|
||||||
className='rounded-full'
|
className='p-1 rounded-full'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon='material-symbols:close-rounded'
|
icon='material-symbols:close-rounded'
|
||||||
width={24}
|
width={16}
|
||||||
height={24}
|
height={16}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -121,6 +126,10 @@ const MainDrawer = ({
|
|||||||
setOpen={setMainDrawerOpen}
|
setOpen={setMainDrawerOpen}
|
||||||
openOnLarge
|
openOnLarge
|
||||||
sidebarContent={<MainDrawerContent />}
|
sidebarContent={<MainDrawerContent />}
|
||||||
|
className={{
|
||||||
|
drawerSide: 'border-r border-base-content/10',
|
||||||
|
drawerSidebarContent: 'min-w-[244px] lg:w-[244px]',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<main className='w-full h-full flex flex-col'>
|
<main className='w-full h-full flex flex-col'>
|
||||||
<Navbar title={pageTitle as string} toggleSidebar={toggleSidebar} />
|
<Navbar title={pageTitle as string} toggleSidebar={toggleSidebar} />
|
||||||
|
|||||||
+64
-11
@@ -86,7 +86,7 @@ export const TABLE_DEFAULT_STYLING = {
|
|||||||
tableHeaderClassName: '',
|
tableHeaderClassName: '',
|
||||||
headerRowClassName: '',
|
headerRowClassName: '',
|
||||||
headerColumnClassName:
|
headerColumnClassName:
|
||||||
'px-4 py-3 border-base-content/10 text-base-content/50',
|
'px-4 py-3 border-base-content/10 text-base-content/50 text-sm font-medium',
|
||||||
tableBodyClassName: '',
|
tableBodyClassName: '',
|
||||||
bodyRowClassName: 'border-t border-base-content/10',
|
bodyRowClassName: 'border-t border-base-content/10',
|
||||||
bodyColumnClassName: 'px-4 py-3 text-base-content',
|
bodyColumnClassName: 'px-4 py-3 text-base-content',
|
||||||
@@ -222,14 +222,37 @@ const Table = <TData extends object>({
|
|||||||
}, [pageSize, setPageSize]);
|
}, [pageSize, setPageSize]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={tableClassNames.containerClassName}>
|
<div
|
||||||
<div className={tableClassNames.tableWrapperClassName}>
|
className={cn(
|
||||||
<table className={tableClassNames.tableClassName}>
|
TABLE_DEFAULT_STYLING.containerClassName,
|
||||||
<thead className={tableClassNames.tableHeaderClassName}>
|
tableClassNames.containerClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.tableWrapperClassName,
|
||||||
|
tableClassNames.tableWrapperClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.tableClassName,
|
||||||
|
tableClassNames.tableClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<thead
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.tableHeaderClassName,
|
||||||
|
tableClassNames.tableHeaderClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<tr
|
<tr
|
||||||
key={headerGroup.id}
|
key={headerGroup.id}
|
||||||
className={tableClassNames.headerRowClassName}
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.headerRowClassName,
|
||||||
|
tableClassNames.headerRowClassName
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{headerGroup.headers.map((header) => {
|
{headerGroup.headers.map((header) => {
|
||||||
const columnRelativeDepth =
|
const columnRelativeDepth =
|
||||||
@@ -262,6 +285,7 @@ const Table = <TData extends object>({
|
|||||||
{
|
{
|
||||||
'border-b': header.colSpan > 1,
|
'border-b': header.colSpan > 1,
|
||||||
},
|
},
|
||||||
|
TABLE_DEFAULT_STYLING.headerColumnClassName,
|
||||||
tableClassNames.headerColumnClassName
|
tableClassNames.headerColumnClassName
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -311,7 +335,12 @@ const Table = <TData extends object>({
|
|||||||
))}
|
))}
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody className={tableClassNames.tableBodyClassName}>
|
<tbody
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.tableBodyClassName,
|
||||||
|
tableClassNames.tableBodyClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
{table.getRowModel().rows.map((row) => {
|
{table.getRowModel().rows.map((row) => {
|
||||||
const customRowContent = renderCustomRow?.(row);
|
const customRowContent = renderCustomRow?.(row);
|
||||||
|
|
||||||
@@ -320,12 +349,19 @@ const Table = <TData extends object>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={row.id} className={tableClassNames.bodyRowClassName}>
|
<tr
|
||||||
|
key={row.id}
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.bodyRowClassName,
|
||||||
|
tableClassNames.bodyRowClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
{row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
<td
|
<td
|
||||||
key={cell.id}
|
key={cell.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
{ 'first:w-9 first:pr-0': withCheckbox },
|
{ 'first:w-9 first:pr-0': withCheckbox },
|
||||||
|
TABLE_DEFAULT_STYLING.bodyColumnClassName,
|
||||||
tableClassNames.bodyColumnClassName
|
tableClassNames.bodyColumnClassName
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -342,14 +378,25 @@ const Table = <TData extends object>({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot className={cn(tableClassNames.tableFooterClassName)}>
|
<tfoot
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.tableFooterClassName,
|
||||||
|
tableClassNames.tableFooterClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
{renderFooter && (
|
{renderFooter && (
|
||||||
<tr className={cn(tableClassNames.footerRowClassName)}>
|
<tr
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.footerRowClassName,
|
||||||
|
tableClassNames.footerRowClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
{table.getAllLeafColumns().map((column) => (
|
{table.getAllLeafColumns().map((column) => (
|
||||||
<td
|
<td
|
||||||
key={column.id}
|
key={column.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
{ 'first:w-9 first:pr-0': withCheckbox },
|
{ 'first:w-9 first:pr-0': withCheckbox },
|
||||||
|
TABLE_DEFAULT_STYLING.footerColumnClassName,
|
||||||
tableClassNames.footerColumnClassName
|
tableClassNames.footerColumnClassName
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -372,7 +419,13 @@ const Table = <TData extends object>({
|
|||||||
emptyContent}
|
emptyContent}
|
||||||
|
|
||||||
{data.length > 0 && table.getRowModel().rows.length > 0 && !isLoading && (
|
{data.length > 0 && table.getRowModel().rows.length > 0 && !isLoading && (
|
||||||
<div className={cn('mt-5', tableClassNames.paginationClassName)}>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'mt-5',
|
||||||
|
TABLE_DEFAULT_STYLING.paginationClassName,
|
||||||
|
tableClassNames.paginationClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Pagination
|
<Pagination
|
||||||
totalItems={isServerSideTable ? totalItems : table.getRowCount()}
|
totalItems={isServerSideTable ? totalItems : table.getRowCount()}
|
||||||
itemsPerPage={table.getState().pagination.pageSize}
|
itemsPerPage={table.getState().pagination.pageSize}
|
||||||
|
|||||||
@@ -39,16 +39,15 @@ const SidebarMenuItem = ({ item, activeLink }: SidebarMenuItemProps) => {
|
|||||||
<li>
|
<li>
|
||||||
<Link
|
<Link
|
||||||
href={item.link}
|
href={item.link}
|
||||||
className={cn(
|
className={cn('px-3 py-1.5', {
|
||||||
{
|
'text-base-content/60': !isItemActive,
|
||||||
'menu-active border-2 border-solid border-base-300': isItemActive,
|
'menu-active border-[1.5px] border-solid border-base-300':
|
||||||
},
|
isItemActive,
|
||||||
'px-3 py-1.5'
|
})}
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{item.icon && <Icon icon={item.icon} width={20} height={20} />}
|
{item.icon && <Icon icon={item.icon} width={20} height={20} />}
|
||||||
|
|
||||||
<span className='text-base'>{item.text}</span>
|
<span className='text-sm'>{item.text}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@@ -62,12 +61,13 @@ const SidebarMenuItem = ({ item, activeLink }: SidebarMenuItemProps) => {
|
|||||||
<details open={isItemActive}>
|
<details open={isItemActive}>
|
||||||
<summary
|
<summary
|
||||||
className={cn({
|
className={cn({
|
||||||
|
'text-base-content/60': !isItemActive,
|
||||||
'text-primary': isItemActive,
|
'text-primary': isItemActive,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{item.icon && <Icon icon={item.icon} width={20} height={20} />}
|
{item.icon && <Icon icon={item.icon} width={20} height={20} />}
|
||||||
|
|
||||||
<span className='text-base'>{item.text}</span>
|
<span className='text-sm'>{item.text}</span>
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@@ -88,7 +88,7 @@ const SidebarMenuItem = ({ item, activeLink }: SidebarMenuItemProps) => {
|
|||||||
|
|
||||||
const SidebarMenu = ({ menu, activeLink }: SidebarMenuProps) => {
|
const SidebarMenu = ({ menu, activeLink }: SidebarMenuProps) => {
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu className='p-3'>
|
||||||
{menu.map((menuItem, menuIdx) => {
|
{menu.map((menuItem, menuIdx) => {
|
||||||
return (
|
return (
|
||||||
<SidebarMenuItem
|
<SidebarMenuItem
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ChangeEventHandler, useState } from 'react';
|
import { ChangeEventHandler, useEffect, useState } from 'react';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import {
|
import {
|
||||||
CellContext,
|
CellContext,
|
||||||
@@ -20,33 +20,32 @@ import SelectInput, {
|
|||||||
OptionType,
|
OptionType,
|
||||||
useSelect,
|
useSelect,
|
||||||
} from '@/components/input/SelectInput';
|
} 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 CheckboxInput from '@/components/input/CheckboxInput';
|
||||||
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
|
|
||||||
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
|
||||||
import RequirePermission from '@/components/helper/RequirePermission';
|
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 { TransferToLaying } from '@/types/api/production/transfer-to-laying';
|
||||||
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
|
import { TransferToLayingApi } from '@/services/api/production/transfer-to-laying';
|
||||||
import { cn, formatDate } from '@/lib/helper';
|
import { cn, formatDate } from '@/lib/helper';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
import { ROWS_OPTIONS } from '@/config/constant';
|
|
||||||
import { Flock } from '@/types/api/master-data/flock';
|
import { Flock } from '@/types/api/master-data/flock';
|
||||||
import { FlockApi } from '@/services/api/master-data';
|
import { ProjectFlockApi } from '@/services/api/production';
|
||||||
import PillBadge from '@/components/PillBadge';
|
import Badge from '@/components/Badge';
|
||||||
|
import { Color } from '@/types/theme';
|
||||||
|
import PopoverContent from '@/components/popover/PopoverContent';
|
||||||
|
|
||||||
const RowOptionsMenu = ({
|
const RowOptionsMenu = ({
|
||||||
type = 'dropdown',
|
|
||||||
props,
|
props,
|
||||||
|
popoverPosition = 'bottom',
|
||||||
approveClickHandler,
|
approveClickHandler,
|
||||||
rejectClickHandler,
|
rejectClickHandler,
|
||||||
deleteClickHandler,
|
deleteClickHandler,
|
||||||
}: {
|
}: {
|
||||||
type: 'dropdown' | 'collapse';
|
|
||||||
props: CellContext<TransferToLaying, unknown>;
|
props: CellContext<TransferToLaying, unknown>;
|
||||||
|
popoverPosition: 'bottom' | 'top';
|
||||||
approveClickHandler: () => void;
|
approveClickHandler: () => void;
|
||||||
rejectClickHandler: () => void;
|
rejectClickHandler: () => void;
|
||||||
deleteClickHandler: () => void;
|
deleteClickHandler: () => void;
|
||||||
@@ -60,17 +59,37 @@ const RowOptionsMenu = ({
|
|||||||
const showApproveButton = showEditButton;
|
const showApproveButton = showEditButton;
|
||||||
const showRejectButton = showEditButton;
|
const showRejectButton = showEditButton;
|
||||||
|
|
||||||
|
const popoverId = `transferToLaying#${props.row.original.id}`;
|
||||||
|
const popoverAnchorName = `--anchor-transferToLaying#${props.row.original.id}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowOptionsMenuWrapper type={type}>
|
<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>
|
||||||
|
|
||||||
|
<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'>
|
<RequirePermission permissions='lti.production.transfer_to_laying.detail'>
|
||||||
<Button
|
<Button
|
||||||
href={`/production/transfer-to-laying/detail/?transferToLayingId=${props.row.original.id}`}
|
href={`/production/transfer-to-laying/detail/?transferToLayingId=${props.row.original.id}`}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='primary'
|
color='none'
|
||||||
className='justify-start text-sm'
|
className='p-3 justify-start text-sm font-semibold w-full'
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:eye-outline' width={16} height={16} />
|
<Icon icon='heroicons:eye' width={20} height={20} />
|
||||||
Detail
|
View Details
|
||||||
</Button>
|
</Button>
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
|
|
||||||
@@ -79,61 +98,60 @@ const RowOptionsMenu = ({
|
|||||||
<Button
|
<Button
|
||||||
href={`/production/transfer-to-laying/detail/edit/?transferToLayingId=${props.row.original.id}`}
|
href={`/production/transfer-to-laying/detail/edit/?transferToLayingId=${props.row.original.id}`}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='warning'
|
color='none'
|
||||||
className='justify-start text-sm'
|
className='p-3 justify-start text-sm font-semibold w-full'
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:edit-outline' width={16} height={16} />
|
<Icon icon='heroicons:pencil-square' width={20} height={20} />
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* TODO: apply RBAC */}
|
|
||||||
{showApproveButton && (
|
{showApproveButton && (
|
||||||
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
|
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
|
||||||
<Button
|
<Button
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='success'
|
color='success'
|
||||||
onClick={approveClickHandler}
|
onClick={approveClickHandler}
|
||||||
className='justify-start text-sm'
|
className='p-3 justify-start text-sm font-semibold w-full'
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:check' width={24} height={24} />
|
<Icon icon='heroicons:check' width={20} height={20} />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showRejectButton && (
|
{showRejectButton && (
|
||||||
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
|
<RequirePermission permissions='lti.production.transfer_to_laying.approve'>
|
||||||
<Button
|
<Button
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='error'
|
color='error'
|
||||||
onClick={rejectClickHandler}
|
onClick={rejectClickHandler}
|
||||||
className='justify-start text-sm'
|
className='p-3 justify-start text-sm font-semibold w-full'
|
||||||
>
|
>
|
||||||
<Icon icon='material-symbols:close' width={24} height={24} />
|
<Icon icon='heroicons:x-mark' width={20} height={20} />
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showDeleteButton && (
|
{showDeleteButton && (
|
||||||
<RequirePermission permissions='lti.production.transfer_to_laying.delete'>
|
<RequirePermission permissions='lti.production.transfer_to_laying.delete'>
|
||||||
|
<hr className='mx-3 border-base-content/10 h-px' />
|
||||||
<Button
|
<Button
|
||||||
onClick={deleteClickHandler}
|
onClick={deleteClickHandler}
|
||||||
variant='ghost'
|
variant='ghost'
|
||||||
color='error'
|
color='error'
|
||||||
className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
|
className='p-3 justify-start text-sm font-semibold w-full'
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon icon='heroicons:trash' width={20} height={20} />
|
||||||
icon='material-symbols:delete-outline-rounded'
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
className='justify-start text-sm'
|
|
||||||
/>
|
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</RequirePermission>
|
</RequirePermission>
|
||||||
)}
|
)}
|
||||||
</RowOptionsMenuWrapper>
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,6 +168,8 @@ const TransferToLayingsTable = () => {
|
|||||||
transferDate: '',
|
transferDate: '',
|
||||||
flockSource: '',
|
flockSource: '',
|
||||||
flockDestination: '',
|
flockDestination: '',
|
||||||
|
filter_by: '',
|
||||||
|
sort_by: '',
|
||||||
},
|
},
|
||||||
paramMap: {
|
paramMap: {
|
||||||
page: 'page',
|
page: 'page',
|
||||||
@@ -157,6 +177,8 @@ const TransferToLayingsTable = () => {
|
|||||||
transferDate: 'transfer_date',
|
transferDate: 'transfer_date',
|
||||||
flockSource: 'flock_source',
|
flockSource: 'flock_source',
|
||||||
flockDestination: 'flock_destination',
|
flockDestination: 'flock_destination',
|
||||||
|
filter_by: 'filter_by',
|
||||||
|
sort_by: 'sort_by',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -181,7 +203,7 @@ const TransferToLayingsTable = () => {
|
|||||||
isLoadingOptions: isLoadingFlockSourceOptions,
|
isLoadingOptions: isLoadingFlockSourceOptions,
|
||||||
loadMore: loadMoreFlockSource,
|
loadMore: loadMoreFlockSource,
|
||||||
hasMore: hasMoreFlockSource,
|
hasMore: hasMoreFlockSource,
|
||||||
} = useSelect<Flock>(FlockApi.basePath, 'id', 'name');
|
} = useSelect<Flock>(ProjectFlockApi.basePath, 'id', 'flock_name');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setInputValue: setFlockDestinationInputValue,
|
setInputValue: setFlockDestinationInputValue,
|
||||||
@@ -189,7 +211,7 @@ const TransferToLayingsTable = () => {
|
|||||||
isLoadingOptions: isLoadingFlockDestinationOptions,
|
isLoadingOptions: isLoadingFlockDestinationOptions,
|
||||||
loadMore: loadMoreFlockDestination,
|
loadMore: loadMoreFlockDestination,
|
||||||
hasMore: hasMoreFlockDestination,
|
hasMore: hasMoreFlockDestination,
|
||||||
} = useSelect<Flock>(FlockApi.basePath, 'id', 'name');
|
} = useSelect<Flock>(ProjectFlockApi.basePath, 'id', 'flock_name');
|
||||||
|
|
||||||
// Flocks value
|
// Flocks value
|
||||||
const [selectedFlockSource, setSelectedFlockSource] =
|
const [selectedFlockSource, setSelectedFlockSource] =
|
||||||
@@ -244,13 +266,6 @@ const TransferToLayingsTable = () => {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
header: '#',
|
|
||||||
cell: (props) =>
|
|
||||||
tableFilterState.pageSize * (tableFilterState.page - 1) +
|
|
||||||
props.row.index +
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorKey: 'transfer_date',
|
accessorKey: 'transfer_date',
|
||||||
header: 'Tanggal Transfer',
|
header: 'Tanggal Transfer',
|
||||||
@@ -274,6 +289,7 @@ const TransferToLayingsTable = () => {
|
|||||||
{
|
{
|
||||||
accessorKey: 'notes',
|
accessorKey: 'notes',
|
||||||
header: 'Alasan Transfer',
|
header: 'Alasan Transfer',
|
||||||
|
enableSorting: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Status',
|
header: 'Status',
|
||||||
@@ -282,34 +298,39 @@ const TransferToLayingsTable = () => {
|
|||||||
props.row.original.approval.action === 'REJECTED';
|
props.row.original.approval.action === 'REJECTED';
|
||||||
let latestApprovalStepName = props.row.original.approval.step_name;
|
let latestApprovalStepName = props.row.original.approval.step_name;
|
||||||
|
|
||||||
let pillBadgeColor: 'yellow' | 'green' | 'gray' | 'red' = 'gray';
|
let badgeColor: Color = 'neutral';
|
||||||
|
|
||||||
switch (latestApprovalStepName.toLowerCase()) {
|
switch (latestApprovalStepName.toLowerCase()) {
|
||||||
case 'pengajuan':
|
case 'pengajuan':
|
||||||
pillBadgeColor = 'yellow';
|
badgeColor = 'neutral';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'disetujui':
|
case 'disetujui':
|
||||||
pillBadgeColor = 'green';
|
badgeColor = 'success';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLatestApprovalRejected) {
|
if (isLatestApprovalRejected) {
|
||||||
pillBadgeColor = 'red';
|
badgeColor = 'error';
|
||||||
latestApprovalStepName = 'Ditolak';
|
latestApprovalStepName = 'Ditolak';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PillBadge
|
<Badge
|
||||||
content={latestApprovalStepName}
|
variant='soft'
|
||||||
color={pillBadgeColor}
|
className={{
|
||||||
className='text-sm'
|
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) => {
|
cell: (props) => {
|
||||||
const currentPageSize = props.table.getPaginationRowModel().rows.length;
|
const currentPageSize = props.table.getPaginationRowModel().rows.length;
|
||||||
const currentPageRows = props.table.getPaginationRowModel().flatRows;
|
const currentPageRows = props.table.getPaginationRowModel().flatRows;
|
||||||
@@ -346,31 +367,13 @@ const TransferToLayingsTable = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{currentPageSize > 3 && (
|
|
||||||
<RowDropdownOptions isLast2Rows={isLast2Rows}>
|
|
||||||
<RowOptionsMenu
|
<RowOptionsMenu
|
||||||
type='dropdown'
|
|
||||||
props={props}
|
props={props}
|
||||||
approveClickHandler={approveClickHandler}
|
approveClickHandler={approveClickHandler}
|
||||||
rejectClickHandler={rejectClickHandler}
|
rejectClickHandler={rejectClickHandler}
|
||||||
deleteClickHandler={deleteClickHandler}
|
deleteClickHandler={deleteClickHandler}
|
||||||
|
popoverPosition={isLast2Rows ? 'top' : 'bottom'}
|
||||||
/>
|
/>
|
||||||
</RowDropdownOptions>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currentPageSize <= 3 && (
|
|
||||||
<RowCollapseOptions>
|
|
||||||
<RowOptionsMenu
|
|
||||||
type='collapse'
|
|
||||||
props={props}
|
|
||||||
approveClickHandler={approveClickHandler}
|
|
||||||
rejectClickHandler={rejectClickHandler}
|
|
||||||
deleteClickHandler={deleteClickHandler}
|
|
||||||
/>
|
|
||||||
</RowCollapseOptions>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -397,17 +400,21 @@ const TransferToLayingsTable = () => {
|
|||||||
const confirmationModalDeleteClickHandler = async () => {
|
const confirmationModalDeleteClickHandler = async () => {
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
|
|
||||||
try {
|
const deleteResponse = await TransferToLayingApi.delete(
|
||||||
await TransferToLayingApi.delete(selectedTransferToLaying?.id as number);
|
selectedTransferToLaying?.id as number
|
||||||
|
);
|
||||||
|
|
||||||
toast.success('Berhasil menghapus data transfer ke laying!');
|
if (isResponseError(deleteResponse)) {
|
||||||
refreshTransferToLayings();
|
toast.error(deleteResponse.message);
|
||||||
} catch (error) {
|
|
||||||
toast.success('Gagal menghapus data transfer ke laying!');
|
|
||||||
} finally {
|
|
||||||
deleteModal.closeModal();
|
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshTransferToLayings();
|
||||||
|
|
||||||
|
deleteModal.closeModal();
|
||||||
|
toast.success('Berhasil menghapus data transfer ke laying!');
|
||||||
|
setIsDeleteLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmationModalApproveClickHandler = async (notes: string) => {
|
const confirmationModalApproveClickHandler = async (notes: string) => {
|
||||||
@@ -499,20 +506,19 @@ const TransferToLayingsTable = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// track sorting
|
useEffect(() => {
|
||||||
// useEffect(() => {
|
if (sorting.length === 1) {
|
||||||
// const isNameSorted = sorting.find((sortItem) => sortItem.id === 'name');
|
updateFilter('filter_by', sorting[0].id);
|
||||||
|
updateFilter('sort_by', sorting[0].desc ? 'desc' : 'asc');
|
||||||
// if (!isNameSorted) {
|
} else {
|
||||||
// updateFilter('nameSort', '');
|
updateFilter('filter_by', '');
|
||||||
// } else {
|
updateFilter('sort_by', '');
|
||||||
// updateFilter('nameSort', isNameSorted.desc ? 'desc' : 'asc');
|
}
|
||||||
// }
|
}, [sorting]);
|
||||||
// }, [sorting, updateFilter]);
|
|
||||||
|
|
||||||
return (
|
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='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 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'>
|
<div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
|
||||||
@@ -579,12 +585,10 @@ const TransferToLayingsTable = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-cols-12 justify-end gap-4'>
|
<div className='grid grid-cols-12 justify-end gap-4'>
|
||||||
<TextInput
|
<DateInput
|
||||||
required
|
|
||||||
type='date'
|
|
||||||
label='Tanggal Transfer'
|
|
||||||
name='transfer_date'
|
name='transfer_date'
|
||||||
placeholder='Masukkan tanggal transfer'
|
label='Tanggal Transfer'
|
||||||
|
placeholder='Tanggal Transfer'
|
||||||
value={tableFilterState.transferDate}
|
value={tableFilterState.transferDate}
|
||||||
onChange={transferDateChangeHandler}
|
onChange={transferDateChangeHandler}
|
||||||
className={{
|
className={{
|
||||||
@@ -619,20 +623,6 @@ const TransferToLayingsTable = () => {
|
|||||||
wrapper: 'col-span-12 sm:col-span-3',
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -653,26 +643,21 @@ const TransferToLayingsTable = () => {
|
|||||||
: 0
|
: 0
|
||||||
}
|
}
|
||||||
onPageChange={setPage}
|
onPageChange={setPage}
|
||||||
|
onPageSizeChange={setPageSize}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
sorting={sorting}
|
sorting={sorting}
|
||||||
setSorting={setSorting}
|
setSorting={setSorting}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
setRowSelection={setRowSelection}
|
setRowSelection={setRowSelection}
|
||||||
enableRowSelection={tableEnableRowSelectionHandler}
|
enableRowSelection={tableEnableRowSelectionHandler}
|
||||||
|
withCheckbox
|
||||||
className={{
|
className={{
|
||||||
containerClassName: cn({
|
containerClassName: cn({
|
||||||
'mb-20':
|
'w-full mb-20':
|
||||||
isResponseSuccess(transferToLayings) &&
|
isResponseSuccess(transferToLayings) &&
|
||||||
transferToLayings?.data?.length === 0,
|
transferToLayings?.data?.length === 0,
|
||||||
}),
|
}),
|
||||||
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
headerColumnClassName: 'text-nowrap',
|
||||||
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',
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-2
@@ -80,7 +80,7 @@ export const TransferToLayingFormSchema: Yup.ObjectSchema<TransferToLayingFormSc
|
|||||||
)
|
)
|
||||||
.required('Kuantitas wajib diisi!'),
|
.required('Kuantitas wajib diisi!'),
|
||||||
|
|
||||||
maxQuantity: Yup.number().min(1).required(), // internal helper field
|
maxQuantity: Yup.number().min(0).required(), // internal helper field
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Minimal 1 kandang terisi!')
|
.min(1, 'Minimal 1 kandang terisi!')
|
||||||
@@ -102,7 +102,7 @@ export const TransferToLayingFormSchema: Yup.ObjectSchema<TransferToLayingFormSc
|
|||||||
)
|
)
|
||||||
.required('Kuantitas wajib diisi!'),
|
.required('Kuantitas wajib diisi!'),
|
||||||
|
|
||||||
maxQuantity: Yup.number().min(1).required(), // internal helper field
|
maxQuantity: Yup.number().min(0).required(), // internal helper field
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Minimal 1 kandang terisi!')
|
.min(1, 'Minimal 1 kandang terisi!')
|
||||||
|
|||||||
@@ -123,6 +123,13 @@ const DailyMarketingsTable = ({
|
|||||||
accessorKey: 'average_weight',
|
accessorKey: 'average_weight',
|
||||||
header: 'Bobot Rata-Rata (Kg)',
|
header: 'Bobot Rata-Rata (Kg)',
|
||||||
cell: (props) => formatNumber(props.row.original.average_weight_kg),
|
cell: (props) => formatNumber(props.row.original.average_weight_kg),
|
||||||
|
footer: () => {
|
||||||
|
const totalAverageWeightKg = isResponseSuccess(dailyMarketings)
|
||||||
|
? dailyMarketings?.total?.total_average_weight
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
return totalAverageWeightKg ? formatNumber(totalAverageWeightKg) : '-';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'total_weight',
|
accessorKey: 'total_weight',
|
||||||
@@ -140,6 +147,13 @@ const DailyMarketingsTable = ({
|
|||||||
accessorKey: 'sales_price',
|
accessorKey: 'sales_price',
|
||||||
header: 'Harga Jual (Rp)',
|
header: 'Harga Jual (Rp)',
|
||||||
cell: (props) => formatCurrency(props.row.original.sales_price_per_kg),
|
cell: (props) => formatCurrency(props.row.original.sales_price_per_kg),
|
||||||
|
footer: () => {
|
||||||
|
const totalSalesPrice = isResponseSuccess(dailyMarketings)
|
||||||
|
? dailyMarketings?.total?.total_sales_price
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
return totalSalesPrice ? formatNumber(totalSalesPrice) : '-';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'hpp_price',
|
accessorKey: 'hpp_price',
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import Button, { ButtonProps } from '@/components/Button';
|
||||||
|
|
||||||
|
export interface PopoverButtonProps extends ButtonProps {
|
||||||
|
popoverTarget: string;
|
||||||
|
anchorName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PopoverButton = ({
|
||||||
|
children,
|
||||||
|
popoverTarget,
|
||||||
|
anchorName,
|
||||||
|
...props
|
||||||
|
}: PopoverButtonProps) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
popoverTarget={popoverTarget}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
anchorName: anchorName,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PopoverButton;
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { cn } from '@/lib/helper';
|
||||||
|
|
||||||
|
export interface PopoverContentProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
id: string;
|
||||||
|
anchorName: string; // Must include `--` like "--menu-anchor"
|
||||||
|
popover?: 'auto' | 'hint' | 'manual';
|
||||||
|
position?:
|
||||||
|
| 'top'
|
||||||
|
| 'bottom'
|
||||||
|
| 'left'
|
||||||
|
| 'right'
|
||||||
|
| 'top-start'
|
||||||
|
| 'top-end'
|
||||||
|
| 'bottom-start'
|
||||||
|
| 'bottom-end'
|
||||||
|
| 'left-start'
|
||||||
|
| 'left-end'
|
||||||
|
| 'right-start'
|
||||||
|
| 'right-end';
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionAreaMap: Record<
|
||||||
|
NonNullable<PopoverContentProps['position']>,
|
||||||
|
string
|
||||||
|
> = {
|
||||||
|
top: 'top center',
|
||||||
|
bottom: 'bottom center',
|
||||||
|
left: 'left center',
|
||||||
|
right: 'right center',
|
||||||
|
|
||||||
|
'top-start': 'top left',
|
||||||
|
'top-end': 'top right',
|
||||||
|
'bottom-start': 'bottom left',
|
||||||
|
'bottom-end': 'bottom right',
|
||||||
|
|
||||||
|
'left-start': 'left top',
|
||||||
|
'left-end': 'left bottom',
|
||||||
|
|
||||||
|
'right-start': 'right top',
|
||||||
|
'right-end': 'right bottom',
|
||||||
|
};
|
||||||
|
|
||||||
|
const PopoverContent = ({
|
||||||
|
children,
|
||||||
|
id,
|
||||||
|
anchorName,
|
||||||
|
popover = 'auto',
|
||||||
|
position = 'bottom-start',
|
||||||
|
className,
|
||||||
|
}: PopoverContentProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(className)}
|
||||||
|
id={id}
|
||||||
|
popover={popover}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
inset: 'unset',
|
||||||
|
positionAnchor: anchorName,
|
||||||
|
positionArea: positionAreaMap[position],
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PopoverContent;
|
||||||
@@ -12,7 +12,7 @@ const RowCollapseOptions = ({ children }: RowCollapseOptionsProps) => {
|
|||||||
return (
|
return (
|
||||||
<Collapse
|
<Collapse
|
||||||
title={
|
title={
|
||||||
<Button>
|
<Button variant='ghost' color='none'>
|
||||||
<Icon icon='material-symbols:more-vert' width={16} height={16} />
|
<Icon icon='material-symbols:more-vert' width={16} height={16} />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const RowDropdownOptions = ({
|
|||||||
'dropdown-end': isLast2Rows,
|
'dropdown-end': isLast2Rows,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Button tabIndex={0}>
|
<Button tabIndex={0} variant='ghost' color='none'>
|
||||||
<Icon icon='material-symbols:more-vert' width={16} height={16} />
|
<Icon icon='material-symbols:more-vert' width={16} height={16} />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [
|
|||||||
permission: ['lti.production.recording.list'],
|
permission: ['lti.production.recording.list'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Transfer to Laying',
|
text: 'Transfer ke Laying',
|
||||||
link: '/production/transfer-to-laying',
|
link: '/production/transfer-to-laying',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+2
@@ -41,7 +41,9 @@ export type DailyMarketingRow = BaseMetadata & BaseDailyMarketingRow;
|
|||||||
|
|
||||||
export interface SalesSummary {
|
export interface SalesSummary {
|
||||||
total_qty: number;
|
total_qty: number;
|
||||||
|
total_average_weight: number;
|
||||||
total_weight_kg: number;
|
total_weight_kg: number;
|
||||||
|
total_sales_price: number;
|
||||||
total_sales_amount: number;
|
total_sales_amount: number;
|
||||||
total_hpp_amount: number;
|
total_hpp_amount: number;
|
||||||
total_hpp_price_per_kg: number;
|
total_hpp_price_per_kg: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user