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