base create order

This commit is contained in:
hamid zarghami
2026-06-23 10:12:56 +03:30
parent 6975e2d0b0
commit 223b1b5e8f
15 changed files with 1205 additions and 2 deletions
@@ -0,0 +1,191 @@
import { type FC, useMemo, useState } from 'react'
import type { FormikProps } from 'formik'
import { Add, Minus, Trash } from 'iconsax-react'
import Input from '@/components/Input'
import type { Food } from '@/pages/food/types/Types'
import { formatFaNumber, 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
onUpdateQuantity: (foodId: string, quantity: number) => void
onRemoveItem: (foodId: string) => void
}
const CreateOrderItemsSection: FC<CreateOrderItemsSectionProps> = ({
formik,
foods,
onAddFood,
onUpdateQuantity,
onRemoveItem,
}) => {
const [search, setSearch] = useState('')
const foodsMap = useMemo(
() => new Map(foods.map((food) => [food.id, food])),
[foods]
)
const filteredFoods = useMemo(() => {
const query = search.trim().toLowerCase()
if (!query) return foods
return foods.filter((food) => food.title.toLowerCase().includes(query))
}, [foods, search])
const selectedItems = formik.values.items
.map((item) => {
const food = foodsMap.get(item.foodId)
if (!food) return null
return { ...item, food }
})
.filter(Boolean)
return (
<div className='w-full bg-white rounded-4xl p-8'>
<div className='text-lg font-light'>آیتمهای سفارش</div>
<div className='mt-6 border border-border rounded-xl p-4'>
<Input
variant='search'
className='bg-[#EEF0F7]'
placeholder='جستجوی غذا...'
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className='mt-3 space-y-2 max-h-56 overflow-y-auto'>
{filteredFoods.length === 0 ? (
<div className='text-center py-6 text-xs text-description'>
غذایی یافت نشد
</div>
) : (
filteredFoods.map((food) => {
const inCart = formik.values.items.some(
(item) => item.foodId === food.id
)
return (
<div
key={food.id}
className='flex items-center gap-3 p-2 rounded-xl hover:bg-[#F8F9FC] transition-colors'
>
{food.images?.[0] ? (
<img
src={food.images[0]}
alt={food.title}
className='w-11 h-11 rounded-lg object-cover flex-shrink-0'
/>
) : (
<div className='w-11 h-11 rounded-lg bg-gray-100 flex-shrink-0' />
)}
<div className='flex-1 min-w-0'>
<div className='text-sm truncate'>{food.title}</div>
<div className='text-xs text-description mt-0.5'>
{formatPrice(getFoodUnitPrice(food))}
</div>
</div>
<button
type='button'
onClick={() => onAddFood(food.id)}
className={`flex items-center gap-1 px-3 h-8 rounded-lg text-xs transition-colors ${
inCart
? 'bg-primary/10 text-primary'
: 'bg-primary text-white'
}`}
>
<Add size={14} color={inCart ? '#000' : '#fff'} />
{inCart ? 'افزودن' : 'انتخاب'}
</button>
</div>
)
})
)}
</div>
</div>
<div className='mt-6'>
<div className='text-sm mb-3'>سبد سفارش</div>
{selectedItems.length === 0 ? (
<div className='border border-dashed border-border rounded-xl py-10 text-center text-xs text-description'>
هنوز آیتمی انتخاب نشده است
</div>
) : (
<div className='space-y-3'>
{selectedItems.map((item) => {
if (!item) return null
const unitPrice = getFoodUnitPrice(item.food)
return (
<div
key={item.foodId}
className='flex items-center gap-3 p-3 border border-border rounded-xl'
>
{item.food.images?.[0] ? (
<img
src={item.food.images[0]}
alt={item.food.title}
className='w-12 h-12 rounded-lg object-cover flex-shrink-0'
/>
) : (
<div className='w-12 h-12 rounded-lg bg-gray-100 flex-shrink-0' />
)}
<div className='flex-1 min-w-0'>
<div className='text-sm truncate'>{item.food.title}</div>
<div className='text-xs text-description mt-1'>
{formatPrice(unitPrice)}
</div>
</div>
<div className='flex items-center gap-2'>
<button
type='button'
onClick={() =>
onUpdateQuantity(item.foodId, item.quantity - 1)
}
className='w-8 h-8 rounded-lg border border-border flex items-center justify-center'
>
<Minus size={14} color='#000' />
</button>
<span className='w-6 text-center text-sm'>
{formatFaNumber(item.quantity)}
</span>
<button
type='button'
onClick={() =>
onUpdateQuantity(item.foodId, item.quantity + 1)
}
className='w-8 h-8 rounded-lg border border-border flex items-center justify-center'
>
<Add size={14} color='#000' />
</button>
</div>
<div className='text-sm font-medium min-w-[90px] text-left'>
{formatPrice(unitPrice * item.quantity)}
</div>
<button
type='button'
onClick={() => onRemoveItem(item.foodId)}
className='text-red-500 p-1'
>
<Trash size={18} color='#EF4444' />
</button>
</div>
)
})}
</div>
)}
{formik.touched.items && formik.errors.items && typeof formik.errors.items === 'string' && (
<div className='text-xs text-red-500 mt-2'>{formik.errors.items}</div>
)}
</div>
</div>
)
}
export default CreateOrderItemsSection