152 lines
6.9 KiB
TypeScript
152 lines
6.9 KiB
TypeScript
import { type FC, useMemo, useState } from 'react'
|
||
import type { FormikProps } from 'formik'
|
||
import { Add } from 'iconsax-react'
|
||
import Input from '@/components/Input'
|
||
import type { Food } from '@/pages/food/types/Types'
|
||
import { formatPrice } from '@/helpers/func'
|
||
import { getFoodUnitPrice } from '../hooks/useCreateOrderForm'
|
||
import type { CreateOrderFormValues } from '../hooks/useCreateOrderForm'
|
||
|
||
interface CreateOrderItemsSectionProps {
|
||
formik: FormikProps<CreateOrderFormValues>
|
||
foods: Food[]
|
||
onAddFood: (foodId: string) => void
|
||
}
|
||
|
||
const CreateOrderItemsSection: FC<CreateOrderItemsSectionProps> = ({
|
||
formik,
|
||
foods,
|
||
onAddFood,
|
||
}) => {
|
||
const [search, setSearch] = useState('')
|
||
const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null)
|
||
|
||
const categories = useMemo(() => {
|
||
const categoryMap = new Map<string, string>()
|
||
foods.forEach((food) => {
|
||
if (food.category?.id) {
|
||
categoryMap.set(food.category.id, food.category.title)
|
||
}
|
||
})
|
||
return Array.from(categoryMap.entries())
|
||
.map(([id, title]) => ({ id, title }))
|
||
.sort((a, b) => a.title.localeCompare(b.title, 'fa'))
|
||
}, [foods])
|
||
|
||
const filteredFoods = useMemo(() => {
|
||
let result = foods
|
||
if (selectedCategoryId) {
|
||
result = result.filter((food) => food.category?.id === selectedCategoryId)
|
||
}
|
||
const query = search.trim().toLowerCase()
|
||
if (query) {
|
||
result = result.filter((food) => food.title.toLowerCase().includes(query))
|
||
}
|
||
return result
|
||
}, [foods, search, selectedCategoryId])
|
||
|
||
return (
|
||
<div className='w-full h-full bg-white rounded-4xl p-5 flex flex-col min-h-0'>
|
||
<div className='text-sm font-light flex-shrink-0'>انتخاب غذا</div>
|
||
|
||
<div className='mt-3 flex-1 min-h-0 flex flex-col border border-border rounded-xl p-3'>
|
||
<Input
|
||
variant='search'
|
||
className='bg-[#EEF0F7]'
|
||
placeholder='جستجوی غذا...'
|
||
value={search}
|
||
onChange={(e) => setSearch(e.target.value)}
|
||
/>
|
||
|
||
{categories.length > 0 && (
|
||
<div className='mt-2 flex gap-1.5 overflow-x-auto flex-shrink-0 pb-0.5'>
|
||
<button
|
||
type='button'
|
||
onClick={() => setSelectedCategoryId(null)}
|
||
className={`flex-shrink-0 px-2.5 h-7 rounded-full text-[11px] transition-colors ${
|
||
selectedCategoryId === null
|
||
? 'bg-primary text-white'
|
||
: 'bg-[#EEF0F7] text-description hover:bg-[#E4E7F0]'
|
||
}`}
|
||
>
|
||
همه
|
||
</button>
|
||
{categories.map((category) => (
|
||
<button
|
||
key={category.id}
|
||
type='button'
|
||
onClick={() => setSelectedCategoryId(category.id)}
|
||
className={`flex-shrink-0 px-2.5 h-7 rounded-full text-[11px] transition-colors whitespace-nowrap ${
|
||
selectedCategoryId === category.id
|
||
? 'bg-primary text-white'
|
||
: 'bg-[#EEF0F7] text-description hover:bg-[#E4E7F0]'
|
||
}`}
|
||
>
|
||
{category.title}
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
|
||
<div className='mt-2 flex-1 min-h-0 overflow-y-auto space-y-1'>
|
||
{filteredFoods.length === 0 ? (
|
||
<div className='text-center py-8 text-xs text-description'>
|
||
غذایی یافت نشد
|
||
</div>
|
||
) : (
|
||
filteredFoods.map((food) => {
|
||
const inCart = formik.values.items.some(
|
||
(item) => item.foodId === food.id
|
||
)
|
||
const cartQty = formik.values.items.find(
|
||
(item) => item.foodId === food.id
|
||
)?.quantity
|
||
|
||
return (
|
||
<div
|
||
key={food.id}
|
||
className='flex items-center gap-2 p-1.5 rounded-lg hover:bg-[#F8F9FC] transition-colors'
|
||
>
|
||
{food.images?.[0] ? (
|
||
<img
|
||
src={food.images[0]}
|
||
alt={food.title}
|
||
className='w-9 h-9 rounded-lg object-cover flex-shrink-0'
|
||
/>
|
||
) : (
|
||
<div className='w-9 h-9 rounded-lg bg-gray-100 flex-shrink-0' />
|
||
)}
|
||
<div className='flex-1 min-w-0'>
|
||
<div className='text-xs truncate'>{food.title}</div>
|
||
<div className='text-[11px] text-description'>
|
||
{formatPrice(getFoodUnitPrice(food))}
|
||
</div>
|
||
</div>
|
||
<button
|
||
type='button'
|
||
onClick={() => onAddFood(food.id)}
|
||
className={`flex items-center gap-1 px-2.5 h-7 rounded-lg text-[11px] transition-colors flex-shrink-0 ${
|
||
inCart
|
||
? 'bg-primary/10 text-primary'
|
||
: 'bg-primary text-white'
|
||
}`}
|
||
>
|
||
<Add size={12} color={inCart ? '#000' : '#fff'} />
|
||
{inCart ? `×${cartQty}` : 'انتخاب'}
|
||
</button>
|
||
</div>
|
||
)
|
||
})
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{formik.touched.items && formik.errors.items && typeof formik.errors.items === 'string' && (
|
||
<div className='text-xs text-red-500 mt-2 flex-shrink-0'>{formik.errors.items}</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default CreateOrderItemsSection
|