feat(FE): Add project flock closing modal and zustand store

This commit is contained in:
rstubryan
2026-02-20 10:23:47 +07:00
parent 4c3e7c615f
commit 797f88fe15
4 changed files with 178 additions and 47 deletions
@@ -37,6 +37,7 @@ import ProjectFlockConfirmationModal from './ProjectFlockConfirmationModal';
import { useProjectFlockStore } from '@/stores/production/project-flock/project-flock.store';
import { ProjectFlockFormValues } from './form/ProjectFlockForm.schema';
import { useChickinStore } from '@/stores/production/chickin/chickin.store';
import { useProjectFlockClosingStore } from '@/stores/production/project-flock-closing/project-flock-closing.store';
const RowOptionsMenu = ({
props,
@@ -195,6 +196,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
const confirmModal = useModal();
const successModal = useModal();
const chickinApproveModal = useModal();
const closingModal = useModal();
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
'APPROVED'
);
@@ -210,6 +212,15 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
setChickinApproveLoading,
} = useChickinStore();
const {
isClosingModalOpen,
isKandangClosed,
isClosingLoading,
closingCallback,
closeClosingModal,
setClosingLoading,
} = useProjectFlockClosingStore();
// ===== Fetch Data =====
const {
data: projectFlocks,
@@ -309,6 +320,14 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
}
}, [isChickinApproveModalOpen, chickinApproveModal]);
useEffect(() => {
if (isClosingModalOpen) {
closingModal.openModal();
} else {
closingModal.closeModal();
}
}, [isClosingModalOpen, closingModal]);
useEffect(() => {
if (isSuccess) {
successModal.openModal();
@@ -1025,6 +1044,45 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
isLoading: isChickinApproveLoading,
}}
/>
{/* Project Flock Closing Modal */}
<ConfirmationModal
ref={closingModal.ref}
type='error'
text={
!isKandangClosed
? 'Apakah kamu yakin ingin mengakhiri project ini ? *Pastikan persediaan produk di gudang terkait sudah kosong, dan BOP sudah selesai'
: 'Apakah kamu yakin ingin membuka kembali project ini ? *Project ini akan kembali ke status aktif'
}
className={{
modal: 'z-9999',
}}
secondaryButton={{
text: 'Tidak',
onClick: () => {
closeClosingModal();
closingModal.closeModal();
},
}}
primaryButton={{
text: 'Ya',
color: 'error',
isLoading: isClosingLoading,
onClick: async () => {
if (closingCallback) {
setClosingLoading(true);
try {
await closingCallback(!isKandangClosed ? 'close' : 'unclose');
} finally {
setClosingLoading(false);
closeClosingModal();
closingModal.closeModal();
refreshProjectFlocks();
}
}
},
}}
/>
</>
);
};
@@ -17,9 +17,8 @@ import { Icon } from '@iconify/react';
import useSWR from 'swr';
import { ProjectFlockKandangApi } from '@/services/api/production/project-flock-kandang';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import { useMemo, useState } from 'react';
import { useProjectFlockClosingStore } from '@/stores/production/project-flock-closing/project-flock-closing.store';
import { useMemo } from 'react';
import toast from 'react-hot-toast';
import { useRouter } from 'next/navigation';
import { ApprovalApi } from '@/services/api/approval';
@@ -53,9 +52,8 @@ const ProjectFlockClosingForm = ({
projectFlockKandang: ProjectFlockKandang;
}) => {
const router = useRouter();
const closeModal = useModal();
const [isClosingLoading, setIsClosingLoading] = useState(false);
const { openClosingModal } = useProjectFlockClosingStore();
const { data: closingData, isLoading } = useSWR(
`${ProjectFlockKandangApi.basePath}/${projectFlockKandang.id}/closing`,
@@ -80,29 +78,34 @@ const ProjectFlockClosingForm = ({
: true;
}, [projectFlockKandangApprovals]);
const confirmationModalCloseClickHandler = async () => {
setIsClosingLoading(true);
const deleteProjectFlockRes = await ProjectFlockKandangApi.closing(
projectFlockKandang?.id as number,
{
closed_date: !isKandangClosed
? formatDate(new Date(), 'YYYY-MM-DD')
: '',
action: !isKandangClosed ? 'close' : 'unclose',
}
);
if (isResponseSuccess(deleteProjectFlockRes)) {
toast.success(deleteProjectFlockRes?.message as string);
router.push(
`/production/project-flock/detail?projectFlockId=${projectFlock.id}`
const handleCloseClick = () => {
const closingCallback = async (action: 'close' | 'unclose') => {
const deleteProjectFlockRes = await ProjectFlockKandangApi.closing(
projectFlockKandang?.id as number,
{
closed_date:
action === 'close' ? formatDate(new Date(), 'YYYY-MM-DD') : '',
action,
}
);
}
if (isResponseError(deleteProjectFlockRes)) {
toast.error(deleteProjectFlockRes?.message as string);
}
setIsClosingLoading(false);
closeModal.closeModal();
if (isResponseSuccess(deleteProjectFlockRes)) {
toast.success(deleteProjectFlockRes?.message as string);
router.push(
`/production/project-flock/detail?projectFlockId=${projectFlock.id}`
);
}
if (isResponseError(deleteProjectFlockRes)) {
toast.error(deleteProjectFlockRes?.message as string);
}
};
openClosingModal(
projectFlockKandang,
projectFlock.id,
isKandangClosed,
closingCallback
);
};
// const errorStock = useMemo(() => {
@@ -334,7 +337,7 @@ const ProjectFlockClosingForm = ({
color='error'
isLoading={isLoading}
disabled={!isCanCloseValid}
onClick={() => closeModal.openModal()}
onClick={handleCloseClick}
>
<Icon
icon={
@@ -347,25 +350,6 @@ const ProjectFlockClosingForm = ({
</Button>
</RequirePermission>
</div>
<ConfirmationModal
ref={closeModal.ref}
type='error'
text={
!isKandangClosed
? 'Apakah kamu yakin ingin mengakhiri project ini ? *Pastikan persediaan produk di gudang terkait sudah kosong, dan BOP sudah selesai'
: 'Apakah kamu yakin ingin membuka kembali project ini ? *Project ini akan kembali ke status aktif'
}
secondaryButton={{
text: 'Tidak',
}}
primaryButton={{
text: 'Ya',
color: 'error',
isLoading: isClosingLoading,
onClick: confirmationModalCloseClickHandler,
}}
/>
</div>
</>
);