Add Waste at Product Recipe

This commit is contained in:
efrilm 2025-09-13 04:08:49 +07:00
parent aa2946e627
commit fab31f1540
3 changed files with 70 additions and 27 deletions

View File

@ -42,6 +42,7 @@ export interface ProductRecipe {
variant_id: string | null variant_id: string | null
ingredient_id: string ingredient_id: string
quantity: number quantity: number
waste: number
created_at: string created_at: string
updated_at: string updated_at: string
product: Product product: Product
@ -54,6 +55,7 @@ export interface ProductRecipeRequest {
ingredient_id: string ingredient_id: string
quantity: number quantity: number
outlet_id: string | null outlet_id: string | null
waste: number
} }
export interface IngredientUnit { export interface IngredientUnit {

View File

@ -11,8 +11,6 @@ import Typography from '@mui/material/Typography'
// Third-party Imports // Third-party Imports
import PerfectScrollbar from 'react-perfect-scrollbar' import PerfectScrollbar from 'react-perfect-scrollbar'
// Type Imports
// Component Imports // Component Imports
import CustomTextField from '@core/components/mui/TextField' import CustomTextField from '@core/components/mui/TextField'
import { Autocomplete } from '@mui/material' import { Autocomplete } from '@mui/material'
@ -25,6 +23,7 @@ import { useOutlets } from '../../../../../services/queries/outlets'
import { Product } from '../../../../../types/services/product' import { Product } from '../../../../../types/services/product'
import { ProductRecipeRequest } from '../../../../../types/services/productRecipe' import { ProductRecipeRequest } from '../../../../../types/services/productRecipe'
import { resetProductVariant } from '../../../../../redux-store/slices/productRecipe' import { resetProductVariant } from '../../../../../redux-store/slices/productRecipe'
import { IngredientItem } from '@/types/services/ingredient'
type Props = { type Props = {
open: boolean open: boolean
@ -38,7 +37,8 @@ const initialData = {
product_id: '', product_id: '',
variant_id: '', variant_id: '',
ingredient_id: '', ingredient_id: '',
quantity: 0 quantity: 0,
waste: 0
} }
const AddRecipeDrawer = (props: Props) => { const AddRecipeDrawer = (props: Props) => {
@ -55,23 +55,45 @@ const AddRecipeDrawer = (props: Props) => {
const [ingredientDebouncedInput] = useDebounce(ingredientInput, 500) const [ingredientDebouncedInput] = useDebounce(ingredientInput, 500)
const [formData, setFormData] = useState<ProductRecipeRequest>(initialData) const [formData, setFormData] = useState<ProductRecipeRequest>(initialData)
// Add state untuk menyimpan selected ingredient
const [selectedIngredient, setSelectedIngredient] = useState<IngredientItem | null>(null)
const { data: outlets, isLoading: outletsLoading } = useOutlets({ const { data: outlets, isLoading: outletsLoading } = useOutlets({
search: outletDebouncedInput search: outletDebouncedInput
}) })
// Modifikasi query ingredients dengan enabled condition
const { data: ingredients, isLoading: ingredientsLoading } = useIngredients({ const { data: ingredients, isLoading: ingredientsLoading } = useIngredients({
search: ingredientDebouncedInput search: ingredientDebouncedInput
}) })
const outletOptions = useMemo(() => outlets?.outlets || [], [outlets]) const outletOptions = useMemo(() => outlets?.outlets || [], [outlets])
const ingredientOptions = useMemo(() => ingredients?.data || [], [ingredients])
// Perbaiki ingredient options untuk include selected ingredient
const ingredientOptions = useMemo(() => {
const options = ingredients?.data || []
// Jika ada selected ingredient dan tidak ada di current options, tambahkan
if (selectedIngredient && !options.find(opt => opt.id === selectedIngredient.id)) {
return [selectedIngredient, ...options]
}
return options
}, [ingredients, selectedIngredient])
const { createProductRecipe, updateProductRecipe } = useProductRecipesMutation() const { createProductRecipe, updateProductRecipe } = useProductRecipesMutation()
useEffect(() => { useEffect(() => {
if (currentProductRecipe.id) { if (currentProductRecipe.id) {
setFormData(currentProductRecipe) setFormData(currentProductRecipe)
// Set selected ingredient dari current product recipe
const currentIngredient = ingredients?.data?.find(ing => ing.id === currentProductRecipe.ingredient_id)
if (currentIngredient) {
setSelectedIngredient(currentIngredient)
} }
}, [currentProductRecipe]) }
}, [currentProductRecipe, ingredients])
const handleSubmit = (e: any) => { const handleSubmit = (e: any) => {
e.preventDefault() e.preventDefault()
@ -101,24 +123,16 @@ const AddRecipeDrawer = (props: Props) => {
handleClose() handleClose()
dispatch(resetProductVariant()) dispatch(resetProductVariant())
setFormData(initialData) setFormData(initialData)
} setSelectedIngredient(null) // Reset selected ingredient
setIngredientInput('') // Reset input
const handleInputChange = (e: any) => {
setFormData({
...formData,
[e.target.name]: e.target.value
})
} }
const setTitleDrawer = (recipe: any) => { const setTitleDrawer = (recipe: any) => {
const addOrEdit = currentProductRecipe.id ? 'Edit ' : 'Add ' const addOrEdit = currentProductRecipe.id ? 'Edit ' : 'Add '
let title = 'Original' let title = 'Original'
if (recipe?.name) { if (recipe?.name) {
title = recipe?.name title = recipe?.name
} }
return addOrEdit + title return addOrEdit + title
} }
@ -144,13 +158,14 @@ const AddRecipeDrawer = (props: Props) => {
<Typography color='text.primary' className='font-medium'> <Typography color='text.primary' className='font-medium'>
Basic Information Basic Information
</Typography> </Typography>
<Autocomplete <Autocomplete
options={outletOptions} options={outletOptions}
loading={outletsLoading} loading={outletsLoading}
getOptionLabel={option => option.name} getOptionLabel={option => option.name}
value={outletOptions.find(p => p.id === formData.outlet_id) || null} value={outletOptions.find(p => p.id === formData.outlet_id) || null}
onInputChange={(event, newOutlettInput) => { onInputChange={(event, newOutletInput) => {
setOutletInput(newOutlettInput) setOutletInput(newOutletInput)
}} }}
onChange={(event, newValue) => { onChange={(event, newValue) => {
setFormData({ setFormData({
@ -161,7 +176,6 @@ const AddRecipeDrawer = (props: Props) => {
renderInput={params => ( renderInput={params => (
<CustomTextField <CustomTextField
{...params} {...params}
className=''
label='Outlet' label='Outlet'
fullWidth fullWidth
InputProps={{ InputProps={{
@ -171,24 +185,35 @@ const AddRecipeDrawer = (props: Props) => {
/> />
)} )}
/> />
{/* Perbaiki Autocomplete untuk Ingredients */}
<Autocomplete <Autocomplete
options={ingredientOptions || []} options={ingredientOptions || []}
loading={ingredientsLoading} loading={ingredientsLoading}
getOptionLabel={option => option.name} getOptionLabel={option => option.name}
value={ingredientOptions?.find(p => p.id === formData.ingredient_id) || null} value={selectedIngredient}
onInputChange={(event, newIngredientInput) => { onInputChange={(event, newIngredientInput) => {
setIngredientInput(newIngredientInput) setIngredientInput(newIngredientInput)
}} }}
onChange={(event, newValue) => { onChange={(event, newValue) => {
setSelectedIngredient(newValue) // Set selected ingredient
setFormData({ setFormData({
...formData, ...formData,
ingredient_id: newValue?.id || '' ingredient_id: newValue?.id || ''
}) })
// Clear input search setelah selection
if (newValue) {
setIngredientInput('')
}
}} }}
// Tambahkan props untuk mencegah clear on blur
clearOnBlur={false}
// Handle case ketika input kosong tapi ada selected value
inputValue={selectedIngredient ? selectedIngredient.name : ingredientInput}
renderInput={params => ( renderInput={params => (
<CustomTextField <CustomTextField
{...params} {...params}
className=''
label='Ingredient' label='Ingredient'
fullWidth fullWidth
InputProps={{ InputProps={{
@ -198,6 +223,18 @@ const AddRecipeDrawer = (props: Props) => {
/> />
)} )}
/> />
{/* Unit Field - Disabled, value from selected ingredient */}
<CustomTextField
label='Unit'
fullWidth
disabled
value={selectedIngredient?.unit?.name || ''}
InputProps={{
readOnly: true
}}
/>
<CustomTextField <CustomTextField
type='number' type='number'
label='Quantity' label='Quantity'
@ -205,6 +242,15 @@ const AddRecipeDrawer = (props: Props) => {
value={formData.quantity} value={formData.quantity}
onChange={e => setFormData({ ...formData, quantity: Number(e.target.value) })} onChange={e => setFormData({ ...formData, quantity: Number(e.target.value) })}
/> />
<CustomTextField
type='number'
label='Waste'
fullWidth
value={formData.waste}
onChange={e => setFormData({ ...formData, waste: Number(e.target.value) })}
/>
<div className='flex items-center gap-4'> <div className='flex items-center gap-4'>
<Button <Button
variant='contained' variant='contained'

View File

@ -161,7 +161,7 @@ const ProductDetail = () => {
<TableCell className='font-semibold text-center'> <TableCell className='font-semibold text-center'>
<div className='flex items-center justify-center gap-2'> <div className='flex items-center justify-center gap-2'>
<i className='tabler-package text-blue-600' /> <i className='tabler-package text-blue-600' />
Stock Available Waste
</div> </div>
</TableCell> </TableCell>
<TableCell className='font-semibold text-right'> <TableCell className='font-semibold text-right'>
@ -197,12 +197,7 @@ const ProductDetail = () => {
</TableCell> </TableCell>
<TableCell className='text-center'>{formatCurrency(item.ingredient.cost)}</TableCell> <TableCell className='text-center'>{formatCurrency(item.ingredient.cost)}</TableCell>
<TableCell className='text-center'> <TableCell className='text-center'>
<Chip <Chip label={item.waste ?? 0} size='small' color={'success'} variant='outlined' />
label={item.ingredient.stock}
size='small'
color={item.ingredient.stock > 5 ? 'success' : 'warning'}
variant='outlined'
/>
</TableCell> </TableCell>
<TableCell className='text-right font-medium'> <TableCell className='text-right font-medium'>
{formatCurrency(item.ingredient.cost * item.quantity)} {formatCurrency(item.ingredient.cost * item.quantity)}