2025-08-06 03:57:45 +07:00
|
|
|
// React Imports
|
|
|
|
|
import { useMemo, useState } from 'react'
|
|
|
|
|
|
|
|
|
|
// MUI Imports
|
|
|
|
|
import Button from '@mui/material/Button'
|
|
|
|
|
import Divider from '@mui/material/Divider'
|
|
|
|
|
import Drawer from '@mui/material/Drawer'
|
|
|
|
|
import IconButton from '@mui/material/IconButton'
|
|
|
|
|
import Typography from '@mui/material/Typography'
|
|
|
|
|
|
|
|
|
|
// Third-party Imports
|
|
|
|
|
|
|
|
|
|
// Type Imports
|
|
|
|
|
|
|
|
|
|
// Components Imports
|
|
|
|
|
import CustomTextField from '@core/components/mui/TextField'
|
|
|
|
|
import { Autocomplete, CircularProgress } from '@mui/material'
|
|
|
|
|
import { useDebounce } from 'use-debounce'
|
2025-08-07 14:31:42 +07:00
|
|
|
import { useInventoriesMutation } from '../../../../../services/mutations/inventories'
|
|
|
|
|
import { useOutlets } from '../../../../../services/queries/outlets'
|
|
|
|
|
import { useProducts } from '../../../../../services/queries/products'
|
|
|
|
|
import { InventoryAdjustRequest } from '../../../../../types/services/inventory'
|
2025-08-06 03:57:45 +07:00
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
|
open: boolean
|
|
|
|
|
handleClose: () => void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AdjustmentStockDrawer = (props: Props) => {
|
|
|
|
|
// Props
|
|
|
|
|
const { open, handleClose } = props
|
|
|
|
|
|
2025-08-06 14:41:23 +07:00
|
|
|
const { mutate: adjustInventory, isPending: isCreating } = useInventoriesMutation().adjustInventory
|
2025-08-06 03:57:45 +07:00
|
|
|
|
|
|
|
|
// States
|
|
|
|
|
const [productInput, setProductInput] = useState('')
|
|
|
|
|
const [productDebouncedInput] = useDebounce(productInput, 500) // debounce for better UX
|
|
|
|
|
const [outletInput, setOutletInput] = useState('')
|
|
|
|
|
const [outletDebouncedInput] = useDebounce(outletInput, 500) // debounce for better UX
|
|
|
|
|
const [formData, setFormData] = useState<InventoryAdjustRequest>({
|
|
|
|
|
product_id: '',
|
|
|
|
|
outlet_id: '',
|
|
|
|
|
delta: 0,
|
|
|
|
|
reason: ''
|
|
|
|
|
})
|
|
|
|
|
|
2025-08-06 14:41:23 +07:00
|
|
|
const { data: outlets, isLoading: outletsLoading } = useOutlets({
|
2025-08-06 03:57:45 +07:00
|
|
|
search: outletDebouncedInput
|
|
|
|
|
})
|
2025-08-06 14:41:23 +07:00
|
|
|
const { data: products, isLoading } = useProducts({
|
2025-08-06 03:57:45 +07:00
|
|
|
search: productDebouncedInput
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const outletOptions = useMemo(() => outlets?.outlets || [], [outlets])
|
|
|
|
|
const options = useMemo(() => products?.products || [], [products])
|
|
|
|
|
|
|
|
|
|
// Handle Form Submit
|
|
|
|
|
const handleFormSubmit = (e: any) => {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
|
|
|
|
|
adjustInventory(
|
|
|
|
|
{ ...formData, delta: Number(formData.delta) },
|
|
|
|
|
{
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
handleReset()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleInputChange = (e: any) => {
|
|
|
|
|
setFormData({
|
|
|
|
|
...formData,
|
|
|
|
|
[e.target.name]: e.target.value
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle Form Reset
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
handleClose()
|
|
|
|
|
setFormData({
|
|
|
|
|
product_id: '',
|
|
|
|
|
outlet_id: '',
|
|
|
|
|
delta: 0,
|
|
|
|
|
reason: ''
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Drawer
|
|
|
|
|
open={open}
|
|
|
|
|
anchor='right'
|
|
|
|
|
variant='temporary'
|
|
|
|
|
onClose={handleReset}
|
|
|
|
|
ModalProps={{ keepMounted: true }}
|
|
|
|
|
sx={{ '& .MuiDrawer-paper': { width: { xs: 300, sm: 400 } } }}
|
|
|
|
|
>
|
|
|
|
|
<div className='flex items-center justify-between pli-6 plb-5'>
|
|
|
|
|
<Typography variant='h5'>Adjust Inventory</Typography>
|
|
|
|
|
<IconButton size='small' onClick={handleReset}>
|
|
|
|
|
<i className='tabler-x text-textSecondary text-2xl' />
|
|
|
|
|
</IconButton>
|
|
|
|
|
</div>
|
|
|
|
|
<Divider />
|
|
|
|
|
<div className='p-6'>
|
|
|
|
|
<form onSubmit={handleFormSubmit} className='flex flex-col gap-5'>
|
|
|
|
|
<Autocomplete
|
|
|
|
|
options={outletOptions}
|
|
|
|
|
loading={outletsLoading}
|
|
|
|
|
getOptionLabel={option => option.name}
|
|
|
|
|
value={outletOptions.find(p => p.id === formData.outlet_id) || null}
|
|
|
|
|
onInputChange={(event, newOutlettInput) => {
|
|
|
|
|
setOutletInput(newOutlettInput)
|
|
|
|
|
}}
|
|
|
|
|
onChange={(event, newValue) => {
|
|
|
|
|
setFormData({
|
|
|
|
|
...formData,
|
|
|
|
|
outlet_id: newValue?.id || ''
|
|
|
|
|
})
|
|
|
|
|
}}
|
|
|
|
|
renderInput={params => (
|
|
|
|
|
<CustomTextField
|
|
|
|
|
{...params}
|
|
|
|
|
className=''
|
|
|
|
|
label='Outlet'
|
|
|
|
|
fullWidth
|
|
|
|
|
InputProps={{
|
|
|
|
|
...params.InputProps,
|
|
|
|
|
endAdornment: (
|
|
|
|
|
<>
|
|
|
|
|
{outletsLoading && <CircularProgress size={18} />}
|
|
|
|
|
{params.InputProps.endAdornment}
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<Autocomplete
|
|
|
|
|
options={options}
|
|
|
|
|
loading={isLoading}
|
|
|
|
|
getOptionLabel={option => option.name}
|
|
|
|
|
value={options.find(p => p.id === formData.product_id) || null}
|
|
|
|
|
onInputChange={(event, newProductInput) => {
|
|
|
|
|
setProductInput(newProductInput)
|
|
|
|
|
}}
|
|
|
|
|
onChange={(event, newValue) => {
|
|
|
|
|
setFormData({
|
|
|
|
|
...formData,
|
|
|
|
|
product_id: newValue?.id || ''
|
|
|
|
|
})
|
|
|
|
|
}}
|
|
|
|
|
renderInput={params => (
|
|
|
|
|
<CustomTextField
|
|
|
|
|
{...params}
|
|
|
|
|
className=''
|
|
|
|
|
label='Product'
|
|
|
|
|
fullWidth
|
|
|
|
|
InputProps={{
|
|
|
|
|
...params.InputProps,
|
|
|
|
|
endAdornment: (
|
|
|
|
|
<>
|
|
|
|
|
{isLoading && <CircularProgress size={18} />}
|
|
|
|
|
{params.InputProps.endAdornment}
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<CustomTextField
|
|
|
|
|
fullWidth
|
|
|
|
|
label='Delta'
|
|
|
|
|
name='delta'
|
|
|
|
|
value={formData.delta}
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
placeholder='0'
|
|
|
|
|
/>
|
|
|
|
|
<CustomTextField
|
|
|
|
|
fullWidth
|
|
|
|
|
label='Reason'
|
|
|
|
|
value={formData.reason}
|
|
|
|
|
name='reason'
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
multiline
|
|
|
|
|
rows={4}
|
|
|
|
|
placeholder='Write a Comment...'
|
|
|
|
|
/>
|
|
|
|
|
<div className='flex items-center gap-4'>
|
|
|
|
|
<Button variant='contained' type='submit' disabled={isCreating}>
|
|
|
|
|
{isCreating ? 'Adjusting...' : 'Adjust'}
|
|
|
|
|
</Button>
|
|
|
|
|
<Button variant='tonal' color='error' type='reset' onClick={handleReset}>
|
|
|
|
|
Discard
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</Drawer>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default AdjustmentStockDrawer
|