feat(FE): api integration production standards

This commit is contained in:
randy-ar
2025-12-27 13:46:19 +07:00
parent 663c1dea14
commit d49bca1d40
8 changed files with 1167 additions and 581 deletions
@@ -1,9 +1,54 @@
'use client';
import ProductionStandardForm from '@/components/pages/master-data/production-standard/form/ProductionStandardForm';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { ProductionStandardApi } from '@/services/api/master-data';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
const EditProductionStandardPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
// Get Query Params
const productionStandardId = searchParams.get('productionStandardId');
// Fetch Data
const { data: productionStandard, isLoading: isLoadingProductionStandard } =
useSWR(productionStandardId, (id: number) =>
ProductionStandardApi.getSingle(id)
);
if (!productionStandardId) {
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 (
!isLoadingProductionStandard &&
(!productionStandard || isResponseError(productionStandard))
) {
router.replace('/404');
return;
}
return (
<>
<ProductionStandardForm formType='edit' />
{isLoadingProductionStandard && (
<span className='loading loading-spinner loading-xl' />
)}
{!isLoadingProductionStandard &&
isResponseSuccess(productionStandard) && (
<ProductionStandardForm
formType='edit'
initialValue={productionStandard.data}
/>
)}
</>
);
};
@@ -1,9 +1,54 @@
'use client';
import ProductionStandardForm from '@/components/pages/master-data/production-standard/form/ProductionStandardForm';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { ProductionStandardApi } from '@/services/api/master-data';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
const DetailProductionStandardPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
// Get Query Params
const productionStandardId = searchParams.get('productionStandardId');
// Fetch Data
const { data: productionStandard, isLoading: isLoadingProductionStandard } =
useSWR(productionStandardId, (id: number) =>
ProductionStandardApi.getSingle(id)
);
if (!productionStandardId) {
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 (
!isLoadingProductionStandard &&
(!productionStandard || isResponseError(productionStandard))
) {
router.replace('/404');
return;
}
return (
<>
<ProductionStandardForm formType='detail' />
{isLoadingProductionStandard && (
<span className='loading loading-spinner loading-xl' />
)}
{!isLoadingProductionStandard &&
isResponseSuccess(productionStandard) && (
<ProductionStandardForm
formType='detail'
initialValue={productionStandard.data}
/>
)}
</>
);
};
@@ -6,7 +6,7 @@ import Table, { TABLE_DEFAULT_STYLING } from '@/components/Table';
import { ProductionStandard } from '@/types/api/master-data/production-standard';
import { Icon } from '@iconify/react';
import useSWR from 'swr';
import { productionStandardApi } from '@/services/api/master-data';
import { ProductionStandardApi } from '@/services/api/master-data';
import { isResponseSuccess } from '@/lib/api-helper';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import { CellContext } from '@tanstack/react-table';
@@ -80,14 +80,14 @@ const ProductionStandardTable = () => {
isLoading: productionStandardsLoading,
mutate: refreshProductionStandards,
} = useSWR(
`${productionStandardApi.basePath}`,
productionStandardApi.getAllFetcher
`${ProductionStandardApi.basePath}`,
ProductionStandardApi.getAllFetcher
);
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
await productionStandardApi.delete(
await ProductionStandardApi.delete(
selectedProductionStandard?.id as number
);
refreshProductionStandards();
@@ -100,8 +100,8 @@ const ProductionStandardTable = () => {
return (
<>
<div className='flex flex-col gap-6 p-6'>
<div className='flex flex-row gap-6 justify-end'>
<Button href='/master-data/production-standard/add'>
<div className='flex flex-row gap-6 justify-start'>
<Button href='/master-data/production-standard/add' variant='outline'>
<Icon icon='mdi:plus' /> Tambah
</Button>
</div>
@@ -121,8 +121,8 @@ const ProductionStandardTable = () => {
accessorKey: 'name',
},
{
header: 'Jumlah Week',
accessorFn: (row) => row.details.length,
header: 'Kategori',
accessorFn: (row) => row.project_category,
},
{
header: 'Aksi',
@@ -1,41 +1,14 @@
import * as Yup from 'yup';
export const ProductionStandardFormSchema = Yup.object({
name: Yup.string().required('Nama wajib diisi!'),
project_category: Yup.string().required('Kategori proyek wajib diisi!'),
details: Yup.array().of(
Yup.object({
week: Yup.number().required('Minggu wajib diisi!'),
production_standard_details: Yup.object({
target_hen_day_production: Yup.number().required(
'Produksi telur per hari wajib diisi!'
),
target_hen_house_production: Yup.number().required(
'Produksi telur per kandang wajib diisi!'
),
target_egg_weight: Yup.number().required('Berat telur wajib diisi!'),
target_egg_mass: Yup.number().required('Massa telur wajib diisi!'),
}),
standard_growth_details: Yup.object({
target_mean_bw: Yup.number().required('Berat rata-rata wajib diisi!'),
max_depletion: Yup.number().required('Maksimal depletion wajib diisi!'),
min_uniformity: Yup.number().required(
'Minimal uniformitas wajib diisi!'
),
feed_intake: Yup.number().required('Pengambilan makanan wajib diisi!'),
}),
})
),
});
export const UpdateProductionStandardFormSchema = ProductionStandardFormSchema;
export type ProductionStandardFormValues = Yup.InferType<
typeof ProductionStandardFormSchema
>;
export const ProductionStandardRepeaterFormSchema = Yup.object({
// Schema for LAYING category (production_standard_details is required)
const LayingRepeaterFormSchema = Yup.object({
week: Yup.number().required('Minggu wajib diisi!'),
production_standard_uniformity_details: Yup.object({
target_mean_bw: Yup.number().required('Berat rata-rata wajib diisi!'),
max_depletion: Yup.number().required('Maksimal depletion wajib diisi!'),
min_uniformity: Yup.number().required('Minimal uniformitas wajib diisi!'),
feed_intake: Yup.number().required('Pengambilan makanan wajib diisi!'),
}),
production_standard_details: Yup.object({
target_hen_day_production: Yup.number().required(
'Produksi telur per hari wajib diisi!'
@@ -45,18 +18,74 @@ export const ProductionStandardRepeaterFormSchema = Yup.object({
),
target_egg_weight: Yup.number().required('Berat telur wajib diisi!'),
target_egg_mass: Yup.number().required('Massa telur wajib diisi!'),
}),
standard_growth_details: Yup.object({
}).required(),
});
// Schema for GROWING category (production_standard_details is optional)
const GrowingRepeaterFormSchema = Yup.object({
week: Yup.number().required('Minggu wajib diisi!'),
production_standard_uniformity_details: Yup.object({
target_mean_bw: Yup.number().required('Berat rata-rata wajib diisi!'),
max_depletion: Yup.number().required('Maksimal depletion wajib diisi!'),
min_uniformity: Yup.number().required('Minimal uniformitas wajib diisi!'),
feed_intake: Yup.number().required('Pengambilan makanan wajib diisi!'),
}),
production_standard_details: Yup.object({
target_hen_day_production: Yup.number().optional(),
target_hen_house_production: Yup.number().optional(),
target_egg_weight: Yup.number().optional(),
target_egg_mass: Yup.number().optional(),
}).optional(),
});
// Explicit types for better type inference
export type LayingRepeaterFormValues = Yup.InferType<
typeof LayingRepeaterFormSchema
>;
export type GrowingRepeaterFormValues = Yup.InferType<
typeof GrowingRepeaterFormSchema
>;
// Union type for repeater form values
export type ProductionStandardRepeaterFormSchemaValues =
| LayingRepeaterFormValues
| GrowingRepeaterFormValues;
// Dynamic schema factory for repeater form based on project category
export const createProductionStandardRepeaterFormSchema = (
category: string
) => {
// For LAYING category, production_standard_details is required
if (category === 'LAYING') {
return LayingRepeaterFormSchema;
}
// For GROWING category, production_standard_details is optional
return GrowingRepeaterFormSchema;
};
// Dynamic schema factory for main form based on project category
export const createProductionStandardFormSchema = (category: string) => {
return Yup.object({
name: Yup.string().required('Nama wajib diisi!'),
project_category: Yup.string().required('Kategori proyek wajib diisi!'),
details: Yup.array().of(
createProductionStandardRepeaterFormSchema(category)
),
});
};
// Static schemas for backward compatibility (default to LAYING)
export const ProductionStandardFormSchema =
createProductionStandardFormSchema('LAYING');
export const UpdateProductionStandardFormSchema = ProductionStandardFormSchema;
export type ProductionStandardFormValues = Yup.InferType<
typeof ProductionStandardFormSchema
>;
export const ProductionStandardRepeaterFormSchema = LayingRepeaterFormSchema;
export const UpdateProductionStandardRepeaterFormSchema =
ProductionStandardRepeaterFormSchema;
export type ProductionStandardRepeaterFormSchemaValues = Yup.InferType<
typeof ProductionStandardRepeaterFormSchema
>;
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,34 @@
[
{
"id": 1,
"name": "Standar Uniformity A",
"project_category": "LAYING",
"created_user": {
"id": 1,
"id_user": 1,
"email": "admin@mbugroup.id",
"name": "Super Admin"
},
"details": [
{
"week": 1,
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 55,
"max_depletion": 3,
"min_uniformity": 60,
"feed_intake": 25
},
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 1,
"target_hen_house_production": 1,
"target_egg_weight": 1,
"target_egg_mass": 1
}
}
]
},
{
"id": 3,
"name": "Standard Growing 2024",
@@ -13,7 +43,8 @@
"details": [
{
"week": 13,
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1608,
"max_depletion": 2.217125905431294,
"min_uniformity": 82.53307938674605,
@@ -38,13 +69,15 @@
"details": [
{
"week": 7,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 88.75664879714013,
"target_hen_house_production": 88.14547241912292,
"target_egg_weight": 56.500738261325466,
"target_egg_mass": 51.3608296108157
},
"standard_growth_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1630,
"max_depletion": 1.4984809075731345,
"min_uniformity": 89.58032440497733,
@@ -69,13 +102,15 @@
"details": [
{
"week": 5,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 96.61629851755295,
"target_hen_house_production": 92.28797293699245,
"target_egg_weight": 56.58098085770421,
"target_egg_mass": 52.43691607207049
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1879,
"max_depletion": 2.627489091697176,
"min_uniformity": 82.66289615405532,
@@ -100,13 +135,15 @@
"details": [
{
"week": 19,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 90.64987149673148,
"target_hen_house_production": 84.72381158749832,
"target_egg_weight": 52.66407930502588,
"target_egg_mass": 48.67508874158
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1640,
"max_depletion": 1.0327075188137618,
"min_uniformity": 81.06885977450052,
@@ -131,13 +168,15 @@
"details": [
{
"week": 18,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 93.92688146007806,
"target_hen_house_production": 88.99021279347687,
"target_egg_weight": 52.34548967695446,
"target_egg_mass": 47.022424468842786
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1613,
"max_depletion": 1.4131114163932998,
"min_uniformity": 87.70472314168066,
@@ -162,7 +201,8 @@
"details": [
{
"week": 10,
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1679,
"max_depletion": 1.6915361117048733,
"min_uniformity": 86.90679412785661,
@@ -187,13 +227,15 @@
"details": [
{
"week": 17,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 80.64302567936814,
"target_hen_house_production": 89.82086172466285,
"target_egg_weight": 55.226688911717915,
"target_egg_mass": 53.11072600271201
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1874,
"max_depletion": 2.438323895989795,
"min_uniformity": 84.30289784580617,
@@ -218,13 +260,15 @@
"details": [
{
"week": 13,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 82.2346989800578,
"target_hen_house_production": 90.75391628121226,
"target_egg_weight": 57.499497168597166,
"target_egg_mass": 47.20514521984387
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1831,
"max_depletion": 1.074492532699157,
"min_uniformity": 85.74444671505677,
@@ -249,13 +293,15 @@
"details": [
{
"week": 2,
"production_standard_details": {
"egg_production_standard_detail": {
"id": 1,
"target_hen_day_production": 90.49925722287992,
"target_hen_house_production": 89.55923007437376,
"target_egg_weight": 58.22187327861563,
"target_egg_mass": 54.45919757347778
},
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1809,
"max_depletion": 2.2870196905499673,
"min_uniformity": 83.61968975899043,
@@ -280,7 +326,8 @@
"details": [
{
"week": 17,
"production_standard_uniformity_details": {
"growth_standard_detail": {
"id": 1,
"target_mean_bw": 1803,
"max_depletion": 2.3862272943774725,
"min_uniformity": 88.37012562585544,
@@ -291,4 +338,4 @@
}
]
}
]
]
+2 -18
View File
@@ -147,24 +147,8 @@ export const FlockApi = new BaseApiService<
UpdateFlockPayload
>('/master-data/flocks');
export class ProductionStandardApi extends BaseApiService<
export const ProductionStandardApi = new BaseApiService<
ProductionStandard,
unknown,
unknown
> {
constructor(basePath: string) {
super(basePath);
}
async getAllFetcher() {
return await getDummyAllFetcher();
}
async getSingleFetcher(id: number) {
return await getDummySingleFetcher(id);
}
}
export const productionStandardApi = new ProductionStandardApi(
'/master-data/production-standard'
);
>('/master-data/production-standards');
+42 -4
View File
@@ -12,8 +12,8 @@ export interface ProductionStandard {
export interface StandardDetails {
week: number;
standard_growth_details: StandardGrowthDetails;
production_standard_details: ProductionStandardDetails;
growth_standard_detail: StandardGrowthDetails;
egg_production_standard_detail: ProductionStandardDetails;
}
export interface ProductionStandardDetails {
@@ -27,7 +27,45 @@ export interface StandardGrowthDetails {
target_mean_bw: number;
max_depletion: number;
min_uniformity: number;
max_cv: number;
week: number;
feed_intake: number;
}
export interface CreateProductionStandardPayload {
name: string;
project_category: string;
details: {
week: number;
growth_standard_detail: {
target_mean_bw: number;
max_depletion: number;
min_uniformity: number;
feed_intake: number;
};
egg_production_standard_detail: {
target_hen_day_production: number;
target_hen_house_production: number;
target_egg_weight: number;
target_egg_mass: number;
};
}[];
}
export interface UpdateProductionStandardPayload {
name: string;
project_category: string;
details: {
week: number;
growth_standard_detail: {
target_mean_bw: number;
max_depletion: number;
min_uniformity: number;
feed_intake: number;
};
egg_production_standard_detail: {
target_hen_day_production: number;
target_hen_house_production: number;
target_egg_weight: number;
target_egg_mass: number;
};
}[];
}