mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 15:25:46 +00:00
refactor(FE-88): memisahkan file api project flock & penyesuaian tipe data dan paylod dengan BE
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
|
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
|
||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { ProjectFlockApi } from '@/services/api/production';
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
|
||||||
@@ -12,10 +12,11 @@ const ProjectFlockEdit = () => {
|
|||||||
|
|
||||||
const projectFlockId = searchParams.get('projectFlockId');
|
const projectFlockId = searchParams.get('projectFlockId');
|
||||||
|
|
||||||
const { data: projectFlock, isLoading: isLoadingCostumer } = useSWR(
|
const {
|
||||||
projectFlockId,
|
data: projectFlock,
|
||||||
(id: number) => ProjectFlockApi.getSingle(id)
|
isLoading: isLoadingProjectFlock,
|
||||||
);
|
mutate: refreshProjectFlocks,
|
||||||
|
} = useSWR(projectFlockId, (id: number) => ProjectFlockApi.getSingle(id));
|
||||||
|
|
||||||
if (!projectFlockId) {
|
if (!projectFlockId) {
|
||||||
router.back();
|
router.back();
|
||||||
@@ -27,18 +28,25 @@ const ProjectFlockEdit = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoadingCostumer && (!projectFlock || isResponseError(projectFlock))) {
|
if (
|
||||||
|
!isLoadingProjectFlock &&
|
||||||
|
(!projectFlock || isResponseError(projectFlock))
|
||||||
|
) {
|
||||||
router.replace('/404');
|
router.replace('/404');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full p-4 flex flex-row justify-center'>
|
<div className='w-full p-4 flex flex-col justify-center'>
|
||||||
{isLoadingCostumer && (
|
{isLoadingProjectFlock && (
|
||||||
<span className='loading loading-spinner loading-xl' />
|
<span className='loading loading-spinner loading-xl' />
|
||||||
)}
|
)}
|
||||||
{!isLoadingCostumer && isResponseSuccess(projectFlock) && (
|
{!isLoadingProjectFlock && isResponseSuccess(projectFlock) && (
|
||||||
<ProjectFlockForm formType='edit' initialValues={projectFlock.data} />
|
<>
|
||||||
|
{JSON.stringify(projectFlock.data)}
|
||||||
|
|
||||||
|
<ProjectFlockForm formType='edit' initialValues={projectFlock.data} />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
|
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
|
||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { FlockApi } from '@/services/api/master-data';
|
import { FlockApi } from '@/services/api/master-data';
|
||||||
import { ProjectFlockApi } from '@/services/api/production';
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -23,12 +23,13 @@ const ProjectFlockDetail = () => {
|
|||||||
mutate: refreshProjectFlock,
|
mutate: refreshProjectFlock,
|
||||||
} = useSWR(projectFlockId, (id: number) => ProjectFlockApi.getSingle(id));
|
} = useSWR(projectFlockId, (id: number) => ProjectFlockApi.getSingle(id));
|
||||||
|
|
||||||
const flockUrl = `${FlockApi.basePath}`;
|
|
||||||
const {
|
const {
|
||||||
data: flock,
|
data: approvalLines,
|
||||||
isLoading: isLoadingFlock,
|
isLoading: isLoadingApprovalLines,
|
||||||
mutate: refreshFlock,
|
mutate: refreshApprovalLines,
|
||||||
} = useSWR(flockUrl, FlockApi.getAllFetcher);
|
} = useSWR('approvals', (id: number) =>
|
||||||
|
ProjectFlockApi.getApprovalLines((projectFlockId ?? 0) as number)
|
||||||
|
);
|
||||||
|
|
||||||
if (!projectFlockId) {
|
if (!projectFlockId) {
|
||||||
router.back();
|
router.back();
|
||||||
@@ -48,37 +49,17 @@ const ProjectFlockDetail = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach flock id to project flock
|
|
||||||
let projectFlockAttached: ProjectFlock | undefined;
|
|
||||||
|
|
||||||
if (isResponseSuccess(projectFlock) && isResponseSuccess(flock)) {
|
|
||||||
projectFlockAttached = {
|
|
||||||
...projectFlock.data,
|
|
||||||
flock: flock.data.find(
|
|
||||||
(flock) =>
|
|
||||||
flock.name ==
|
|
||||||
projectFlock?.data?.flock_name
|
|
||||||
.trim()
|
|
||||||
.split(/\s+/)
|
|
||||||
.slice(0, -1)
|
|
||||||
.join(' ')
|
|
||||||
),
|
|
||||||
};
|
|
||||||
console.log('projectFlockAttached');
|
|
||||||
console.log(projectFlockAttached);
|
|
||||||
console.log('flocks');
|
|
||||||
console.log(flock.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full p-4 flex flex-row justify-center'>
|
<div className='w-full p-4 flex flex-col justify-center'>
|
||||||
{isLoadingProjectFlock && (
|
{isLoadingProjectFlock ||
|
||||||
<span className='loading loading-spinner loading-xl' />
|
(isLoadingApprovalLines && (
|
||||||
)}
|
<span className='loading loading-spinner loading-xl' />
|
||||||
{projectFlockAttached && (
|
))}
|
||||||
|
{isResponseSuccess(projectFlock) && isResponseSuccess(approvalLines) && (
|
||||||
<ProjectFlockForm
|
<ProjectFlockForm
|
||||||
formType='detail'
|
formType='detail'
|
||||||
initialValues={projectFlockAttached}
|
initialValues={projectFlock.data}
|
||||||
|
initialApprovals={approvalLines.data}
|
||||||
refreshProjectFlocks={refreshProjectFlock}
|
refreshProjectFlocks={refreshProjectFlock}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import { HTMLAttributes, ReactNode, useEffect, useState } from 'react';
|
||||||
|
import { cn } from '@/lib/helper';
|
||||||
|
|
||||||
|
export interface TabItem {
|
||||||
|
id: string;
|
||||||
|
label: ReactNode;
|
||||||
|
content?: ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TabsProps
|
||||||
|
extends Omit<HTMLAttributes<HTMLDivElement>, 'className'> {
|
||||||
|
tabs: TabItem[];
|
||||||
|
variant?: 'bordered' | 'lifted' | 'boxed';
|
||||||
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
||||||
|
placement?: 'top' | 'bottom';
|
||||||
|
/** Tab yang aktif secara default (uncontrolled mode) */
|
||||||
|
defaultActiveId?: string;
|
||||||
|
/** Tab yang aktif (controlled mode, dikontrol parent) */
|
||||||
|
activeTabId?: string;
|
||||||
|
className?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
wrapper?: string;
|
||||||
|
tab?: string;
|
||||||
|
content?: string;
|
||||||
|
};
|
||||||
|
onTabChange?: (tabId: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tabs = ({
|
||||||
|
tabs,
|
||||||
|
variant,
|
||||||
|
size = 'md',
|
||||||
|
placement = 'top',
|
||||||
|
defaultActiveId,
|
||||||
|
activeTabId: controlledActiveId,
|
||||||
|
className,
|
||||||
|
onTabChange,
|
||||||
|
...props
|
||||||
|
}: TabsProps) => {
|
||||||
|
// State internal hanya dipakai kalau `activeTabId` (controlled) tidak diset
|
||||||
|
const [uncontrolledActiveId, setUncontrolledActiveId] = useState(
|
||||||
|
defaultActiveId || tabs[0]?.id || ''
|
||||||
|
);
|
||||||
|
|
||||||
|
const isControlled = controlledActiveId !== undefined;
|
||||||
|
const activeTabId = isControlled ? controlledActiveId : uncontrolledActiveId;
|
||||||
|
|
||||||
|
const handleTabChange = (tabId: string) => {
|
||||||
|
if (tabId === activeTabId) return;
|
||||||
|
if (!isControlled) setUncontrolledActiveId(tabId);
|
||||||
|
onTabChange?.(tabId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { wrapper: wrapperClassName, tab: tabClassName } =
|
||||||
|
typeof className === 'object'
|
||||||
|
? className
|
||||||
|
: { wrapper: className, tab: undefined };
|
||||||
|
|
||||||
|
const getTabsClasses = () => {
|
||||||
|
const variantClasses: Record<string, string> = {
|
||||||
|
bordered: 'tabs-bordered',
|
||||||
|
lifted: 'tabs-lift',
|
||||||
|
boxed: 'tabs-box',
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizeClasses: Record<string, string> = {
|
||||||
|
xs: 'tabs-xs',
|
||||||
|
sm: 'tabs-sm',
|
||||||
|
md: '',
|
||||||
|
lg: 'tabs-lg',
|
||||||
|
xl: 'tabs-xl',
|
||||||
|
};
|
||||||
|
|
||||||
|
const placementClasses: Record<string, string> = {
|
||||||
|
top: '',
|
||||||
|
bottom: 'tabs-bottom',
|
||||||
|
};
|
||||||
|
|
||||||
|
return cn(
|
||||||
|
'tabs',
|
||||||
|
variant && variantClasses[variant],
|
||||||
|
sizeClasses[size],
|
||||||
|
placementClasses[placement],
|
||||||
|
wrapperClassName
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTabClasses = (isActive: boolean, isDisabled?: boolean) =>
|
||||||
|
cn(
|
||||||
|
'tab',
|
||||||
|
{
|
||||||
|
'tab-active': isActive,
|
||||||
|
'tab-disabled': isDisabled,
|
||||||
|
},
|
||||||
|
tabClassName
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeContent = tabs.find((tab) => tab.id === activeTabId)?.content;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={cn(
|
||||||
|
'w-full',
|
||||||
|
typeof className === 'string' ? className : undefined
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div role='tablist' className={getTabsClasses()}>
|
||||||
|
{tabs.map(({ id, label, disabled }) => (
|
||||||
|
<button
|
||||||
|
key={id}
|
||||||
|
role='tab'
|
||||||
|
className={getTabClasses(id === activeTabId, disabled)}
|
||||||
|
onClick={() => !disabled && handleTabChange(id)}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{activeContent && <div className='mt-4'>{activeContent}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tabs;
|
||||||
@@ -29,7 +29,6 @@ const ChickinFormKandang = ({
|
|||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-4'>
|
<div className='flex flex-col gap-4'>
|
||||||
<FormHeader
|
<FormHeader
|
||||||
type='add'
|
|
||||||
title='Chick In DOC'
|
title='Chick In DOC'
|
||||||
backUrl={`/production/project-flock/chickin/add?projectFlockId=${initialValues?.project_flock?.id}`}
|
backUrl={`/production/project-flock/chickin/add?projectFlockId=${initialValues?.project_flock?.id}`}
|
||||||
/>
|
/>
|
||||||
@@ -96,7 +95,7 @@ const ChickinFormKandang = ({
|
|||||||
tabs={[
|
tabs={[
|
||||||
{
|
{
|
||||||
id: 'formChickIn',
|
id: 'formChickIn',
|
||||||
label: 'Form Chick In',
|
label: 'Tambah Chick In',
|
||||||
content: (
|
content: (
|
||||||
<ChickinFormView
|
<ChickinFormView
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
import Alert from '@/components/Alert';
|
||||||
|
import Button from '@/components/Button';
|
||||||
|
import Card from '@/components/Card';
|
||||||
|
import { useModal } from '@/components/Modal';
|
||||||
|
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||||
|
import PillBadge from '@/components/PillBadge';
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import { cn, formatDate, formatNumber } from '@/lib/helper';
|
||||||
|
import { ChickinApi } from '@/services/api/production/chickin';
|
||||||
|
import {
|
||||||
|
Chickin,
|
||||||
|
ProjectFlockKandang,
|
||||||
|
} from '@/types/api/production/project-flock-kandang';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
|
const ChickinLogsView = ({
|
||||||
|
initialValues,
|
||||||
|
afterSubmit,
|
||||||
|
}: {
|
||||||
|
initialValues: ProjectFlockKandang;
|
||||||
|
afterSubmit?: () => void;
|
||||||
|
}) => {
|
||||||
|
const confirmModal = useModal();
|
||||||
|
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
||||||
|
const [chickinErrorMessage, setChickinErrorMessage] = useState('');
|
||||||
|
|
||||||
|
const handleClickApprove = () => {
|
||||||
|
confirmModal.openModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmationModalApproveClickHandler = async () => {
|
||||||
|
setChickinErrorMessage('');
|
||||||
|
setIsApproveLoading(true);
|
||||||
|
const approveChickinRes = await ChickinApi.singleApproval(
|
||||||
|
initialValues?.id as number,
|
||||||
|
'APPROVED'
|
||||||
|
);
|
||||||
|
if (isResponseSuccess(approveChickinRes)) {
|
||||||
|
toast.success(approveChickinRes?.message as string);
|
||||||
|
}
|
||||||
|
if (isResponseError(approveChickinRes)) {
|
||||||
|
toast.error(approveChickinRes?.message as string);
|
||||||
|
setChickinErrorMessage(approveChickinRes?.message as string);
|
||||||
|
}
|
||||||
|
confirmModal.closeModal();
|
||||||
|
setIsApproveLoading(false);
|
||||||
|
if (afterSubmit) {
|
||||||
|
afterSubmit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card
|
||||||
|
title='Riwayat Chick In'
|
||||||
|
className={{
|
||||||
|
wrapper: 'w-full bg-white',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className='flex flex-row justify-start gap-3 mt-3'>
|
||||||
|
<Button
|
||||||
|
color='success'
|
||||||
|
variant='outline'
|
||||||
|
onClick={handleClickApprove}
|
||||||
|
>
|
||||||
|
<Icon width={24} height={24} icon='material-symbols:check' />
|
||||||
|
Approve
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Table<Chickin>
|
||||||
|
data={initialValues?.chickins || []}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
header: '#',
|
||||||
|
cell: (props) => props.row.index + 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.chick_in_date,
|
||||||
|
header: 'Tanggal Chick In',
|
||||||
|
cell: (props) => {
|
||||||
|
return formatDate(props.getValue() as string, 'DD MMM YYYY');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.product_warehouse?.warehouse?.name,
|
||||||
|
header: 'Kandang',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.product_warehouse?.product?.name,
|
||||||
|
header: 'Produk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.usage_qty ?? row.pending_usage_qty,
|
||||||
|
header: 'Jumlah Chick In',
|
||||||
|
cell: (props) => {
|
||||||
|
if (props.row.original.usage_qty != 0) {
|
||||||
|
return formatNumber(props.row.original.usage_qty);
|
||||||
|
} else if (props.row.original.pending_usage_qty != 0) {
|
||||||
|
return formatNumber(props.row.original.pending_usage_qty);
|
||||||
|
} else {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.pending_usage_qty,
|
||||||
|
header: 'Status',
|
||||||
|
cell: (props) => {
|
||||||
|
return (
|
||||||
|
<PillBadge
|
||||||
|
content={
|
||||||
|
props.row.original.usage_qty !== 0
|
||||||
|
? 'Disetujui'
|
||||||
|
: props.row.original.pending_usage_qty !== 0
|
||||||
|
? 'Pending'
|
||||||
|
: '-'
|
||||||
|
}
|
||||||
|
color={
|
||||||
|
props.row.original.usage_qty !== 0
|
||||||
|
? 'green'
|
||||||
|
: props.row.original.pending_usage_qty !== 0
|
||||||
|
? 'yellow'
|
||||||
|
: 'gray'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
className={{
|
||||||
|
containerClassName: cn({
|
||||||
|
'mb-20': initialValues?.chickins?.length === 0,
|
||||||
|
}),
|
||||||
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
||||||
|
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
||||||
|
headerRowClassName: 'border-b border-b-gray-200',
|
||||||
|
headerColumnClassName:
|
||||||
|
'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
|
||||||
|
bodyRowClassName: 'border-b border-b-gray-200',
|
||||||
|
bodyColumnClassName:
|
||||||
|
'px-6 py-3 last:flex last:flex-row last:justify-end',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{chickinErrorMessage && (
|
||||||
|
<div className='w-full' onClick={() => setChickinErrorMessage('')}>
|
||||||
|
<Alert color='error'>{chickinErrorMessage}</Alert>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
<ConfirmationModal
|
||||||
|
ref={confirmModal.ref}
|
||||||
|
type='success'
|
||||||
|
text={`Apakah anda yakin ingin approve data Chickin yang Pending?`}
|
||||||
|
secondaryButton={{
|
||||||
|
text: 'Tidak',
|
||||||
|
}}
|
||||||
|
primaryButton={{
|
||||||
|
text: 'Ya',
|
||||||
|
color: 'success',
|
||||||
|
onClick: confirmationModalApproveClickHandler,
|
||||||
|
isLoading: isApproveLoading,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChickinLogsView;
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import Card from '@/components/Card';
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import {
|
||||||
|
ChickinFormValues,
|
||||||
|
ChickinRequestFormValues,
|
||||||
|
ChickinSchema,
|
||||||
|
} from '../ChickinForm.schema';
|
||||||
|
import DateInput from '@/components/input/DateInput';
|
||||||
|
import SelectInput, { OptionType } from '@/components/input/SelectInput';
|
||||||
|
import NumberInput from '@/components/input/NumberInput';
|
||||||
|
import Button from '@/components/Button';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useFormik } from 'formik';
|
||||||
|
import { flushSync } from 'react-dom';
|
||||||
|
import { CreateChickinPayload } from '@/types/api/production/chickin';
|
||||||
|
import { ChickinApi } from '@/services/api/production/chickin';
|
||||||
|
import { isResponseError } from '@/lib/api-helper';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import Alert from '@/components/Alert';
|
||||||
|
|
||||||
|
const ChickinFormView = ({
|
||||||
|
formType = 'add',
|
||||||
|
initialValues,
|
||||||
|
afterSubmit,
|
||||||
|
}: {
|
||||||
|
formType?: 'add' | 'detail' | 'edit';
|
||||||
|
initialValues: ProjectFlockKandang;
|
||||||
|
afterSubmit?: () => void;
|
||||||
|
}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const [chickinErrorMessage, setChickinErrorMessage] = useState('');
|
||||||
|
|
||||||
|
const createChickin = useCallback(
|
||||||
|
async (payload: CreateChickinPayload) => {
|
||||||
|
const createChickinRes = await ChickinApi.create(payload);
|
||||||
|
if (isResponseError(createChickinRes)) {
|
||||||
|
setChickinErrorMessage(createChickinRes.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success(createChickinRes?.message as string);
|
||||||
|
// router.push(
|
||||||
|
// `/production/project-flock/chickin/add?projectFlockId=${initialValues?.project_flock?.id}`
|
||||||
|
// );
|
||||||
|
if (afterSubmit) {
|
||||||
|
afterSubmit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[router]
|
||||||
|
);
|
||||||
|
const handleReset = async () => {
|
||||||
|
flushSync(() => {
|
||||||
|
formik.resetForm({
|
||||||
|
values: {
|
||||||
|
project_flock_kandang_id: initialValues?.id,
|
||||||
|
chickin_requests: initialValues?.available_qtys
|
||||||
|
? initialValues.available_qtys.map((availableQty) => ({
|
||||||
|
chick_in_date: '',
|
||||||
|
product_warehouse_id: availableQty.product_warehouse.id,
|
||||||
|
available_qty: availableQty.available_qty,
|
||||||
|
note: `Chickin project-flock-kandang-${initialValues?.id} product-warehouse-${availableQty.product_warehouse.id}`,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
formik.setTouched({
|
||||||
|
chickin_requests: initialValues?.available_qtys?.map(() => ({
|
||||||
|
chick_in_date: true,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
const errors = await formik.validateForm();
|
||||||
|
formik.setErrors(errors);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formik = useFormik<ChickinFormValues>({
|
||||||
|
enableReinitialize: true,
|
||||||
|
validationSchema: ChickinSchema,
|
||||||
|
initialValues: {
|
||||||
|
project_flock_kandang_id: initialValues?.id,
|
||||||
|
chickin_requests: initialValues?.available_qtys
|
||||||
|
? initialValues.available_qtys.map((availableQty) => ({
|
||||||
|
chick_in_date: '',
|
||||||
|
product_warehouse_id: availableQty.product_warehouse.id,
|
||||||
|
available_qty: availableQty.available_qty,
|
||||||
|
note: `Chickin project-flock-kandang-${initialValues?.id} product-warehouse-${availableQty.product_warehouse.id}`,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
onSubmit: (values) => {
|
||||||
|
setChickinErrorMessage('');
|
||||||
|
createChickin(values as CreateChickinPayload);
|
||||||
|
if (afterSubmit) {
|
||||||
|
afterSubmit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setValues: formikSetValues } = formik;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formikSetValues({
|
||||||
|
project_flock_kandang_id: initialValues?.id,
|
||||||
|
chickin_requests: initialValues?.available_qtys
|
||||||
|
? initialValues.available_qtys.map((availableQty) => ({
|
||||||
|
chick_in_date: '',
|
||||||
|
product_warehouse_id: availableQty.product_warehouse.id,
|
||||||
|
available_qty: availableQty.available_qty,
|
||||||
|
note: `Chickin project-flock-kandang-${initialValues?.id} product-warehouse-${availableQty.product_warehouse.id}`,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
}, [formikSetValues, initialValues]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className='flex flex-col gap-4'
|
||||||
|
onReset={(e) => {
|
||||||
|
handleReset();
|
||||||
|
}}
|
||||||
|
onSubmit={formik.handleSubmit}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
title='Informasi Chick In DOC'
|
||||||
|
className={{
|
||||||
|
wrapper: 'w-full bg-white',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table<ChickinRequestFormValues>
|
||||||
|
data={formik.values.chickin_requests || []}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.chick_in_date,
|
||||||
|
header: 'Tanggal Chick In',
|
||||||
|
cell(props) {
|
||||||
|
return (
|
||||||
|
<DateInput
|
||||||
|
name={`chickin_requests[${props.row.index}].chick_in_date`}
|
||||||
|
value={
|
||||||
|
formik.values.chickin_requests[props.row.index]
|
||||||
|
?.chick_in_date as string
|
||||||
|
}
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.product_warehouse_id,
|
||||||
|
header: 'Produk',
|
||||||
|
cell(props) {
|
||||||
|
const availableQty = initialValues?.available_qtys?.find(
|
||||||
|
(availableQty) =>
|
||||||
|
availableQty.product_warehouse.id ===
|
||||||
|
props.row.original.product_warehouse_id
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<SelectInput
|
||||||
|
value={
|
||||||
|
{
|
||||||
|
label: availableQty?.product_warehouse?.product?.name,
|
||||||
|
value: availableQty?.product_warehouse?.product?.id,
|
||||||
|
} as OptionType
|
||||||
|
}
|
||||||
|
options={[]}
|
||||||
|
isDisabled
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row) => row.product_warehouse_id,
|
||||||
|
header: 'Jumlah (ekor)',
|
||||||
|
cell(props) {
|
||||||
|
const availableQty = initialValues?.available_qtys?.find(
|
||||||
|
(availableQty) =>
|
||||||
|
availableQty.product_warehouse.id ===
|
||||||
|
props.row.original.product_warehouse_id
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<NumberInput
|
||||||
|
name='qty[]'
|
||||||
|
value={availableQty?.available_qty}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
className={{
|
||||||
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
||||||
|
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
||||||
|
headerRowClassName: 'border-b border-b-gray-200',
|
||||||
|
headerColumnClassName:
|
||||||
|
'px-2 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-2 py-2 last:flex last:flex-row last:justify-end',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
}}
|
||||||
|
emptyContent={
|
||||||
|
<div className='w-full p-5 text-center'>
|
||||||
|
<span className='text-lg opacity-50'>
|
||||||
|
Isi persediaan DOC untuk kandang belum tersedia...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<div className='flex flex-row justify-center gap-3'>
|
||||||
|
<Button type='reset' color='warning' disabled={formik.isSubmitting}>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type='submit'
|
||||||
|
color='primary'
|
||||||
|
disabled={!formik.isValid || formik.isSubmitting}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{chickinErrorMessage && (
|
||||||
|
<div className='w-full' onClick={() => setChickinErrorMessage('')}>
|
||||||
|
<Alert color='error'>{chickinErrorMessage}</Alert>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChickinFormView;
|
||||||
@@ -13,7 +13,7 @@ import { ROWS_OPTIONS } from '@/config/constant';
|
|||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { cn } from '@/lib/helper';
|
import { cn } from '@/lib/helper';
|
||||||
import { AreaApi, KandangApi, LocationApi } from '@/services/api/master-data';
|
import { AreaApi, KandangApi, LocationApi } from '@/services/api/master-data';
|
||||||
import { ProjectFlockApi } from '@/services/api/production';
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
import { BaseApiResponse } from '@/types/api/api-general';
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ import PillBadge from '@/components/PillBadge';
|
|||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { cn } from '@/lib/helper';
|
import { cn } from '@/lib/helper';
|
||||||
import {
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
ProjectFlockApi,
|
import { ProjectFlockKandangApi } from '@/services/api/production';
|
||||||
ProjectFlockKandangApi,
|
|
||||||
} from '@/services/api/production';
|
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import TextInput from '@/components/input/TextInput';
|
|||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
import Collapse from '@/components/Collapse';
|
import Collapse from '@/components/Collapse';
|
||||||
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
import { BaseApiResponse } from '@/types/api/api-general';
|
import { BaseApiResponse, BaseGroupedApproval } from '@/types/api/api-general';
|
||||||
import { APPROVAL_WORKFLOWS, FLOCK_CATEGORY_OPTIONS } from '@/config/constant';
|
import { APPROVAL_WORKFLOWS, FLOCK_CATEGORY_OPTIONS } from '@/config/constant';
|
||||||
import { useModal } from '@/components/Modal';
|
import { useModal } from '@/components/Modal';
|
||||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||||
@@ -45,10 +45,12 @@ import StepItem from '@/components/steps/StepItem';
|
|||||||
import Tooltip from '@/components/Tooltip';
|
import Tooltip from '@/components/Tooltip';
|
||||||
import { id, is } from 'react-day-picker/locale';
|
import { id, is } from 'react-day-picker/locale';
|
||||||
import { formatDate } from '@/lib/helper';
|
import { formatDate } from '@/lib/helper';
|
||||||
|
import Card from '@/components/Card';
|
||||||
|
|
||||||
interface ProjectFlockFormProps {
|
interface ProjectFlockFormProps {
|
||||||
formType?: 'add' | 'edit' | 'detail';
|
formType?: 'add' | 'edit' | 'detail';
|
||||||
initialValues?: ProjectFlock;
|
initialValues?: ProjectFlock;
|
||||||
|
initialApprovals?: BaseGroupedApproval[];
|
||||||
refreshProjectFlocks?: KeyedMutator<
|
refreshProjectFlocks?: KeyedMutator<
|
||||||
BaseApiResponse<ProjectFlock> | undefined
|
BaseApiResponse<ProjectFlock> | undefined
|
||||||
>;
|
>;
|
||||||
@@ -57,6 +59,7 @@ interface ProjectFlockFormProps {
|
|||||||
const ProjectFlockForm = ({
|
const ProjectFlockForm = ({
|
||||||
formType = 'add',
|
formType = 'add',
|
||||||
initialValues,
|
initialValues,
|
||||||
|
initialApprovals,
|
||||||
refreshProjectFlocks,
|
refreshProjectFlocks,
|
||||||
}: ProjectFlockFormProps) => {
|
}: ProjectFlockFormProps) => {
|
||||||
// State
|
// State
|
||||||
@@ -70,14 +73,16 @@ const ProjectFlockForm = ({
|
|||||||
useState('');
|
useState('');
|
||||||
const [selectedArea, setSelectedArea] = useState('');
|
const [selectedArea, setSelectedArea] = useState('');
|
||||||
const [selectedLocation, setSelectedLocation] = useState('');
|
const [selectedLocation, setSelectedLocation] = useState('');
|
||||||
const [disabledLocation, setDisabledLocation] = useState(true);
|
const [disabledLocation, setDisabledLocation] = useState(
|
||||||
|
initialValues?.location?.id ? false : true
|
||||||
|
);
|
||||||
const [openSelectKandangs, setOpenSelectKandangs] = useState(
|
const [openSelectKandangs, setOpenSelectKandangs] = useState(
|
||||||
initialValues?.kandangs && initialValues?.kandangs?.length > 0
|
initialValues?.kandangs && initialValues?.kandangs?.length > 0
|
||||||
);
|
);
|
||||||
const [optionsKandang, setOptionsKandang] = useState<Kandang[]>(
|
const [optionsKandang, setOptionsKandang] = useState<Kandang[]>(
|
||||||
initialValues?.kandangs ?? []
|
initialValues?.kandangs ?? []
|
||||||
);
|
);
|
||||||
const [selectedFlock, setSelectedFlock] = useState<number>(
|
const [selectedFlock, setSelectedFlock] = useState<number | undefined>(
|
||||||
initialValues?.flock?.id ?? 0
|
initialValues?.flock?.id ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -131,7 +136,12 @@ const ProjectFlockForm = ({
|
|||||||
options: optionsLocation,
|
options: optionsLocation,
|
||||||
isLoadingOptions: isLoadingLocations,
|
isLoadingOptions: isLoadingLocations,
|
||||||
rawData: locations,
|
rawData: locations,
|
||||||
} = useSelect(LocationApi.basePath, 'id', 'name');
|
} = useSelect(LocationApi.basePath, 'id', 'name', '', {
|
||||||
|
area_id:
|
||||||
|
selectedArea != ''
|
||||||
|
? selectedArea
|
||||||
|
: ((initialValues?.area?.id ?? '') as string),
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
options: optionsFcr,
|
options: optionsFcr,
|
||||||
@@ -150,27 +160,34 @@ const ProjectFlockForm = ({
|
|||||||
} = useSWR(kandangUrl, KandangApi.getAllFetcher);
|
} = useSWR(kandangUrl, KandangApi.getAllFetcher);
|
||||||
|
|
||||||
const { data: periodFlocks, isLoading: isLoadingPeriodFlocks } = useSWR(
|
const { data: periodFlocks, isLoading: isLoadingPeriodFlocks } = useSWR(
|
||||||
`${selectedFlock.toString()}/periods`,
|
`${selectedFlock?.toString()}/periods`,
|
||||||
(id: string) => ProjectFlockApi.getNextPeriod(id)
|
(id: string) => ProjectFlockApi.getNextPeriod(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: approvalLines, isLoading: isLoadingApprovalLines } = useSWR(
|
|
||||||
selectedFlock.toString(),
|
|
||||||
(id: number) => ProjectFlockApi.getApprovalLines(id)
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isResponseSuccess(kandang)) {
|
if (isResponseSuccess(kandang)) {
|
||||||
if (selectedLocation) {
|
if (selectedLocation) {
|
||||||
setOptionsKandang(kandang.data);
|
setOptionsKandang(kandang.data);
|
||||||
setOpenSelectKandangs(true);
|
setOpenSelectKandangs(true);
|
||||||
} else {
|
} else {
|
||||||
|
formik.setFieldValue('kandang_ids', []);
|
||||||
setOptionsKandang([]);
|
setOptionsKandang([]);
|
||||||
setOpenSelectKandangs(false);
|
setOpenSelectKandangs(false);
|
||||||
formik.setFieldValue('kandang_ids', []);
|
const selectedRowIds = Object.keys(rowSelection)
|
||||||
|
.filter((id) => rowSelection[id])
|
||||||
|
.map((id) => parseInt(id));
|
||||||
|
if (
|
||||||
|
JSON.stringify(kandang.data.map((k) => k.id)) !==
|
||||||
|
JSON.stringify(formik.values.kandang_ids)
|
||||||
|
) {
|
||||||
|
formik.setFieldValue('kandang_ids', []);
|
||||||
|
setRowSelection({});
|
||||||
|
} else {
|
||||||
|
formik.setFieldValue('kandang_ids', selectedRowIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [kandang]);
|
}, [kandang, selectedLocation]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialValues?.kandangs) {
|
if (initialValues?.kandangs) {
|
||||||
refreshKandang();
|
refreshKandang();
|
||||||
@@ -181,7 +198,7 @@ const ProjectFlockForm = ({
|
|||||||
);
|
);
|
||||||
setRowSelection(newRowSelection);
|
setRowSelection(newRowSelection);
|
||||||
}
|
}
|
||||||
}, [initialValues, refreshKandang]);
|
}, [initialValues, kandang]);
|
||||||
|
|
||||||
// Options Handler
|
// Options Handler
|
||||||
const areaChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const areaChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
@@ -202,9 +219,13 @@ const ProjectFlockForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
|
formik.setFieldValue('kandang_ids', []);
|
||||||
setSelectedLocation((val as OptionType)?.value as string);
|
setSelectedLocation((val as OptionType)?.value as string);
|
||||||
optionChangeHandler(val, 'location');
|
optionChangeHandler(val, 'location');
|
||||||
formik.setFieldValue('kandang_ids', []);
|
const selectedRowIds = Object.keys(rowSelection)
|
||||||
|
.filter((id) => rowSelection[id])
|
||||||
|
.map((id) => parseInt(id));
|
||||||
|
formik.setFieldValue('kandang_ids', selectedRowIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
const optionChangeHandler = (
|
const optionChangeHandler = (
|
||||||
@@ -216,13 +237,8 @@ const ProjectFlockForm = ({
|
|||||||
`${inputName}_id`,
|
`${inputName}_id`,
|
||||||
val ? (val as OptionType)?.value : 0
|
val ? (val as OptionType)?.value : 0
|
||||||
);
|
);
|
||||||
formik.setFieldValue(
|
|
||||||
`${inputName}_name`,
|
|
||||||
val ? (val as OptionType)?.label : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
formik.setFieldTouched(`${inputName}_id`, true);
|
formik.setFieldTouched(`${inputName}_id`, true);
|
||||||
formik.setFieldTouched(`${inputName}_name`, true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const categoryChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const categoryChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
@@ -267,11 +283,12 @@ const ProjectFlockForm = ({
|
|||||||
// Formik InitialValue
|
// Formik InitialValue
|
||||||
const formikInitialValues = useMemo<ProjectFlockFormValues>(() => {
|
const formikInitialValues = useMemo<ProjectFlockFormValues>(() => {
|
||||||
return {
|
return {
|
||||||
name: initialValues?.name ?? '',
|
name: initialValues?.flock_name,
|
||||||
flock: initialValues?.flock_name
|
flock: initialValues?.flock
|
||||||
? {
|
? {
|
||||||
value: initialValues?.flock?.id ?? 0,
|
value: initialValues?.flock?.id ?? 0,
|
||||||
label: initialValues?.flock_name,
|
label:
|
||||||
|
initialValues?.flock?.name ?? initialValues?.flock_name ?? '',
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
area: initialValues?.area
|
area: initialValues?.area
|
||||||
@@ -312,11 +329,57 @@ const ProjectFlockForm = ({
|
|||||||
| undefined
|
| undefined
|
||||||
)[],
|
)[],
|
||||||
};
|
};
|
||||||
}, [initialValues, flocks]);
|
}, [initialValues]);
|
||||||
|
|
||||||
// Formik
|
// Formik
|
||||||
const formik = useFormik<ProjectFlockFormValues>({
|
const formik = useFormik<ProjectFlockFormValues>({
|
||||||
initialValues: formikInitialValues,
|
initialValues: {
|
||||||
|
name: initialValues?.flock_name,
|
||||||
|
flock: initialValues?.flock
|
||||||
|
? {
|
||||||
|
value: initialValues?.flock?.id ?? 0,
|
||||||
|
label:
|
||||||
|
initialValues?.flock?.name ?? initialValues?.flock_name ?? '',
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
area: initialValues?.area
|
||||||
|
? {
|
||||||
|
value: initialValues.area?.id,
|
||||||
|
label: initialValues.area.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
category_option: initialValues?.category
|
||||||
|
? {
|
||||||
|
value: initialValues.category,
|
||||||
|
label: initialValues.category,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
fcr: initialValues?.fcr
|
||||||
|
? {
|
||||||
|
value: initialValues.fcr?.id,
|
||||||
|
label: initialValues.fcr.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
location: initialValues?.location
|
||||||
|
? {
|
||||||
|
value: initialValues.location?.id,
|
||||||
|
label: initialValues.location.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
flock_id: initialValues?.flock?.id ?? 0,
|
||||||
|
flock_name: initialValues?.flock_name ?? '',
|
||||||
|
area_id: initialValues?.area?.id ?? 0,
|
||||||
|
category: initialValues?.category as NonNullable<
|
||||||
|
'GROWING' | 'LAYING' | undefined
|
||||||
|
>,
|
||||||
|
fcr_id: initialValues?.fcr?.id ?? 0,
|
||||||
|
location_id: initialValues?.location?.id ?? 0,
|
||||||
|
period: initialValues?.period ?? 1,
|
||||||
|
kandang_ids: initialValues?.kandangs?.map((k: Kandang) => k.id) as (
|
||||||
|
| number
|
||||||
|
| undefined
|
||||||
|
)[],
|
||||||
|
} as ProjectFlockFormValues,
|
||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
validationSchema:
|
validationSchema:
|
||||||
formType == 'add' ? ProjectFlockFormSchema : UpdateProjectFlockFormSchema,
|
formType == 'add' ? ProjectFlockFormSchema : UpdateProjectFlockFormSchema,
|
||||||
@@ -326,7 +389,7 @@ const ProjectFlockForm = ({
|
|||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
setProjectFlockFormErrorMessage('');
|
setProjectFlockFormErrorMessage('');
|
||||||
const payload: CreateProjectFlockPayload = {
|
const payload: CreateProjectFlockPayload = {
|
||||||
flock_name: values.flock_name as string,
|
flock_name: values.flock?.label as string,
|
||||||
area_id: values.area_id as number,
|
area_id: values.area_id as number,
|
||||||
category: values.category as string,
|
category: values.category as string,
|
||||||
fcr_id: values.fcr_id as number,
|
fcr_id: values.fcr_id as number,
|
||||||
@@ -367,7 +430,7 @@ const ProjectFlockForm = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
formikSetValues(formikInitialValues);
|
formikSetValues(formikInitialValues);
|
||||||
}, [formikSetValues, formikInitialValues]);
|
}, [formikSetValues]);
|
||||||
|
|
||||||
// Aktifkan lokasi jika formType = 'detail'
|
// Aktifkan lokasi jika formType = 'detail'
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -397,7 +460,7 @@ const ProjectFlockForm = ({
|
|||||||
if (isResponseError(periodFlocks)) {
|
if (isResponseError(periodFlocks)) {
|
||||||
console.log(periodFlocks?.message as string);
|
console.log(periodFlocks?.message as string);
|
||||||
}
|
}
|
||||||
}, [periodFlocks, toast]);
|
}, [periodFlocks]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selectedRowIds = Object.keys(rowSelection)
|
const selectedRowIds = Object.keys(rowSelection)
|
||||||
@@ -495,11 +558,11 @@ const ProjectFlockForm = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{formType == 'detail' && isResponseSuccess(approvalLines) && (
|
{formType == 'detail' && initialApprovals && (
|
||||||
<div className='w-full flex items-center gap-2 my-4'>
|
<div className='w-full flex items-center gap-2 my-4'>
|
||||||
<Steps className='w-full'>
|
<Steps className='w-full'>
|
||||||
{projectFlockSteps?.steps.map((step, idx) => {
|
{projectFlockSteps?.steps.map((step, idx) => {
|
||||||
const approvalLogs = approvalLines.data.find(
|
const approvalLogs = initialApprovals.find(
|
||||||
(approve) => approve.step_number == step.step_number
|
(approve) => approve.step_number == step.step_number
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
@@ -523,7 +586,7 @@ const ProjectFlockForm = ({
|
|||||||
content={
|
content={
|
||||||
<ul>
|
<ul>
|
||||||
{approvalLogs &&
|
{approvalLogs &&
|
||||||
approvalLogs.approvals.map((approval, idx) => {
|
approvalLogs?.approvals?.map((approval, idx) => {
|
||||||
return (
|
return (
|
||||||
<li className='mb-2' key={`key-logs-${idx}`}>
|
<li className='mb-2' key={`key-logs-${idx}`}>
|
||||||
<div className='flex flex-col w-full text-start text-base'>
|
<div className='flex flex-col w-full text-start text-base'>
|
||||||
@@ -601,8 +664,43 @@ const ProjectFlockForm = ({
|
|||||||
<Icon icon='mdi:times' width={24} height={24} />
|
<Icon icon='mdi:times' width={24} height={24} />
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
{initialValues?.approval?.step_number == 2 && (
|
||||||
|
<Button
|
||||||
|
variant='outline'
|
||||||
|
color='success'
|
||||||
|
className='w-full sm:w-fit'
|
||||||
|
onClick={() => {
|
||||||
|
router.push(
|
||||||
|
`/production/project-flock/chickin/add?projectFlockId=${initialValues?.id}`
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Chickin
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<Card
|
||||||
|
className={{
|
||||||
|
body: 'text-primary',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{JSON.stringify(formik.values)}
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
className={{
|
||||||
|
body: 'text-success',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{JSON.stringify(formik.initialValues)}
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
className={{
|
||||||
|
body: 'text-error',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{JSON.stringify(formik.errors)}
|
||||||
|
</Card>
|
||||||
<form
|
<form
|
||||||
className='w-auto h-auto'
|
className='w-auto h-auto'
|
||||||
onSubmit={formik.handleSubmit}
|
onSubmit={formik.handleSubmit}
|
||||||
@@ -634,6 +732,10 @@ const ProjectFlockForm = ({
|
|||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
optionChangeHandler(val, 'flock');
|
optionChangeHandler(val, 'flock');
|
||||||
setSelectedFlock((val as OptionType)?.value as number);
|
setSelectedFlock((val as OptionType)?.value as number);
|
||||||
|
formik.setFieldValue(
|
||||||
|
'flock_name',
|
||||||
|
(val as OptionType)?.label
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
options={optionsFlock}
|
options={optionsFlock}
|
||||||
isLoading={isLoadingFlocks}
|
isLoading={isLoadingFlocks}
|
||||||
@@ -650,7 +752,11 @@ const ProjectFlockForm = ({
|
|||||||
label='Lokasi'
|
label='Lokasi'
|
||||||
value={formik.values.location as OptionType}
|
value={formik.values.location as OptionType}
|
||||||
onChange={locationChangeHandler}
|
onChange={locationChangeHandler}
|
||||||
options={optionsLocation}
|
options={
|
||||||
|
selectedArea != '' || initialValues?.area?.id
|
||||||
|
? optionsLocation
|
||||||
|
: []
|
||||||
|
}
|
||||||
isLoading={isLoadingLocations}
|
isLoading={isLoadingLocations}
|
||||||
isError={
|
isError={
|
||||||
formik.touched.location_id &&
|
formik.touched.location_id &&
|
||||||
@@ -695,7 +801,7 @@ const ProjectFlockForm = ({
|
|||||||
name='period'
|
name='period'
|
||||||
label='Periode'
|
label='Periode'
|
||||||
placeholder='Masukkan periode yang project'
|
placeholder='Masukkan periode yang project'
|
||||||
value={formik.values.period as number}
|
value={formik.values.period ?? (1 as number)}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
isError={
|
isError={
|
||||||
formik.touched.period && Boolean(formik.errors.period)
|
formik.touched.period && Boolean(formik.errors.period)
|
||||||
@@ -743,6 +849,7 @@ const ProjectFlockForm = ({
|
|||||||
setRowSelection={setRowSelection}
|
setRowSelection={setRowSelection}
|
||||||
selectedIds={formik.values.kandang_ids}
|
selectedIds={formik.values.kandang_ids}
|
||||||
formType={formType}
|
formType={formType}
|
||||||
|
initialValues={initialValues?.kandangs ?? []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
@@ -764,7 +871,10 @@ const ProjectFlockForm = ({
|
|||||||
type='submit'
|
type='submit'
|
||||||
color='primary'
|
color='primary'
|
||||||
isLoading={formik.isSubmitting}
|
isLoading={formik.isSubmitting}
|
||||||
disabled={!formik.isValid || formik.isSubmitting}
|
disabled={
|
||||||
|
!formik.isValid || formik.isSubmitting
|
||||||
|
// TODO: Add logic && ketika nilai kandang_ids sudah beda dari initial values
|
||||||
|
}
|
||||||
className='px-4'
|
className='px-4'
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
|
|||||||
@@ -5,148 +5,159 @@ import PillBadge from '@/components/PillBadge';
|
|||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { cn } from '@/lib/helper';
|
import { cn } from '@/lib/helper';
|
||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
import { OnChangeFn } from '@tanstack/react-table';
|
import { OnChangeFn, Row } from '@tanstack/react-table';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const ProjectFlockKandangTable = ({
|
const ProjectFlockKandangTable = ({
|
||||||
listKandang,
|
listKandang,
|
||||||
rowSelection,
|
rowSelection,
|
||||||
setRowSelection,
|
setRowSelection,
|
||||||
selectedIds,
|
selectedIds,
|
||||||
|
initialValues,
|
||||||
formType = 'add',
|
formType = 'add',
|
||||||
}: {
|
}: {
|
||||||
listKandang: Kandang[];
|
listKandang: Kandang[];
|
||||||
rowSelection: Record<string, boolean>;
|
rowSelection: Record<string, boolean>;
|
||||||
setRowSelection: OnChangeFn<Record<string, boolean>>;
|
setRowSelection: OnChangeFn<Record<string, boolean>>;
|
||||||
selectedIds: (number | undefined)[];
|
selectedIds: (number | undefined)[];
|
||||||
|
initialValues?: Kandang[];
|
||||||
formType: 'add' | 'edit' | 'detail';
|
formType: 'add' | 'edit' | 'detail';
|
||||||
}) => {
|
}) => {
|
||||||
console.log('selectedIds');
|
const initialKandangIdSet = useMemo(() => {
|
||||||
console.log(selectedIds);
|
return initialValues?.map((k) => k.id) ?? [];
|
||||||
|
}, [initialValues]);
|
||||||
|
const isRowEnabled = (row: Row<Kandang>) => {
|
||||||
|
const isDisabled =
|
||||||
|
!initialKandangIdSet.includes(row.original.id) &&
|
||||||
|
(row.original.status == 'ACTIVE' ||
|
||||||
|
row.original.status == 'PENGAJUAN' ||
|
||||||
|
formType == 'detail');
|
||||||
|
return !isDisabled;
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Table<Kandang>
|
<>
|
||||||
data={listKandang}
|
{JSON.stringify(initialKandangIdSet)}
|
||||||
columns={[
|
<Table<Kandang>
|
||||||
{
|
data={listKandang}
|
||||||
id: 'select',
|
columns={[
|
||||||
header: ({ table }) => {
|
{
|
||||||
const allRows = table.getRowModel().rows;
|
id: 'select',
|
||||||
const selectableRows = allRows.filter(
|
header: ({ table }) => {
|
||||||
(row) =>
|
const allRows = table.getRowModel().rows;
|
||||||
row.original.status == 'NON_ACTIVE' ||
|
// 1. Filter semua baris dengan logika yang sama persis seperti di cell
|
||||||
row.original.status == 'PENGAJUAN'
|
const selectableRows = allRows.filter(isRowEnabled);
|
||||||
);
|
|
||||||
|
|
||||||
const allSelected =
|
// 2. Cek apakah SEMUA baris yang BISA DIPILIH sudah terpilih
|
||||||
selectableRows.every((row) => row.getIsSelected()) &&
|
const allSelected =
|
||||||
selectableRows.length != 0 &&
|
selectableRows.length > 0 &&
|
||||||
formType != 'detail';
|
selectableRows.every((row) => row.getIsSelected());
|
||||||
|
|
||||||
const someSelected =
|
// 3. Cek apakah BEBERAPA baris yang BISA DIPILIH sudah terpilih
|
||||||
selectableRows.some((row) => row.getIsSelected()) &&
|
const someSelected =
|
||||||
!allSelected &&
|
selectableRows.some((row) => row.getIsSelected()) &&
|
||||||
formType != 'detail';
|
!allSelected;
|
||||||
|
|
||||||
const toggleSelectableRows = () => {
|
// 4. Fungsi toggle HANYA akan mentoggle baris yang BISA DIPILIH
|
||||||
const shouldSelect = !allSelected;
|
const toggleSelectableRows = () => {
|
||||||
selectableRows.forEach((row) => row.toggleSelected(shouldSelect));
|
const shouldSelect = !allSelected;
|
||||||
};
|
selectableRows.forEach((row) =>
|
||||||
|
row.toggleSelected(shouldSelect)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex flex-row justify-center'>
|
<div className='w-full flex flex-row justify-center'>
|
||||||
|
<CheckboxInput
|
||||||
|
name='allRow'
|
||||||
|
checked={allSelected}
|
||||||
|
indeterminate={someSelected}
|
||||||
|
onChange={toggleSelectableRows}
|
||||||
|
disabled={
|
||||||
|
selectableRows.length === 0 || formType == 'detail'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
<CheckboxInput
|
<CheckboxInput
|
||||||
name='allRow'
|
name='row'
|
||||||
checked={allSelected}
|
checked={
|
||||||
indeterminate={someSelected}
|
(row.getIsSelected() &&
|
||||||
onChange={toggleSelectableRows}
|
(row.original.status == 'NON_ACTIVE' ||
|
||||||
|
row.original.status == 'PENGAJUAN')) ||
|
||||||
|
(selectedIds && selectedIds.includes(row.original.id))
|
||||||
|
}
|
||||||
disabled={
|
disabled={
|
||||||
listKandang.filter(
|
formType == 'detail' ||
|
||||||
(kandang) =>
|
(!initialKandangIdSet.includes(row.original.id) &&
|
||||||
kandang.status == 'NON_ACTIVE' ||
|
(row.original.status == 'ACTIVE' ||
|
||||||
kandang.status == 'PENGAJUAN'
|
row.original.status == 'PENGAJUAN'))
|
||||||
).length == 0 || formType == 'detail'
|
|
||||||
}
|
}
|
||||||
|
indeterminate={row.getIsSomeSelected()}
|
||||||
|
onChange={row.getToggleSelectedHandler()}
|
||||||
/>
|
/>
|
||||||
</div>
|
);
|
||||||
);
|
},
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
{
|
||||||
return (
|
accessorFn: (row) => row.name,
|
||||||
<CheckboxInput
|
header: 'Kandang',
|
||||||
name='row'
|
|
||||||
checked={
|
|
||||||
(row.getIsSelected() &&
|
|
||||||
(row.original.status == 'NON_ACTIVE' ||
|
|
||||||
row.original.status == 'PENGAJUAN')) ||
|
|
||||||
selectedIds.includes(row.original.id)
|
|
||||||
}
|
|
||||||
disabled={
|
|
||||||
!row.getCanSelect() ||
|
|
||||||
(row.original.status != 'NON_ACTIVE' &&
|
|
||||||
row.original.status != 'PENGAJUAN') ||
|
|
||||||
formType == 'detail'
|
|
||||||
}
|
|
||||||
indeterminate={row.getIsSomeSelected()}
|
|
||||||
onChange={row.getToggleSelectedHandler()}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorFn: (row) => row.status,
|
||||||
accessorFn: (row) => row.name,
|
header: 'Status',
|
||||||
header: 'Kandang',
|
cell: (props) => {
|
||||||
},
|
return (
|
||||||
{
|
<PillBadge
|
||||||
accessorFn: (row) => row.status,
|
color={(() => {
|
||||||
header: 'Status',
|
switch (props.row.original.status) {
|
||||||
cell: (props) => {
|
case 'ACTIVE':
|
||||||
return (
|
return 'red';
|
||||||
<PillBadge
|
case 'PENGAJUAN':
|
||||||
color={(() => {
|
return 'green';
|
||||||
switch (props.row.original.status) {
|
case 'NON_ACTIVE':
|
||||||
case 'ACTIVE':
|
return 'blue';
|
||||||
return 'red';
|
default:
|
||||||
case 'PENGAJUAN':
|
return 'gray';
|
||||||
return 'green';
|
}
|
||||||
case 'NON_ACTIVE':
|
})()}
|
||||||
return 'blue';
|
content={props.row.original.status
|
||||||
default:
|
.toLowerCase()
|
||||||
return 'gray';
|
.replace(/_/g, ' ')
|
||||||
}
|
.replace(/\b\w/g, (char) => char.toUpperCase())}
|
||||||
})()}
|
/>
|
||||||
content={props.row.original.status
|
);
|
||||||
.toLowerCase()
|
},
|
||||||
.replace(/_/g, ' ')
|
|
||||||
.replace(/\b\w/g, (char) => char.toUpperCase())}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorFn: (row) => row.capacity,
|
||||||
accessorFn: (row) => row.capacity,
|
header: 'Kapasitas',
|
||||||
header: 'Kapasitas',
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorFn: (row) => row.pic?.name,
|
||||||
accessorFn: (row) => row.pic?.name,
|
header: 'Penanggung Jawab',
|
||||||
header: 'Penanggung Jawab',
|
},
|
||||||
},
|
]}
|
||||||
]}
|
className={{
|
||||||
className={{
|
containerClassName: cn({
|
||||||
containerClassName: cn({
|
'mb-20': listKandang?.length === 0,
|
||||||
'mb-20': listKandang?.length === 0,
|
}),
|
||||||
}),
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
||||||
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
||||||
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
headerRowClassName: 'border-b border-b-gray-200',
|
||||||
headerRowClassName: 'border-b border-b-gray-200',
|
headerColumnClassName:
|
||||||
headerColumnClassName:
|
'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
|
||||||
'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',
|
||||||
bodyRowClassName: 'border-b border-b-gray-200',
|
bodyColumnClassName:
|
||||||
bodyColumnClassName:
|
'px-6 py-3 last:flex last:flex-row last:justify-end',
|
||||||
'px-6 py-3 last:flex last:flex-row last:justify-end',
|
paginationClassName: 'hidden',
|
||||||
paginationClassName: 'hidden',
|
}}
|
||||||
}}
|
rowSelection={rowSelection}
|
||||||
rowSelection={rowSelection}
|
setRowSelection={setRowSelection}
|
||||||
setRowSelection={setRowSelection}
|
/>
|
||||||
/>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
UpdateRecordingFormSchema,
|
UpdateRecordingFormSchema,
|
||||||
} from './RecordingForm.schema';
|
} from './RecordingForm.schema';
|
||||||
import { useRecordingFormHandlers } from './useRecordingFormHandlers';
|
import { useRecordingFormHandlers } from './useRecordingFormHandlers';
|
||||||
import { ProjectFlockApi } from '@/services/api/production';
|
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { RECORDING_FLAG_OPTIONS } from '@/config/constant';
|
import { RECORDING_FLAG_OPTIONS } from '@/config/constant';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { BaseApiService } from '@/services/api/base';
|
import { BaseApiService } from '@/services/api/base';
|
||||||
import {
|
|
||||||
CreateProjectFlockPayload,
|
|
||||||
ProjectFlock,
|
|
||||||
UpdateProjectFlockPayload,
|
|
||||||
} from '@/types/api/production/project-flock';
|
|
||||||
import {
|
import {
|
||||||
CreateRecordingPayload,
|
CreateRecordingPayload,
|
||||||
Recording,
|
Recording,
|
||||||
@@ -11,11 +6,6 @@ import {
|
|||||||
} from '@/types/api/production/recording';
|
} from '@/types/api/production/recording';
|
||||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||||
|
|
||||||
export const ProjectFlockApi = new BaseApiService<
|
|
||||||
ProjectFlock,
|
|
||||||
CreateProjectFlockPayload,
|
|
||||||
UpdateProjectFlockPayload
|
|
||||||
>('/production/project-flocks');
|
|
||||||
export const ProjectFlockKandangApi = new BaseApiService<
|
export const ProjectFlockKandangApi = new BaseApiService<
|
||||||
ProjectFlockKandang,
|
ProjectFlockKandang,
|
||||||
unknown,
|
unknown,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import {
|
||||||
|
Chickin,
|
||||||
|
CreateChickinPayload,
|
||||||
|
UpdateChickinPayload,
|
||||||
|
} from '@/types/api/production/chickin';
|
||||||
|
import { BaseApiService } from '../base';
|
||||||
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
import { httpClient } from '@/services/http/client';
|
||||||
|
|
||||||
|
export class ChickinService extends BaseApiService<
|
||||||
|
Chickin,
|
||||||
|
CreateChickinPayload,
|
||||||
|
UpdateChickinPayload
|
||||||
|
> {
|
||||||
|
constructor(basePath: string = '/production/chickins') {
|
||||||
|
super(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Approve single marketing data
|
||||||
|
*/
|
||||||
|
async singleApproval(
|
||||||
|
id: number,
|
||||||
|
action: 'APPROVED' | 'REJECTED'
|
||||||
|
): Promise<BaseApiResponse<{ message: string }> | undefined> {
|
||||||
|
try {
|
||||||
|
const path = `${this.basePath}/approvals`;
|
||||||
|
return await httpClient<BaseApiResponse<{ message: string }>>(path, {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
action: action,
|
||||||
|
approvable_ids: [id],
|
||||||
|
notes: `${action} chickin ${id}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error approve chickin:', error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChickinApi = new ChickinService('/production/chickins');
|
||||||
Reference in New Issue
Block a user