fix(FE-92-93-105): adding input note and quantity for create/edit chickin

This commit is contained in:
randy-ar
2025-10-25 06:15:29 +07:00
parent 51bce1a2c7
commit a13a51a16f
7 changed files with 169 additions and 44 deletions
+56 -33
View File
@@ -3,6 +3,7 @@
import Button from '@/components/Button';
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 Table from '@/components/Table';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
@@ -14,7 +15,7 @@ import { Kandang } from '@/types/api/master-data/kandang';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
import { Icon } from '@iconify/react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useEffect, useState } from 'react';
import { use, useEffect, useState } from 'react';
import useSWR from 'swr';
@@ -33,6 +34,11 @@ const AddChickin = () => {
const [selectedKandang, setSelectedKandang] = useState<Kandang | undefined>(
undefined
);
const [projectFlockKandang, setProjectFlockKandang] = useState<
BaseApiResponse<ProjectFlockKandang>
>();
const [isLoadingProjectFlockKandang, setIsLoadingProjectFlockKandang] =
useState(false);
const [searchProjectFlock, setSearchProjectFlock] = useState('');
// Fetch Data
@@ -41,44 +47,26 @@ const AddChickin = () => {
(id: number) => ProjectFlockApi.getSingle(id)
);
const { data: listProjectFlock, isLoading: isLoadingListProjectFlock } =
useSWR(`${ProjectFlockApi.basePath}?${new URLSearchParams({
search: searchProjectFlock,
}).toString()}`, ProjectFlockApi.getAllFetcher);
useSWR(
`${ProjectFlockApi.basePath}?${new URLSearchParams({
search: searchProjectFlock,
}).toString()}`,
ProjectFlockApi.getAllFetcher
);
const getProjectFlockKandangUrl = `/kandangs/lookup`;
const {
data: projectFlockKandang,
isLoading: isLoadingProjectFlockKandang,
mutate: refreshProjectFlockKandang,
} = useSWR(getProjectFlockKandangUrl, () =>
ProjectFlockApi.customRequest<BaseApiResponse<ProjectFlockKandang>, 'GET'>(
getProjectFlockKandangUrl,
{
method: 'GET',
params: {
project_flock_id: projectFlockId ?? 0,
kandang_id: selectedKandang?.id,
},
}
)
);
// Mapping Options
const options = isResponseSuccess(listProjectFlock)
? listProjectFlock?.data.map((projectFlock) => {
return {
value: projectFlock.id,
label: `${projectFlock?.flock.name} - ${projectFlock?.category} - Periode ${projectFlock.period}` ,
label: `${projectFlock?.flock.name} - ${projectFlock?.category} - Periode ${projectFlock.period}`,
};
})
: [];
const chickinModal = useModal();
// Use Effect
useEffect(() => {
refreshProjectFlockKandang();
}, [selectedKandang, refreshProjectFlockKandang]);
const alertModal = useModal();
if (!projectFlockId) {
router.back();
@@ -99,13 +87,35 @@ const AddChickin = () => {
}
// Handle Function
const handleChickinClick = (kandang: Kandang) => {
const handleChickinClick = async (kandang: Kandang) => {
setIsLoadingProjectFlockKandang(true);
setSelectedKandang(kandang);
refreshProjectFlockKandang();
chickinModal.openModal();
const ProjectFlockKandangRes = await ProjectFlockApi.customRequest<
BaseApiResponse<ProjectFlockKandang>,
'GET'
>(getProjectFlockKandangUrl, {
method: 'GET',
params: {
project_flock_id: projectFlockId ?? 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 = () => {
refreshProjectFlockKandang();
chickinModal.closeModal();
router.push('/production/chickin');
};
@@ -126,7 +136,7 @@ const AddChickin = () => {
</Button>
<div className='flex flex-col gap-4 w-full my-4'>
<div className='max-w-1/4'>
<div className='max-w-full sm:max-w-1/2 md:max-w-3/5 lg:max-w-2/5'>
<SelectInput
required
isSearchable
@@ -173,10 +183,10 @@ const AddChickin = () => {
<Button
color='success'
variant='outline'
isLoading={isLoadingProjectFlockKandang}
onClick={() => {
handleChickinClick(props.row.original);
}}
disabled={isLoadingProjectFlockKandang}
>
<Icon
icon='mdi:home-import-outline'
@@ -240,6 +250,19 @@ const AddChickin = () => {
/>
)}
</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();
},
}}
/>
</>
)}
</>
@@ -0,0 +1,11 @@
import SuspenseHelper from "@/components/helper/SuspenseHelper"
const Layout = ({
children
}: Readonly<{
children: React.ReactNode
}>) => {
return <SuspenseHelper>{children}</SuspenseHelper>
}
export default Layout;
@@ -0,0 +1,74 @@
'use client'
import { isResponseError, isResponseSuccess } from "@/lib/api-helper";
import { ChickinApi } from "@/services/api/production";
import { useRouter, useSearchParams } from "next/navigation";
import useSWR from "swr";
const DetailChickin = () => {
const router = useRouter();
const searchParams = useSearchParams();
const chickinId = searchParams.get('chickinId');
const {
data: chickin,
isLoading,
mutate: refreshChickin,
} = useSWR(
chickinId,
(id: number) => ChickinApi.getSingle(id)
);
if(!chickinId){
router.back();
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
<span className='loading loading-spinner loading-xl' />
</div>
);
}
if (
!isLoading &&
(!chickin || isResponseError(chickin))
) {
router.replace('/404');
return;
}
return (
<>
<div className="w-full p-4 flex flex-col justify-center gap-4">
{isLoading && <span className='loading loading-spinner loading-xl' />}
{!isLoading && isResponseSuccess(chickin) && (
<>
<div className="card shadow">
<div className="card-body">
<div className="card-title">
Informasi Project Flock
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<div className="font-semibold">Flock</div>
<div >{chickin.data.project_flock_kandang?.project_flock.flock.name}</div>
</div>
</div>
</div>
</div>
<div className="card shadow">
<div className="card-body">
<div className="card-title">
Informasi Chickin
</div>
</div>
</div>
</>
)}
</div>
</>
);
}
export default DetailChickin;
@@ -279,15 +279,15 @@ const RowOptionsMenu = ({
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)}
>
<Button
href={`/production/chickin/detail?projectFlockId=${props.row.original.id}`}
{/* <Button
href={`/production/chickin/detail?chickinId=${props.row.original.id}`}
variant='ghost'
color='primary'
className='justify-start text-sm'
>
<Icon icon='mdi:eye-outline' width={16} height={16} />
Detail
</Button>
</Button> */}
<Button
variant='ghost'
color='warning'
@@ -11,7 +11,7 @@ import {
ChickinFormValues,
UpdateChickinFormSchema,
} from '@/components/pages/production/chickin/form/ChickinForm.schema';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { use, useCallback, useEffect, useMemo, useState } from 'react';
import { useFormik } from 'formik';
import { ChickinApi } from '@/services/api/production';
import DateInput from '@/components/input/DateInput';
@@ -45,8 +45,8 @@ const ChickinForm = ({
const formikInitialValue = useMemo<ChickinFormValues>(() => {
return {
chick_in_date: formatDateForInput(initialValues?.chick_in_date) ?? '',
note: initialValues?.note ?? `Catatan Chickin ${initialValues?.project_flock_kandang?.project_flock.flock.name}`,
quantity: initialValues?.quantity ?? 1,
note: initialValues?.note ?? '',
quantity: initialValues?.quantity ?? initialValues?.project_flock_kandang?.available_quantity ?? 0,
};
}, [initialValues]);
@@ -103,6 +103,8 @@ const ChickinForm = ({
const payload = {
chick_in_date: values.chick_in_date,
project_flock_kandang_id: initialValues?.project_flock_kandang?.id,
note: values.note,
quantity: values.quantity,
};
// cek type form yang disubmit
@@ -151,21 +153,28 @@ const ChickinForm = ({
name='quantity'
label='Jumlah Chickin'
required
isError={formik.touched.quantity && Boolean(formik.errors.quantity)}
errorMessage={formik.errors.quantity}
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
}
type='number'
disabled
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>
+2
View File
@@ -14,6 +14,8 @@ export type Chickin = BaseMetadata & BaseChickin;
export type CreateChickinPayload = {
project_flock_kandang_id: number;
chick_in_date: string;
note: string;
quantity?: number;
}
export type UpdateChickinPayload = CreateChickinPayload;
+7 -1
View File
@@ -7,6 +7,12 @@ export type BaseProjectFlockKandang = {
kandang_id: number;
kandang: Kandang;
project_flock: ProjectFlock;
available_quantity?: number;
}
export type ProjectFlockKandang = BaseProjectFlockKandang;
export type ProjectFlockKandang = BaseProjectFlockKandang;
export type LookupProjectFlockKandangPayload = {
project_flock_id: number;
kandang_id: number;
}