Expense Add
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { Button, Typography } from '@mui/material'
|
||||
import {
|
||||
Button,
|
||||
Typography,
|
||||
IconButton,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Paper
|
||||
} from '@mui/material'
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import CustomAutocomplete from '@/@core/components/mui/Autocomplete'
|
||||
import CustomTextField from '@/@core/components/mui/TextField'
|
||||
@@ -53,195 +64,160 @@ const PurchaseIngredientsTable: React.FC<PurchaseIngredientsTableProps> = ({
|
||||
]
|
||||
|
||||
return (
|
||||
<Grid size={12} sx={{ mt: 4 }}>
|
||||
<Grid size={{ xs: 12 }} sx={{ mt: 4 }}>
|
||||
<Typography variant='h6' sx={{ mb: 2, fontWeight: 600 }}>
|
||||
Bahan Baku / Ingredients
|
||||
</Typography>
|
||||
|
||||
{/* Table Header */}
|
||||
<Grid container spacing={1} sx={{ mb: 2, px: 1 }}>
|
||||
<Grid size={1.8}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Bahan Baku
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1.8}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Deskripsi
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Kuantitas
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Satuan
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Discount
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Harga
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Pajak
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Waste
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<Typography variant='subtitle2' fontWeight={600}>
|
||||
Total
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={0.6}></Grid>
|
||||
</Grid>
|
||||
<TableContainer component={Paper} variant='outlined'>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow sx={{ backgroundColor: 'grey.50' }}>
|
||||
<TableCell sx={{ fontWeight: 'bold', minWidth: 180 }}>Bahan Baku</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', minWidth: 150 }}>Deskripsi</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 100 }}>Kuantitas</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>Satuan</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 100 }}>Discount</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>Harga</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>Pajak</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>Waste</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold', width: 100, textAlign: 'right' }}>Total</TableCell>
|
||||
<TableCell sx={{ width: 50 }}></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{formData.ingredientItems.map((item: IngredientItem, index: number) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={ingredientOptions}
|
||||
value={item.ingredient}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'ingredient', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='Pilih Bahan Baku' />}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
value={item.deskripsi}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'deskripsi', e.target.value)
|
||||
}
|
||||
placeholder='Deskripsi'
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
type='number'
|
||||
value={item.kuantitas}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'kuantitas', parseInt(e.target.value) || 1)
|
||||
}
|
||||
inputProps={{ min: 1 }}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={satuanOptions}
|
||||
value={item.satuan}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'satuan', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='Pilih...' />}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
value={item.discount}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'discount', e.target.value)
|
||||
}
|
||||
placeholder='0%'
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
type='number'
|
||||
value={item.harga === 0 ? '' : item.harga?.toString() || ''}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
|
||||
{/* Ingredient Items */}
|
||||
{formData.ingredientItems.map((item: IngredientItem, index: number) => (
|
||||
<Grid container spacing={1} key={item.id} sx={{ mb: 2, alignItems: 'center' }}>
|
||||
<Grid size={1.8}>
|
||||
<CustomAutocomplete
|
||||
fullWidth
|
||||
size='small'
|
||||
options={ingredientOptions}
|
||||
value={item.ingredient}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'ingredient', newValue)}
|
||||
renderInput={params => (
|
||||
<CustomTextField {...params} placeholder='Pilih Bahan Baku' size='small' fullWidth />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1.8}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
value={item.deskripsi}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'deskripsi', e.target.value)
|
||||
}
|
||||
placeholder='Deskripsi'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
type='number'
|
||||
value={item.kuantitas}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'kuantitas', parseInt(e.target.value) || 1)
|
||||
}
|
||||
inputProps={{ min: 1 }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<CustomAutocomplete
|
||||
fullWidth
|
||||
size='small'
|
||||
options={satuanOptions}
|
||||
value={item.satuan}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'satuan', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='Pilih...' size='small' fullWidth />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
value={item.discount}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleIngredientChange(index, 'discount', e.target.value)
|
||||
}
|
||||
placeholder='0%'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
type='number'
|
||||
value={item.harga === 0 ? '' : item.harga?.toString() || ''} // Ubah ini: 0 jadi empty string
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
if (value === '') {
|
||||
handleIngredientChange(index, 'harga', null)
|
||||
return
|
||||
}
|
||||
|
||||
if (value === '') {
|
||||
// Jika kosong, set ke null atau undefined, bukan 0
|
||||
handleIngredientChange(index, 'harga', null) // atau undefined
|
||||
return
|
||||
}
|
||||
|
||||
const numericValue = parseFloat(value)
|
||||
handleIngredientChange(index, 'harga', isNaN(numericValue) ? 0 : numericValue)
|
||||
}}
|
||||
inputProps={{ min: 0, step: 'any' }}
|
||||
placeholder='0'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<CustomAutocomplete
|
||||
fullWidth
|
||||
size='small'
|
||||
options={pajakOptions}
|
||||
value={item.pajak}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'pajak', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='...' size='small' fullWidth />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1.2}>
|
||||
<CustomAutocomplete
|
||||
fullWidth
|
||||
size='small'
|
||||
options={wasteOptions}
|
||||
value={item.waste}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'waste', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='...' size='small' fullWidth />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<CustomTextField fullWidth size='small' value={item.total} InputProps={{ readOnly: true }} />
|
||||
</Grid>
|
||||
<Grid size={0.6}>
|
||||
<Button
|
||||
variant='outlined'
|
||||
color='error'
|
||||
size='small'
|
||||
onClick={() => removeIngredientItem(index)}
|
||||
sx={{ minWidth: 'auto', p: 1 }}
|
||||
>
|
||||
<i className='tabler-trash' />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
))}
|
||||
const numericValue = parseFloat(value)
|
||||
handleIngredientChange(index, 'harga', isNaN(numericValue) ? 0 : numericValue)
|
||||
}}
|
||||
inputProps={{ min: 0, step: 'any' }}
|
||||
placeholder='0'
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={pajakOptions}
|
||||
value={item.pajak}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'pajak', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='...' />}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={wasteOptions}
|
||||
value={item.waste}
|
||||
onChange={(event, newValue) => handleIngredientChange(index, 'waste', newValue)}
|
||||
renderInput={params => <CustomTextField {...params} placeholder='...' />}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<CustomTextField
|
||||
fullWidth
|
||||
size='small'
|
||||
value={item.total}
|
||||
InputProps={{ readOnly: true }}
|
||||
sx={{
|
||||
'& .MuiInputBase-input': {
|
||||
textAlign: 'right'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
size='small'
|
||||
color='error'
|
||||
onClick={() => removeIngredientItem(index)}
|
||||
disabled={formData.ingredientItems.length === 1}
|
||||
>
|
||||
<i className='tabler-trash' />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
{/* Add New Item Button */}
|
||||
<Grid container spacing={1}>
|
||||
<Grid size={12}>
|
||||
<Button
|
||||
variant='outlined'
|
||||
onClick={addIngredientItem}
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
color: 'primary.main',
|
||||
borderColor: 'primary.main'
|
||||
}}
|
||||
>
|
||||
+ Tambah bahan baku
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Button
|
||||
startIcon={<i className='tabler-plus' />}
|
||||
onClick={addIngredientItem}
|
||||
variant='outlined'
|
||||
size='small'
|
||||
sx={{ mt: 1 }}
|
||||
>
|
||||
Tambah bahan baku
|
||||
</Button>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -464,64 +464,75 @@ const PurchaseSummary: React.FC<PurchaseSummaryProps> = ({ formData, handleInput
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{/* Dropdown */}
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={[{ label: '1-10003 Gi...', value: '1-10003' }]}
|
||||
getOptionLabel={option => (typeof option === 'string' ? option : option.label)}
|
||||
value={{ label: '1-10003 Gi...', value: '1-10003' }}
|
||||
onChange={(_, newValue) => {
|
||||
// Handle change if needed
|
||||
}}
|
||||
renderInput={params => <CustomTextField {...params} size='small' />}
|
||||
sx={{ minWidth: 120 }}
|
||||
/>
|
||||
<Button
|
||||
variant='text'
|
||||
color='primary'
|
||||
size='small'
|
||||
sx={{ textTransform: 'none', fontSize: '14px', p: 0, textAlign: 'left' }}
|
||||
onClick={() => handleInputChange('showUangMuka', !formData.showUangMuka)}
|
||||
>
|
||||
{formData.showUangMuka ? '- Sembunyikan Uang Muka' : '+ Uang Muka'}
|
||||
</Button>
|
||||
{formData.showUangMuka && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{/* Dropdown */}
|
||||
<CustomAutocomplete
|
||||
size='small'
|
||||
options={[{ label: '1-10003 Gi...', value: '1-10003' }]}
|
||||
getOptionLabel={option => (typeof option === 'string' ? option : option.label)}
|
||||
value={{ label: '1-10003 Gi...', value: '1-10003' }}
|
||||
onChange={(_, newValue) => {
|
||||
// Handle change if needed
|
||||
}}
|
||||
renderInput={params => <CustomTextField {...params} size='small' />}
|
||||
sx={{ minWidth: 120 }}
|
||||
/>
|
||||
|
||||
{/* Amount input */}
|
||||
<CustomTextField
|
||||
size='small'
|
||||
placeholder='0'
|
||||
value={formData.downPayment || '0'}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleInputChange('downPayment', e.target.value)
|
||||
}
|
||||
sx={{ width: '80px' }}
|
||||
inputProps={{
|
||||
style: { textAlign: 'center' }
|
||||
}}
|
||||
/>
|
||||
{/* Amount input */}
|
||||
<CustomTextField
|
||||
size='small'
|
||||
placeholder='0'
|
||||
value={formData.downPayment || '0'}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
handleInputChange('downPayment', e.target.value)
|
||||
}
|
||||
sx={{ width: '80px' }}
|
||||
inputProps={{
|
||||
style: { textAlign: 'center' }
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Percentage/Fixed toggle */}
|
||||
<ToggleButtonGroup
|
||||
value={formData.downPaymentType || 'fixed'}
|
||||
exclusive
|
||||
onChange={(_, newValue) => {
|
||||
if (newValue) handleInputChange('downPaymentType', newValue)
|
||||
{/* Percentage/Fixed toggle */}
|
||||
<ToggleButtonGroup
|
||||
value={formData.downPaymentType || 'fixed'}
|
||||
exclusive
|
||||
onChange={(_, newValue) => {
|
||||
if (newValue) handleInputChange('downPaymentType', newValue)
|
||||
}}
|
||||
size='small'
|
||||
>
|
||||
<ToggleButton value='percentage' sx={{ px: 1.5 }}>
|
||||
%
|
||||
</ToggleButton>
|
||||
<ToggleButton value='fixed' sx={{ px: 1.5 }}>
|
||||
Rp
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</Box>
|
||||
|
||||
{/* Right side text */}
|
||||
<Typography
|
||||
variant='body1'
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
fontWeight: 400
|
||||
}}
|
||||
size='small'
|
||||
>
|
||||
<ToggleButton value='percentage' sx={{ px: 1.5 }}>
|
||||
%
|
||||
</ToggleButton>
|
||||
<ToggleButton value='fixed' sx={{ px: 1.5 }}>
|
||||
Rp
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
Uang muka {downPayment > 0 ? downPayment.toLocaleString('id-ID') : '0'}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Right side text */}
|
||||
<Typography
|
||||
variant='body1'
|
||||
sx={{
|
||||
fontSize: '16px',
|
||||
fontWeight: 400
|
||||
}}
|
||||
>
|
||||
Uang muka {downPayment > 0 ? downPayment.toLocaleString('id-ID') : '0'}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Sisa Tagihan */}
|
||||
|
||||
Reference in New Issue
Block a user