pos-dashboard-v2/src/views/apps/account/AccountFormDrawer.tsx

309 lines
8.8 KiB
TypeScript
Raw Normal View History

2025-09-11 00:16:00 +07:00
// React Imports
import { useState, useEffect } from 'react'
// MUI Imports
import Button from '@mui/material/Button'
import Drawer from '@mui/material/Drawer'
import IconButton from '@mui/material/IconButton'
import MenuItem from '@mui/material/MenuItem'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
// Third-party Imports
import { useForm, Controller } from 'react-hook-form'
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
import CustomAutocomplete from '@/@core/components/mui/Autocomplete'
// Account Type
export type AccountType = {
id: number
code: string
name: string
category: string
balance: string
}
type Props = {
open: boolean
handleClose: () => void
accountData?: AccountType[]
setData: (data: AccountType[]) => void
editingAccount?: AccountType | null
}
type FormValidateType = {
name: string
code: string
category: string
parentAccount?: string
}
// Categories available for accounts
const accountCategories = [
'Kas & Bank',
'Piutang',
'Persediaan',
'Aset Tetap',
'Hutang',
'Ekuitas',
'Pendapatan',
'Beban'
]
// Parent accounts (dummy data for dropdown)
const parentAccounts = [
{ id: 1, code: '1-10001', name: 'Kas' },
{ id: 2, code: '1-10002', name: 'Bank BCA' },
{ id: 3, code: '1-10003', name: 'Bank Mandiri' },
{ id: 4, code: '1-10101', name: 'Piutang Usaha' },
{ id: 5, code: '1-10201', name: 'Persediaan Barang' },
{ id: 6, code: '2-20001', name: 'Hutang Usaha' },
{ id: 7, code: '3-30001', name: 'Modal Pemilik' },
{ id: 8, code: '4-40001', name: 'Penjualan' },
{ id: 9, code: '5-50001', name: 'Beban Gaji' }
]
// Vars
const initialData = {
name: '',
code: '',
category: '',
parentAccount: ''
}
const AccountFormDrawer = (props: Props) => {
// Props
const { open, handleClose, accountData, setData, editingAccount } = props
// Determine if we're editing
const isEdit = !!editingAccount
// Hooks
const {
control,
reset: resetForm,
handleSubmit,
formState: { errors }
} = useForm<FormValidateType>({
defaultValues: initialData
})
// Reset form when editingAccount changes or drawer opens
useEffect(() => {
if (open) {
if (editingAccount) {
// Populate form with existing data
resetForm({
name: editingAccount.name,
code: editingAccount.code,
category: editingAccount.category,
parentAccount: ''
})
} else {
// Reset to initial data for new account
resetForm(initialData)
}
}
}, [editingAccount, open, resetForm])
const onSubmit = (data: FormValidateType) => {
if (isEdit && editingAccount) {
// Update existing account
const updatedAccounts =
accountData?.map(account =>
account.id === editingAccount.id
? {
...account,
code: data.code,
name: data.name,
category: data.category
}
: account
) || []
setData(updatedAccounts)
} else {
// Create new account
const newAccount: AccountType = {
id: accountData?.length ? Math.max(...accountData.map(a => a.id)) + 1 : 1,
code: data.code,
name: data.name,
category: data.category,
balance: '0'
}
setData([...(accountData ?? []), newAccount])
}
handleClose()
resetForm(initialData)
}
const handleReset = () => {
handleClose()
resetForm(initialData)
}
return (
<Drawer
open={open}
anchor='right'
variant='temporary'
onClose={handleReset}
ModalProps={{ keepMounted: true }}
sx={{
'& .MuiDrawer-paper': {
width: { xs: 300, sm: 400 },
display: 'flex',
flexDirection: 'column',
height: '100%'
}
}}
>
{/* Sticky Header */}
<Box
sx={{
position: 'sticky',
top: 0,
zIndex: 10,
backgroundColor: 'background.paper',
borderBottom: 1,
borderColor: 'divider'
}}
>
<div className='flex items-center justify-between plb-5 pli-6'>
<Typography variant='h5'>{isEdit ? 'Edit Akun' : 'Tambah Akun Baru'}</Typography>
<IconButton size='small' onClick={handleReset}>
<i className='tabler-x text-2xl text-textPrimary' />
</IconButton>
</div>
</Box>
{/* Scrollable Content */}
<Box sx={{ flex: 1, overflowY: 'auto' }}>
<form id='account-form' onSubmit={handleSubmit(data => onSubmit(data))}>
<div className='flex flex-col gap-6 p-6'>
{/* Nama */}
<div>
<Typography variant='body2' className='mb-2'>
Nama <span className='text-red-500'>*</span>
</Typography>
<Controller
name='name'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder='Nama'
{...(errors.name && { error: true, helperText: 'Field ini wajib diisi.' })}
/>
)}
/>
</div>
{/* Kode */}
<div>
<Typography variant='body2' className='mb-2'>
Kode <span className='text-red-500'>*</span>
</Typography>
<Controller
name='code'
control={control}
rules={{ required: true }}
render={({ field }) => (
<CustomTextField
{...field}
fullWidth
placeholder='Kode'
{...(errors.code && { error: true, helperText: 'Field ini wajib diisi.' })}
/>
)}
/>
</div>
{/* Kategori */}
<div>
<Typography variant='body2' className='mb-2'>
Kategori <span className='text-red-500'>*</span>
</Typography>
<Controller
name='category'
control={control}
rules={{ required: true }}
render={({ field: { onChange, value, ...field } }) => (
<CustomAutocomplete
{...field}
options={accountCategories}
value={value || null}
onChange={(_, newValue) => onChange(newValue || '')}
renderInput={params => (
<CustomTextField
{...params}
placeholder='Pilih kategori'
{...(errors.category && { error: true, helperText: 'Field ini wajib diisi.' })}
/>
)}
isOptionEqualToValue={(option, value) => option === value}
/>
)}
/>
</div>
{/* Sub Akun dari */}
<div>
<Typography variant='body2' className='mb-2'>
Sub Akun dari
</Typography>
<Controller
name='parentAccount'
control={control}
render={({ field: { onChange, value, ...field } }) => (
<CustomAutocomplete
{...field}
options={parentAccounts}
value={parentAccounts.find(account => `${account.code} ${account.name}` === value) || null}
onChange={(_, newValue) => onChange(newValue ? `${newValue.code} ${newValue.name}` : '')}
getOptionLabel={option => `${option.code} ${option.name}`}
renderInput={params => <CustomTextField {...params} placeholder='Pilih akun' />}
isOptionEqualToValue={(option, value) =>
`${option.code} ${option.name}` === `${value.code} ${value.name}`
}
/>
)}
/>
</div>
</div>
</form>
</Box>
{/* Sticky Footer */}
<Box
sx={{
position: 'sticky',
bottom: 0,
zIndex: 10,
backgroundColor: 'background.paper',
borderTop: 1,
borderColor: 'divider',
p: 3
}}
>
<div className='flex items-center gap-4'>
<Button variant='contained' type='submit' form='account-form'>
{isEdit ? 'Update' : 'Simpan'}
</Button>
<Button variant='tonal' color='error' onClick={() => handleReset()}>
Batal
</Button>
</div>
</Box>
</Drawer>
)
}
export default AccountFormDrawer