mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-106-91-339-238): Slicing UI Chickin DOC Refactored
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
|
||||
export default function AddChickinKandang() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const kandangId = searchParams.get('kandangId');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Tambah Chickin untuk Kandang ID: {kandangId}</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,426 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import Badge from '@/components/Badge';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import SelectInput, { OptionType } from '@/components/input/SelectInput';
|
||||
import Modal, { useModal } from '@/components/Modal';
|
||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import ChickinForm from '@/components/pages/production/chickin/form/ChickinForm';
|
||||
import PillBadge from '@/components/PillBadge';
|
||||
import Table from '@/components/Table';
|
||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
import { cn } from '@/lib/helper';
|
||||
import { ProjectFlockApi } from '@/services/api/production';
|
||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { is } from 'react-day-picker/locale';
|
||||
|
||||
import useSWR from 'swr';
|
||||
|
||||
const AddChickin = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const projectFlockId = searchParams.get('projectFlockId');
|
||||
|
||||
// Tables Props
|
||||
const { state: tableFilterState } = useTableFilter({
|
||||
initial: { search: '' },
|
||||
paramMap: { page: 'page', pageSize: 'limit' },
|
||||
});
|
||||
|
||||
// States
|
||||
const [selectedKandang, setSelectedKandang] = useState<Kandang | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [projectFlockKandang, setProjectFlockKandang] =
|
||||
useState<BaseApiResponse<ProjectFlockKandang>>();
|
||||
const [isLoadingProjectFlockKandang, setIsLoadingProjectFlockKandang] =
|
||||
useState(false);
|
||||
const [searchProjectFlock, setSearchProjectFlock] = useState('');
|
||||
const [selectedProjectFlock, setSelectedProjectFlock] =
|
||||
useState<OptionType | null>(null);
|
||||
|
||||
// Fetch Data
|
||||
const { data: projectFlock, isLoading: isLoadingProjectFlock } = useSWR(
|
||||
projectFlockId ?? selectedProjectFlock?.value.toString(),
|
||||
(id: number) => ProjectFlockApi.getSingle(id)
|
||||
);
|
||||
const { data: listProjectFlock, isLoading: isLoadingListProjectFlock } =
|
||||
useSWR(
|
||||
`${ProjectFlockApi.basePath}?${new URLSearchParams({
|
||||
search: searchProjectFlock,
|
||||
}).toString()}`,
|
||||
ProjectFlockApi.getAllFetcher
|
||||
);
|
||||
|
||||
const getProjectFlockKandangUrl = `/kandangs/lookup`;
|
||||
// Mapping Options
|
||||
const options = isResponseSuccess(listProjectFlock)
|
||||
? listProjectFlock?.data.map((projectFlock) => {
|
||||
return {
|
||||
value: projectFlock.id,
|
||||
label: `${projectFlock?.flock?.name} - Periode ${projectFlock?.period}`,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const chickinModal = useModal();
|
||||
const alertModal = useModal();
|
||||
|
||||
// Handle Function
|
||||
const handleChickinClick = async (kandang: Kandang) => {
|
||||
setIsLoadingProjectFlockKandang(true);
|
||||
setSelectedKandang(kandang);
|
||||
const ProjectFlockKandangRes = await ProjectFlockApi.customRequest<
|
||||
BaseApiResponse<ProjectFlockKandang>,
|
||||
'GET'
|
||||
>(getProjectFlockKandangUrl, {
|
||||
method: 'GET',
|
||||
params: {
|
||||
project_flock_id: projectFlockId ?? selectedProjectFlock?.value ?? 0,
|
||||
kandang_id: kandang.id,
|
||||
},
|
||||
});
|
||||
if (isResponseSuccess(ProjectFlockKandangRes)) {
|
||||
setProjectFlockKandang(ProjectFlockKandangRes);
|
||||
setIsLoadingProjectFlockKandang(false);
|
||||
if (
|
||||
ProjectFlockKandangRes.data.available_quantity &&
|
||||
ProjectFlockKandangRes.data.available_quantity > 0
|
||||
) {
|
||||
chickinModal.openModal();
|
||||
} else {
|
||||
alertModal.openModal();
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleAfterSubmit = () => {
|
||||
chickinModal.closeModal();
|
||||
router.push('/production/chickin');
|
||||
};
|
||||
const handleChangeProjectFlock = (val: OptionType | null) => {
|
||||
setSelectedProjectFlock(val);
|
||||
if (projectFlockId) {
|
||||
router.push('/production/chickin/add');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<>
|
||||
<section className='w-full p-4'>
|
||||
<header className='flex flex-col gap-4'>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<Button
|
||||
href='/production/project-flock'
|
||||
variant='link'
|
||||
className='w-fit p-0 text-primary'
|
||||
>
|
||||
<Icon icon='uil:arrow-left' width={24} height={24} />
|
||||
Kembali
|
||||
</Button>
|
||||
<h1 className='text-2xl font-semibold text-center'>
|
||||
Daftar Kandang Project Flock
|
||||
</h1>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col gap-4 w-full my-4'>
|
||||
<div className='max-w-full sm:max-w-1/2 md:max-w-3/5 lg:max-w-2/5'>
|
||||
<SelectInput
|
||||
required
|
||||
label='Ganti Project Flock'
|
||||
placeholder='Pilih Project Flock'
|
||||
options={options}
|
||||
onInputChange={(val) => {
|
||||
setSearchProjectFlock(val);
|
||||
}}
|
||||
isLoading={isLoadingListProjectFlock}
|
||||
value={
|
||||
isResponseSuccess(projectFlock)
|
||||
? {
|
||||
label: `${projectFlock.data?.flock?.name}`,
|
||||
value: projectFlock.data?.id,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onChange={(val) => {
|
||||
handleChangeProjectFlock(val as OptionType);
|
||||
}}
|
||||
isSearchable
|
||||
isClearable
|
||||
startAdornment={
|
||||
isResponseSuccess(projectFlock) && (
|
||||
<Badge
|
||||
variant='soft'
|
||||
color='success'
|
||||
size='sm'
|
||||
className={{
|
||||
badge: 'whitespace-nowrap font-semibold',
|
||||
}}
|
||||
>
|
||||
Periode {projectFlock.data?.period}
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<Card
|
||||
title='Informasi Flock'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white mb-3',
|
||||
}}
|
||||
>
|
||||
<Table<ProjectFlock>
|
||||
emptyContent={
|
||||
<div className='w-full p-5 text-center'>
|
||||
{projectFlockId && isResponseError(projectFlock) ? (
|
||||
<span className='text-lg opacity-50'>
|
||||
{projectFlock.message}
|
||||
</span>
|
||||
) : (
|
||||
<span className='text-lg opacity-50'>
|
||||
Pilih project flock terlebih dahulu...
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
data={isResponseSuccess(projectFlock) ? [projectFlock.data] : []}
|
||||
columns={[
|
||||
{
|
||||
header: 'Area',
|
||||
accessorKey: 'area.name',
|
||||
},
|
||||
{
|
||||
header: 'Lokasi',
|
||||
accessorKey: 'location.name',
|
||||
},
|
||||
{
|
||||
header: 'Nama Flock',
|
||||
accessorKey: 'flock.name',
|
||||
},
|
||||
{
|
||||
header: 'Kategori',
|
||||
accessorKey: 'category',
|
||||
},
|
||||
{
|
||||
header: 'Status',
|
||||
accessorKey: 'status',
|
||||
cell: (props) => {
|
||||
return props.row.original.approval.step_name ? (
|
||||
<PillBadge
|
||||
color={(() => {
|
||||
switch (
|
||||
props.row.original.approval.step_name.toUpperCase()
|
||||
) {
|
||||
case 'AKTIF':
|
||||
return 'red';
|
||||
case 'PENGAJUAN':
|
||||
return 'green';
|
||||
default:
|
||||
return 'gray';
|
||||
}
|
||||
})()}
|
||||
content={props.row.original.approval.step_name
|
||||
.toLowerCase()
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/\b\w/g, (char) => char.toUpperCase())}
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Periode',
|
||||
accessorKey: 'period',
|
||||
},
|
||||
{
|
||||
header: 'FCR Layer',
|
||||
accessorKey: 'fcr.name',
|
||||
},
|
||||
]}
|
||||
page={undefined}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20':
|
||||
isResponseSuccess(projectFlock) &&
|
||||
projectFlock.data?.kandangs?.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',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card
|
||||
title='Daftar Chickin'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white',
|
||||
}}
|
||||
>
|
||||
<Table<Kandang>
|
||||
emptyContent={
|
||||
<div className='w-full p-5 text-center'>
|
||||
{projectFlockId && isResponseError(projectFlock) ? (
|
||||
<span className='text-lg opacity-50'>
|
||||
{projectFlock.message}
|
||||
</span>
|
||||
) : (
|
||||
<span className='text-lg opacity-50'>
|
||||
Pilih project flock terlebih dahulu...
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
data={
|
||||
isResponseSuccess(projectFlock)
|
||||
? projectFlock.data?.kandangs
|
||||
: []
|
||||
}
|
||||
columns={[
|
||||
{
|
||||
header: '#',
|
||||
cell: (props) =>
|
||||
tableFilterState.pageSize * (tableFilterState.page - 1) +
|
||||
props.row.index +
|
||||
1,
|
||||
},
|
||||
{
|
||||
accessorFn: () =>
|
||||
isResponseSuccess(projectFlock)
|
||||
? projectFlock.data.area.name
|
||||
: '',
|
||||
header: 'Area',
|
||||
},
|
||||
{
|
||||
accessorFn: () =>
|
||||
isResponseSuccess(projectFlock)
|
||||
? projectFlock.data.location.name
|
||||
: '',
|
||||
header: 'Lokasi',
|
||||
},
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: 'Kandang',
|
||||
},
|
||||
{
|
||||
accessorKey: 'capacity',
|
||||
header: 'Kapasitas',
|
||||
},
|
||||
{
|
||||
accessorKey: 'pic.name',
|
||||
header: 'Penanggung Jawab',
|
||||
},
|
||||
{
|
||||
header: 'Aksi',
|
||||
cell: (props) => {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
color='success'
|
||||
variant='outline'
|
||||
onClick={() => {
|
||||
handleChickinClick(props.row.original);
|
||||
}}
|
||||
disabled={isLoadingProjectFlockKandang}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:home-import-outline'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
Chickin
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
page={undefined}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20':
|
||||
isResponseSuccess(projectFlock) &&
|
||||
projectFlock.data?.kandangs?.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',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</section>
|
||||
<Modal ref={chickinModal.ref}>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<h1 className='text-xl font-semibold text-center mb-6'>
|
||||
Chickin Kandang - {selectedKandang?.name}
|
||||
</h1>
|
||||
<Button
|
||||
color='error'
|
||||
variant='link'
|
||||
onClick={chickinModal.closeModal}
|
||||
>
|
||||
<Icon
|
||||
className='text-black'
|
||||
icon='uil:times'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
{isResponseSuccess(projectFlockKandang) &&
|
||||
isResponseSuccess(projectFlock) &&
|
||||
!isLoadingProjectFlockKandang && (
|
||||
<ChickinForm
|
||||
initialValues={{
|
||||
project_flock_kandang: projectFlockKandang.data,
|
||||
created_user: projectFlock.data?.created_user,
|
||||
created_at: projectFlock.data?.created_at,
|
||||
updated_at: projectFlock.data?.updated_at,
|
||||
approval: projectFlock.data?.approval,
|
||||
}}
|
||||
afterSubmit={handleAfterSubmit}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
<ConfirmationModal
|
||||
ref={alertModal.ref}
|
||||
type='info'
|
||||
text={`Persediaan Day Old Chick pada kandang (${selectedKandang?.name}) belum ada, mohon isi terlebih dahulu di bagian Persediaan!`}
|
||||
secondaryButton={undefined}
|
||||
primaryButton={{
|
||||
text: 'Ya',
|
||||
color: 'info',
|
||||
onClick: () => {
|
||||
alertModal.closeModal();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddChickin;
|
||||
@@ -0,0 +1,46 @@
|
||||
'use client';
|
||||
|
||||
import ChickinForm from '@/components/pages/production/chickin/form/ChickinForm';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
import { ProjectFlockKandangApi } from '@/services/api/production';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export default function AddChickinKandang() {
|
||||
const searchParams = useSearchParams();
|
||||
const projectFlockKandangId = searchParams.get('projectFlockKandangId');
|
||||
const projectFlockId = searchParams.get('projectFlockId');
|
||||
const router = useRouter();
|
||||
|
||||
const { data: projectFlockKandang, isLoading: isLoading } = useSWR(
|
||||
projectFlockKandangId,
|
||||
(id: number) => ProjectFlockKandangApi.getSingle(id)
|
||||
);
|
||||
|
||||
if (!projectFlockKandangId) {
|
||||
router.push(`/production/chickin/add?projectFlockId=${projectFlockId}`);
|
||||
return (
|
||||
<div className='w-full flex flex-row justify-center items-center p-4'>
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isLoading && !projectFlockKandang) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className='w-full p-4'>
|
||||
{isLoading && <span className='loading loading-spinner loading-xl' />}
|
||||
{!isLoading &&
|
||||
isResponseSuccess(projectFlockKandang) &&
|
||||
projectFlockId && (
|
||||
<ChickinForm initialValues={projectFlockKandang.data} />
|
||||
)}
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
'use client';
|
||||
|
||||
import { FormHeader } from '@/components/helper/form/FormHeader';
|
||||
import ProjectFlockChickinDetail from '@/components/pages/production/project-flock/chickin/ProjectFlockChickinDetail';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
const AddChickin = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const projectFlockId = searchParams.get('projectFlockId');
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className='w-full p-4'>
|
||||
<FormHeader
|
||||
title='Daftar Kandang Project Flock'
|
||||
backUrl='/production/project-flock'
|
||||
/>
|
||||
<ProjectFlockChickinDetail projectFlockId={Number(projectFlockId)} />
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddChickin;
|
||||
-8
@@ -312,14 +312,6 @@ const DetailChickin = () => {
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<ChickinForm
|
||||
initialValues={chickin?.data}
|
||||
formType='edit'
|
||||
afterSubmit={() => {
|
||||
refreshChickin();
|
||||
chickinModal.closeModal();
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<ConfirmationModal
|
||||
@@ -2,15 +2,27 @@ import Button from '@/components/Button';
|
||||
import { Icon } from '@iconify/react';
|
||||
|
||||
interface FormHeaderProps {
|
||||
type: 'add' | 'edit' | 'detail';
|
||||
type?: 'add' | 'edit' | 'detail';
|
||||
title: string;
|
||||
backUrl: string;
|
||||
backUrl?: string;
|
||||
onBackClick?: () => void;
|
||||
}
|
||||
|
||||
export const FormHeader = ({ type, title, backUrl }: FormHeaderProps) => {
|
||||
export const FormHeader = ({
|
||||
type,
|
||||
title,
|
||||
backUrl,
|
||||
onBackClick,
|
||||
}: FormHeaderProps) => {
|
||||
return (
|
||||
<header className='flex flex-col gap-4'>
|
||||
<Button href={backUrl} variant='link' className='w-fit p-0 text-primary'>
|
||||
<Button
|
||||
type='button'
|
||||
href={!onBackClick ? backUrl : undefined}
|
||||
onClick={onBackClick}
|
||||
variant='link'
|
||||
className='w-fit p-0 text-primary'
|
||||
>
|
||||
<Icon icon='uil:arrow-left' width={24} height={24} />
|
||||
Kembali
|
||||
</Button>
|
||||
@@ -18,6 +30,7 @@ export const FormHeader = ({ type, title, backUrl }: FormHeaderProps) => {
|
||||
{type === 'add' && `Tambah ${title}`}
|
||||
{type === 'edit' && `Edit ${title}`}
|
||||
{type === 'detail' && `Detail ${title}`}
|
||||
{!type && title}
|
||||
</h1>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,8 @@ import { TableRowSizeSelector } from '@/components/table/TableRowSizeSelector';
|
||||
import { TableToolbar } from '@/components/table/TableToolbar';
|
||||
import { ROWS_OPTIONS } from '@/config/constant';
|
||||
import { cn } from '@/lib/helper';
|
||||
import { SalesOrder } from '@/types/api/marketing/marketing';
|
||||
import { Marketing, MarketingProducts } from '@/types/api/marketing/marketing';
|
||||
import { Customer } from '@/types/api/master-data/customer';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { CellContext } from '@tanstack/react-table';
|
||||
import { useCallback, useState } from 'react';
|
||||
@@ -18,7 +19,7 @@ const RowsOptionsMenu = ({
|
||||
deleteClickHandler,
|
||||
}: {
|
||||
type: 'dropdown' | 'collapse';
|
||||
props: CellContext<SalesOrder, unknown>;
|
||||
props: CellContext<Marketing, unknown>;
|
||||
deleteClickHandler: () => void;
|
||||
}) => {
|
||||
return (
|
||||
@@ -111,7 +112,59 @@ const SalesOrderTable = () => {
|
||||
/>
|
||||
</div>
|
||||
<Table
|
||||
data={[]}
|
||||
data={[
|
||||
{
|
||||
id: 1,
|
||||
so_number: 'SO-001',
|
||||
so_date: '2024-01-01',
|
||||
so_docs: 'Dokumen SO 1.pdf',
|
||||
customer: {
|
||||
id: 1,
|
||||
name: 'Customer A',
|
||||
} as Customer,
|
||||
sales_person: {
|
||||
id: 1,
|
||||
name: 'Sales Person A',
|
||||
},
|
||||
notes: 'Catatan untuk SO 1',
|
||||
grand_total: 1000000,
|
||||
approval: {
|
||||
step_name: 'Approved',
|
||||
},
|
||||
marketing_products: [
|
||||
{
|
||||
id: 1,
|
||||
qty: 10,
|
||||
unit_price: 100000,
|
||||
avg_weigth: 1.5,
|
||||
total_weight: 15,
|
||||
total_price: 1000000,
|
||||
product_warehouse: {
|
||||
id: 1,
|
||||
product: {
|
||||
id: 1,
|
||||
name: 'Product A',
|
||||
},
|
||||
},
|
||||
} as MarketingProducts,
|
||||
{
|
||||
id: 2,
|
||||
qty: 5,
|
||||
unit_price: 200000,
|
||||
avg_weigth: 2.0,
|
||||
total_weight: 10,
|
||||
total_price: 1000000,
|
||||
product_warehouse: {
|
||||
id: 2,
|
||||
product: {
|
||||
id: 2,
|
||||
name: 'Product B',
|
||||
},
|
||||
},
|
||||
} as MarketingProducts,
|
||||
],
|
||||
} as Marketing,
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
header: '#',
|
||||
@@ -122,7 +175,7 @@ const SalesOrderTable = () => {
|
||||
header: 'No. Order',
|
||||
},
|
||||
{
|
||||
accessorKey: 'tanggal',
|
||||
accessorKey: 'so_date',
|
||||
header: 'Tanggal',
|
||||
},
|
||||
{
|
||||
@@ -130,7 +183,7 @@ const SalesOrderTable = () => {
|
||||
header: 'Status',
|
||||
},
|
||||
{
|
||||
accessorKey: 'customer',
|
||||
accessorKey: 'customer.name',
|
||||
header: 'Customer',
|
||||
},
|
||||
{
|
||||
@@ -138,8 +191,18 @@ const SalesOrderTable = () => {
|
||||
header: 'Grand Total',
|
||||
},
|
||||
{
|
||||
accessorKey: 'product_details',
|
||||
accessorKey: 'marketing_products.length',
|
||||
header: 'Product Details',
|
||||
cell: (props) => (
|
||||
<ul className='list-disc list-inside'>
|
||||
{props.row.original.marketing_products?.map((product) => (
|
||||
<li key={product.id}>
|
||||
{product.product_warehouse.product.name} - Qty:{' '}
|
||||
{product.qty}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
),
|
||||
},
|
||||
{
|
||||
header: 'Aksi',
|
||||
|
||||
@@ -87,7 +87,7 @@ const ChickinTable = () => {
|
||||
<div className='flex flex-col gap-2 mb-4'>
|
||||
<div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-2'>
|
||||
<Button
|
||||
href='/production/chickin/add?projectFlockId=1'
|
||||
href='/production/project-flock/chickin/add?projectFlockId=1'
|
||||
variant='outline'
|
||||
color='primary'
|
||||
className='w-full sm:w-fit'
|
||||
@@ -260,14 +260,14 @@ const ChickinTable = () => {
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<ChickinForm
|
||||
{/* <ChickinForm
|
||||
initialValues={selectedChickin}
|
||||
formType='edit'
|
||||
afterSubmit={() => {
|
||||
refreshChickins();
|
||||
chickinModal.closeModal();
|
||||
}}
|
||||
/>
|
||||
/> */}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
@@ -287,7 +287,7 @@ const RowOptionsMenu = ({
|
||||
return (
|
||||
<RowOptionsMenuWrapper type={type}>
|
||||
<Button
|
||||
href={`/production/chickin/detail?chickinId=${props.row.original.id}`}
|
||||
href={`/production/project-flock/chickin/detail?chickinId=${props.row.original.id}`}
|
||||
variant='ghost'
|
||||
color='primary'
|
||||
className='justify-start text-sm'
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
import * as Yup from 'yup';
|
||||
|
||||
export const ChickinFormSchema = Yup.object({
|
||||
chick_in_date: Yup.string().required('Tanggal masuk wajib diisi!'),
|
||||
note: Yup.string().required('Catatan wajib diisi!'),
|
||||
quantity: Yup.number()
|
||||
.min(1, 'Jumlah wajib diisi!')
|
||||
.required('Jumlah wajib diisi!'),
|
||||
});
|
||||
|
||||
export type ChickinFormValues = Yup.InferType<typeof ChickinFormSchema>;
|
||||
|
||||
export const UpdateChickinFormSchema = ChickinFormSchema;
|
||||
import { Product } from '@/types/api/master-data/product';
|
||||
import { Supplier } from '@/types/api/master-data/supplier';
|
||||
|
||||
@@ -1,220 +1,227 @@
|
||||
'use client';
|
||||
|
||||
import Button from '@/components/Button';
|
||||
import {
|
||||
Chickin,
|
||||
CreateChickinPayload,
|
||||
UpdateChickinPayload,
|
||||
} from '@/types/api/production/chickin';
|
||||
import {
|
||||
ChickinFormSchema,
|
||||
ChickinFormValues,
|
||||
UpdateChickinFormSchema,
|
||||
} from '@/components/pages/production/chickin/form/ChickinForm.schema';
|
||||
import { use, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import { ChickinApi } from '@/services/api/production';
|
||||
import Card from '@/components/Card';
|
||||
import { FormHeader } from '@/components/helper/form/FormHeader';
|
||||
import DateInput from '@/components/input/DateInput';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Icon } from '@iconify/react';
|
||||
import TextArea from '@/components/input/TextArea';
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import FileInput from '@/components/input/FileInput';
|
||||
import NumberInput from '@/components/input/NumberInput';
|
||||
import SelectInput from '@/components/input/SelectInput';
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import Table from '@/components/Table';
|
||||
import { formatNumber } from '@/lib/helper';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import {
|
||||
AvailableQty,
|
||||
ProjectFlockKandang,
|
||||
} from '@/types/api/production/project-flock-kandang';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
interface ChickinFormProps {
|
||||
formType?: 'add' | 'detail' | 'edit';
|
||||
initialValues?: Chickin;
|
||||
afterSubmit?: () => void;
|
||||
}
|
||||
|
||||
const ChickinForm = ({
|
||||
const ChickinFormKandang = ({
|
||||
formType = 'add',
|
||||
initialValues,
|
||||
afterSubmit,
|
||||
}: ChickinFormProps) => {
|
||||
// Helper Function
|
||||
const formatDateForInput = (dateString?: string): string => {
|
||||
if (!dateString) return '';
|
||||
return new Date(dateString).toISOString().split('T')[0];
|
||||
};
|
||||
|
||||
// State
|
||||
const [chickinFormErrorMessage, setChickinFormErrorMessage] = useState('');
|
||||
|
||||
// Initial Value
|
||||
const formikInitialValue = useMemo<ChickinFormValues>(() => {
|
||||
return {
|
||||
chick_in_date: formatDateForInput(initialValues?.chick_in_date) ?? '',
|
||||
note: initialValues?.note ?? '',
|
||||
quantity:
|
||||
initialValues?.quantity ??
|
||||
initialValues?.project_flock_kandang?.available_quantity ??
|
||||
0,
|
||||
};
|
||||
}, [initialValues]);
|
||||
|
||||
// Handle Submit Function
|
||||
const handleCreate = useCallback(
|
||||
async (
|
||||
payload: CreateChickinPayload,
|
||||
afterSubmit: (() => void) | undefined
|
||||
) => {
|
||||
const res = await ChickinApi.create(payload);
|
||||
if (isResponseError(res)) {
|
||||
setChickinFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
afterSubmit?.();
|
||||
},
|
||||
[]
|
||||
);
|
||||
const handleUpdate = useCallback(
|
||||
async (
|
||||
payload: UpdateChickinPayload,
|
||||
afterSubmit: (() => void) | undefined
|
||||
) => {
|
||||
const res = await ChickinApi.update(payload.id, payload);
|
||||
if (isResponseError(res)) {
|
||||
setChickinFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
afterSubmit?.();
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
// Formik
|
||||
const formik = useFormik<ChickinFormValues>({
|
||||
initialValues: formikInitialValue,
|
||||
enableReinitialize: true,
|
||||
validationSchema:
|
||||
formType === 'edit' ? UpdateChickinFormSchema : ChickinFormSchema,
|
||||
onSubmit: async (values) => {
|
||||
// reset error message
|
||||
setChickinFormErrorMessage('');
|
||||
|
||||
if (
|
||||
initialValues?.project_flock_kandang?.id == undefined ||
|
||||
(formType == 'edit' && initialValues?.id == undefined)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create payload
|
||||
const payload = {
|
||||
chick_in_date: values.chick_in_date,
|
||||
project_flock_kandang_id: initialValues?.project_flock_kandang?.id,
|
||||
note: values.note,
|
||||
quantity: values.quantity,
|
||||
id: initialValues.id ?? 0,
|
||||
};
|
||||
|
||||
// cek type form yang disubmit
|
||||
console.log(formType);
|
||||
switch (formType) {
|
||||
case 'add':
|
||||
handleCreate(payload, afterSubmit);
|
||||
break;
|
||||
case 'edit':
|
||||
handleUpdate(payload, afterSubmit);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Initialize Formik
|
||||
const { setValues: formikSetValues } = formik;
|
||||
useEffect(() => {
|
||||
formikSetValues(formikInitialValue);
|
||||
}, [formikSetValues, formikInitialValue]);
|
||||
|
||||
}: {
|
||||
formType?: 'add' | 'detail' | 'edit';
|
||||
initialValues: ProjectFlockKandang;
|
||||
afterSubmit?: () => void;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
className='min-h-48 flex flex-col gap-4'
|
||||
onSubmit={formik.handleSubmit}
|
||||
onReset={formik.handleReset}
|
||||
>
|
||||
<DateInput
|
||||
value={formik.values.chick_in_date}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
name='chick_in_date'
|
||||
label='Tanggal Chickin'
|
||||
required
|
||||
isError={
|
||||
formik.touched.chick_in_date && Boolean(formik.errors.chick_in_date)
|
||||
}
|
||||
errorMessage={formik.errors.chick_in_date}
|
||||
<div className='flex flex-col gap-4'>
|
||||
<FormHeader
|
||||
type='add'
|
||||
title='Chick In DOC'
|
||||
backUrl={`/production/project-flock/chickin/add?projectFlockId=${initialValues.project_flock.id}`}
|
||||
/>
|
||||
<NumberInput
|
||||
value={formik.values.quantity}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
name='quantity'
|
||||
label='Jumlah (Ekor)'
|
||||
required
|
||||
isError={
|
||||
(formik.touched.quantity && Boolean(formik.errors.quantity)) ||
|
||||
formik.values.quantity == 0
|
||||
}
|
||||
errorMessage={
|
||||
formik.values.quantity == 0
|
||||
? 'Masukan Persediaan Day Old Chick terlebih dahulu.'
|
||||
: formik.errors.quantity
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
<TextArea
|
||||
required
|
||||
label='Catatan'
|
||||
name='note'
|
||||
placeholder='Masukan catatan chickin'
|
||||
value={formik.values.note}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={formik.touched.note && Boolean(formik.errors.note)}
|
||||
errorMessage={formik.errors.note}
|
||||
/>
|
||||
{initialValues?.project_flock_kandang?.id == undefined && (
|
||||
<p className='text-error'>Project Flock Kandang tidak ditemukan.</p>
|
||||
)}
|
||||
{chickinFormErrorMessage && (
|
||||
<div
|
||||
role='alert'
|
||||
className='alert alert-error'
|
||||
onClick={() => {
|
||||
setChickinFormErrorMessage('');
|
||||
<Card
|
||||
title='Informasi Kandang'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white mt-4',
|
||||
}}
|
||||
>
|
||||
<Icon icon='mdi:times' />
|
||||
<span>{chickinFormErrorMessage}</span>
|
||||
<Table<Kandang>
|
||||
emptyContent={
|
||||
<div className='w-full p-5 text-center'>
|
||||
<span className='text-lg opacity-50'>
|
||||
Informasi Kandang belum tersedia...
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className='flex justify-center mt-auto gap-2'>
|
||||
<Button color='warning' type='reset'>
|
||||
}
|
||||
data={[initialValues.kandang]}
|
||||
columns={[
|
||||
{
|
||||
header: 'Area',
|
||||
accessorFn: () => initialValues.project_flock?.area.name || '-',
|
||||
},
|
||||
{
|
||||
header: 'Lokasi',
|
||||
accessorFn: () =>
|
||||
initialValues.project_flock?.location.name || '-',
|
||||
},
|
||||
{
|
||||
header: 'Flock',
|
||||
accessorFn: () => initialValues.project_flock?.flock.name || '-',
|
||||
},
|
||||
{
|
||||
header: 'Kandang',
|
||||
accessorFn: (row) => row?.name || '-',
|
||||
},
|
||||
{
|
||||
header: 'Kapasitas',
|
||||
accessorFn: (row) =>
|
||||
(row?.capacity && formatNumber(row?.capacity)) || '-',
|
||||
},
|
||||
{
|
||||
header: 'Penanggung Jawab',
|
||||
accessorFn: (row) => row?.pic?.name || '-',
|
||||
},
|
||||
]}
|
||||
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-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',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card
|
||||
title='Informasi Chick In DOC'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white',
|
||||
}}
|
||||
>
|
||||
<Table<AvailableQty>
|
||||
data={initialValues.available_qtys || []}
|
||||
columns={[
|
||||
{
|
||||
accessorFn: (row) => row.chick_in_date,
|
||||
header: 'Tanggal Chick In',
|
||||
cell(props) {
|
||||
return (
|
||||
<DateInput
|
||||
name='chick_in_date[]'
|
||||
value={props.row.original.chick_in_date}
|
||||
onChange={(e) => {
|
||||
props.row.original.chick_in_date = e.target.value;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.po_number,
|
||||
header: 'No. Surat Jalan',
|
||||
cell(props) {
|
||||
return (
|
||||
<TextInput
|
||||
name='po_number[]'
|
||||
value={props.row.original.po_number}
|
||||
onChange={(e) => {
|
||||
props.row.original.po_number = e.target.value;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Dokumen Surat Jalan',
|
||||
cell(props) {
|
||||
return (
|
||||
<FileInput
|
||||
name='document_path[]'
|
||||
onChange={(e) => {
|
||||
props.row.original.document_path = e.target.value;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.supplier?.name,
|
||||
header: 'Supplier',
|
||||
cell(props) {
|
||||
return (
|
||||
<SelectInput
|
||||
value={
|
||||
props.row.original.supplier?.name &&
|
||||
props.row.original.supplier?.id
|
||||
? {
|
||||
label: props.row.original.supplier.name,
|
||||
value: props.row.original.supplier.id,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
options={[]}
|
||||
isDisabled
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.product_warehouse.product.name,
|
||||
header: 'Produk',
|
||||
cell(props) {
|
||||
return (
|
||||
<SelectInput
|
||||
value={{
|
||||
label: props.row.original.product_warehouse.product.name,
|
||||
value: props.row.original.product_warehouse.product.id,
|
||||
}}
|
||||
options={[]}
|
||||
isDisabled
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.product_warehouse.quantity,
|
||||
header: 'Jumlah (ekor)',
|
||||
cell(props) {
|
||||
return (
|
||||
<NumberInput
|
||||
name='qty[]'
|
||||
value={props.row.original.product_warehouse.quantity}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
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'>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
type='submit'
|
||||
isLoading={formik.isSubmitting}
|
||||
disabled={
|
||||
!formik.isValid ||
|
||||
formik.isSubmitting ||
|
||||
!initialValues?.project_flock_kandang?.id
|
||||
}
|
||||
>
|
||||
<Button type='submit' color='primary'>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChickinForm;
|
||||
export default ChickinFormKandang;
|
||||
|
||||
@@ -9,7 +9,6 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import Table from '@/components/Table';
|
||||
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
|
||||
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
|
||||
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
|
||||
import { ROWS_OPTIONS } from '@/config/constant';
|
||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
import { cn } from '@/lib/helper';
|
||||
@@ -60,7 +59,7 @@ const RowOptionsMenu = ({
|
||||
</Button>
|
||||
{props.row.original.approval.step_name === 'Aktif' && (
|
||||
<Button
|
||||
href={`/production/chickin/add?projectFlockId=${props.row.original.id}`}
|
||||
href={`/production/project-flock/chickin/add?projectFlockId=${props.row.original.id}`}
|
||||
variant='ghost'
|
||||
color='success'
|
||||
className='justify-start text-sm'
|
||||
@@ -84,13 +83,12 @@ const RowOptionsMenu = ({
|
||||
onClick={deleteClickHandler}
|
||||
variant='ghost'
|
||||
color='error'
|
||||
className='text-error hover:text-inherit'
|
||||
className='text-error hover:text-inherit justify-start text-sm'
|
||||
>
|
||||
<Icon
|
||||
icon='material-symbols:delete-outline-rounded'
|
||||
width={16}
|
||||
height={16}
|
||||
className='justify-start text-sm'
|
||||
/>
|
||||
Delete
|
||||
</Button>
|
||||
@@ -499,7 +497,7 @@ const ProjectFlockTable = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentPageSize > 1 && (
|
||||
{currentPageSize > 2 && (
|
||||
<RowDropdownOptions isLast2Rows={isLast2Rows}>
|
||||
<RowOptionsMenu
|
||||
type='dropdown'
|
||||
@@ -509,7 +507,7 @@ const ProjectFlockTable = () => {
|
||||
</RowDropdownOptions>
|
||||
)}
|
||||
|
||||
{currentPageSize <= 1 && (
|
||||
{currentPageSize <= 2 && (
|
||||
<RowCollapseOptions>
|
||||
<RowOptionsMenu
|
||||
type='collapse'
|
||||
@@ -576,18 +574,6 @@ const ProjectFlockTable = () => {
|
||||
ref={confirmModal.ref}
|
||||
type='success'
|
||||
text={`Apakah anda yakin ingin reject data transfer ke laying ini (${selectedRowIds.length} data)?`}
|
||||
// text={
|
||||
// selectedFlocks.length > 0
|
||||
// ? `Apakah anda yakin ingin approve Project Flock berikut? (${selectedFlocks
|
||||
// .map(
|
||||
// (flock) =>
|
||||
// `${flock.flock?.name ?? '(Tanpa nama)'} - ${
|
||||
// flock.area?.name ?? '-'
|
||||
// }`
|
||||
// )
|
||||
// .join(', ')})`
|
||||
// : 'Tidak ada Project Flock yang dipilih.'
|
||||
// }
|
||||
secondaryButton={{
|
||||
text: 'Tidak',
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
'use client';
|
||||
|
||||
import Badge from '@/components/Badge';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import SelectInput, { OptionType } from '@/components/input/SelectInput';
|
||||
import PillBadge from '@/components/PillBadge';
|
||||
import Table from '@/components/Table';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
import { cn } from '@/lib/helper';
|
||||
import { ProjectFlockApi } from '@/services/api/production';
|
||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import useSWR from 'swr';
|
||||
|
||||
const ProjectFlockChickinDetail = ({
|
||||
projectFlockId,
|
||||
}: {
|
||||
projectFlockId: number | undefined;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
|
||||
// Tables Props
|
||||
const { state: tableFilterState } = useTableFilter({
|
||||
initial: { search: '' },
|
||||
paramMap: { page: 'page', pageSize: 'limit' },
|
||||
});
|
||||
|
||||
// States
|
||||
const [searchProjectFlock, setSearchProjectFlock] = useState('');
|
||||
const [selectedProjectFlock, setSelectedProjectFlock] =
|
||||
useState<OptionType | null>(null);
|
||||
const [projectFlock, setProjectFlock] = useState<ProjectFlock>();
|
||||
|
||||
// Fetch Data
|
||||
const { data: listProjectFlock, isLoading: isLoadingListProjectFlock } =
|
||||
useSWR(
|
||||
`${ProjectFlockApi.basePath}?${new URLSearchParams({
|
||||
search: searchProjectFlock,
|
||||
}).toString()}`,
|
||||
ProjectFlockApi.getAllFetcher
|
||||
);
|
||||
|
||||
// Mapping Options
|
||||
const options = isResponseSuccess(listProjectFlock)
|
||||
? listProjectFlock?.data.map((projectFlock) => {
|
||||
return {
|
||||
value: projectFlock.id,
|
||||
label: `${projectFlock?.flock?.name} - Periode ${projectFlock?.period}`,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
// Handle Function
|
||||
const handleChickinClick = async (kandang: Kandang) => {
|
||||
router.push(
|
||||
`/production/project-flock/chickin/add/kandang?projectFlockKandangId=${kandang.project_flock_kandang_id}&projectFlockId=${projectFlockId ?? selectedProjectFlock?.value}`
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeProjectFlock = (val: OptionType | null) => {
|
||||
setSelectedProjectFlock(val);
|
||||
if (isResponseSuccess(listProjectFlock) && val) {
|
||||
const selected = listProjectFlock.data.find(
|
||||
(pf) => pf.id === Number(val.value)
|
||||
);
|
||||
setProjectFlock(selected);
|
||||
} else {
|
||||
setProjectFlock(undefined);
|
||||
}
|
||||
if (projectFlockId) {
|
||||
router.push('/production/project-flock/chickin/add');
|
||||
}
|
||||
if (!val && projectFlockId) {
|
||||
router.push('/production/project-flock/chickin/add');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (projectFlockId && isResponseSuccess(listProjectFlock)) {
|
||||
setProjectFlock(
|
||||
listProjectFlock.data.find((pf) => pf.id === Number(projectFlockId))
|
||||
);
|
||||
}
|
||||
}, [projectFlockId, listProjectFlock]);
|
||||
return (
|
||||
<>
|
||||
<div className='flex flex-col gap-4 w-full my-4'>
|
||||
<div className='max-w-full sm:max-w-1/2 md:max-w-3/5 lg:max-w-2/5'>
|
||||
<SelectInput
|
||||
required
|
||||
label='Ganti Project Flock'
|
||||
placeholder='Pilih Project Flock'
|
||||
options={options}
|
||||
onInputChange={(val) => {
|
||||
setSearchProjectFlock(val);
|
||||
}}
|
||||
isLoading={isLoadingListProjectFlock}
|
||||
value={
|
||||
projectFlock
|
||||
? {
|
||||
label: `${projectFlock?.flock?.name}`,
|
||||
value: projectFlock?.id,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onChange={(val) => {
|
||||
handleChangeProjectFlock(val as OptionType | null);
|
||||
}}
|
||||
isSearchable
|
||||
isClearable
|
||||
startAdornment={
|
||||
projectFlock && (
|
||||
<Badge
|
||||
variant='soft'
|
||||
color='success'
|
||||
size='sm'
|
||||
className={{
|
||||
badge: 'whitespace-nowrap font-semibold',
|
||||
}}
|
||||
>
|
||||
Periode {projectFlock?.period}
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Card
|
||||
title='Informasi Flock'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white mb-3',
|
||||
}}
|
||||
>
|
||||
<Table<ProjectFlock>
|
||||
emptyContent={
|
||||
<div className='w-full p-5 text-center'>
|
||||
<span className='text-lg opacity-50'>
|
||||
Pilih project flock terlebih dahulu...
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
data={projectFlock ? [projectFlock] : []}
|
||||
columns={[
|
||||
{
|
||||
header: 'Area',
|
||||
accessorKey: 'area.name',
|
||||
},
|
||||
{
|
||||
header: 'Lokasi',
|
||||
accessorKey: 'location.name',
|
||||
},
|
||||
{
|
||||
header: 'Nama Flock',
|
||||
accessorKey: 'flock.name',
|
||||
},
|
||||
{
|
||||
header: 'Kategori',
|
||||
accessorKey: 'category',
|
||||
},
|
||||
{
|
||||
header: 'Status',
|
||||
accessorKey: 'status',
|
||||
cell: (props) => {
|
||||
return props.row.original.approval?.step_name ? (
|
||||
<PillBadge
|
||||
color={(() => {
|
||||
switch (
|
||||
props.row.original.approval?.step_name.toUpperCase()
|
||||
) {
|
||||
case 'AKTIF':
|
||||
return 'red';
|
||||
case 'PENGAJUAN':
|
||||
return 'green';
|
||||
default:
|
||||
return 'gray';
|
||||
}
|
||||
})()}
|
||||
content={props.row.original.approval?.step_name
|
||||
.toLowerCase()
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/\b\w/g, (char) => char.toUpperCase())}
|
||||
/>
|
||||
) : (
|
||||
'-'
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: 'Periode',
|
||||
accessorKey: 'period',
|
||||
},
|
||||
{
|
||||
header: 'FCR Layer',
|
||||
accessorKey: 'fcr.name',
|
||||
},
|
||||
]}
|
||||
page={undefined}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20': projectFlock && projectFlock.kandangs?.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',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card
|
||||
title='Daftar Kandang'
|
||||
className={{
|
||||
wrapper: 'w-full bg-white',
|
||||
}}
|
||||
>
|
||||
<Table<Kandang>
|
||||
emptyContent={
|
||||
<div className='w-full p-5 text-center'>
|
||||
<span className='text-lg opacity-50'>
|
||||
Pilih project flock terlebih dahulu...
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
data={projectFlock ? projectFlock.kandangs : []}
|
||||
columns={[
|
||||
{
|
||||
header: '#',
|
||||
cell: (props) =>
|
||||
tableFilterState.pageSize * (tableFilterState.page - 1) +
|
||||
props.row.index +
|
||||
1,
|
||||
},
|
||||
{
|
||||
accessorFn: () => (projectFlock ? projectFlock.area.name : ''),
|
||||
header: 'Area',
|
||||
},
|
||||
{
|
||||
accessorFn: () =>
|
||||
projectFlock ? projectFlock.location.name : '',
|
||||
header: 'Lokasi',
|
||||
},
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: 'Kandang',
|
||||
},
|
||||
{
|
||||
accessorKey: 'capacity',
|
||||
header: 'Kapasitas',
|
||||
},
|
||||
{
|
||||
accessorKey: 'pic.name',
|
||||
header: 'Penanggung Jawab',
|
||||
},
|
||||
{
|
||||
header: 'Aksi',
|
||||
cell: (props) => {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
color='success'
|
||||
variant='outline'
|
||||
onClick={() => {
|
||||
handleChickinClick(props.row.original);
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:home-import-outline'
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
Chickin
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
page={undefined}
|
||||
className={{
|
||||
containerClassName: cn({
|
||||
'mb-20': projectFlock && projectFlock.kandangs?.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',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectFlockChickinDetail;
|
||||
@@ -77,7 +77,7 @@ const ProjectFlockForm = ({
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
const [isApproveLoading, setIsApproveLoading] = useState(false);
|
||||
const [isApprovedDisabled, setIsApprovedDisabled] = useState(
|
||||
initialValues?.approval.step_name == 'Pengajuan' ? false : true
|
||||
initialValues?.approval?.step_name == 'Pengajuan' ? false : true
|
||||
);
|
||||
const [isRejectedDisabled, setIsRejectedDisabled] =
|
||||
useState(!isApprovedDisabled);
|
||||
@@ -726,7 +726,25 @@ const ProjectFlockForm = ({
|
||||
</div>
|
||||
</form>
|
||||
{formType != 'add' && (
|
||||
<div className='w-full'>
|
||||
<div className='flex flex-row gap-2 mb-6'>
|
||||
{formType != 'edit' && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
router.push(
|
||||
`/production/project-flock/detail/edit?projectFlockId=${initialValues?.id}`
|
||||
);
|
||||
}}
|
||||
color='warning'
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:pencil-outline'
|
||||
width={16}
|
||||
height={16}
|
||||
className='justify-start text-sm'
|
||||
/>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (initialValues?.id) {
|
||||
|
||||
@@ -121,6 +121,10 @@ const ProjectFlockKandangTable = ({
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.capacity,
|
||||
header: 'Kapasitas',
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => row.pic?.name,
|
||||
header: 'Penanggung Jawab',
|
||||
|
||||
@@ -22,11 +22,11 @@ export const MAIN_DRAWER_LINKS: MAIN_DRAWER_MENU[] = [
|
||||
link: '/production/project-flock',
|
||||
icon: 'material-symbols:list-alt-add-outline-rounded',
|
||||
},
|
||||
{
|
||||
title: 'Chick In',
|
||||
link: '/production/chickin',
|
||||
icon: 'mdi:home-import-outline',
|
||||
},
|
||||
// { // DI HILANGKAN PADA VERSI REFACTORING
|
||||
// title: 'Chick In',
|
||||
// link: '/production/chickin',
|
||||
// icon: 'mdi:home-import-outline',
|
||||
// },
|
||||
{
|
||||
title: 'Recording',
|
||||
link: '/production/recording',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseApiService } from './base';
|
||||
import { BaseApiService } from '@/services/api/base';
|
||||
import {
|
||||
CreateProjectFlockPayload,
|
||||
ProjectFlock,
|
||||
@@ -14,12 +14,18 @@ import {
|
||||
CreateChickinPayload,
|
||||
UpdateChickinPayload,
|
||||
} from '@/types/api/production/chickin';
|
||||
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<
|
||||
ProjectFlockKandang,
|
||||
unknown,
|
||||
unknown
|
||||
>('/production/project-flock-kandangs');
|
||||
export const RecordingApi = new BaseApiService<
|
||||
Recording,
|
||||
CreateRecordingPayload,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
CreateProjectFlockPayload,
|
||||
ProjectFlock,
|
||||
UpdateProjectFlockPayload,
|
||||
} from '@/types/api/production/project-flock';
|
||||
import { BaseApiService } from '../base';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import { sleep } from '@/lib/helper';
|
||||
import { httpClient } from '@/services/http/client';
|
||||
import axios from 'axios';
|
||||
|
||||
export class ProjectFlockService extends BaseApiService<
|
||||
ProjectFlock,
|
||||
CreateProjectFlockPayload,
|
||||
UpdateProjectFlockPayload
|
||||
> {
|
||||
constructor(basePath: string = '') {
|
||||
super(basePath);
|
||||
}
|
||||
async getSingleProjectFlockKandang(): Promise<BaseApiResponse | undefined> {
|
||||
try {
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError<BaseApiResponse>(error)) {
|
||||
return error.response?.data;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-5
@@ -15,6 +15,9 @@ export type BaseMarketing = {
|
||||
so_date: string;
|
||||
sales_person: CreatedUser;
|
||||
notes: string;
|
||||
grand_total: number;
|
||||
approval: BaseApproval;
|
||||
marketing_products?: MarketingProducts[];
|
||||
};
|
||||
|
||||
export type MarketingProducts = {
|
||||
@@ -22,18 +25,29 @@ export type MarketingProducts = {
|
||||
qty: number;
|
||||
unit_price: number;
|
||||
avg_weigth: number;
|
||||
total_weight: number;
|
||||
total_price: number;
|
||||
product_warehouse: ProductWarehouse;
|
||||
delivery_date?: string;
|
||||
vehicle_number?: string;
|
||||
marketing_delivery_products?: MarketingDeliveryProducts;
|
||||
};
|
||||
|
||||
export type SalesOrder = BaseMetadata & BaseMarketing;
|
||||
export type MarketingDeliveryProducts = {
|
||||
id: number;
|
||||
qty: number;
|
||||
unit_price: number;
|
||||
avg_weigth: number;
|
||||
total_weight: number;
|
||||
total_price: number;
|
||||
delivery_date: string;
|
||||
vehicle_number: string;
|
||||
};
|
||||
|
||||
export type CreateSalesOrderPayload = {
|
||||
export type Marketing = BaseMetadata & BaseMarketing;
|
||||
|
||||
export type CreateMarketingPayload = {
|
||||
customer_id: number;
|
||||
date: string;
|
||||
notes: string;
|
||||
};
|
||||
|
||||
export type UpdateSalesOrderPayload = CreateSalesOrderPayload;
|
||||
export type UpdateMarketingPayload = CreateMarketingPayload;
|
||||
|
||||
+1
@@ -9,6 +9,7 @@ export type BaseKandang = {
|
||||
location: BaseLocation;
|
||||
capacity: number;
|
||||
pic: BaseUser;
|
||||
project_flock_kandang_id?: number;
|
||||
};
|
||||
|
||||
export type Kandang = BaseMetadata & BaseKandang;
|
||||
|
||||
+11
-1
@@ -1,5 +1,7 @@
|
||||
import { Kandang } from '@/type/master-data/kandang';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
|
||||
import { Supplier } from '../master-data/supplier';
|
||||
|
||||
export type BaseProjectFlockKandang = {
|
||||
id: number;
|
||||
@@ -7,7 +9,15 @@ export type BaseProjectFlockKandang = {
|
||||
kandang_id: number;
|
||||
kandang: Kandang;
|
||||
project_flock: ProjectFlock;
|
||||
available_quantity?: number;
|
||||
available_qtys?: AvailableQty[];
|
||||
};
|
||||
|
||||
export type AvailableQty = {
|
||||
chick_in_date?: string;
|
||||
po_number?: string;
|
||||
document_path?: string;
|
||||
supplier?: Supplier;
|
||||
product_warehouse: ProductWarehouse;
|
||||
};
|
||||
|
||||
export type ProjectFlockKandang = BaseProjectFlockKandang;
|
||||
|
||||
Reference in New Issue
Block a user