mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 15:25:46 +00:00
fix(FE-279): adjust closing project flock kandang
This commit is contained in:
@@ -14,13 +14,13 @@ const ProjectFlockClosingPage = () => {
|
|||||||
const projectFlockKandangId = searchParams.get('projectFlockKandangId');
|
const projectFlockKandangId = searchParams.get('projectFlockKandangId');
|
||||||
|
|
||||||
const { data: projectFlockKandang, isLoading: isLoadingProjectFlockKandang } =
|
const { data: projectFlockKandang, isLoading: isLoadingProjectFlockKandang } =
|
||||||
useSWR(projectFlockKandangId, (id: number) =>
|
useSWR(`get-flock-kandang-id/${projectFlockKandangId}`, () =>
|
||||||
ProjectFlockKandangApi.getSingle(id)
|
ProjectFlockKandangApi.getSingle(parseInt(projectFlockKandangId ?? ''))
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: projectFlock, isLoading: isLoadingProjectFlock } = useSWR(
|
const { data: projectFlock, isLoading: isLoadingProjectFlock } = useSWR(
|
||||||
projectFlockId,
|
`get-flock-id/${projectFlockId}`,
|
||||||
(id: number) => ProjectFlockApi.getSingle(id)
|
() => ProjectFlockApi.getSingle(parseInt(projectFlockId ?? ''))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!projectFlockId || !projectFlockKandangId) {
|
if (!projectFlockId || !projectFlockKandangId) {
|
||||||
|
|||||||
@@ -6,9 +6,147 @@ import useSWRImmutable from 'swr/immutable';
|
|||||||
|
|
||||||
import { useAuth } from '@/services/hooks/useAuth';
|
import { useAuth } from '@/services/hooks/useAuth';
|
||||||
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
|
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
|
||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { BaseApiResponse, GetMeResponse } from '@/types/api/api-general';
|
import { GetMeResponse } from '@/types/api/api-general';
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
|
// TODO: delete this later, DONT HARDCODE USER DATA
|
||||||
|
const DUMMY_USER = {
|
||||||
|
id: 1,
|
||||||
|
email: 'admin@mbugroup.id',
|
||||||
|
npk: '0001',
|
||||||
|
name: 'Super Admin',
|
||||||
|
image: null,
|
||||||
|
created_at: '2025-09-30T03:24:20.899229Z',
|
||||||
|
updated_at: '2025-09-30T03:24:20.899229Z',
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
key: 'mbu.super_admin',
|
||||||
|
name: 'MBU Administrator',
|
||||||
|
client: {
|
||||||
|
id: 1,
|
||||||
|
name: 'PT Mitra Berlian Unggas',
|
||||||
|
alias: 'MBU',
|
||||||
|
},
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'mbu:purchase:read',
|
||||||
|
action: 'read',
|
||||||
|
client: {
|
||||||
|
id: 1,
|
||||||
|
name: 'PT Mitra Berlian Unggas',
|
||||||
|
alias: 'MBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'mbu:purchase:create',
|
||||||
|
action: 'create',
|
||||||
|
client: {
|
||||||
|
id: 1,
|
||||||
|
name: 'PT Mitra Berlian Unggas',
|
||||||
|
alias: 'MBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'mbu:purchase:approve',
|
||||||
|
action: 'approve',
|
||||||
|
client: {
|
||||||
|
id: 1,
|
||||||
|
name: 'PT Mitra Berlian Unggas',
|
||||||
|
alias: 'MBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
key: 'lti.super_admin',
|
||||||
|
name: 'LTI Administrator',
|
||||||
|
client: {
|
||||||
|
id: 2,
|
||||||
|
name: 'PT Lumbung Telur Indonesia',
|
||||||
|
alias: 'LTI',
|
||||||
|
},
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'lti:purchase:read',
|
||||||
|
action: 'read',
|
||||||
|
client: {
|
||||||
|
id: 2,
|
||||||
|
name: 'PT Lumbung Telur Indonesia',
|
||||||
|
alias: 'LTI',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'lti:purchase:create',
|
||||||
|
action: 'create',
|
||||||
|
client: {
|
||||||
|
id: 2,
|
||||||
|
name: 'PT Lumbung Telur Indonesia',
|
||||||
|
alias: 'LTI',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'lti:purchase:approve',
|
||||||
|
action: 'approve',
|
||||||
|
client: {
|
||||||
|
id: 2,
|
||||||
|
name: 'PT Lumbung Telur Indonesia',
|
||||||
|
alias: 'LTI',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
key: 'manbu.super_admin',
|
||||||
|
name: 'MANBU Administrator',
|
||||||
|
client: {
|
||||||
|
id: 3,
|
||||||
|
name: 'PT Mandiri Berlian Unggas',
|
||||||
|
alias: 'MANBU',
|
||||||
|
},
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'manbu:purchase:read',
|
||||||
|
action: 'read',
|
||||||
|
client: {
|
||||||
|
id: 3,
|
||||||
|
name: 'PT Mandiri Berlian Unggas',
|
||||||
|
alias: 'MANBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: 'manbu:purchase:create',
|
||||||
|
action: 'create',
|
||||||
|
client: {
|
||||||
|
id: 3,
|
||||||
|
name: 'PT Mandiri Berlian Unggas',
|
||||||
|
alias: 'MANBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: 'manbu:purchase:approve',
|
||||||
|
action: 'approve',
|
||||||
|
client: {
|
||||||
|
id: 3,
|
||||||
|
name: 'PT Mandiri Berlian Unggas',
|
||||||
|
alias: 'MANBU',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
interface RequireAuthProps {
|
interface RequireAuthProps {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
@@ -18,20 +156,17 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { setUser, setIsLoadingUser } = useAuth();
|
const { setUser, setIsLoadingUser } = useAuth();
|
||||||
|
|
||||||
const {
|
const { data: userResponse, isLoading: isLoadingUserResponse } =
|
||||||
data: userResponse,
|
useSWRImmutable<GetMeResponse & { ok?: boolean }, unknown, SWRHttpKey>(
|
||||||
isLoading: isLoadingUserResponse,
|
'/auth/sso/userinfo',
|
||||||
error: userErrorResponse,
|
httpClientFetcher,
|
||||||
} = useSWRImmutable<
|
{
|
||||||
GetMeResponse & { ok?: boolean },
|
shouldRetryOnError: false,
|
||||||
AxiosError<BaseApiResponse>,
|
revalidateOnFocus: false,
|
||||||
SWRHttpKey
|
revalidateOnReconnect: false,
|
||||||
>('/sso/userinfo', httpClientFetcher, {
|
refreshInterval: 0,
|
||||||
shouldRetryOnError: false,
|
}
|
||||||
revalidateOnFocus: false,
|
);
|
||||||
revalidateOnReconnect: false,
|
|
||||||
refreshInterval: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoadingUser(isLoadingUserResponse);
|
setIsLoadingUser(isLoadingUserResponse);
|
||||||
@@ -40,25 +175,23 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isResponseSuccess(userResponse)) {
|
if (isResponseSuccess(userResponse)) {
|
||||||
setUser(userResponse.data);
|
setUser(userResponse.data);
|
||||||
} else if (
|
} else {
|
||||||
isResponseError(userErrorResponse?.response?.data) &&
|
// router.replace(process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string);
|
||||||
typeof window !== 'undefined'
|
// TODO: remove this later, DONT HARDCODE USER DATA
|
||||||
) {
|
setUser(DUMMY_USER);
|
||||||
router.replace(
|
|
||||||
`${process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string}?redirect_url=${window.location.href}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, [userResponse, userErrorResponse, setIsLoadingUser, setUser]);
|
}, [userResponse, setIsLoadingUser, setUser]);
|
||||||
|
|
||||||
if (isLoadingUserResponse && !userResponse && !userErrorResponse) {
|
// TODO: uncomment this later
|
||||||
return (
|
// if (isLoadingUserResponse && !userResponse) {
|
||||||
<div className='w-full flex flex-row justify-center items-center p-4'>
|
// return (
|
||||||
<span className='loading loading-spinner loading-xl' />
|
// <div className='w-full flex flex-row justify-center items-center p-4'>
|
||||||
</div>
|
// <span className='loading loading-spinner loading-xl' />
|
||||||
);
|
// </div>
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
return <>{isResponseSuccess(userResponse) && children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RequireAuth;
|
export default RequireAuth;
|
||||||
|
|||||||
@@ -144,33 +144,45 @@ const ApprovalSteps = ({ approvals }: ApprovalStepsProps) => {
|
|||||||
|
|
||||||
export const formatGroupedApprovalsToApprovalSteps = (
|
export const formatGroupedApprovalsToApprovalSteps = (
|
||||||
approvalLine: ApprovalLine,
|
approvalLine: ApprovalLine,
|
||||||
groupedApprovals: BaseGroupedApproval[],
|
groupedApprovals: BaseGroupedApproval[] | undefined,
|
||||||
latestApproval: BaseApproval
|
latestApproval: BaseApproval | undefined
|
||||||
): ApprovalStepsProps['approvals'] => {
|
): ApprovalStepsProps['approvals'] => {
|
||||||
const formattedApprovalSteps: ApprovalStepsProps['approvals'] =
|
const formattedApprovalSteps: ApprovalStepsProps['approvals'] =
|
||||||
approvalLine.map((approvalLineItem) => {
|
approvalLine.map((approvalLineItem) => {
|
||||||
const approvalGroup = groupedApprovals.find(
|
const approvalGroup = groupedApprovals?.find(
|
||||||
(approvalGroupItem) =>
|
(approvalGroupItem) =>
|
||||||
approvalGroupItem.step_number === approvalLineItem.step_number
|
approvalGroupItem.step_number === approvalLineItem.step_number
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentStepNumber = approvalLineItem.step_number;
|
const currentStepNumber = approvalLineItem.step_number;
|
||||||
const lastStepNumber =
|
const lastStepNumber =
|
||||||
groupedApprovals[groupedApprovals.length - 1]?.step_number;
|
groupedApprovals?.[groupedApprovals.length - 1]?.step_number;
|
||||||
|
|
||||||
const isLatestApprovalRejected = latestApproval.action === 'REJECTED';
|
const isLatestApprovalRejected = latestApproval?.action === 'REJECTED';
|
||||||
|
|
||||||
if (!approvalGroup && currentStepNumber <= lastStepNumber) {
|
// Only throw error if we have a valid lastStepNumber to compare against
|
||||||
throw new Error(
|
if (
|
||||||
`Approval dengan ${approvalLineItem.step_name} tidak ditemukan!`
|
!approvalGroup &&
|
||||||
);
|
lastStepNumber !== undefined &&
|
||||||
|
currentStepNumber <= lastStepNumber
|
||||||
|
) {
|
||||||
|
// throw new Error(
|
||||||
|
// `Approval dengan ${approvalLineItem.step_name} tidak ditemukan!`
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!approvalGroup) {
|
if (!approvalGroup) {
|
||||||
const isWaiting = currentStepNumber === latestApproval.step_number + 1;
|
// Check if this step is waiting (only if we have latestApproval)
|
||||||
|
const isWaiting =
|
||||||
|
latestApproval?.step_number !== undefined &&
|
||||||
|
currentStepNumber === latestApproval.step_number + 1;
|
||||||
|
|
||||||
|
// Check if previous approval was rejected
|
||||||
const isPreviousApprovalRejected =
|
const isPreviousApprovalRejected =
|
||||||
groupedApprovals[groupedApprovals.length - 1].approvals[0].action ===
|
groupedApprovals &&
|
||||||
'REJECTED';
|
groupedApprovals.length > 0 &&
|
||||||
|
groupedApprovals[groupedApprovals.length - 1]?.approvals?.[0]
|
||||||
|
?.action === 'REJECTED';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: approvalLineItem.step_name,
|
name: approvalLineItem.step_name,
|
||||||
@@ -184,7 +196,11 @@ export const formatGroupedApprovalsToApprovalSteps = (
|
|||||||
|
|
||||||
let approvalStatus: ApprovalStepStatus = 'IDLE';
|
let approvalStatus: ApprovalStepStatus = 'IDLE';
|
||||||
|
|
||||||
if (approvalGroup.step_number <= latestApproval.step_number) {
|
// Only compare if latestApproval and its step_number exist
|
||||||
|
if (
|
||||||
|
latestApproval?.step_number !== undefined &&
|
||||||
|
approvalGroup.step_number <= latestApproval.step_number
|
||||||
|
) {
|
||||||
if (approvalGroup.approvals) {
|
if (approvalGroup.approvals) {
|
||||||
switch (approvalGroup?.approvals[0]?.action) {
|
switch (approvalGroup?.approvals[0]?.action) {
|
||||||
case 'CREATED':
|
case 'CREATED':
|
||||||
@@ -203,6 +219,7 @@ export const formatGroupedApprovalsToApprovalSteps = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
latestApproval?.step_number !== undefined &&
|
||||||
approvalGroup.step_number === latestApproval.step_number + 1 &&
|
approvalGroup.step_number === latestApproval.step_number + 1 &&
|
||||||
!isLatestApprovalRejected
|
!isLatestApprovalRejected
|
||||||
) {
|
) {
|
||||||
@@ -353,14 +370,33 @@ const useApprovalSteps = ({
|
|||||||
|
|
||||||
// Formatting Akhir
|
// Formatting Akhir
|
||||||
const approvals = useMemo(() => {
|
const approvals = useMemo(() => {
|
||||||
if (isLoading || !approvalLines.length || !latestApproval) {
|
if (isLoading || !approvalLines.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to derive latestApproval from groupedApprovals if not provided
|
||||||
|
let effectiveLatestApproval = latestApproval;
|
||||||
|
|
||||||
|
if (!effectiveLatestApproval && groupedApprovals.length > 0) {
|
||||||
|
// Get all approvals from grouped data
|
||||||
|
const allApprovals = groupedApprovals.flatMap((group) => group.approvals);
|
||||||
|
|
||||||
|
if (allApprovals.length > 0) {
|
||||||
|
// Use the most recent approval (last in array)
|
||||||
|
effectiveLatestApproval = allApprovals[allApprovals.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If still no latestApproval, return empty
|
||||||
|
if (!effectiveLatestApproval) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return formatGroupedApprovalsToApprovalSteps(
|
return formatGroupedApprovalsToApprovalSteps(
|
||||||
approvalLines,
|
approvalLines,
|
||||||
groupedApprovals,
|
groupedApprovals,
|
||||||
latestApproval
|
effectiveLatestApproval
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Gagal memformat approval steps:', error);
|
console.warn('Gagal memformat approval steps:', error);
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import { useState } from 'react';
|
|||||||
import ApprovalSteps, {
|
import ApprovalSteps, {
|
||||||
useApprovalSteps,
|
useApprovalSteps,
|
||||||
} from '@/components/pages/ApprovalSteps';
|
} from '@/components/pages/ApprovalSteps';
|
||||||
import { PROJECT_FLOCK_KANDANG_APPROVAL_LINE } from '@/config/approval-line';
|
|
||||||
import ChickinFormView from '@/components/pages/production/chickin/form/tabs/ChickinFormView';
|
import ChickinFormView from '@/components/pages/production/chickin/form/tabs/ChickinFormView';
|
||||||
import ChickinLogsView from '@/components/pages/production/chickin/form/tabs/ChickLogsView';
|
import ChickinLogsView from '@/components/pages/production/chickin/form/tabs/ChickLogsView';
|
||||||
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
|
import DrawerHeader from '@/components/helper/drawer/DrawerHeader';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import Badge from '@/components/Badge';
|
import Badge from '@/components/Badge';
|
||||||
|
import { CHICKINS_APPROVAL_LINE } from '@/config/approval-line';
|
||||||
const ChickinFormKandang = ({
|
const ChickinFormKandang = ({
|
||||||
formType = 'add',
|
formType = 'add',
|
||||||
initialValues,
|
initialValues,
|
||||||
@@ -34,8 +34,8 @@ const ChickinFormKandang = ({
|
|||||||
refresh: refreshApprovals,
|
refresh: refreshApprovals,
|
||||||
} = useApprovalSteps({
|
} = useApprovalSteps({
|
||||||
latestApproval: initialValues?.approval,
|
latestApproval: initialValues?.approval,
|
||||||
approvalLines: PROJECT_FLOCK_KANDANG_APPROVAL_LINE,
|
approvalLines: CHICKINS_APPROVAL_LINE,
|
||||||
moduleName: 'PROJECT_FLOCK_KANDANGS',
|
moduleName: 'CHICKINS',
|
||||||
moduleId: initialValues?.id.toString() ?? '',
|
moduleId: initialValues?.id.toString() ?? '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ const ChickinLogsView = ({
|
|||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{initialValues?.approval?.step_number == 1 && (
|
{initialValues?.approval?.step_number >= 1 && (
|
||||||
<Button
|
<Button
|
||||||
color='success'
|
color='success'
|
||||||
onClick={handleClickApprove}
|
onClick={handleClickApprove}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const ProjectFlockClosingForm = ({
|
|||||||
const deleteProjectFlockRes = await ProjectFlockKandangApi.closing(
|
const deleteProjectFlockRes = await ProjectFlockKandangApi.closing(
|
||||||
projectFlock?.id as number,
|
projectFlock?.id as number,
|
||||||
{
|
{
|
||||||
closed_date: formatDate(new Date(), 'yyyy-MM-dd'),
|
closed_date: formatDate(new Date(), 'YYYY-MM-DD'),
|
||||||
action: isCanClose ? 'close' : 'unclose',
|
action: isCanClose ? 'close' : 'unclose',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -212,7 +212,7 @@ const ProjectFlockClosingForm = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{errorExpense && (
|
{errorExpense && (
|
||||||
<div className='text-center text-error'>
|
<div className='text-center text-error text-sm'>
|
||||||
*Pastikan semua biaya sudah selesai sebelum melakukan closing.
|
*Pastikan semua biaya sudah selesai sebelum melakukan closing.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -260,7 +260,7 @@ const ProjectFlockClosingForm = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{errorStock && (
|
{errorStock && (
|
||||||
<div className='text-center text-error'>
|
<div className='text-center text-error text-sm'>
|
||||||
*Masih ada sisa stock yang belum dihabiskan.
|
*Masih ada sisa stock yang belum dihabiskan.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ import toast from 'react-hot-toast';
|
|||||||
import ApprovalSteps, {
|
import ApprovalSteps, {
|
||||||
useApprovalSteps,
|
useApprovalSteps,
|
||||||
} from '@/components/pages/ApprovalSteps';
|
} from '@/components/pages/ApprovalSteps';
|
||||||
import { PROJECT_FLOCK_APPROVAL_LINE } from '@/config/approval-line';
|
import {
|
||||||
|
PROJECT_FLOCK_APPROVAL_LINE,
|
||||||
|
PROJECT_FLOCK_KANDANGS_APPROVAL_LINE,
|
||||||
|
} from '@/config/approval-line';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { ProjectFlockKandangApi } from '@/services/api/production';
|
||||||
|
|
||||||
const ProjectFlockDetail = ({
|
const ProjectFlockDetail = ({
|
||||||
projectFlock,
|
projectFlock,
|
||||||
@@ -38,10 +43,20 @@ const ProjectFlockDetail = ({
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedKandang = projectFlock.kandangs.find(
|
const selectedKandang = projectFlock.kandangs?.find(
|
||||||
(kandang) => kandang.id === Number(selectedKandangId)
|
(kandang) => kandang.id === Number(selectedKandangId)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { data: projectFlockKandang, isLoading: projectFlockKandangLoading } =
|
||||||
|
useSWR(
|
||||||
|
selectedKandangId
|
||||||
|
? `${ProjectFlockKandangApi.basePath}/get-detail/${selectedKandangId}`
|
||||||
|
: null,
|
||||||
|
selectedKandangId
|
||||||
|
? () => ProjectFlockKandangApi.getSingle(parseInt(selectedKandangId))
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
approvals,
|
approvals,
|
||||||
isLoading: approvalsLoading,
|
isLoading: approvalsLoading,
|
||||||
@@ -53,6 +68,17 @@ const ProjectFlockDetail = ({
|
|||||||
moduleId: projectFlock?.id.toString() ?? '',
|
moduleId: projectFlock?.id.toString() ?? '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { approvals: kandangApprovals, isLoading: kandangApprovalsLoading } =
|
||||||
|
useApprovalSteps({
|
||||||
|
latestApproval:
|
||||||
|
selectedKandangId && isResponseSuccess(projectFlockKandang)
|
||||||
|
? projectFlockKandang?.data?.approval
|
||||||
|
: undefined,
|
||||||
|
approvalLines: PROJECT_FLOCK_KANDANGS_APPROVAL_LINE,
|
||||||
|
moduleName: 'PROJECT_FLOCK_KANDANGS',
|
||||||
|
moduleId: selectedKandangId ?? '',
|
||||||
|
});
|
||||||
|
|
||||||
const confirmationModalDeleteClickHandler = async () => {
|
const confirmationModalDeleteClickHandler = async () => {
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
const deleteProjectFlockRes = await ProjectFlockApi.delete(
|
const deleteProjectFlockRes = await ProjectFlockApi.delete(
|
||||||
@@ -151,7 +177,7 @@ const ProjectFlockDetail = ({
|
|||||||
className={{ badge: 'rounded-lg px-2' }}
|
className={{ badge: 'rounded-lg px-2' }}
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:bookmark' width={12} height={12} />
|
<Icon icon='mdi:bookmark' width={12} height={12} />
|
||||||
{` ${formatTitleCase(projectFlock.category)}`}
|
{` ${formatTitleCase(projectFlock.category ?? '')}`}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
{/* Information Grid */}
|
{/* Information Grid */}
|
||||||
@@ -194,7 +220,7 @@ const ProjectFlockDetail = ({
|
|||||||
>
|
>
|
||||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Area
|
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Area
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-2'>{projectFlock.area.name}</div>
|
<div className='col-span-2'>{projectFlock.area?.name}</div>
|
||||||
|
|
||||||
{/* BARIS 2 */}
|
{/* BARIS 2 */}
|
||||||
<div
|
<div
|
||||||
@@ -204,7 +230,7 @@ const ProjectFlockDetail = ({
|
|||||||
>
|
>
|
||||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Lokasi
|
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Lokasi
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-2'>{projectFlock.location.name}</div>
|
<div className='col-span-2'>{projectFlock.location?.name}</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
|
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
|
||||||
@@ -213,7 +239,7 @@ const ProjectFlockDetail = ({
|
|||||||
>
|
>
|
||||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> FCR
|
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> FCR
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-2'>{projectFlock.fcr.name}</div>
|
<div className='col-span-2'>{projectFlock.fcr?.name}</div>
|
||||||
|
|
||||||
{/* BARIS 3 (Terakhir - TIDAK PERLU garis di bawahnya) */}
|
{/* BARIS 3 (Terakhir - TIDAK PERLU garis di bawahnya) */}
|
||||||
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
|
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
|
||||||
@@ -221,7 +247,7 @@ const ProjectFlockDetail = ({
|
|||||||
Kategori
|
Kategori
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-2'>
|
<div className='col-span-2'>
|
||||||
{formatTitleCase(projectFlock.category)}
|
{formatTitleCase(projectFlock.category ?? '')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -231,6 +257,9 @@ const ProjectFlockDetail = ({
|
|||||||
<div className='border-t-1 border-gray-300'>
|
<div className='border-t-1 border-gray-300'>
|
||||||
<div className='p-4 flex flex-col gap-4'>
|
<div className='p-4 flex flex-col gap-4'>
|
||||||
<h2 className='text-2xl font-semibold'>Kandang Aktif</h2>
|
<h2 className='text-2xl font-semibold'>Kandang Aktif</h2>
|
||||||
|
{kandangApprovals && !kandangApprovalsLoading && (
|
||||||
|
<ApprovalSteps approvals={kandangApprovals} />
|
||||||
|
)}
|
||||||
{/* Badge Row */}
|
{/* Badge Row */}
|
||||||
<div className='flex flex-row gap-2'>
|
<div className='flex flex-row gap-2'>
|
||||||
<Badge
|
<Badge
|
||||||
@@ -246,7 +275,7 @@ const ProjectFlockDetail = ({
|
|||||||
height={12}
|
height={12}
|
||||||
color={'success'}
|
color={'success'}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
Kandang Aktif ({projectFlock.kandangs.length})
|
Kandang Aktif ({projectFlock.kandangs?.length})
|
||||||
</Badge>
|
</Badge>
|
||||||
<div className='divider divider-horizontal p-0 m-0'></div>
|
<div className='divider divider-horizontal p-0 m-0'></div>
|
||||||
<Badge
|
<Badge
|
||||||
@@ -355,7 +384,7 @@ const ProjectFlockDetail = ({
|
|||||||
color='neutral'
|
color='neutral'
|
||||||
disabled={projectFlock.approval.step_number == 1}
|
disabled={projectFlock.approval.step_number == 1}
|
||||||
>
|
>
|
||||||
{projectFlock.kandangs.map((kandang) => (
|
{projectFlock.kandangs?.map((kandang) => (
|
||||||
<div
|
<div
|
||||||
key={kandang.id}
|
key={kandang.id}
|
||||||
className={`grid grid-cols-2 gap-6 cursor-pointer hover:text-gray-800`}
|
className={`grid grid-cols-2 gap-6 cursor-pointer hover:text-gray-800`}
|
||||||
|
|||||||
@@ -9,9 +9,28 @@ export const PROJECT_FLOCK_APPROVAL_LINE: ApprovalLine = [
|
|||||||
step_number: 2,
|
step_number: 2,
|
||||||
step_name: 'Aktif',
|
step_name: 'Aktif',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
step_number: 3,
|
||||||
|
step_name: 'Selesai',
|
||||||
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const PROJECT_FLOCK_KANDANG_APPROVAL_LINE: ApprovalLine = [
|
export const PROJECT_FLOCK_KANDANGS_APPROVAL_LINE: ApprovalLine = [
|
||||||
|
{
|
||||||
|
step_number: 1,
|
||||||
|
step_name: 'Pengajuan',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step_number: 2,
|
||||||
|
step_name: 'Disetujui',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step_number: 3,
|
||||||
|
step_name: 'Closed',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const CHICKINS_APPROVAL_LINE: ApprovalLine = [
|
||||||
{
|
{
|
||||||
step_number: 1,
|
step_number: 1,
|
||||||
step_name: 'Pengajuan',
|
step_name: 'Pengajuan',
|
||||||
|
|||||||
@@ -57,13 +57,6 @@ export const MAIN_DRAWER_LINKS: MAIN_DRAWER_MENU[] = [
|
|||||||
link: '/expense',
|
link: '/expense',
|
||||||
icon: 'uil:wallet',
|
icon: 'uil:wallet',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
title: 'Perhitungan Sapronak',
|
|
||||||
link: '/us-284',
|
|
||||||
icon: 'uil:calculator',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
title: 'Persediaan',
|
title: 'Persediaan',
|
||||||
link: '/inventory',
|
link: '/inventory',
|
||||||
|
|||||||
@@ -54,120 +54,119 @@ export class ProjectFlockKandangService extends BaseApiService<
|
|||||||
id: number
|
id: number
|
||||||
): Promise<BaseApiResponse<CheckClosingResponse> | undefined> {
|
): Promise<BaseApiResponse<CheckClosingResponse> | undefined> {
|
||||||
// Dummy data - replace with actual API call when backend is ready
|
// Dummy data - replace with actual API call when backend is ready
|
||||||
return new Promise((resolve) => {
|
// return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
resolve({
|
// resolve({
|
||||||
code: 200,
|
// code: 200,
|
||||||
status: 'success',
|
// status: 'success',
|
||||||
message: 'Cek persyaratan closing kandang',
|
// message: 'Cek persyaratan closing kandang',
|
||||||
data: {
|
// data: {
|
||||||
unfinished_expenses: 2,
|
// unfinished_expenses: 2,
|
||||||
stock_remaining: [
|
// stock_remaining: [
|
||||||
{
|
// {
|
||||||
id: 1,
|
// id: 1,
|
||||||
product_id: 1,
|
// product_id: 1,
|
||||||
warehouse_id: 1,
|
// warehouse_id: 1,
|
||||||
quantity: 0,
|
// quantity: 0,
|
||||||
product: {
|
// product: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
name: 'Pakan Starter',
|
// name: 'Pakan Starter',
|
||||||
brand: 'Brand A',
|
// brand: 'Brand A',
|
||||||
sku: 'PKN-STR-001',
|
// sku: 'PKN-STR-001',
|
||||||
product_price: 15000,
|
// product_price: 15000,
|
||||||
selling_price: 17000,
|
// selling_price: 17000,
|
||||||
tax: 0,
|
// tax: 0,
|
||||||
expiry_period: 365,
|
// expiry_period: 365,
|
||||||
flags: ['active'],
|
// flags: ['active'],
|
||||||
uom: {
|
// uom: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
name: 'Kg',
|
// name: 'Kg',
|
||||||
created_user: {
|
// created_user: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
id_user: 1,
|
// id_user: 1,
|
||||||
email: 'admin@example.com',
|
// email: 'admin@example.com',
|
||||||
name: 'Admin User',
|
// name: 'Admin User',
|
||||||
},
|
// },
|
||||||
created_at: '2024-01-01',
|
// created_at: '2024-01-01',
|
||||||
updated_at: '2024-01-01',
|
// updated_at: '2024-01-01',
|
||||||
},
|
// },
|
||||||
product_category: {
|
// product_category: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
name: 'Pakan',
|
// name: 'Pakan',
|
||||||
code: 'PKN',
|
// code: 'PKN',
|
||||||
created_user: {
|
// created_user: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
id_user: 1,
|
// id_user: 1,
|
||||||
email: 'admin@example.com',
|
// email: 'admin@example.com',
|
||||||
name: 'Admin User',
|
// name: 'Admin User',
|
||||||
},
|
// },
|
||||||
created_at: '2024-01-01',
|
// created_at: '2024-01-01',
|
||||||
updated_at: '2024-01-01',
|
// updated_at: '2024-01-01',
|
||||||
},
|
// },
|
||||||
suppliers: [],
|
// suppliers: [],
|
||||||
created_user: {
|
// created_user: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
id_user: 1,
|
// id_user: 1,
|
||||||
email: 'admin@example.com',
|
// email: 'admin@example.com',
|
||||||
name: 'Admin User',
|
// name: 'Admin User',
|
||||||
},
|
// },
|
||||||
created_at: '2024-01-01',
|
// created_at: '2024-01-01',
|
||||||
updated_at: '2024-01-01',
|
// updated_at: '2024-01-01',
|
||||||
},
|
// },
|
||||||
warehouse: {
|
// warehouse: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
name: 'Gudang Utama',
|
// name: 'Gudang Utama',
|
||||||
type: 'AREA',
|
// type: 'AREA',
|
||||||
area: {
|
// area: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
name: 'Area 1',
|
// name: 'Area 1',
|
||||||
},
|
// },
|
||||||
created_user: {
|
// created_user: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
id_user: 1,
|
// id_user: 1,
|
||||||
email: 'admin@example.com',
|
// email: 'admin@example.com',
|
||||||
name: 'Admin User',
|
// name: 'Admin User',
|
||||||
},
|
// },
|
||||||
created_at: '2024-01-01',
|
// created_at: '2024-01-01',
|
||||||
updated_at: '2024-01-01',
|
// updated_at: '2024-01-01',
|
||||||
},
|
// },
|
||||||
created_user: {
|
// created_user: {
|
||||||
id: 1,
|
// id: 1,
|
||||||
id_user: 1,
|
// id_user: 1,
|
||||||
email: 'admin@example.com',
|
// email: 'admin@example.com',
|
||||||
name: 'Admin User',
|
// name: 'Admin User',
|
||||||
},
|
// },
|
||||||
created_at: '2025-01-01',
|
// created_at: '2025-01-01',
|
||||||
updated_at: '2025-01-01',
|
// updated_at: '2025-01-01',
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
expenses: [
|
// expenses: [
|
||||||
{
|
// {
|
||||||
id: 1,
|
// id: 1,
|
||||||
po_number: 'PO-BOP-LTI-00001',
|
// po_number: 'PO-BOP-LTI-00001',
|
||||||
category: 'NON-BOP',
|
// category: 'NON-BOP',
|
||||||
total: 110000,
|
// total: 110000,
|
||||||
status: 'SELESAI',
|
// status: 'SELESAI',
|
||||||
step_name: 'Approval Finance',
|
// step_name: 'Approval Finance',
|
||||||
step: 5,
|
// step: 5,
|
||||||
reference_number: 'BOP-LTI-00001',
|
// reference_number: 'BOP-LTI-00001',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: 3,
|
// id: 3,
|
||||||
po_number: 'PO-BOP-LTI-00003',
|
// po_number: 'PO-BOP-LTI-00003',
|
||||||
category: 'BOP',
|
// category: 'BOP',
|
||||||
total: 110000,
|
// total: 110000,
|
||||||
status: 'SELESAI',
|
// status: 'SELESAI',
|
||||||
step_name: 'Approval Finance',
|
// step_name: 'Approval Finance',
|
||||||
step: 5,
|
// step: 5,
|
||||||
reference_number: 'BOP-LTI-00003',
|
// reference_number: 'BOP-LTI-00003',
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}, 500); // Simulate network delay
|
// }, 500); // Simulate network delay
|
||||||
});
|
// });
|
||||||
|
|
||||||
/*
|
|
||||||
// Original API call - uncomment when backend is ready
|
// Original API call - uncomment when backend is ready
|
||||||
try {
|
try {
|
||||||
const path = `${this.basePath}/${id}/closing/check`;
|
const path = `${this.basePath}/${id}/closing/check`;
|
||||||
@@ -181,7 +180,6 @@ export class ProjectFlockKandangService extends BaseApiService<
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user