+
+
{formatNumber(chickinPopulation ?? 0)}
{formatCurrency(
@@ -281,8 +281,8 @@ const ClosingOverheadTable = ({
: 0
)}
-
-
+
+
{formatNumber(generalInformation?.population ?? 0)}
diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx
index 58749cf2..bfb13d9a 100644
--- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx
+++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx
@@ -67,7 +67,7 @@ const lineColors: Record
= {
act_fcr: '#10B981',
std_fcr: '#10B981',
act_fcr_cum: '#F52419',
- std_fcr_cum: '#10B981',
+ std_fcr_cum: '#F52419',
normal: '#10B981',
abnormal: '#F52419',
act_deplesi: '#10B981',
@@ -659,44 +659,50 @@ const DashboardLineChart = ({
seriesData = comparisonChart?.series || [];
}
- return seriesData
- .filter((series) => visibleSeries.has(series.id))
- .map((series, index) => {
- const isStandard = series.id
- .toString()
- .toLowerCase()
- .includes('std');
- // Use series.id directly as dataKey to match dataset fields
- const dataKey = series.id.toString();
+ return seriesData.map((series, originalIndex) => {
+ // Skip rendering if series is not visible
+ if (!visibleSeries.has(series.id)) {
+ return null;
+ }
- return (
-
- );
- });
+ const isStandard = series.id
+ .toString()
+ .toLowerCase()
+ .includes('std');
+ const dataKey = series.id.toString();
+
+ return (
+
+ );
+ });
})()}
diff --git a/src/components/pages/dashboard/export/DashboardExportCharts.tsx b/src/components/pages/dashboard/export/DashboardExportCharts.tsx
index ba0b2fe2..3281dbf8 100644
--- a/src/components/pages/dashboard/export/DashboardExportCharts.tsx
+++ b/src/components/pages/dashboard/export/DashboardExportCharts.tsx
@@ -66,7 +66,7 @@ const lineColors: Record = {
act_fcr: '#10B981',
std_fcr: '#10B981',
act_fcr_cum: '#F52419',
- std_fcr_cum: '#10B981',
+ std_fcr_cum: '#F52419',
normal: '#10B981',
abnormal: '#F52419',
act_deplesi: '#10B981',
diff --git a/src/components/pages/expense/ExpenseStatusBadge.tsx b/src/components/pages/expense/ExpenseStatusBadge.tsx
index a7fcb3e9..eee84224 100644
--- a/src/components/pages/expense/ExpenseStatusBadge.tsx
+++ b/src/components/pages/expense/ExpenseStatusBadge.tsx
@@ -1,6 +1,7 @@
-import PillBadge from '@/components/PillBadge';
+import StatusBadge from '@/components/helper/StatusBadge';
import { BaseApproval } from '@/types/api/api-general';
+import { Color } from '@/types/theme';
interface ExpenseStatusBadgeProps {
approval?: BaseApproval;
@@ -11,49 +12,45 @@ const ExpenseStatusBadge = ({ approval }: ExpenseStatusBadgeProps) => {
const latestApprovalStepNumber = approval?.step_number;
- let expenseStatusPillBadgeColor:
- | 'yellow'
- | 'green'
- | 'gray'
- | 'red'
- | 'purple'
- | 'blue' = 'gray';
+ let expenseStatusBadgeColor: Color = 'neutral';
switch (latestApprovalStepNumber) {
case 1:
- expenseStatusPillBadgeColor = 'gray';
+ expenseStatusBadgeColor = 'neutral';
break;
case 2:
- expenseStatusPillBadgeColor = 'purple';
+ expenseStatusBadgeColor = 'info';
break;
case 3:
- expenseStatusPillBadgeColor = 'blue';
+ expenseStatusBadgeColor = 'warning';
break;
case 4:
- expenseStatusPillBadgeColor = 'yellow';
+ expenseStatusBadgeColor = 'error';
break;
case 5:
- expenseStatusPillBadgeColor = 'green';
+ expenseStatusBadgeColor = 'success';
break;
case 6:
- expenseStatusPillBadgeColor = 'green';
+ expenseStatusBadgeColor = 'success';
break;
}
if (isLatestApprovalRejected) {
- expenseStatusPillBadgeColor = 'red';
+ expenseStatusBadgeColor = 'error';
}
return (
-
);
};
diff --git a/src/components/pages/expense/ExpensesTable.tsx b/src/components/pages/expense/ExpensesTable.tsx
index d2d4754c..6d992e30 100644
--- a/src/components/pages/expense/ExpensesTable.tsx
+++ b/src/components/pages/expense/ExpensesTable.tsx
@@ -596,12 +596,11 @@ const ExpensesTable = () => {
diff --git a/src/components/pages/expense/RealizationStatusBadge.tsx b/src/components/pages/expense/RealizationStatusBadge.tsx
index 720c1d03..d04d35c3 100644
--- a/src/components/pages/expense/RealizationStatusBadge.tsx
+++ b/src/components/pages/expense/RealizationStatusBadge.tsx
@@ -1,6 +1,7 @@
-import PillBadge from '@/components/PillBadge';
+import StatusBadge from '@/components/helper/StatusBadge';
import { BaseApproval } from '@/types/api/api-general';
+import { Color } from '@/types/theme';
interface RealizationStatusBadgeProps {
approval?: BaseApproval;
@@ -15,23 +16,21 @@ const RealizationStatusBadge = ({ approval }: RealizationStatusBadgeProps) => {
? 'Sudah Realisasi'
: 'Belum Realisasi';
- let realizationStatusPillBadgeColor:
- | 'yellow'
- | 'green'
- | 'gray'
- | 'red'
- | 'purple'
- | 'blue' = isExpenseRealized ? 'green' : 'yellow';
+ let realizationStatusBadgeColor: Color = isExpenseRealized
+ ? 'success'
+ : 'warning';
if (isLatestApprovalRejected) {
- realizationStatusPillBadgeColor = 'red';
+ realizationStatusBadgeColor = 'error';
}
return (
-
);
};
diff --git a/src/components/pages/inventory/movement/MovementTable.tsx b/src/components/pages/inventory/movement/MovementTable.tsx
index 4a155c1c..c0d51a50 100644
--- a/src/components/pages/inventory/movement/MovementTable.tsx
+++ b/src/components/pages/inventory/movement/MovementTable.tsx
@@ -151,12 +151,11 @@ const MovementTable = () => {
diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts
index eb59a9c0..86951db9 100644
--- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts
+++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts
@@ -32,7 +32,7 @@ const GrowingRepeaterFormSchema = Yup.object({
target_hen_house_production: Yup.number().optional(),
target_egg_weight: Yup.number().optional(),
target_egg_mass: Yup.number().optional(),
- standard_fcr: Yup.number().optional(),
+ standard_fcr: Yup.number().required('Wajib diisi!'),
}).optional(),
});
diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx
index c445a840..1b490fbb 100644
--- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx
+++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx
@@ -386,14 +386,6 @@ const ProductionStandardForm = ({
`${row.original.production_standard_details?.target_egg_mass} kg`,
enableSorting: false,
},
- {
- header: 'FCR',
- accessorFn: (row) =>
- row.production_standard_details?.standard_fcr,
- cell: ({ row }) =>
- `${row.original.production_standard_details?.standard_fcr} g`,
- enableSorting: false,
- },
]
: [];
@@ -468,6 +460,13 @@ const ProductionStandardForm = ({
return [
...baseColumns,
...productionColumns,
+ {
+ header: 'FCR',
+ accessorFn: (row) => row.production_standard_details?.standard_fcr,
+ cell: ({ row }) =>
+ `${row.original.production_standard_details?.standard_fcr} g`,
+ enableSorting: false,
+ },
...uniformityColumns,
...(formType !== 'detail' ? [actionColumn] : []),
];
@@ -753,24 +752,46 @@ const ProductionStandardForm = ({
e.preventDefault();
// For GROWING category, clear production_standard_details errors and set default values
+ // but preserve standard_fcr since it's used for both LAYING and GROWING
if (formik.values.project_category === 'GROWING') {
- // Set default values for production_standard_details
+ // Set default values for production_standard_details, preserving standard_fcr
formik.values.details?.forEach((detail) => {
detail.production_standard_details = {
target_hen_day_production: 0,
target_hen_house_production: 0,
target_egg_weight: 0,
target_egg_mass: 0,
- standard_fcr: 0,
+ standard_fcr:
+ detail.production_standard_details?.standard_fcr || 0,
};
});
- // Clear any errors related to production_standard_details
+ // Clear errors only for LAYING-specific fields in production_standard_details
+ // Preserve standard_fcr error since it's required for both categories
const currentErrors = { ...formik.errors };
if (currentErrors.details && Array.isArray(currentErrors.details)) {
const cleanedDetails = currentErrors.details
.map((detailError) => {
if (detailError && typeof detailError === 'object') {
+ const prodDetails = (
+ detailError as {
+ production_standard_details?: ProductionDetailsErrors;
+ }
+ ).production_standard_details;
+
+ // If there's standard_fcr error, preserve it
+ if (prodDetails && prodDetails.standard_fcr) {
+ const { production_standard_details, ...rest } =
+ detailError;
+ return {
+ ...rest,
+ production_standard_details: {
+ standard_fcr: prodDetails.standard_fcr,
+ },
+ };
+ }
+
+ // Otherwise, remove entire production_standard_details errors
const { production_standard_details, ...rest } = detailError;
return Object.keys(rest).length > 0 ? rest : undefined;
}
@@ -896,7 +917,7 @@ const ProductionStandardForm = ({
gridTemplateColumns:
formik.values.project_category === 'LAYING'
? 'repeat(10, minmax(auto, 1fr)) minmax(auto, auto)'
- : 'repeat(4, minmax(auto, 1fr)) minmax(auto, auto)',
+ : 'repeat(5, minmax(auto, 1fr)) minmax(auto, auto)',
}}
>
-
+ )}
+
- >
- )}
+ )
+ ) &&
+ getProductionDetailsTouched(
+ repeaterFormik.touched
+ .production_standard_details,
+ 'standard_fcr'
+ )
+ }
+ />
{
diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx
index 94f078c1..b8b6b1fc 100644
--- a/src/components/pages/production/recording/form/RecordingForm.tsx
+++ b/src/components/pages/production/recording/form/RecordingForm.tsx
@@ -48,6 +48,7 @@ import {
UpdateLayingRecordingPayload,
Recording,
NextDayRecording,
+ RecordingStock,
} from '@/types/api/production/recording';
import { type BaseApiResponse } from '@/types/api/api-general';
import {
@@ -1103,14 +1104,51 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
[formik.values.stocks, type]
);
+ const getStockPendingInfo = useCallback(
+ (productWarehouseId: number) => {
+ if ((type === 'edit' || type === 'detail') && initialValues?.stocks) {
+ const existingStock = initialValues.stocks.find(
+ (s) => s.product_warehouse_id === productWarehouseId
+ ) as RecordingStock | undefined;
+ if (existingStock) {
+ return {
+ usageAmount: existingStock.usage_amount ?? 0,
+ pendingQty: existingStock.pending_qty ?? 0,
+ };
+ }
+ }
+ return {
+ usageAmount: 0,
+ pendingQty: 0,
+ };
+ },
+ [initialValues, type]
+ );
+
const getStockUsageAdornment = useCallback(
(stockIdx: number) => {
- if ((type as 'add' | 'edit' | 'detail') === 'detail') return null;
const stock = formik.values.stocks?.[stockIdx];
if (!stock || !stock.product_warehouse_id) return null;
+
+ const isDetail = (type as 'add' | 'edit' | 'detail') === 'detail';
const availableStock = getAvailableStock(stock.product_warehouse_id);
const requestedUsage = Number(stock.qty) || 0;
const remainingStock = availableStock - requestedUsage;
+ const { pendingQty } = getStockPendingInfo(stock.product_warehouse_id);
+
+ if (isDetail) {
+ if (pendingQty > 0) {
+ return (
+
+ (tersedia: {formatNumber(requestedUsage)} | pending:{' '}
+ {formatNumber(pendingQty)} |
+ pakai: {formatNumber(requestedUsage + pendingQty)})
+
+ );
+ }
+ return null;
+ }
+
if (requestedUsage > 0) {
return (
@@ -1127,7 +1165,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
);
},
- [formik.values.stocks, getAvailableStock, type]
+ [formik.values.stocks, getAvailableStock, getStockPendingInfo, type]
);
const getProjectFlockBadgeAdornment = useCallback(() => {
@@ -2550,8 +2588,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
: null
}
/>
- {(type as 'add' | 'edit' | 'detail') !== 'detail' &&
- getStockUsageAdornment(idx)}
+ {getStockUsageAdornment(idx)}
{(type as 'add' | 'edit' | 'detail') !== 'detail' && (
@@ -2604,209 +2641,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
{/* Depletions Table */}
-
-
- {/* Eggs Table - Only for LAYING Category */}
- {isLayingCategory && (
+ {((type as 'add' | 'edit' | 'detail') !== 'detail' ||
+ (formik.values.depletions?.length ?? 0) > 0) && (