efril #7

Merged
aefril merged 23 commits from efril into main 2025-09-12 21:12:53 +00:00
3 changed files with 70 additions and 27 deletions
Showing only changes of commit fab31f1540 - Show all commits

View File

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

View File

@ -11,8 +11,6 @@ import Typography from '@mui/material/Typography'
// Third-party Imports
import PerfectScrollbar from 'react-perfect-scrollbar'
// Type Imports
// Component Imports
import CustomTextField from '@core/components/mui/TextField'
import { Autocomplete } from '@mui/material'
@ -25,6 +23,7 @@ import { useOutlets } from '../../../../../services/queries/outlets'
import { Product } from '../../../../../types/services/product'
import { ProductRecipeRequest } from '../../../../../types/services/productRecipe'
import { resetProductVariant } from '../../../../../redux-store/slices/productRecipe'
import { IngredientItem } from '@/types/services/ingredient'
type Props = {
open: boolean
@ -38,7 +37,8 @@ const initialData = {
product_id: '',
variant_id: '',
ingredient_id: '',
quantity: 0
quantity: 0,
waste: 0
}
const AddRecipeDrawer = (props: Props) => {
@ -55,23 +55,45 @@ const AddRecipeDrawer = (props: Props) => {
const [ingredientDebouncedInput] = useDebounce(ingredientInput, 500)
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({
search: outletDebouncedInput
})
// Modifikasi query ingredients dengan enabled condition
const { data: ingredients, isLoading: ingredientsLoading } = useIngredients({
search: ingredientDebouncedInput
})
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()
useEffect(() => {
if (currentProductRecipe.id) {
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) => {
e.preventDefault()
@ -101,24 +123,16 @@ const AddRecipeDrawer = (props: Props) => {
handleClose()
dispatch(resetProductVariant())
setFormData(initialData)
}
const handleInputChange = (e: any) => {
setFormData({
...formData,
[e.target.name]: e.target.value
})
setSelectedIngredient(null) // Reset selected ingredient
setIngredientInput('') // Reset input
}
const setTitleDrawer = (recipe: any) => {
const addOrEdit = currentProductRecipe.id ? 'Edit ' : 'Add '
let title = 'Original'
if (recipe?.name) {
title = recipe?.name
}
return addOrEdit + title
}
@ -144,13 +158,14 @@ const AddRecipeDrawer = (props: Props) => {
<Typography color='text.primary' className='font-medium'>
Basic Information
</Typography>
<Autocomplete
options={outletOptions}
loading={outletsLoading}
getOptionLabel={option => option.name}
value={outletOptions.find(p => p.id === formData.outlet_id) || null}
onInputChange={(event, newOutlettInput) => {
setOutletInput(newOutlettInput)
onInputChange={(event, newOutletInput) => {
setOutletInput(newOutletInput)
}}
onChange={(event, newValue) => {
setFormData({
@ -161,7 +176,6 @@ const AddRecipeDrawer = (props: Props) => {
renderInput={params => (
<CustomTextField
{...params}
className=''
label='Outlet'
fullWidth
InputProps={{
@ -171,24 +185,35 @@ const AddRecipeDrawer = (props: Props) => {
/>
)}
/>
{/* Perbaiki Autocomplete untuk Ingredients */}
<Autocomplete
options={ingredientOptions || []}
loading={ingredientsLoading}
getOptionLabel={option => option.name}
value={ingredientOptions?.find(p => p.id === formData.ingredient_id) || null}
value={selectedIngredient}
onInputChange={(event, newIngredientInput) => {
setIngredientInput(newIngredientInput)
}}
onChange={(event, newValue) => {
setSelectedIngredient(newValue) // Set selected ingredient
setFormData({
...formData,
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 => (
<CustomTextField
{...params}
className=''
label='Ingredient'
fullWidth
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
type='number'
label='Quantity'
@ -205,6 +242,15 @@ const AddRecipeDrawer = (props: Props) => {
value={formData.quantity}
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'>
<Button
variant='contained'

View File

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