fix(FE-86-87-88) Hapus tombol edit di index, tambah tombol approve dan delete di detail, dan hit endpoint approve yang udah ada di hoppscocth

This commit is contained in:
randy-ar
2025-10-21 11:37:33 +07:00
parent 838d7277c3
commit e4a1138d8d
2 changed files with 172 additions and 47 deletions
@@ -10,11 +10,12 @@ import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseSuccess } from '@/lib/api-helper';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { cn } from '@/lib/helper';
import { AreaApi, KandangApi, LocationApi } from '@/services/api/master-data';
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 { Icon } from '@iconify/react';
@@ -57,7 +58,7 @@ const RowOptionsMenu = ({
<Icon icon='mdi:eye-outline' width={16} height={16} />
Detail
</Button>
<Button
{/* <Button
href={`/production/project-flock/detail/edit?projectFlockId=${props.row.original.id}`}
variant='ghost'
color='warning'
@@ -65,7 +66,7 @@ const RowOptionsMenu = ({
>
<Icon icon='mdi:pencil-outline' width={16} height={16} />
Edit
</Button>
</Button> */}
<Button
onClick={deleteClickHandler}
variant='ghost'
@@ -194,6 +195,7 @@ const ProjectFlockTable = () => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [selectedFlocks, setSelectedFlocks] = useState<ProjectFlock[]>([]);
const [isApproveLoading, setIsApproveLoading] = useState(false);
// Columns
const projectFlocksColumns: ColumnDef<ProjectFlock>[] = [
@@ -260,7 +262,7 @@ const ProjectFlockTable = () => {
{kandangNames.length > 0 ? kandangNames.join(', ') : 'Tidak ada'}
</div>
);
}else{
} else {
return '-';
}
},
@@ -377,6 +379,30 @@ const ProjectFlockTable = () => {
}
};
const confirmationModalApproveClickHandler = async () => {
setIsApproveLoading(true);
const approveProjectFlockRes = await ProjectFlockApi.customRequest<
BaseApiResponse<ProjectFlock>,
'POST'
>(`/approve`, {
method: 'POST',
payload: 'POST',
params: {
ids: selectedFlocks.map((flock) => flock.id).join(','),
},
});
if (isResponseSuccess(approveProjectFlockRes)) {
toast.success('Project Flock berhasil di-approve!');
confirmModal.closeModal();
}
if (isResponseError(approveProjectFlockRes)) {
toast.error(approveProjectFlockRes?.message as string);
confirmModal.closeModal();
}
setIsApproveLoading(false);
};
return (
<>
<div className='w-full p-0 sm:p-4'>
@@ -557,10 +583,8 @@ const ProjectFlockTable = () => {
primaryButton={{
text: 'Ya',
color: 'success',
onClick: async () => {
toast.success('Project Flock berhasil di-approve!');
confirmModal.closeModal();
},
onClick: confirmationModalApproveClickHandler,
isLoading: isApproveLoading,
}}
/>
</>
@@ -14,7 +14,7 @@ import {
import { Icon } from '@iconify/react';
import { useFormik } from 'formik';
import { useRouter } from 'next/navigation';
import { useEffect, useMemo, useRef, useState } from 'react';
import { use, useEffect, useMemo, useRef, useState } from 'react';
import useSWR from 'swr';
import {
ProjectFlockFormSchema,
@@ -35,6 +35,8 @@ import { httpClient } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general';
import axios from 'axios';
import { FLOCK_CATEGORY_OPTIONS } from '@/config/constant';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
interface ProjectFlockFormProps {
formType?: 'add' | 'edit' | 'detail';
@@ -66,6 +68,12 @@ const ProjectFlockForm = ({
initialValues?.flock?.id ?? 0
);
const deleteModal = useModal();
const confirmModal = useModal();
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [isApproveLoading, setIsApproveLoading] = useState(false);
// Fetch Data
const flockUrl = `${FlockApi.basePath}?${new URLSearchParams({
search: '',
@@ -203,7 +211,7 @@ const ProjectFlockForm = ({
const optionChangeHandler = (
val: OptionType | OptionType[] | null,
inputName: string,
inputName: string
) => {
formik.setFieldValue(inputName, val);
formik.setFieldValue(
@@ -218,7 +226,7 @@ const ProjectFlockForm = ({
formik.setFieldValue('category', (val as OptionType)?.value);
formik.setFieldValue('category_option', val);
formik.setFieldTouched('category', true);
}
};
const kandangChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value, checked } = event.target;
@@ -240,7 +248,11 @@ const ProjectFlockForm = ({
formik.setFieldValue(
'kandang_ids',
optionsKandang
.filter((kandang) => (kandang.status === 'NON_ACTIVE' || formik.values.kandang_ids.includes(kandang.id)))
.filter(
(kandang) =>
kandang.status === 'NON_ACTIVE' ||
formik.values.kandang_ids.includes(kandang.id)
)
.map((kandang) => kandang.id)
);
} else {
@@ -321,7 +333,7 @@ const ProjectFlockForm = ({
fcr_id: initialValues?.fcr?.id ?? 0,
location_id: initialValues?.location?.id ?? 0,
period: initialValues?.period ?? '',
kandang_ids: initialValues?.kandangs?.map((k: Kandang) => k.id) ?? [],
kandang_ids: initialValues?.kandangs?.map((k: Kandang) => k.id),
};
}, [initialValues]);
@@ -391,26 +403,6 @@ const ProjectFlockForm = ({
}
}, [formType, initialValues]);
// Setelah data kandang difetch, centang otomatis kandang yang ada di initialValues
useEffect(() => {
if (formType != 'add' && isResponseSuccess(kandang)) {
if (selectedLocation) {
setOptionsKandang(kandang.data);
setOpenSelectKandangs(true);
const kandangIds =
initialValues?.kandangs?.map((k: Kandang) => k.id) ?? [];
formik.setFieldValue('kandang_ids', kandangIds);
console.log("kandangIds");
console.log(kandangIds);
} else {
setOptionsKandang([]);
setOpenSelectKandangs(false);
formik.setFieldValue('kandang_ids', []);
initialValues.kandangs = [];
}
}
}, [formType, kandang, initialValues]);
useEffect(() => {
formik.validateForm();
}, [formik.values]);
@@ -421,6 +413,43 @@ const ProjectFlockForm = ({
: formik.setFieldValue('period', '');
}, [periodFlocks]);
// Actions handler
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
const deleteProjectFlockRes = await ProjectFlockApi.delete(
initialValues?.id as number
);
if (isResponseSuccess(deleteProjectFlockRes)) {
toast.success(deleteProjectFlockRes?.message as string);
router.push('/production/project-flock');
}
if (isResponseError(deleteProjectFlockRes)) {
toast.error(deleteProjectFlockRes?.message as string);
}
setIsDeleteLoading(false);
};
const confirmationModalApproveClickHandler = async () => {
setIsApproveLoading(true);
const approveProjectFlockRes = await ProjectFlockApi.customRequest<
BaseApiResponse<ProjectFlock>,
'POST'
>(`/${initialValues?.id}/approve`, {
method: 'POST',
});
if (isResponseSuccess(approveProjectFlockRes)) {
toast.success('Project Flock berhasil di-approve!');
confirmModal.closeModal();
}
if (isResponseError(approveProjectFlockRes)) {
toast.error(approveProjectFlockRes?.message as string);
confirmModal.closeModal();
}
setIsApproveLoading(false);
};
return (
<>
<section className='w-full'>
@@ -459,6 +488,22 @@ const ProjectFlockForm = ({
</div>
</div>
)}
<div className='w-full py-4'>
<Button
variant='outline'
color='success'
onClick={() => {
if (initialValues?.id) {
confirmModal.openModal();
}
}}
disabled={!initialValues?.id}
className='w-full sm:w-fit'
>
<Icon icon='material-symbols:check' width={24} height={24} />
Approve
</Button>
</div>
<form
className='w-auto h-auto'
onSubmit={formik.handleSubmit}
@@ -466,7 +511,7 @@ const ProjectFlockForm = ({
>
<div className='card bg-base-100 shadow w-full mb-6'>
<div className='card-body'>
<div className='card-title mb-4'>Informasi Umum</div>
<div className='card-title mb-4'>Informasi Umum {formik.values.kandang_ids && formik.values.kandang_ids.join(', ')}</div>
<div className='grid sm:grid-cols-2 gap-4'>
<SelectInput
@@ -538,8 +583,7 @@ const ProjectFlockForm = ({
onChange={categoryChangeHandler}
options={FLOCK_CATEGORY_OPTIONS}
isError={
formik.touched.category &&
Boolean(formik.errors.category)
formik.touched.category && Boolean(formik.errors.category)
}
errorMessage={formik.errors.category as string}
isClearable
@@ -571,7 +615,9 @@ const ProjectFlockForm = ({
<div className='card-title'>Pilih Kandang</div>
<Button
variant='link'
className='text-primary rotate-0 transition-transform hover:text-inherit'
className={`text-primary rotate-${
openSelectKandangs ? '180' : '0'
} transition-transform hover:text-inherit`}
>
<Icon
icon='material-symbols:keyboard-arrow-down'
@@ -597,24 +643,31 @@ const ProjectFlockForm = ({
type='checkbox'
checked={
optionsKandang
.filter((k) => (k.status === 'NON_ACTIVE' || formik.values.kandang_ids.includes(k.id)))
.filter(
(k) =>
k.status === 'NON_ACTIVE' ||
formik.values.kandang_ids.includes(k.id)
)
.every((k) =>
formik.values.kandang_ids.includes(k.id)
) &&
optionsKandang.filter(
(k) => (k.status === 'NON_ACTIVE' || formik.values.kandang_ids.includes(k.id))
(k) =>
k.status === 'NON_ACTIVE' ||
formik.values.kandang_ids.includes(k.id)
).length > 0
}
className='checkbox'
disabled={formType === 'detail' || optionsKandang.filter(
(k) => (k.status === 'NON_ACTIVE')
).length == 0}
className='checkbox transition-none'
disabled={
formType === 'detail' ||
optionsKandang.filter(
(k) => k.status === 'NON_ACTIVE'
).length == 0
}
onChange={
formType === 'detail'
? () => {}
: kandangCheckAll
}
/>
</label>
@@ -634,7 +687,7 @@ const ProjectFlockForm = ({
<input
value={kandang.id}
type='checkbox'
className='checkbox'
className='checkbox transition-none'
checked={formik.values.kandang_ids.includes(
kandang.id
)}
@@ -645,7 +698,7 @@ const ProjectFlockForm = ({
}
disabled={
formType === 'detail' ||
(kandang.status != 'NON_ACTIVE')
kandang.status != 'NON_ACTIVE'
}
/>
</label>
@@ -703,7 +756,55 @@ const ProjectFlockForm = ({
)}
</div>
</form>
<div className='w-full'>
<Button
onClick={() => {
if (initialValues?.id) {
deleteModal.openModal();
}
}}
color='error'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={16}
height={16}
className='justify-start text-sm'
/>
Delete
</Button>
</div>
</section>
<ConfirmationModal
ref={deleteModal.ref}
type='error'
text={`Apakah anda yakin ingin menghapus data Project Flock ini (${initialValues?.flock?.name} - ${initialValues?.area?.name})?`}
secondaryButton={{
text: 'Tidak',
}}
primaryButton={{
text: 'Ya',
color: 'error',
isLoading: isDeleteLoading,
onClick: confirmationModalDeleteClickHandler,
}}
/>
<ConfirmationModal
ref={confirmModal.ref}
type='success'
text={`Apakah anda yakin ingin approve Project Flock berikut? (${initialValues?.flock?.name} - ${initialValues?.area?.name})?`}
secondaryButton={{
text: 'Tidak',
}}
primaryButton={{
text: 'Ya',
color: 'success',
isLoading: isApproveLoading,
onClick: confirmationModalApproveClickHandler,
}}
/>
</>
);
};