mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 05:22:02 +00:00
fix(resolve): fix resolve MR
This commit is contained in:
@@ -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,49 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
import GradingForm from '@/components/pages/production/recording/grading/form/GradingForm';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
|
||||
const AddGrading = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const recordingId = searchParams.get('recording_id');
|
||||
|
||||
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
||||
recordingId && recordingId !== 'new' ? [recordingId] : null,
|
||||
([id]) => RecordingApi.getSingle(parseInt(id))
|
||||
);
|
||||
|
||||
if (
|
||||
recordingId &&
|
||||
recordingId !== 'new' &&
|
||||
!isLoadingRecording &&
|
||||
(!recording || !isResponseSuccess(recording))
|
||||
) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='w-full p-4 flex flex-row justify-center'>
|
||||
{recordingId && recordingId !== 'new' && isLoadingRecording && (
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
)}
|
||||
{(!recordingId ||
|
||||
recordingId === 'new' ||
|
||||
(!isLoadingRecording && recording && isResponseSuccess(recording))) && (
|
||||
<GradingForm
|
||||
type='add'
|
||||
initialValues={
|
||||
isResponseSuccess(recording) ? recording.data?.eggs?.[0] : undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddGrading;
|
||||
@@ -0,0 +1,53 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
import GradingForm from '@/components/pages/production/recording/grading/form/GradingForm';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
|
||||
const EditGrading = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const recordingId = searchParams.get('recordingId');
|
||||
const gradingId = searchParams.get('gradingId');
|
||||
|
||||
const { data: recording, isLoading: isLoadingRecording } = useSWR(
|
||||
recordingId ? [recordingId] : null,
|
||||
([id]) => RecordingApi.getSingle(parseInt(id))
|
||||
);
|
||||
|
||||
if (!recordingId) {
|
||||
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 (!isLoadingRecording && (!recording || !isResponseSuccess(recording))) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='w-full p-4 flex flex-row justify-center'>
|
||||
{isLoadingRecording && (
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
)}
|
||||
{!isLoadingRecording && recording && isResponseSuccess(recording) && (
|
||||
<GradingForm
|
||||
type='edit'
|
||||
initialValues={recording.data.eggs?.find(
|
||||
(egg) => egg.id === parseInt(gradingId || '0')
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditGrading;
|
||||
@@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
import GradingForm from '@/components/pages/production/recording/grading/form/GradingForm';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
|
||||
const DetailGrading = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const gradingId = searchParams.get('gradingId');
|
||||
|
||||
const { data: grading, isLoading: isLoadingGrading } = useSWR(
|
||||
gradingId ? [gradingId] : null,
|
||||
([id]) => RecordingApi.getSingle(parseInt(id))
|
||||
);
|
||||
|
||||
if (!gradingId) {
|
||||
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 (!isLoadingGrading && (!grading || !isResponseSuccess(grading))) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='w-full p-4 flex flex-row justify-center'>
|
||||
{isLoadingGrading && (
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
)}
|
||||
{!isLoadingGrading && grading && isResponseSuccess(grading) && (
|
||||
<GradingForm
|
||||
type='detail'
|
||||
initialValues={grading.data.eggs?.find(
|
||||
(egg) => egg.id === parseInt(gradingId)
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DetailGrading;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SuspenseHelper from '@/components/helper/SuspenseHelper';
|
||||
|
||||
const Layout = ({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) => {
|
||||
return <SuspenseHelper>{children}</SuspenseHelper>;
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,212 +1,320 @@
|
||||
import * as Yup from 'yup';
|
||||
import { RECORDING_FLAG_OPTIONS } from '@/config/constant';
|
||||
import { Recording } from '@/types/api/production/recording';
|
||||
import {
|
||||
Recording,
|
||||
CreateGrowingRecordingPayload,
|
||||
CreateLayingRecordingPayload,
|
||||
CreateEggPayload,
|
||||
CreateGradingPayload,
|
||||
} from '@/types/api/production/recording';
|
||||
|
||||
export const RecordingFormSchema = Yup.object({
|
||||
flock: Yup.object({
|
||||
value: Yup.number().min(1).required(),
|
||||
label: Yup.string().required(),
|
||||
}).nullable(),
|
||||
flock_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Flock wajib diisi!')
|
||||
.test(
|
||||
'is-valid-flock',
|
||||
'Flock wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Flock wajib diisi!'),
|
||||
location: Yup.object({
|
||||
value: Yup.number().min(1).required(),
|
||||
label: Yup.string().required(),
|
||||
}).nullable(),
|
||||
location_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Lokasi wajib diisi!')
|
||||
.test(
|
||||
'is-valid-location',
|
||||
'Lokasi wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Lokasi wajib diisi!'),
|
||||
coop: Yup.object({
|
||||
value: Yup.number().min(1).required(),
|
||||
label: Yup.string().required(),
|
||||
}).nullable(),
|
||||
coop_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Kandang wajib diisi!')
|
||||
.test(
|
||||
'is-valid-coop',
|
||||
'Kandang wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Kandang wajib diisi!'),
|
||||
recording_date: Yup.date()
|
||||
.required('Tanggal recording wajib diisi')
|
||||
.typeError('Format tanggal tidak valid'),
|
||||
feed_data: Yup.array()
|
||||
.of(
|
||||
Yup.object({
|
||||
feed_id: Yup.string().required('Nama pakan wajib diisi!'),
|
||||
feed_qty: Yup.mixed<number | ''>().notRequired(),
|
||||
feed_stock: Yup.number()
|
||||
.required('Jumlah pakan yang digunakan wajib diisi!')
|
||||
.min(1, 'Jumlah pakan minimal 1!')
|
||||
.typeError('Jumlah pakan yang digunakan harus berupa angka!')
|
||||
.test(
|
||||
'is-not-exceed-qty',
|
||||
'Jumlah pakan yang digunakan tidak boleh melebihi stok tersedia!',
|
||||
function (value) {
|
||||
const { feed_qty } = this.parent;
|
||||
if (value === undefined) return true;
|
||||
if (
|
||||
feed_qty === undefined ||
|
||||
feed_qty === '' ||
|
||||
typeof feed_qty !== 'number'
|
||||
)
|
||||
return true;
|
||||
return value <= feed_qty;
|
||||
}
|
||||
),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data pakan!')
|
||||
.required('Data pakan wajib diisi!'),
|
||||
body_weight: Yup.array()
|
||||
.of(
|
||||
Yup.object({
|
||||
chicken_weight: Yup.number()
|
||||
.required('Berat ayam wajib diisi!')
|
||||
.min(1, 'Berat ayam minimal 1 gram!')
|
||||
.typeError('Berat ayam harus berupa angka!'),
|
||||
chicken_count: Yup.number()
|
||||
.required('Jumlah ayam wajib diisi!')
|
||||
.min(1, 'Jumlah ayam minimal 1 ekor!')
|
||||
.typeError('Jumlah ayam harus berupa angka!'),
|
||||
average_chicken_weight: Yup.number()
|
||||
.required('Rata-rata berat ayam wajib diisi!')
|
||||
.min(1, 'Rata-rata berat ayam minimal 1 gram!')
|
||||
.typeError('Rata-rata berat ayam harus berupa angka!'),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data bobot badan!')
|
||||
.required('Data bobot badan wajib diisi!'),
|
||||
vaccination: Yup.array()
|
||||
.of(
|
||||
Yup.object({
|
||||
vaccine_id: Yup.string().required('Nama vaksin wajib diisi!'),
|
||||
total_stock: Yup.mixed<number | ''>().notRequired(),
|
||||
used_stock: Yup.number()
|
||||
.required('Jumlah vaksin yang digunakan wajib diisi!')
|
||||
.min(1, 'Jumlah vaksin minimal 1!')
|
||||
.typeError('Jumlah vaksin yang digunakan harus berupa angka!')
|
||||
.test(
|
||||
'is-not-exceed-total',
|
||||
'Jumlah vaksin yang digunakan tidak boleh melebihi stok tersedia!',
|
||||
function (value) {
|
||||
const { total_stock } = this.parent;
|
||||
if (value === undefined) return true;
|
||||
if (
|
||||
total_stock === undefined ||
|
||||
total_stock === '' ||
|
||||
typeof total_stock !== 'number'
|
||||
)
|
||||
return true;
|
||||
return value <= total_stock;
|
||||
}
|
||||
),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data vaksinasi!')
|
||||
.required('Data vaksinasi wajib diisi!'),
|
||||
mortality: Yup.array()
|
||||
.of(
|
||||
Yup.object({
|
||||
condition: Yup.mixed<string>()
|
||||
.oneOf(
|
||||
RECORDING_FLAG_OPTIONS.map((opt) => opt.value),
|
||||
'Kondisi tidak valid!'
|
||||
)
|
||||
.required('Kondisi wajib diisi!'),
|
||||
count: Yup.number()
|
||||
.required('Jumlah mortalitas wajib diisi!')
|
||||
.min(1, 'Jumlah mortalitas minimal 1 ekor!')
|
||||
.typeError('Jumlah mortalitas harus berupa angka!'),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data mortalitas!')
|
||||
.required('Data mortalitas wajib diisi!'),
|
||||
type RecordingGrowingFormSchemaType = {
|
||||
project_flock_kandang: {
|
||||
value: number;
|
||||
label: string;
|
||||
} | null;
|
||||
project_flock_kandang_id: number;
|
||||
body_weights: {
|
||||
weight: number | string;
|
||||
avg_weight: number | string;
|
||||
qty: number | string;
|
||||
}[];
|
||||
stocks: {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
}[];
|
||||
depletions: {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
}[];
|
||||
};
|
||||
|
||||
type RecordingLayingFormSchemaType = RecordingGrowingFormSchemaType & {
|
||||
eggs: {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
}[];
|
||||
};
|
||||
|
||||
type RecordingGradingFormSchemaType = {
|
||||
eggs_grading: {
|
||||
recording_egg_id: number;
|
||||
grade: string;
|
||||
qty: number | string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type BodyWeightSchema = {
|
||||
weight: number | string;
|
||||
avg_weight: number | string;
|
||||
qty: number | string;
|
||||
};
|
||||
|
||||
export type StockSchema = {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
};
|
||||
|
||||
export type DepletionSchema = {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
};
|
||||
|
||||
export type EggSchema = {
|
||||
product_warehouse_id: number;
|
||||
qty: number | string;
|
||||
};
|
||||
|
||||
const BodyWeightObjectSchema: Yup.ObjectSchema<BodyWeightSchema> = Yup.object({
|
||||
weight: Yup.number()
|
||||
.required('Berat ayam total wajib diisi!')
|
||||
.min(1, 'Berat ayam total minimal 1 gram!')
|
||||
.typeError('Berat ayam total harus berupa angka!'),
|
||||
avg_weight: Yup.number()
|
||||
.required('Berat ayam rata-rata wajib diisi!')
|
||||
.typeError('Berat ayam rata-rata harus berupa angka!'),
|
||||
qty: Yup.number()
|
||||
.required('Jumlah ayam wajib diisi!')
|
||||
.min(1, 'Jumlah ayam minimal 1 ekor!')
|
||||
.typeError('Jumlah ayam harus berupa angka!'),
|
||||
});
|
||||
|
||||
export const UpdateRecordingFormSchema = RecordingFormSchema;
|
||||
const StockObjectSchema: Yup.ObjectSchema<StockSchema> = Yup.object({
|
||||
product_warehouse_id: Yup.number()
|
||||
.required('Produk wajib diisi!')
|
||||
.min(1, 'Produk wajib diisi!')
|
||||
.typeError('Produk harus berupa angka!'),
|
||||
qty: Yup.number()
|
||||
.required('Jumlah penggunaan wajib diisi!')
|
||||
.min(1, 'Jumlah penggunaan tidak boleh 0!')
|
||||
.typeError('Jumlah penggunaan harus berupa angka!'),
|
||||
});
|
||||
|
||||
export type RecordingFormValues = Yup.InferType<typeof RecordingFormSchema>;
|
||||
const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({
|
||||
product_warehouse_id: Yup.number()
|
||||
.required('Produk depletions wajib diisi!')
|
||||
.min(1, 'Produk depletions wajib diisi!')
|
||||
.typeError('Produk depletions harus berupa angka!'),
|
||||
qty: Yup.number()
|
||||
.required('Jumlah depletions wajib diisi!')
|
||||
.min(1, 'Jumlah depletions minimal 1!')
|
||||
.typeError('Jumlah depletions harus berupa angka!'),
|
||||
});
|
||||
|
||||
export const getRecordingFormInitialValues = (
|
||||
initialValues?: Recording
|
||||
): RecordingFormValues => ({
|
||||
flock: initialValues?.flock
|
||||
const EggObjectSchema: Yup.ObjectSchema<EggSchema> = Yup.object({
|
||||
product_warehouse_id: Yup.number()
|
||||
.required('Kondisi telur wajib diisi!')
|
||||
.min(1, 'Kondisi telur wajib diisi!')
|
||||
.typeError('Kondisi telur harus berupa angka!'),
|
||||
qty: Yup.number()
|
||||
.required('Jumlah telur wajib diisi!')
|
||||
.min(1, 'Jumlah telur tidak boleh 0!')
|
||||
.typeError('Jumlah telur harus berupa angka!'),
|
||||
});
|
||||
|
||||
export const RecordingGrowingFormSchema: Yup.ObjectSchema<RecordingGrowingFormSchemaType> =
|
||||
Yup.object({
|
||||
project_flock_kandang: Yup.object({
|
||||
value: Yup.number().min(1).required(),
|
||||
label: Yup.string().required(),
|
||||
}).nullable(),
|
||||
project_flock_kandang_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Project Flock Kandang wajib diisi!')
|
||||
.test(
|
||||
'is-valid-project-flock-kandang',
|
||||
'Project Flock Kandang wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Project Flock Kandang wajib diisi!')
|
||||
.test(
|
||||
'not-already-recorded',
|
||||
'Project Flock ini sudah direcord hari ini!',
|
||||
function (value) {
|
||||
const recordedProjectFlockIds = this.options.context
|
||||
?.recordedProjectFlockIds as Set<number>;
|
||||
const formType = this.options.context?.type as
|
||||
| 'add'
|
||||
| 'edit'
|
||||
| 'detail';
|
||||
if (formType !== 'add') return true;
|
||||
if (value && recordedProjectFlockIds?.has(value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
),
|
||||
body_weights: Yup.array()
|
||||
.of(BodyWeightObjectSchema)
|
||||
.min(1, 'Minimal harus ada 1 data bobot badan!')
|
||||
.required('Data bobot badan wajib diisi!'),
|
||||
stocks: Yup.array()
|
||||
.of(StockObjectSchema)
|
||||
.min(1, 'Minimal harus ada 1 data stok!')
|
||||
.required('Data stok wajib diisi!'),
|
||||
depletions: Yup.array()
|
||||
.of(DepletionObjectSchema)
|
||||
.min(1, 'Minimal harus ada 1 data depletions!')
|
||||
.required('Data depletions wajib diisi!'),
|
||||
});
|
||||
|
||||
export const RecordingLayingFormSchema: Yup.ObjectSchema<RecordingLayingFormSchemaType> =
|
||||
RecordingGrowingFormSchema.shape({
|
||||
eggs: Yup.array()
|
||||
.of(EggObjectSchema)
|
||||
.min(1, 'Minimal harus ada 1 data telur!')
|
||||
.required('Data telur wajib diisi!'),
|
||||
});
|
||||
|
||||
export const UpdateRecordingGrowingFormSchema =
|
||||
RecordingGrowingFormSchema.shape({
|
||||
project_flock_kandang_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Project Flock Kandang wajib diisi!')
|
||||
.test(
|
||||
'is-valid-project-flock-kandang',
|
||||
'Project Flock Kandang wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Project Flock Kandang wajib diisi!'),
|
||||
});
|
||||
|
||||
export const UpdateRecordingLayingFormSchema = RecordingLayingFormSchema.shape({
|
||||
project_flock_kandang_id: Yup.number()
|
||||
.default(0)
|
||||
.typeError('Project Flock Kandang wajib diisi!')
|
||||
.test(
|
||||
'is-valid-project-flock-kandang',
|
||||
'Project Flock Kandang wajib diisi!',
|
||||
(value) => value !== undefined && value !== null && value > 0
|
||||
)
|
||||
.required('Project Flock Kandang wajib diisi!'),
|
||||
});
|
||||
|
||||
export const RecordingGradingFormSchema: Yup.ObjectSchema<RecordingGradingFormSchemaType> =
|
||||
Yup.object({
|
||||
eggs_grading: Yup.array()
|
||||
.of(
|
||||
Yup.object({
|
||||
recording_egg_id: Yup.number()
|
||||
.required('Recording Egg ID wajib diisi!')
|
||||
.min(1, 'Recording Egg ID minimal 1!')
|
||||
.typeError('Recording Egg ID harus berupa angka!'),
|
||||
grade: Yup.string()
|
||||
.required('Grade telur wajib diisi!')
|
||||
.typeError('Grade telur harus berupa string!'),
|
||||
qty: Yup.number()
|
||||
.required('Jumlah telur wajib diisi!')
|
||||
.min(1, 'Jumlah telur minimal 1!')
|
||||
.typeError('Jumlah telur harus berupa angka!'),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data grading telur!')
|
||||
.required('Data grading telur wajib diisi!'),
|
||||
});
|
||||
|
||||
export const UpdateRecordingGradingFormSchema = RecordingGradingFormSchema;
|
||||
|
||||
export type RecordingGrowingFormValues = Yup.InferType<
|
||||
typeof RecordingGrowingFormSchema
|
||||
>;
|
||||
|
||||
export type RecordingLayingFormValues = Yup.InferType<
|
||||
typeof RecordingLayingFormSchema
|
||||
>;
|
||||
|
||||
export type RecordingGradingFormValues = Yup.InferType<
|
||||
typeof RecordingGradingFormSchema
|
||||
>;
|
||||
|
||||
type RecordingFormData = Partial<Recording> & {
|
||||
body_weights?: CreateGrowingRecordingPayload['body_weights'];
|
||||
stocks?: CreateGrowingRecordingPayload['stocks'] | Recording['stocks'];
|
||||
depletions?:
|
||||
| CreateGrowingRecordingPayload['depletions']
|
||||
| Recording['depletions'];
|
||||
eggs?: CreateLayingRecordingPayload['eggs'] | Recording['eggs'];
|
||||
project_flock_kandang_id?: number;
|
||||
project_flock_category?: string;
|
||||
};
|
||||
|
||||
export const getRecordingGrowingFormInitialValues = (
|
||||
initialValues?: RecordingFormData
|
||||
): RecordingGrowingFormValues => ({
|
||||
project_flock_kandang: initialValues?.project_flock_kandang_id
|
||||
? {
|
||||
value: initialValues.flock.id,
|
||||
label: initialValues.flock.name,
|
||||
value: initialValues.project_flock_kandang_id,
|
||||
label: `Project Flock #${initialValues.project_flock_kandang_id}`,
|
||||
}
|
||||
: null,
|
||||
flock_id: initialValues?.flock?.id ?? 0,
|
||||
location: initialValues?.location
|
||||
? {
|
||||
value: initialValues.location.id,
|
||||
label: initialValues.location.name,
|
||||
}
|
||||
: null,
|
||||
location_id: initialValues?.location?.id ?? 0,
|
||||
coop: initialValues?.coop
|
||||
? {
|
||||
value: initialValues.coop.id,
|
||||
label: initialValues.coop.name,
|
||||
}
|
||||
: null,
|
||||
coop_id: initialValues?.coop?.id ?? 0,
|
||||
recording_date: initialValues?.recording_date
|
||||
? new Date(initialValues.recording_date)
|
||||
: new Date(),
|
||||
feed_data: initialValues?.feed_data
|
||||
? initialValues.feed_data.map((feed) => ({
|
||||
feed_id: feed.feed_name,
|
||||
feed_qty: feed.feed_qty,
|
||||
feed_stock: feed.feed_stock,
|
||||
}))
|
||||
: [
|
||||
{
|
||||
feed_id: '',
|
||||
feed_qty: '',
|
||||
feed_stock: 0,
|
||||
},
|
||||
],
|
||||
body_weight: initialValues?.body_weight ?? [
|
||||
project_flock_kandang_id: initialValues?.project_flock_kandang_id ?? 0,
|
||||
body_weights: initialValues?.body_weights?.map(
|
||||
(bw: NonNullable<CreateGrowingRecordingPayload['body_weights']>[0]) => ({
|
||||
weight: bw.avg_weight * bw.qty,
|
||||
avg_weight: bw.avg_weight,
|
||||
qty: bw.qty,
|
||||
})
|
||||
) ?? [
|
||||
{
|
||||
chicken_weight: 0,
|
||||
chicken_count: 0,
|
||||
average_chicken_weight: 0,
|
||||
weight: '',
|
||||
avg_weight: '',
|
||||
qty: '',
|
||||
},
|
||||
],
|
||||
vaccination: initialValues?.vaccination
|
||||
? initialValues.vaccination.map((vaccine) => ({
|
||||
vaccine_id: vaccine.vaccine_name,
|
||||
total_stock: vaccine.total_stock,
|
||||
used_stock: vaccine.used_stock,
|
||||
}))
|
||||
: [
|
||||
{
|
||||
vaccine_id: '',
|
||||
total_stock: '',
|
||||
used_stock: 0,
|
||||
},
|
||||
],
|
||||
mortality: initialValues?.mortality ?? [
|
||||
stocks: initialValues?.stocks?.map((stock) => ({
|
||||
product_warehouse_id: stock.product_warehouse_id,
|
||||
qty:
|
||||
(stock as { qty?: number; usage_amount?: number }).qty ||
|
||||
(stock as { qty?: number; usage_amount?: number }).usage_amount ||
|
||||
'',
|
||||
})) ?? [
|
||||
{
|
||||
condition: '',
|
||||
count: 0,
|
||||
product_warehouse_id: 0,
|
||||
qty: '',
|
||||
},
|
||||
],
|
||||
depletions: initialValues?.depletions?.map(
|
||||
(
|
||||
depletion: NonNullable<CreateGrowingRecordingPayload['depletions']>[0]
|
||||
) => ({
|
||||
product_warehouse_id: depletion.product_warehouse_id,
|
||||
qty: depletion.qty,
|
||||
})
|
||||
) ?? [
|
||||
{
|
||||
product_warehouse_id: 0,
|
||||
qty: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const getRecordingLayingFormInitialValues = (
|
||||
initialValues?: RecordingFormData
|
||||
): RecordingLayingFormValues => ({
|
||||
...getRecordingGrowingFormInitialValues(initialValues),
|
||||
|
||||
eggs: initialValues?.eggs?.map((egg: CreateEggPayload) => ({
|
||||
product_warehouse_id: egg.product_warehouse_id,
|
||||
qty: egg.qty,
|
||||
})) ?? [
|
||||
{
|
||||
product_warehouse_id: 0,
|
||||
qty: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const getRecordingGradingFormInitialValues = (
|
||||
initialValues?: Partial<CreateGradingPayload> & { recording_egg_id?: number }
|
||||
): RecordingGradingFormValues => ({
|
||||
eggs_grading: initialValues?.eggs_grading?.map((grading) => ({
|
||||
recording_egg_id: grading.recording_egg_id,
|
||||
grade: grading.grade,
|
||||
qty: grading.qty,
|
||||
})) ?? [
|
||||
{
|
||||
recording_egg_id: initialValues?.recording_egg_id ?? 0,
|
||||
grade: '',
|
||||
qty: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { RecordingApi } from '@/services/api/production';
|
||||
import {
|
||||
CreateRecordingPayload,
|
||||
UpdateRecordingPayload,
|
||||
} from '@/types/api/production/recording';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
|
||||
export const useRecordingFormHandlers = (initialValuesId?: number) => {
|
||||
const router = useRouter();
|
||||
const deleteModal = useModal();
|
||||
const [recordingFormErrorMessage, setRecordingFormErrorMessage] =
|
||||
useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const createRecordingHandler = useCallback(
|
||||
async (payload: CreateRecordingPayload) => {
|
||||
const res = await RecordingApi.create(payload);
|
||||
if (isResponseError(res)) {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.push('/flock/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const updateRecordingHandler = useCallback(
|
||||
async (recordingId: number, payload: UpdateRecordingPayload) => {
|
||||
const res = await RecordingApi.update(recordingId, payload);
|
||||
if (res?.status === 'error') {
|
||||
setRecordingFormErrorMessage(res.message);
|
||||
return;
|
||||
}
|
||||
toast.success(res?.message as string);
|
||||
router.refresh();
|
||||
router.push('/flock/recording');
|
||||
},
|
||||
[router]
|
||||
);
|
||||
|
||||
const deleteRecordingClickHandler = useCallback(() => {
|
||||
deleteModal.openModal();
|
||||
}, [deleteModal]);
|
||||
|
||||
const confirmationModalDeleteClickHandler = useCallback(async () => {
|
||||
if (!initialValuesId) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
await RecordingApi.delete(initialValuesId);
|
||||
deleteModal.closeModal();
|
||||
toast.success('Successfully delete Recording!');
|
||||
setIsDeleteLoading(false);
|
||||
router.push('/flock/recording');
|
||||
}, [deleteModal, initialValuesId, router]);
|
||||
|
||||
return {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
isDeleteLoading,
|
||||
createRecordingHandler,
|
||||
updateRecordingHandler,
|
||||
deleteRecordingClickHandler,
|
||||
confirmationModalDeleteClickHandler,
|
||||
};
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,51 @@ export const TRANSFER_TO_LAYING_APPROVAL_LINE: ApprovalLine = [
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const RECORDING_APPROVAL_LINE: ApprovalLine = [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Grading-Telur',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 3,
|
||||
step_name: 'Disetujui',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const GROWING_RECORDING_APPROVAL_LINE: ApprovalLine = [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Grading-Telur',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 3,
|
||||
step_name: 'Disetujui',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const LAYING_RECORDING_APPROVAL_LINE: ApprovalLine = [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Grading-Telur',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 3,
|
||||
step_name: 'Disetujui',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const PURCHASE_ORDER_APPROVAL_LINE: ApprovalLine = [
|
||||
{
|
||||
step_number: 1,
|
||||
|
||||
@@ -244,6 +244,39 @@ export const RECORDING_FLAG_OPTIONS = [
|
||||
{ label: 'Ayam Mati', value: 'Ayam Mati' },
|
||||
];
|
||||
|
||||
export const APPROVAL_WORKFLOWS = [
|
||||
{
|
||||
key: 'PROJECT_FLOCKS',
|
||||
steps: [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Aktif',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'RECORDINGS',
|
||||
steps: [
|
||||
{
|
||||
step_number: 1,
|
||||
step_name: 'Grading-Telur',
|
||||
},
|
||||
{
|
||||
step_number: 2,
|
||||
step_name: 'Pengajuan',
|
||||
},
|
||||
{
|
||||
step_number: 3,
|
||||
step_name: 'Disetujui',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const ACCEPTED_FILE_TYPE = {
|
||||
PDF: {
|
||||
'application/pdf': ['.pdf'],
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { BaseApiService } from '@/services/api/base';
|
||||
import { BaseApproval } from '@/types/api/api-general';
|
||||
|
||||
export const ApprovalApi = new BaseApiService<BaseApproval, unknown, unknown>(
|
||||
'/approvals'
|
||||
);
|
||||
@@ -1,8 +1,17 @@
|
||||
import { BaseApiService } from './base';
|
||||
import { BaseApiResponse } from '@/types/api/api-general';
|
||||
import {
|
||||
CreateProjectFlockPayload,
|
||||
ProjectFlock,
|
||||
UpdateProjectFlockPayload,
|
||||
} from '@/types/api/production/project-flock';
|
||||
import {
|
||||
CreateRecordingPayload,
|
||||
Recording,
|
||||
UpdateRecordingPayload,
|
||||
CreateGradingPayload,
|
||||
UpdateGradingPayload,
|
||||
NextDayRecording,
|
||||
} from '@/types/api/production/recording';
|
||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||
|
||||
@@ -11,8 +20,96 @@ export const ProjectFlockKandangApi = new BaseApiService<
|
||||
unknown,
|
||||
unknown
|
||||
>('/production/project-flock-kandangs');
|
||||
export const RecordingApi = new BaseApiService<
|
||||
export const ProjectFlockApi = new BaseApiService<
|
||||
ProjectFlock,
|
||||
CreateProjectFlockPayload,
|
||||
UpdateProjectFlockPayload
|
||||
>('/production/project-flocks');
|
||||
export class RecordingService extends BaseApiService<
|
||||
Recording,
|
||||
CreateRecordingPayload,
|
||||
UpdateRecordingPayload
|
||||
>('/production/recordings');
|
||||
> {
|
||||
constructor(basePath: string = '') {
|
||||
super(basePath);
|
||||
}
|
||||
|
||||
async approve(
|
||||
idOrIds: number | number[],
|
||||
notes?: string
|
||||
): Promise<BaseApiResponse<Recording[]> | undefined> {
|
||||
const approvable_ids = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
||||
return await this.customRequest<BaseApiResponse<Recording[]>>('approvals', {
|
||||
method: 'POST',
|
||||
payload: {
|
||||
action: 'APPROVED',
|
||||
approvable_ids,
|
||||
notes,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async reject(
|
||||
idOrIds: number | number[],
|
||||
notes: string = ''
|
||||
): Promise<BaseApiResponse<Recording[]> | undefined> {
|
||||
const approvable_ids = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
||||
return await this.customRequest<BaseApiResponse<Recording[]>>('approvals', {
|
||||
method: 'POST',
|
||||
payload: {
|
||||
action: 'REJECTED',
|
||||
approvable_ids,
|
||||
notes,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async createGrading(
|
||||
payload: CreateGradingPayload
|
||||
): Promise<BaseApiResponse<unknown> | undefined> {
|
||||
return await this.customRequest<BaseApiResponse<unknown>>('gradings', {
|
||||
method: 'POST',
|
||||
payload,
|
||||
});
|
||||
}
|
||||
|
||||
async updateGrading(
|
||||
gradingId: number,
|
||||
payload: UpdateGradingPayload
|
||||
): Promise<BaseApiResponse<unknown> | undefined> {
|
||||
return await this.customRequest<BaseApiResponse<unknown>>(
|
||||
`gradings/${gradingId}`,
|
||||
{
|
||||
method: 'PUT',
|
||||
payload,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async deleteGrading(
|
||||
gradingId: number
|
||||
): Promise<BaseApiResponse<unknown> | undefined> {
|
||||
return await this.customRequest<BaseApiResponse<unknown>>(
|
||||
`gradings/${gradingId}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async nextDayRecording(
|
||||
projectFlockId: number
|
||||
): Promise<BaseApiResponse<NextDayRecording> | undefined> {
|
||||
return await this.customRequest<BaseApiResponse<NextDayRecording>>(
|
||||
`next-day`,
|
||||
{
|
||||
method: 'GET',
|
||||
params: {
|
||||
project_flock_kandang_id: projectFlockId,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const RecordingApi = new RecordingService('/production/recordings');
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { BaseApiService } from '@/services/api/base';
|
||||
import {
|
||||
BaseProjectFlockKandang,
|
||||
ProjectFlockKandang,
|
||||
} from '@/types/api/production/project-flock-kandang';
|
||||
|
||||
export const ProjectFlockKandangApi = new BaseApiService<
|
||||
BaseProjectFlockKandang,
|
||||
ProjectFlockKandang,
|
||||
unknown
|
||||
>('project-flock-kandang');
|
||||
+12
-2
@@ -7,8 +7,8 @@ import { BaseApproval, BaseMetadata } from '@/types/api/api-general';
|
||||
|
||||
export type BaseProjectFlock = {
|
||||
id: number;
|
||||
name: string;
|
||||
flock_name: string;
|
||||
name?: string;
|
||||
flock_name?: string;
|
||||
status: string;
|
||||
flock?: Flock;
|
||||
flock_i?: number;
|
||||
@@ -52,6 +52,16 @@ export type ProjectFlockApprovalPayload = {
|
||||
approvable_ids: number[];
|
||||
};
|
||||
|
||||
export type ProjectFlockKandangLookup = {
|
||||
id: number;
|
||||
project_flock_kandang_id: number;
|
||||
project_flock_id: number;
|
||||
kandang_id: number;
|
||||
kandang: Kandang;
|
||||
project_flock: ProjectFlock;
|
||||
quantity: number;
|
||||
};
|
||||
|
||||
export type ProjectFlockAvailableQuantity = {
|
||||
project_flock_id: number;
|
||||
flock_name: string;
|
||||
|
||||
+134
-48
@@ -1,61 +1,147 @@
|
||||
import { BaseMetadata } from '@/types/api/api-general';
|
||||
import { Location } from '@/types/api/master-data/location';
|
||||
import { Kandang } from '@/types/api/master-data/kandang';
|
||||
import { Flock } from '@/types/api/master-data/flock';
|
||||
import { BaseApproval, BaseMetadata, User } from '@/types/api/api-general';
|
||||
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
|
||||
|
||||
export type ProductionMetrics = {
|
||||
total_depletion_qty: number;
|
||||
cum_depletion_rate: number;
|
||||
daily_gain: number;
|
||||
avg_daily_gain: number;
|
||||
cum_intake: number;
|
||||
fcr_value: number;
|
||||
total_chick_qty: number;
|
||||
daily_depletion_rate?: number;
|
||||
cum_depletion?: number;
|
||||
};
|
||||
|
||||
export type BaseRecording = {
|
||||
id: number;
|
||||
flock: Flock;
|
||||
recording_date: string;
|
||||
location: Location;
|
||||
coop: Kandang;
|
||||
feed_data: {
|
||||
feed_name: string;
|
||||
feed_qty: number;
|
||||
feed_stock: number;
|
||||
}[];
|
||||
body_weight: {
|
||||
chicken_weight: number;
|
||||
chicken_count: number;
|
||||
average_chicken_weight: number;
|
||||
}[];
|
||||
vaccination: {
|
||||
vaccine_name: string;
|
||||
total_stock: number;
|
||||
used_stock: number;
|
||||
}[];
|
||||
mortality: {
|
||||
condition: string;
|
||||
count: number;
|
||||
project_flock_kandang_id: number;
|
||||
record_datetime: string;
|
||||
day: number;
|
||||
created_by: User;
|
||||
} & ProductionMetrics;
|
||||
|
||||
export type RecordingBW = {
|
||||
id: number;
|
||||
recording_id: number;
|
||||
avg_weight: number;
|
||||
qty: number;
|
||||
total_weight: number;
|
||||
};
|
||||
|
||||
export type RecordingDepletion = {
|
||||
id: number;
|
||||
recording_id: number;
|
||||
product_warehouse_id: number;
|
||||
qty: number;
|
||||
product_warehouse: ProductWarehouse;
|
||||
};
|
||||
|
||||
export type RecordingStock = {
|
||||
id: number;
|
||||
recording_id: number;
|
||||
product_warehouse_id: number;
|
||||
usage_amount?: number;
|
||||
usage_qty: number;
|
||||
qty: number;
|
||||
pending_qty: number;
|
||||
product_warehouse: ProductWarehouse;
|
||||
};
|
||||
|
||||
export type RecordingEgg = {
|
||||
id: number;
|
||||
recording_id: number;
|
||||
product_warehouse_id: number;
|
||||
qty: number;
|
||||
created_by: User;
|
||||
product_warehouse: ProductWarehouse;
|
||||
gradings?: {
|
||||
grade: string;
|
||||
qty: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type Recording = BaseMetadata & BaseRecording;
|
||||
export type GradingEgg = {
|
||||
id: number;
|
||||
recording_egg_id: number;
|
||||
qty: number;
|
||||
grade: string;
|
||||
created_by: User;
|
||||
};
|
||||
|
||||
export type CreateRecordingPayload = {
|
||||
flock_id: number;
|
||||
recording_date: string;
|
||||
location_id: number;
|
||||
coop_id: number;
|
||||
feed_data: {
|
||||
feed_id: string;
|
||||
feed_qty: number;
|
||||
feed_stock: number;
|
||||
export type Recording = BaseMetadata &
|
||||
BaseRecording & {
|
||||
project_flock_category?: 'GROWING' | 'LAYING';
|
||||
approval?: BaseApproval;
|
||||
egg_grading_status?: string | null;
|
||||
egg_grading_pending_qty?: number | null;
|
||||
egg_grading_completed_qty?: number | null;
|
||||
body_weights?: RecordingBW[];
|
||||
depletions?: RecordingDepletion[];
|
||||
stocks?: RecordingStock[];
|
||||
eggs?: RecordingEgg[];
|
||||
recording_bws?: RecordingBW[];
|
||||
recording_depletions?: RecordingDepletion[];
|
||||
recording_stocks?: RecordingStock[];
|
||||
recording_eggs?: RecordingEgg[];
|
||||
grading_eggs?: GradingEgg[];
|
||||
};
|
||||
|
||||
export type NextDayRecording = {
|
||||
project_flock_kandang_id: number;
|
||||
next_day: number;
|
||||
};
|
||||
|
||||
export type CreateGrowingRecordingPayload = {
|
||||
project_flock_kandang_id: number;
|
||||
body_weights: {
|
||||
avg_weight: number;
|
||||
qty: number;
|
||||
}[];
|
||||
body_weight: {
|
||||
chicken_weight: number;
|
||||
chicken_count: number;
|
||||
average_chicken_weight: number;
|
||||
stocks?: {
|
||||
product_warehouse_id: number;
|
||||
qty: number;
|
||||
}[];
|
||||
vaccination: {
|
||||
vaccine_id: string;
|
||||
total_stock: number;
|
||||
used_stock: number;
|
||||
}[];
|
||||
mortality: {
|
||||
condition: string;
|
||||
count: number;
|
||||
depletions?: {
|
||||
product_warehouse_id: number;
|
||||
qty: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type CreateGradingPayload = {
|
||||
eggs_grading: {
|
||||
recording_egg_id: number;
|
||||
grade: string;
|
||||
qty: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type UpdateGradingPayload = CreateGradingPayload;
|
||||
|
||||
export type CreateGradingRecordingPayload = {
|
||||
eggs_grading: {
|
||||
recording_egg_id: number;
|
||||
grade: string;
|
||||
qty: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type CreateEggPayload = {
|
||||
product_warehouse_id: number;
|
||||
qty: number;
|
||||
};
|
||||
|
||||
export type CreateLayingRecordingPayload = CreateGrowingRecordingPayload & {
|
||||
eggs?: CreateEggPayload[];
|
||||
};
|
||||
|
||||
export type CreateRecordingPayload =
|
||||
| CreateGrowingRecordingPayload
|
||||
| CreateLayingRecordingPayload
|
||||
| CreateGradingRecordingPayload;
|
||||
|
||||
export type UpdateGrowingRecordingPayload = CreateGrowingRecordingPayload;
|
||||
export type UpdateLayingRecordingPayload = CreateLayingRecordingPayload;
|
||||
export type UpdateGradingRecordingPayload = CreateGradingRecordingPayload;
|
||||
|
||||
export type UpdateRecordingPayload = CreateRecordingPayload;
|
||||
|
||||
Reference in New Issue
Block a user