mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'fix/transfer-to-laying' into 'development'
[FIX/FE] Transfer to Laying See merge request mbugroup/lti-web-client!265
This commit is contained in:
@@ -176,24 +176,26 @@ const ApprovalStepsV2 = ({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
{formattedApprovals.length > maxVisibleSteps && (
|
||||||
variant='outline'
|
<Button
|
||||||
color='none'
|
variant='outline'
|
||||||
onClick={seeMoreClickHandler}
|
color='none'
|
||||||
className={cn(
|
onClick={seeMoreClickHandler}
|
||||||
'px-3 py-2 gap-2.5 text-sm text-base-content/50 border border-base-content/10 rounded-lg transition-all'
|
className={cn(
|
||||||
)}
|
'px-3 py-2 gap-2.5 text-sm text-base-content/50 border border-base-content/10 rounded-lg transition-all'
|
||||||
>
|
)}
|
||||||
<Icon
|
>
|
||||||
icon='heroicons-outline:chevron-double-down'
|
<Icon
|
||||||
width={20}
|
icon='heroicons-outline:chevron-double-down'
|
||||||
height={20}
|
width={20}
|
||||||
className={cn('transition-all duration-300', {
|
height={20}
|
||||||
'-rotate-180': isSeeAll,
|
className={cn('transition-all duration-300', {
|
||||||
})}
|
'-rotate-180': isSeeAll,
|
||||||
/>
|
})}
|
||||||
See {isSeeAll ? 'Less' : 'More'}
|
/>
|
||||||
</Button>
|
See {isSeeAll ? 'Less' : 'More'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ const TextInput = ({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'input h-fit px-3 py-2.5 text-sm font-normal leading-6 flex-1 rounded-lg! outline-none! transition-all duration-200 flex items-center bg-white border-base-content/10',
|
'input h-fit px-3 py-2.5 gap-1.5 text-sm font-normal leading-6 flex-1 rounded-lg! outline-none! transition-all duration-200 flex items-center bg-white border-base-content/10',
|
||||||
{
|
{
|
||||||
'border-error': isError,
|
'border-error': isError,
|
||||||
'border-success!': isValid,
|
'border-success!': isValid,
|
||||||
@@ -182,7 +182,7 @@ const TextInput = ({
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'input h-fit px-3 py-2.5 text-sm font-normal leading-6 w-full rounded-lg! outline-none! transition-all duration-200 bg-white border-base-content/10',
|
'input h-fit px-3 py-2.5 gap-1.5 text-sm font-normal leading-6 w-full rounded-lg! outline-none! transition-all duration-200 bg-white border-base-content/10',
|
||||||
{
|
{
|
||||||
'border-error': isError,
|
'border-error': isError,
|
||||||
'border-success!': isValid,
|
'border-success!': isValid,
|
||||||
|
|||||||
@@ -288,6 +288,48 @@ const TransferToLayingFormModal = () => {
|
|||||||
return { available: countAvailable, unavailable: countUnavailable };
|
return { available: countAvailable, unavailable: countUnavailable };
|
||||||
}, [mappedFlockSourceKandangsAvailability]);
|
}, [mappedFlockSourceKandangsAvailability]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: flockDestinationKandangsMaxTargetQty,
|
||||||
|
isLoading: isLoadingFlockDestinationKandangsMaxTargetQty,
|
||||||
|
} = useSWR(
|
||||||
|
formik.values.flockDestination
|
||||||
|
? [
|
||||||
|
'transfer-to-laying',
|
||||||
|
'max-target-qty',
|
||||||
|
String(formik.values.flockDestination.value),
|
||||||
|
]
|
||||||
|
: undefined,
|
||||||
|
([, , id]: string[]) =>
|
||||||
|
TransferToLayingApi.getMappedFlockKandangsMaxTargetQty(Number(id))
|
||||||
|
);
|
||||||
|
|
||||||
|
const mappedFlockDestinationKandangsMaxTargetQty: {
|
||||||
|
kandang_name: string;
|
||||||
|
max_target_qty: number;
|
||||||
|
project_flock_kandang_id: number;
|
||||||
|
}[] = useMemo(() => {
|
||||||
|
if (
|
||||||
|
!flockDestinationKandangsMaxTargetQty ||
|
||||||
|
!selectedFlockDestinationRawData
|
||||||
|
)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return selectedFlockDestinationRawData
|
||||||
|
? selectedFlockDestinationRawData.kandangs.map((kandang) => {
|
||||||
|
const maxQty =
|
||||||
|
flockDestinationKandangsMaxTargetQty[
|
||||||
|
kandang.project_flock_kandang_id
|
||||||
|
]?.max_target_qty;
|
||||||
|
|
||||||
|
return {
|
||||||
|
kandang_name: kandang.name,
|
||||||
|
max_target_qty: maxQty,
|
||||||
|
project_flock_kandang_id: kandang.project_flock_kandang_id,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
}, [flockDestinationKandangsMaxTargetQty, selectedFlockDestinationRawData]);
|
||||||
|
|
||||||
const mappedFlockDestinationKandangsAvailabilityInfo: {
|
const mappedFlockDestinationKandangsAvailabilityInfo: {
|
||||||
available: number;
|
available: number;
|
||||||
unavailable: number;
|
unavailable: number;
|
||||||
@@ -298,9 +340,8 @@ const TransferToLayingFormModal = () => {
|
|||||||
let countAvailable = 0;
|
let countAvailable = 0;
|
||||||
let countUnavailable = 0;
|
let countUnavailable = 0;
|
||||||
|
|
||||||
selectedFlockDestinationRawData?.kandangs.forEach((item) => {
|
mappedFlockDestinationKandangsMaxTargetQty.forEach((item) => {
|
||||||
// TODO: change this to real available quota later
|
if (item.max_target_qty > 0) {
|
||||||
if (item.capacity > 0) {
|
|
||||||
countAvailable += 1;
|
countAvailable += 1;
|
||||||
} else {
|
} else {
|
||||||
countUnavailable += 1;
|
countUnavailable += 1;
|
||||||
@@ -308,7 +349,7 @@ const TransferToLayingFormModal = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return { available: countAvailable, unavailable: countUnavailable };
|
return { available: countAvailable, unavailable: countUnavailable };
|
||||||
}, [selectedFlockDestinationRawData]);
|
}, [mappedFlockDestinationKandangsMaxTargetQty]);
|
||||||
|
|
||||||
const totalEnteredChickenForTransfer =
|
const totalEnteredChickenForTransfer =
|
||||||
formik.values.flockSourceKandangs.reduce(
|
formik.values.flockSourceKandangs.reduce(
|
||||||
@@ -648,10 +689,9 @@ const TransferToLayingFormModal = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full rounded-xl border border-base-content/10'>
|
<div className='w-full rounded-xl border border-base-content/10'>
|
||||||
{selectedFlockDestinationRawData?.kandangs.map(
|
{mappedFlockDestinationKandangsMaxTargetQty.map(
|
||||||
(item, itemIdx) => {
|
(item, itemIdx) => {
|
||||||
// TODO: change this to real available quota later
|
const isAvailable = item.max_target_qty > 0;
|
||||||
const isAvailable = item.capacity > 0;
|
|
||||||
const isChecked =
|
const isChecked =
|
||||||
formik.values.flockDestinationKandangs.some(
|
formik.values.flockDestinationKandangs.some(
|
||||||
(k) =>
|
(k) =>
|
||||||
@@ -669,11 +709,10 @@ const TransferToLayingFormModal = () => {
|
|||||||
{
|
{
|
||||||
kandang: {
|
kandang: {
|
||||||
value: item.project_flock_kandang_id,
|
value: item.project_flock_kandang_id,
|
||||||
label: item.name,
|
label: item.kandang_name,
|
||||||
},
|
},
|
||||||
quantity: '',
|
quantity: '',
|
||||||
// TODO: change this to real available quota later
|
maxQuantity: item.max_target_qty,
|
||||||
maxQuantity: item.capacity,
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
@@ -718,9 +757,8 @@ const TransferToLayingFormModal = () => {
|
|||||||
'cursor-not-allowed': !isAvailable,
|
'cursor-not-allowed': !isAvailable,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{item.name}{' '}
|
{item.kandang_name}{' '}
|
||||||
{/* TODO: change this to real available quota later */}
|
<span className='text-base-content/20'>{`(Max: ${item.max_target_qty})`}</span>
|
||||||
<span className='text-base-content/20'>{`(Max: ${item.capacity})`}</span>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import {
|
import {
|
||||||
CellContext,
|
CellContext,
|
||||||
@@ -33,6 +33,7 @@ import { cn, formatDate, formatNumber } from '@/lib/helper';
|
|||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
import { Color } from '@/types/theme';
|
import { Color } from '@/types/theme';
|
||||||
|
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
|
||||||
|
|
||||||
const RowOptionsMenu = ({
|
const RowOptionsMenu = ({
|
||||||
props,
|
props,
|
||||||
@@ -432,6 +433,10 @@ const TransferToLayingsTable = () => {
|
|||||||
setIsRejectLoading(false);
|
setIsRejectLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
|
updateFilter('search', e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
const filterSubmitHandler = (values: TransferToLayingFilter) => {
|
const filterSubmitHandler = (values: TransferToLayingFilter) => {
|
||||||
updateFilter('startDate', values.startDate);
|
updateFilter('startDate', values.startDate);
|
||||||
updateFilter('endDate', values.endDate);
|
updateFilter('endDate', values.endDate);
|
||||||
@@ -527,7 +532,27 @@ const TransferToLayingsTable = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-row justify-center items-center gap-3'>
|
<div className='flex flex-1 flex-row justify-start sm:justify-end items-center gap-3 flex-wrap'>
|
||||||
|
<DebouncedTextInput
|
||||||
|
name='search'
|
||||||
|
placeholder='Search'
|
||||||
|
value={tableFilterState.search ?? ''}
|
||||||
|
onChange={searchChangeHandler}
|
||||||
|
startAdornment={
|
||||||
|
<Icon
|
||||||
|
icon='heroicons:magnifying-glass'
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
className={{
|
||||||
|
wrapper: 'w-full min-w-24 max-w-3xs',
|
||||||
|
inputWrapper: 'rounded-xl! shadow-button-soft',
|
||||||
|
input:
|
||||||
|
'placeholder:font-semibold placeholder:text-base-content/50',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant='outline'
|
variant='outline'
|
||||||
color='none'
|
color='none'
|
||||||
|
|||||||
+11
-13
@@ -176,6 +176,11 @@ export const getFilledTransferToLayingFormInitialValues = async (
|
|||||||
initialValues?.from_project_flock.id as number
|
initialValues?.from_project_flock.id as number
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mappedFlockDestinationKandangsMaxTargetQty =
|
||||||
|
await TransferToLayingApi.getMappedFlockKandangsMaxTargetQty(
|
||||||
|
initialValues?.to_project_flock.id as number
|
||||||
|
);
|
||||||
|
|
||||||
const formattedFlockSourceKandangs = initialValues?.sources
|
const formattedFlockSourceKandangs = initialValues?.sources
|
||||||
? initialValues.sources.map((sourceKandang) => ({
|
? initialValues.sources.map((sourceKandang) => ({
|
||||||
kandang: {
|
kandang: {
|
||||||
@@ -197,20 +202,8 @@ export const getFilledTransferToLayingFormInitialValues = async (
|
|||||||
maxTotalQuantity += item.quantity;
|
maxTotalQuantity += item.quantity;
|
||||||
});
|
});
|
||||||
|
|
||||||
const flockDestination = await ProjectFlockApi.getSingle(
|
|
||||||
initialValues?.to_project_flock.id as number
|
|
||||||
);
|
|
||||||
|
|
||||||
const formattedFlockDestinationKandangs = initialValues?.targets
|
const formattedFlockDestinationKandangs = initialValues?.targets
|
||||||
? initialValues.targets.map((targetKandang) => {
|
? initialValues.targets.map((targetKandang) => {
|
||||||
const kandang = isResponseSuccess(flockDestination)
|
|
||||||
? flockDestination?.data?.kandangs.find(
|
|
||||||
(kandang) =>
|
|
||||||
String(kandang.project_flock_kandang_id) ===
|
|
||||||
String(targetKandang.target_project_flock_kandang.id)
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kandang: {
|
kandang: {
|
||||||
value: targetKandang.target_project_flock_kandang.id,
|
value: targetKandang.target_project_flock_kandang.id,
|
||||||
@@ -218,7 +211,12 @@ export const getFilledTransferToLayingFormInitialValues = async (
|
|||||||
},
|
},
|
||||||
quantity: targetKandang.qty,
|
quantity: targetKandang.qty,
|
||||||
|
|
||||||
maxQuantity: kandang?.capacity ?? 0,
|
maxQuantity:
|
||||||
|
(mappedFlockDestinationKandangsMaxTargetQty &&
|
||||||
|
mappedFlockDestinationKandangsMaxTargetQty[
|
||||||
|
targetKandang.target_project_flock_kandang.id
|
||||||
|
].max_target_qty) ??
|
||||||
|
0,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ import {
|
|||||||
UpdateTransferToLayingPayload,
|
UpdateTransferToLayingPayload,
|
||||||
} from '@/types/api/production/transfer-to-laying';
|
} from '@/types/api/production/transfer-to-laying';
|
||||||
import { httpClient } from '@/services/http/client';
|
import { httpClient } from '@/services/http/client';
|
||||||
import { ProjectFlockAvailableQuantity } from '@/types/api/production/project-flock';
|
import {
|
||||||
|
ProjectFlockAvailableQuantity,
|
||||||
|
ProjectFlockMaxQuantity,
|
||||||
|
} from '@/types/api/production/project-flock';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
|
||||||
export class TransferToLayingService extends BaseApiService<
|
export class TransferToLayingService extends BaseApiService<
|
||||||
@@ -132,7 +135,7 @@ export class TransferToLayingService extends BaseApiService<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAvailabelQty(projectFlockId: number) {
|
async getAvailableQty(projectFlockId: number) {
|
||||||
try {
|
try {
|
||||||
const availableQtyRes = await httpClient<
|
const availableQtyRes = await httpClient<
|
||||||
BaseApiResponse<ProjectFlockAvailableQuantity>
|
BaseApiResponse<ProjectFlockAvailableQuantity>
|
||||||
@@ -154,7 +157,7 @@ export class TransferToLayingService extends BaseApiService<
|
|||||||
|
|
||||||
async getMappedFlockKandangsAvailability(projectFlockId: number) {
|
async getMappedFlockKandangsAvailability(projectFlockId: number) {
|
||||||
try {
|
try {
|
||||||
const flockAvailableQty = await this.getAvailabelQty(projectFlockId);
|
const flockAvailableQty = await this.getAvailableQty(projectFlockId);
|
||||||
|
|
||||||
const flockKandangsAvailableQty = isResponseSuccess(flockAvailableQty)
|
const flockKandangsAvailableQty = isResponseSuccess(flockAvailableQty)
|
||||||
? flockAvailableQty.data.kandangs
|
? flockAvailableQty.data.kandangs
|
||||||
@@ -177,6 +180,47 @@ export class TransferToLayingService extends BaseApiService<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getMaxTargetQty(projectFlockId: number) {
|
||||||
|
try {
|
||||||
|
const availableQtyRes = await httpClient<
|
||||||
|
BaseApiResponse<ProjectFlockMaxQuantity>
|
||||||
|
>(`${this.basePath}/project-flocks/${projectFlockId}/max-target-qty`);
|
||||||
|
|
||||||
|
return availableQtyRes;
|
||||||
|
} catch (error) {
|
||||||
|
if (axios.isAxiosError<BaseApiResponse<ProjectFlockMaxQuantity>>(error)) {
|
||||||
|
return error.response?.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMappedFlockKandangsMaxTargetQty(projectFlockId: number) {
|
||||||
|
try {
|
||||||
|
const flockMaxTargetQty = await this.getMaxTargetQty(projectFlockId);
|
||||||
|
|
||||||
|
const flockKandangsMaxTargetQty = isResponseSuccess(flockMaxTargetQty)
|
||||||
|
? flockMaxTargetQty.data.project_flock_kandangs
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const mappedFlockKandangsMaxTargetQty: Record<
|
||||||
|
number,
|
||||||
|
(typeof flockKandangsMaxTargetQty)[0]
|
||||||
|
> = {};
|
||||||
|
|
||||||
|
flockKandangsMaxTargetQty.forEach((item) => {
|
||||||
|
if (!mappedFlockKandangsMaxTargetQty[item.project_flock_kandang_id]) {
|
||||||
|
mappedFlockKandangsMaxTargetQty[item.project_flock_kandang_id] = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return mappedFlockKandangsMaxTargetQty;
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getApprovalHistory(
|
async getApprovalHistory(
|
||||||
transferToLayingId: number,
|
transferToLayingId: number,
|
||||||
group: boolean = true,
|
group: boolean = true,
|
||||||
|
|||||||
+8
@@ -89,6 +89,14 @@ export type ProjectFlockAvailableQuantity = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ProjectFlockMaxQuantity = {
|
||||||
|
project_flock_id: number;
|
||||||
|
project_flock_kandangs: {
|
||||||
|
project_flock_kandang_id: number;
|
||||||
|
max_target_qty: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
export type ProjectFlockPeriods = {
|
export type ProjectFlockPeriods = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user