chore: adjust ProjectFlockForm styling

This commit is contained in:
ValdiANS
2026-02-03 09:40:16 +07:00
parent d826746f29
commit 68f3c95b81
@@ -658,37 +658,48 @@ const ProjectFlockForm = ({
return (
<>
<section className='w-full'>
<section className='w-full h-full sm:w-[446px] overflow-y-auto'>
{/* Header */}
<DrawerHeader
leftIcon={formType == 'add' ? 'mdi:close' : 'mdi:arrow-left'}
leftIconSize={24}
leftIcon={
formType == 'add' ? 'heroicons:chevron-left' : 'mdi:arrow-left'
}
leftIconHref={
formType == 'add'
? '/production/project-flock'
: `/production/project-flock/detail?projectFlockId=${initialValues?.id}`
}
leftIconClassName='hover:text-gray-400'
subtitle={formType == 'add' ? 'Add Flock' : 'Update Flock'}
subtitleClassName='text-sm text-neutral'
showDivider
subtitle={formType == 'add' ? 'Add List Flock' : 'Update Flock'}
className='sticky top-0 z-10 bg-base-100'
>
{formType == 'edit' && (
<Button
type='button'
variant='ghost'
color='none'
onClick={() => {
if (initialValues?.id) {
deleteModal.openModal();
}
}}
variant='link'
className='p-0 text-error'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={20}
height={20}
className='justify-start text-sm'
/>
<Icon icon='heroicons:trash' width={20} height={20} />
</Button>
)}
{formType == 'add' && (
<Button
type='button'
variant='ghost'
color='none'
onClick={() => {
router.push('/production/project-flock');
}}
className='p-0 text-error'
>
<Icon icon='heroicons:trash' width={20} height={20} />
</Button>
)}
</DrawerHeader>
@@ -719,145 +730,147 @@ const ProjectFlockForm = ({
onReset={formik.handleReset}
>
{/* Form Informasi Umum */}
<div className='divider mt-3'></div>
<div className='flex flex-col gap-4 px-4'>
<h2 className='text-2xl font-semibold'>Informasi Umum</h2>
<div className='flex flex-col gap-4'>
<SelectInput
required
label='Area'
value={formik.values.area as OptionType}
onChange={areaChangeHandler}
options={optionsArea}
isLoading={isLoadingAreas}
isError={
formik.touched.area_id && Boolean(formik.errors.area_id)
}
errorMessage={formik.errors.area_id as string}
onInputChange={setInputValueArea}
onMenuScrollToBottom={loadMoreArea}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Lokasi'
value={formik.values.location as OptionType}
onChange={locationChangeHandler}
options={
selectedArea != '' || initialValues?.area?.id
? optionsLocation
: []
}
isLoading={isLoadingLocations}
isError={
formik.touched.location_id &&
Boolean(formik.errors.location_id)
}
onInputChange={setInputValueLocation}
onMenuScrollToBottom={loadMoreLocation}
errorMessage={formik.errors.location_id as string}
isClearable
isDisabled={formType != 'add' || disabledLocation}
/>
<SelectInput
required
label='Flock'
value={
formik.values.flock_name
? ({
label: formik.values.flock_name,
value: optionsFlock.find((flock) => {
return flock.label === formik.values.flock_name;
})?.value,
} as OptionType)
: undefined
}
onChange={(val) => {
optionChangeHandler(val, 'flock');
setSelectedFlock((val as OptionType)?.label);
formik.setFieldValue(
'flock_name',
(val as OptionType)?.label
);
}}
options={optionsFlock}
onInputChange={setInputValueFlock}
onMenuScrollToBottom={loadMoreFlock}
isLoading={isLoadingFlocks}
isError={
formik.touched.flock_name && Boolean(formik.errors.flock_name)
}
errorMessage={formik.errors.flock_name as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='FCR'
value={formik.values.fcr as OptionType}
onChange={(val) => {
optionChangeHandler(val, 'fcr');
}}
onInputChange={setInputValueFcr}
onMenuScrollToBottom={loadMoreFcr}
options={optionsFcr}
isLoading={isLoadingFcrs}
isError={formik.touched.fcr_id && Boolean(formik.errors.fcr_id)}
errorMessage={formik.errors.fcr_id as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Kategori'
value={formik.values.category_option as OptionType}
onChange={categoryChangeHandler}
options={FLOCK_CATEGORY_OPTIONS}
isError={
formik.touched.category && Boolean(formik.errors.category)
}
errorMessage={formik.errors.category as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Standar Produksi'
value={formik.values.production_standard as OptionType}
onChange={(val) => {
optionChangeHandler(val, 'production_standard');
}}
onInputChange={setInputValueProductionStandard}
onMenuScrollToBottom={loadMoreProductionStandard}
options={optionsProductionStandards}
isLoading={isLoadingProductionStandards}
isError={
formik.touched.production_standard_id &&
Boolean(formik.errors.production_standard_id)
}
errorMessage={formik.errors.production_standard_id as string}
isClearable
isDisabled={formType != 'add'}
/>
<NumberInput
name='period'
label='Periode'
disabled
readOnly
placeholder='Period'
value={selectedLocation ? inputPeriod : ''}
/>
</div>
<div className='flex flex-col p-4'>
<h2 className='text-base font-medium text-base-content/50 font-roboto'>
Informasi Umum
</h2>
<SelectInput
required
label='Area'
placeholder='Pilih Area'
value={formik.values.area as OptionType}
onChange={areaChangeHandler}
options={optionsArea}
isLoading={isLoadingAreas}
isError={formik.touched.area_id && Boolean(formik.errors.area_id)}
errorMessage={formik.errors.area_id as string}
onInputChange={setInputValueArea}
onMenuScrollToBottom={loadMoreArea}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Lokasi'
placeholder='Pilih Lokasi'
value={formik.values.location as OptionType}
onChange={locationChangeHandler}
options={
selectedArea != '' || initialValues?.area?.id
? optionsLocation
: []
}
isLoading={isLoadingLocations}
isError={
formik.touched.location_id && Boolean(formik.errors.location_id)
}
onInputChange={setInputValueLocation}
onMenuScrollToBottom={loadMoreLocation}
errorMessage={formik.errors.location_id as string}
isClearable
isDisabled={formType != 'add' || disabledLocation}
/>
<SelectInput
required
label='Flock'
placeholder='Pilih Flock'
value={
formik.values.flock_name
? ({
label: formik.values.flock_name,
value: optionsFlock.find((flock) => {
return flock.label === formik.values.flock_name;
})?.value,
} as OptionType)
: undefined
}
onChange={(val) => {
optionChangeHandler(val, 'flock');
setSelectedFlock((val as OptionType)?.label);
formik.setFieldValue('flock_name', (val as OptionType)?.label);
}}
options={optionsFlock}
onInputChange={setInputValueFlock}
onMenuScrollToBottom={loadMoreFlock}
isLoading={isLoadingFlocks}
isError={
formik.touched.flock_name && Boolean(formik.errors.flock_name)
}
errorMessage={formik.errors.flock_name as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='FCR'
placeholder='Pilih FCR'
value={formik.values.fcr as OptionType}
onChange={(val) => {
optionChangeHandler(val, 'fcr');
}}
onInputChange={setInputValueFcr}
onMenuScrollToBottom={loadMoreFcr}
options={optionsFcr}
isLoading={isLoadingFcrs}
isError={formik.touched.fcr_id && Boolean(formik.errors.fcr_id)}
errorMessage={formik.errors.fcr_id as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Kategori'
placeholder='Pilih Kategori'
value={formik.values.category_option as OptionType}
onChange={categoryChangeHandler}
options={FLOCK_CATEGORY_OPTIONS}
isError={
formik.touched.category && Boolean(formik.errors.category)
}
errorMessage={formik.errors.category as string}
isClearable
isDisabled={formType != 'add'}
/>
<SelectInput
required
label='Standar Produksi'
placeholder='Pilih Standar Produksi'
value={formik.values.production_standard as OptionType}
onChange={(val) => {
optionChangeHandler(val, 'production_standard');
}}
onInputChange={setInputValueProductionStandard}
onMenuScrollToBottom={loadMoreProductionStandard}
options={optionsProductionStandards}
isLoading={isLoadingProductionStandards}
isError={
formik.touched.production_standard_id &&
Boolean(formik.errors.production_standard_id)
}
errorMessage={formik.errors.production_standard_id as string}
isClearable
isDisabled={formType != 'add'}
/>
<NumberInput
name='period'
label='Periode'
disabled
readOnly
placeholder='Periode Flock'
value={selectedLocation ? inputPeriod : ''}
/>
</div>
{/* Form Pilih Kandang */}
<div className='divider'></div>
<div className='flex flex-col gap-4 px-4 pb-4'>
<h2 className='text-2xl font-semibold'>Pilih Kandang</h2>
<div className='flex flex-col gap-3 p-4 border-y border-base-content/10'>
<h2 className='text-base font-medium text-base-content/50 font-roboto'>
Informasi Kandang
</h2>
<div className='overflow-x-auto duration-300 ease-in-out'>
{isLoadingKandang && (
<span className='loading loading-dots loading-xl'></span>
<span className='loading loading-dots loading-xl block mx-auto' />
)}
<ProjectFlockKandangTable
listPeriods={
@@ -874,207 +887,236 @@ const ProjectFlockForm = ({
</div>
{/* Card Estimasi Budget */}
<div className='divider'></div>
<div className='flex flex-col gap-4 px-4 pb-4'>
<h2 className='text-2xl font-semibold'>
Estimasi Anggaran Per Flock
</h2>
<div className='flex flex-col p-4'>
<div className='flex flex-col gap-4'>
{formik.values.project_budgets &&
formik.values.project_budgets.length > 0 ? (
formik.values.project_budgets.map((budget, index) => (
<Card
key={index}
variant='bordered'
className={{
wrapper: 'w-full',
body: 'p-3',
}}
>
<div className='flex flex-col gap-2'>
<div className='flex flex-row justify-between items-center mb-2'>
<div className='text-lg'>Anggaran ke-{index + 1}</div>
<Button
type='button'
color='error'
onClick={() =>
onDeleteBudgetRowHandler(
budget.nonstock_id as number,
<div key={index} className='flex flex-col'>
{/* <div className='flex flex-row justify-between items-center mb-2'>
<Button
type='button'
color='error'
onClick={() =>
onDeleteBudgetRowHandler(
budget.nonstock_id as number,
index
)
}
>
<Icon icon='mdi:trash' width={16} height={16} />
</Button>
</div> */}
<div className='flex flex-row justify-between items-center'>
<h2 className='text-base font-medium text-base-content/50 font-roboto'>
Estimasi Anggaran Per Flock
</h2>
<Button
type='button'
variant='ghost'
color='none'
onClick={() =>
onDeleteBudgetRowHandler(
budget.nonstock_id as number,
index
)
}
className='p-0 text-error'
>
<Icon icon='heroicons:trash' width={20} height={20} />
</Button>
</div>
<div className='flex flex-row justify-between items-center'>
<SelectInput
isClearable
label='Jenis Produk'
options={filteredNonStockOptions ?? []}
isLoading={isLoadingNonstocks}
placeholder='Pilih Jenis Produk'
value={formik.values.project_budgets[index].nonstock}
onInputChange={setInputValueNonstock}
onMenuScrollToBottom={loadMoreNonstock}
onChange={(val) => {
const updatedBudgets = [
...formik.values.project_budgets,
];
updatedBudgets[index].nonstock = val as OptionType;
updatedBudgets[index].nonstock_id =
(val as OptionType) ? (val as OptionType).value : 0;
formik.setFieldValue(
'project_budgets',
updatedBudgets
);
formik.setFieldTouched(
`project_budgets[${index}].nonstock_id`,
true
);
}}
errorMessage={
(
formik.errors.project_budgets?.[
index
)
}
>
<Icon icon='mdi:trash' width={16} height={16} />
</Button>
</div>
<div className='flex flex-row justify-between items-center'>
<SelectInput
isClearable
options={filteredNonStockOptions ?? []}
isLoading={isLoadingNonstocks}
placeholder='Pilih barang non stock'
value={formik.values.project_budgets[index].nonstock}
onInputChange={setInputValueNonstock}
onMenuScrollToBottom={loadMoreNonstock}
onChange={(val) => {
const updatedBudgets = [
...formik.values.project_budgets,
];
updatedBudgets[index].nonstock = val as OptionType;
updatedBudgets[index].nonstock_id =
(val as OptionType)
? (val as OptionType).value
: 0;
formik.setFieldValue(
'project_budgets',
updatedBudgets
);
formik.setFieldTouched(
`project_budgets[${index}].nonstock_id`,
true
);
}}
errorMessage={
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.nonstock_id as string
}
isError={
formik.touched.project_budgets?.[index]
?.nonstock_id &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.nonstock_id as string
}
isError={
formik.touched.project_budgets?.[index]
?.nonstock_id &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.nonstock_id as string
)
}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].qty`}
placeholder='Masukkan jumlah'
value={formik.values.project_budgets[index].qty}
onChange={(e) =>
handleBudgetChange(index, 'qty', e.target.value)
}
onBlur={formik.handleBlur}
allowNegative={false}
endAdornment={
<div className='text-gray-500'>
)
}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].qty`}
label='Jumlah Pembelian'
placeholder='Masukkan Jumlah Pembelian'
value={formik.values.project_budgets[index].qty}
onChange={(e) =>
handleBudgetChange(index, 'qty', e.target.value)
}
onBlur={formik.handleBlur}
allowNegative={false}
inputPrefix={
<div className='w-full h-full py-1 flex flex-row items-stretch justify-between gap-3'>
<span className='text-sm text-base-content/60 self-center text-nowrap truncate'>
{isResponseSuccess(nonstocks)
? (nonstocks.data.find(
(ns) => ns.id === budget.nonstock_id
)?.uom?.name ?? '')
: ''}
</div>
}
errorMessage={
</span>
<div className='w-px bg-base-content/10' />
</div>
}
errorMessage={
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.qty as string
}
isError={
formik.touched.project_budgets?.[index]?.qty &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.qty as string
}
isError={
formik.touched.project_budgets?.[index]?.qty &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.qty as string
)
}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].price`}
value={formik.values.project_budgets[index].price}
onChange={(e) =>
handleBudgetChange(index, 'price', e.target.value)
}
onBlur={formik.handleBlur}
placeholder='Masukkan harga satuan'
allowNegative={false}
startAdornment='Rp'
endAdornment={
<div className='text-gray-500'>
{`Per ${
isResponseSuccess(nonstocks)
? (nonstocks.data.find(
(ns) => ns.id === budget.nonstock_id
)?.uom?.name ?? 'Item')
: 'Item'
}`}
</div>
}
errorMessage={
)
}
className={{
inputPrefix:
'py-0 px-0 pl-3 text-base-content/50 bg-transparent border-r-0',
inputWrapper: 'border-l-0 pl-5',
}}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].price`}
label='Harga Satuan (Rp)'
value={formik.values.project_budgets[index].price}
onChange={(e) =>
handleBudgetChange(index, 'price', e.target.value)
}
onBlur={formik.handleBlur}
placeholder='Masukkan Harga Satuan (Rp)'
allowNegative={false}
inputPrefix={
<div className='w-full h-full py-1 flex flex-row items-stretch justify-between gap-3'>
<span className='text-sm text-base-content/60 self-center text-nowrap truncate'>
Rp
</span>
<div className='w-px bg-base-content/10' />
</div>
}
errorMessage={
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.price as string
}
isError={
formik.touched.project_budgets?.[index]?.price &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.price as string
}
isError={
formik.touched.project_budgets?.[index]?.price &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.price as string
)
}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].total_price`}
value={
formik.values.project_budgets[index].total_price
}
onChange={(e) =>
handleBudgetChange(
index,
'total_price',
e.target.value
)
}
onBlur={formik.handleBlur}
placeholder='Masukkan harga total'
allowNegative={false}
startAdornment='Rp'
endAdornment={
<div className='text-gray-500'>Total</div>
}
errorMessage={
)
}
className={{
inputPrefix:
'py-0 px-0 pl-3 text-base-content/50 bg-transparent border-r-0',
inputWrapper: 'border-l-0 pl-5',
}}
/>
</div>
<div className='flex flex-row justify-between items-center'>
<NumberInput
name={`project_budgets[${index}].total_price`}
label='Total Harga'
value={formik.values.project_budgets[index].total_price}
onChange={(e) =>
handleBudgetChange(
index,
'total_price',
e.target.value
)
}
onBlur={formik.handleBlur}
placeholder='Masukkan Total Harga'
allowNegative={false}
inputPrefix={
<div className='w-full h-full py-1 flex flex-row items-stretch justify-between gap-3'>
<span className='text-sm text-base-content/60 self-center text-nowrap truncate'>
Rp
</span>
<div className='w-px bg-base-content/10' />
</div>
}
errorMessage={
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.total_price as string
}
isError={
formik.touched.project_budgets?.[index]
?.total_price &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.total_price as string
}
isError={
formik.touched.project_budgets?.[index]
?.total_price &&
Boolean(
(
formik.errors.project_budgets?.[
index
] as FormikErrors<ProjectFlockBudgetsSchemaType>
)?.total_price as string
)
}
/>
</div>
)
}
className={{
inputPrefix:
'py-0 px-0 pl-3 text-base-content/50 bg-transparent border-r-0',
inputWrapper: 'border-l-0 pl-5',
}}
/>
</div>
</Card>
</div>
))
) : (
<div className='text-center py-4 text-gray-400'>
@@ -1093,7 +1135,9 @@ const ProjectFlockForm = ({
</div>
</div>
<AlertErrorList formErrorList={formErrorList} onClose={close} />
<div className='p-4'>
<AlertErrorList formErrorList={formErrorList} onClose={close} />
</div>
<div className='flex flex-row justify-center gap-2 flex-wrap my-6 px-4'>
{formType !== 'detail' && (
@@ -1133,6 +1177,9 @@ const ProjectFlockForm = ({
isLoading: isDeleteLoading,
onClick: confirmationModalDeleteClickHandler,
}}
className={{
modal: 'w-full sm:w-[446px]',
}}
/>
</>
);