From 588cbe00f358df1c74bcd72348ea5f2cb7804884 Mon Sep 17 00:00:00 2001 From: shafi54 <108669266+shafi-aviz@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:08:00 +0530 Subject: [PATCH] enh --- .commandcode/taste/taste.md | 4 + .../manage-orders/orders/index_old.tsx | 801 ------------------ .../app/(drawer)/products/add_old.tsx | 82 -- .../src/components/ProductForm_old.tsx | 262 ------ 4 files changed, 4 insertions(+), 1145 deletions(-) create mode 100644 .commandcode/taste/taste.md delete mode 100644 apps/admin-ui/app/(drawer)/manage-orders/orders/index_old.tsx delete mode 100644 apps/admin-ui/app/(drawer)/products/add_old.tsx delete mode 100644 apps/admin-ui/src/components/ProductForm_old.tsx diff --git a/.commandcode/taste/taste.md b/.commandcode/taste/taste.md new file mode 100644 index 0000000..f562cac --- /dev/null +++ b/.commandcode/taste/taste.md @@ -0,0 +1,4 @@ +# Taste (Continuously Learned by [CommandCode][cmd]) + +[cmd]: https://commandcode.ai/ + diff --git a/apps/admin-ui/app/(drawer)/manage-orders/orders/index_old.tsx b/apps/admin-ui/app/(drawer)/manage-orders/orders/index_old.tsx deleted file mode 100644 index fd17855..0000000 --- a/apps/admin-ui/app/(drawer)/manage-orders/orders/index_old.tsx +++ /dev/null @@ -1,801 +0,0 @@ -import React, { useState , useEffect } from 'react'; -import { View, TouchableOpacity, Alert, TextInput, ActivityIndicator, Linking } from 'react-native'; -import { AppContainer, MyText, tw, MyFlatList, BottomDialog, BottomDropdown, Checkbox, theme, MyTextInput } from 'common-ui'; -import { trpc } from '@/src/trpc-client'; -import { useRouter, useLocalSearchParams } from 'expo-router'; -import dayjs from 'dayjs'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { Entypo } from '@expo/vector-icons'; -import CancelOrderDialog from '@/components/CancelOrderDialog'; -import { OrderOptionsMenu } from '@/components/OrderOptionsMenu'; -import * as Location from 'expo-location'; - -const AdminNotesForm = ({ orderId, existingNotes, onClose, refetch }: { orderId: string; existingNotes?: string | null; onClose: () => void; refetch: () => void }) => { - const [notesText, setNotesText] = useState(existingNotes || ''); - const updateNotesMutation = trpc.admin.order.updateNotes.useMutation(); - - return ( - - Admin Notes - - - { - updateNotesMutation.mutate( - { orderId: parseInt(orderId), adminNotes: notesText }, - { - onSuccess: () => { - onClose(); - Alert.alert('Success', 'Notes updated successfully'); - refetch(); - }, - onError: (error: any) => { - Alert.alert('Error', error.message || 'Failed to update notes'); - }, - } - ); - }} - > - Save - - - - ); -}; - - -interface OrderType { - id: number; - orderId: string; - readableId: number; - customerName: string | null; - customerMobile?: string | null; - address: string; - addressId: number; - latitude: number | null; - longitude: number | null; - totalAmount: number; - deliveryCharge: number; - items: { - id?: number; - name: string; - quantity: number; - price: number; - amount: number; - unit: string; - isPackaged?: boolean; - isPackageVerified?: boolean; - productSize: number; - }[]; - createdAt: string; - deliveryTime: string | null; - status: 'pending' | 'delivered' | 'cancelled'; - isPackaged: boolean; - isDelivered: boolean; - isCod: boolean; - isFlashDelivery: boolean; - couponCode?: string; - couponDescription?: string; - discountAmount?: number; - adminNotes?: string | null; - userNotes?: string | null; - userNegativityScore?: number; -} - -const OrderItem = ({ order, refetch }: { order: OrderType; refetch: () => void }) => { - const id = order.orderId; - const router = useRouter(); - const [menuOpen, setMenuOpen] = useState(false); - const [itemsDialogOpen, setItemsDialogOpen] = useState(false); - const [notesDialogOpen, setNotesDialogOpen] = useState(false); - const [cancelDialogOpen, setCancelDialogOpen] = useState(false); - const [userNotesDialogOpen, setUserNotesDialogOpen] = useState(false); - const [adminNotesDialogOpen, setAdminNotesDialogOpen] = useState(false); - const [updatingItems, setUpdatingItems] = useState>(new Set()); - - const updatePackagedMutation = trpc.admin.order.updatePackaged.useMutation(); - const updateDeliveredMutation = trpc.admin.order.updateDelivered.useMutation(); - const updateItemPackagingMutation = trpc.admin.order.updateOrderItemPackaging.useMutation(); - - const handleOrderPress = () => { - router.push(`/manage-orders/order-details/${order.orderId}` as any); - }; - - const handleMenuOption = () => { - setMenuOpen(false); - router.push(`/manage-orders/order-details/${order.orderId}` as any); - }; - - const handleMarkPackaged = (isPackaged: boolean) => { - updatePackagedMutation.mutate( - { orderId: order.orderId.toString(), isPackaged }, - { - onSuccess: () => { - refetch(); - }, - } - ); - }; - - const handleMarkDelivered = (isDelivered: boolean) => { - updateDeliveredMutation.mutate( - { orderId: order.orderId.toString(), isDelivered }, - { - onSuccess: () => { - refetch(); - }, - } - ); - }; - - const handleItemPackagingToggle = (itemId: number, field: 'isPackaged' | 'isPackageVerified', value: boolean) => { - setUpdatingItems(prev => new Set(prev).add(itemId)); - - updateItemPackagingMutation.mutate( - { orderItemId: itemId, [field]: value }, - { - onSuccess: () => { - setUpdatingItems(prev => { - const newSet = new Set(prev); - newSet.delete(itemId); - return newSet; - }); - refetch(); - }, - onError: (error: any) => { - setUpdatingItems(prev => { - const newSet = new Set(prev); - newSet.delete(itemId); - return newSet; - }); - Alert.alert("Error", error.message || "Failed to update packaging status"); - }, - } - ); - }; - - return ( - <> - - {/* Header Section */} - - - - - 0 ? 'text-yellow-600' : 'text-gray-900')}`}> - {order.customerName || order.customerMobile || 'Unknown Customer'} - - - #{order.readableId} - - {order.isFlashDelivery && ( - - - FLASH - - )} - - - - - {dayjs(order.createdAt).format('MMM D, h:mm A')} - - {order.userNegativityScore && order.userNegativityScore > 0 && ( - - - Negative Customer - - )} - - - - setMenuOpen(true)} - style={tw`p-2 -mr-2 -mt-2 rounded-full`} - > - - - - - - {/* Main Content */} - - {/* Status Badges */} - - {/* - {order.status} - */} - {/* {order.isCod && ( - - COD - - )} */} - - Packaged - handleMarkPackaged(!order.isPackaged)} - onPress={() => {}} - size={18} - fillColor={theme.colors.gray500} - checkColor="#FFFFFF" - /> - - - Delivered - handleMarkDelivered(!order.isDelivered)} - size={18} - fillColor="#10B981" - checkColor="#FFFFFF" - /> - - {order.status === 'cancelled' && ( - - CANCELLED - - )} - - - {/* Delivery Info */} - - - - Delivery Address - - {order.address} - - - - - {order.isFlashDelivery ? "1 Hr Delivery:" : "Slot:"} {order.isFlashDelivery ? dayjs(order.createdAt).add(30, 'minutes').format('MMM D, h:mm A') : order.deliveryTime ? dayjs(order.deliveryTime).format("ddd, MMM D • h:mm A") : 'Not scheduled'} - - - {order.isFlashDelivery && ( - - - - 1 Hour Delivery • High Priority - - - )} - - - - {/* Items Summary & Total */} - - - - setItemsDialogOpen(true)} - style={tw`flex-row items-center py-2 px-3 bg-blue-50 rounded-lg flex-1 mr-3`} - > - - - {order.items.length} {order.items.length === 1 ? 'item' : 'items'} - - {order.isFlashDelivery && ( - - - - )} - - - Total: - ₹{order.totalAmount} - - - - - - {/* Coupons */} - {order.couponCode && ( - - Applied Coupons - - - {order.couponCode} - - {order.couponDescription && ( - - {order.couponDescription} - - )} - {order.discountAmount && ( - - Discount: ₹{order.discountAmount} - - )} - - - )} - - {/* Notes Section */} - - {order.userNotes && ( - setUserNotesDialogOpen(true)} - > - - - User Notes - - - )} - {order.adminNotes && ( - setNotesDialogOpen(true)} - > - - - Admin Notes - - - )} - - - {/* Footer / Delivery Charge */} - {order.deliveryCharge > 0 && ( - - - Delivery Charge - ₹{order.deliveryCharge} - - - )} - - - - setMenuOpen(false)} - order={{ - id: order.id, - readableId: order.readableId, - isPackaged: order.isPackaged, - isDelivered: order.isDelivered, - isFlashDelivery: order.isFlashDelivery, - address: order.address, - addressId: order.addressId, - adminNotes: order.adminNotes, - userNotes: order.userNotes, - latitude: order.latitude, - longitude: order.longitude, - status: order.status, - }} - onViewDetails={handleMenuOption} - onTogglePackaged={() => handleMarkPackaged(!order.isPackaged)} - onToggleDelivered={() => handleMarkDelivered(!order.isDelivered)} - onOpenAdminNotes={() => { - setMenuOpen(false); - setNotesDialogOpen(true); - }} - onCancelOrder={() => { - setMenuOpen(false); - setCancelDialogOpen(true); - }} - onAttachLocation={() => refetch()} - onWhatsApp={() => {}} - onDial={() => {}} - /> - - setItemsDialogOpen(false)}> - - - - Order Items - - {order.isFlashDelivery && ( - - - FLASH - - )} - - - Total: ₹{order.totalAmount} - - {order.items.map((item, idx) => ( - - - - {item.quantity * item.productSize } {item.unit} - - - {item.name.length > 30 ? `${item.name.substring(0, 30)}...` : item.name} - - {item.isPackaged !== undefined && item.isPackageVerified !== undefined && ( - <> - - pkg - handleItemPackagingToggle(item.id!, 'isPackaged', !item.isPackaged)} - size={18} - fillColor={updatingItems.has(item.id!) ? "#F59E0B" : "#10B981"} - checkColor="#FFFFFF" - /> - - - verf - handleItemPackagingToggle(item.id!, 'isPackageVerified', !item.isPackageVerified)} - size={18} - fillColor={updatingItems.has(item.id!) ? "#F59E0B" : "#10B981"} - checkColor="#FFFFFF" - /> - - {updatingItems.has(item.id!) && ( - - )} - - )} - - - ))} - - - - setNotesDialogOpen(false)}> - setNotesDialogOpen(false)} refetch={refetch} /> - - - setCancelDialogOpen(false)} - onSuccess={refetch} - /> - - setUserNotesDialogOpen(false)}> - - - User Notes - - - - {order.userNotes} - - - - - - setAdminNotesDialogOpen(false)}> - - - Admin Notes - - - - {order.adminNotes} - - - - - - ); - }; - -export default function Orders() { - const router = useRouter(); - const { filter } = useLocalSearchParams<{ filter?: string }>(); - const [selectedSlot, setSelectedSlot] = useState(null); - const [selectedSlotType, setSelectedSlotType] = useState<'slot' | 'flash' | null>(null); - const [packagedFilter, setPackagedFilter] = useState<'all' | 'packaged' | 'not_packaged'>('all'); - const [packagedChecked, setPackagedChecked] = useState(false); - const [notPackagedChecked, setNotPackagedChecked] = useState(false); - const [deliveredFilter, setDeliveredFilter] = useState<'all' | 'delivered' | 'not_delivered'>('all'); - const [deliveredChecked, setDeliveredChecked] = useState(false); - const [notDeliveredChecked, setNotDeliveredChecked] = useState(false); - const [cancellationFilter, setCancellationFilter] = useState<'all' | 'cancelled' | 'not_cancelled'>('all'); - const [cancelledChecked, setCancelledChecked] = useState(false); - const [notCancelledChecked, setNotCancelledChecked] = useState(false); - const [flashDeliveryFilter, setFlashDeliveryFilter] = useState<'all' | 'flash' | 'regular'>('all'); - const [flashChecked, setFlashChecked] = useState(false); - const [regularChecked, setRegularChecked] = useState(false); - const [filterDialogOpen, setFilterDialogOpen] = useState(false); - - // Handle initial filter from URL params - useEffect(() => { - if (filter === 'flash') { - setSelectedSlotType('flash'); - setFlashDeliveryFilter('flash'); - setFlashChecked(true); - setRegularChecked(false); - } - }, [filter]); - const { data: slotsData } = trpc.admin.slots.getAll.useQuery(); - const { data, isLoading, isFetchingNextPage, fetchNextPage, hasNextPage, refetch } = trpc.admin.order.getAll.useInfiniteQuery( - { - limit: 20, - slotId: selectedSlotType === 'slot' ? selectedSlot : null, - packagedFilter, - deliveredFilter, - cancellationFilter, - flashDeliveryFilter: selectedSlotType === 'flash' ? 'flash' : flashDeliveryFilter - }, - { - getNextPageParam: (lastPage) => lastPage?.nextCursor, - } - ); - - const orders = data?.pages.flatMap(page => page?.orders) || []; - - if (isLoading) { - return ( - - - Loading orders... - - ); - } - - const slotOptions = [ - { label: '⚡ Flash Deliveries', value: 'flash' }, - ...(slotsData?.slots?.map(slot => ({ - label: dayjs(slot.deliveryTime).format('ddd DD MMM, h:mm a'), - value: slot.id.toString(), - })) || []) - ]; - - - return ( - <> - item!.orderId} - renderItem={({ item }) => item ? : null} - onEndReached={() => { - if (hasNextPage && !isFetchingNextPage) { - fetchNextPage(); - } - }} - onEndReachedThreshold={0.5} - onRefresh={() => refetch()} - ListHeaderComponent={ - <> - - - { - if (val === 'flash') { - setSelectedSlotType('flash'); - setSelectedSlot(null); - setFlashDeliveryFilter('flash'); - // Reset other filters when switching to flash - setPackagedFilter('all'); - setPackagedChecked(false); - setNotPackagedChecked(false); - setDeliveredFilter('all'); - setDeliveredChecked(false); - setNotDeliveredChecked(false); - setCancellationFilter('all'); - setCancelledChecked(false); - setNotCancelledChecked(false); - } else { - setSelectedSlotType('slot'); - setSelectedSlot(val ? Number(val) : null); - setFlashDeliveryFilter('all'); - } - }} - placeholder="All slots" - /> - - setFilterDialogOpen(true)} - style={tw`p-2`} - > - - - - {!isLoading && selectedSlotType && ( - - - {selectedSlotType === 'flash' - ? `${orders.length} Flash delivery orders` - : `${orders.length} Orders in slot` - } - - - )} - - } - ListFooterComponent={ - isFetchingNextPage ? ( - - - Loading more... - - ) : null - } - /> - - setFilterDialogOpen(false)}> - - - Packaged Status - - { - const newValue = !packagedChecked; - setPackagedChecked(newValue); - if (newValue && notPackagedChecked) { - setPackagedFilter('all'); - } else if (newValue) { - setPackagedFilter('packaged'); - } else if (notPackagedChecked) { - setPackagedFilter('not_packaged'); - } else { - setPackagedFilter('all'); - } - }} - /> - Packaged - - - { - const newValue = !notPackagedChecked; - setNotPackagedChecked(newValue); - if (packagedChecked && newValue) { - setPackagedFilter('all'); - } else if (newValue) { - setPackagedFilter('not_packaged'); - } else if (packagedChecked) { - setPackagedFilter('packaged'); - } else { - setPackagedFilter('all'); - } - }} - /> - Not Packaged - - - - Delivered Status - - { - const newValue = !deliveredChecked; - setDeliveredChecked(newValue); - if (newValue && notDeliveredChecked) { - setDeliveredFilter('all'); - } else if (newValue) { - setDeliveredFilter('delivered'); - } else if (notDeliveredChecked) { - setDeliveredFilter('not_delivered'); - } else { - setDeliveredFilter('all'); - } - }} - /> - Delivered - - - { - const newValue = !notDeliveredChecked; - setNotDeliveredChecked(newValue); - if (deliveredChecked && newValue) { - setDeliveredFilter('all'); - } else if (newValue) { - setDeliveredFilter('not_delivered'); - } else if (deliveredChecked) { - setDeliveredFilter('delivered'); - } else { - setDeliveredFilter('all'); - } - }} - /> - Not Delivered - - - - Cancellation Status - - { - const newValue = !cancelledChecked; - setCancelledChecked(newValue); - if (newValue && notCancelledChecked) { - setCancellationFilter('all'); - } else if (newValue) { - setCancellationFilter('cancelled'); - } else if (notCancelledChecked) { - setCancellationFilter('not_cancelled'); - } else { - setCancellationFilter('all'); - } - }} - /> - Cancelled - - - { - const newValue = !notCancelledChecked; - setNotCancelledChecked(newValue); - if (cancelledChecked && newValue) { - setCancellationFilter('all'); - } else if (newValue) { - setCancellationFilter('not_cancelled'); - } else if (cancelledChecked) { - setCancellationFilter('cancelled'); - } else { - setCancellationFilter('all'); - } - }} - /> - Not Cancelled - - - - Delivery Type - - { - const newValue = !flashChecked; - setFlashChecked(newValue); - if (newValue && regularChecked) { - setFlashDeliveryFilter('all'); - } else if (newValue) { - setFlashDeliveryFilter('flash'); - } else if (regularChecked) { - setFlashDeliveryFilter('regular'); - } else { - setFlashDeliveryFilter('all'); - } - }} - /> - ⚡ 1 Hr Delivery - - - { - const newValue = !regularChecked; - setRegularChecked(newValue); - if (flashChecked && newValue) { - setFlashDeliveryFilter('all'); - } else if (newValue) { - setFlashDeliveryFilter('regular'); - } else if (flashChecked) { - setFlashDeliveryFilter('flash'); - } else { - setFlashDeliveryFilter('all'); - } - }} - /> - Regular Delivery - - - - - - ); -} diff --git a/apps/admin-ui/app/(drawer)/products/add_old.tsx b/apps/admin-ui/app/(drawer)/products/add_old.tsx deleted file mode 100644 index 33b9a71..0000000 --- a/apps/admin-ui/app/(drawer)/products/add_old.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { Alert } from 'react-native'; -import { AppContainer, ImageUploaderNeoPayload } from 'common-ui'; -import ProductForm from '@/src/components/ProductForm'; -import { trpc } from '@/src/trpc-client'; -import { useUploadToObjectStorage } from '@/hooks/useUploadToObjectStore'; - -export default function AddProduct() { - const createProduct = trpc.admin.product.createProduct.useMutation(); - const { refetch: refetchProducts } = trpc.admin.product.getProducts.useQuery(undefined, { - enabled: false, - }); - const { upload, isUploading } = useUploadToObjectStorage(); - - const handleSubmit = async (values: any, images: ImageUploaderNeoPayload[]) => { - try { - let uploadUrls: string[] = []; - - if (images.length > 0) { - const blobs = await Promise.all( - images.map(async (img) => { - const response = await fetch(img.url); - const blob = await response.blob(); - return { blob, mimeType: img.mimeType || 'image/jpeg' }; - }) - ); - - const result = await upload({ images: blobs, contextString: 'product_info' }); - uploadUrls = result.presignedUrls; - } - - await createProduct.mutateAsync({ - name: values.name, - shortDescription: values.shortDescription, - longDescription: values.longDescription, - unitId: parseInt(values.unitId), - storeId: parseInt(values.storeId), - price: parseFloat(values.price), - marketPrice: values.marketPrice ? parseFloat(values.marketPrice) : undefined, - incrementStep: 1, - productQuantity: values.productQuantity || 1, - isSuspended: values.isSuspended || false, - isFlashAvailable: values.isFlashAvailable || false, - flashPrice: values.flashPrice ? parseFloat(values.flashPrice) : undefined, - uploadUrls, - tagIds: values.tagIds || [], - }); - - await refetchProducts(); - Alert.alert('Success', 'Product created successfully!'); - } catch (error: any) { - Alert.alert('Error', error.message || 'Failed to create product'); - } - }; - - const initialValues = { - name: '', - shortDescription: '', - longDescription: '', - unitId: 0, - price: '', - storeId: 1, - marketPrice: '', - deals: [{ quantity: '', price: '', validTill: new Date() }], - tagIds: [], - isSuspended: false, - isFlashAvailable: false, - flashPrice: '', - productQuantity: 1, - }; - - return ( - - - - ); -} diff --git a/apps/admin-ui/src/components/ProductForm_old.tsx b/apps/admin-ui/src/components/ProductForm_old.tsx deleted file mode 100644 index ac8d4e3..0000000 --- a/apps/admin-ui/src/components/ProductForm_old.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import React, { useState, useEffect, useCallback, forwardRef, useImperativeHandle, useMemo } from 'react'; -import { View, TouchableOpacity } from 'react-native'; -import { Formik, FieldArray } from 'formik'; -import * as Yup from 'yup'; -import { MyTextInput, BottomDropdown, MyText, useTheme, DatePicker, tw, useFocusCallback, Checkbox, ImageUploaderNeo, ImageUploaderNeoItem, ImageUploaderNeoPayload } from 'common-ui'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { trpc } from '../trpc-client'; - -interface ProductFormData { - name: string; - shortDescription: string; - longDescription: string; - unitId: number; - storeId: number; - price: string; - marketPrice: string; - isSuspended: boolean; - isFlashAvailable: boolean; - flashPrice: string; - deals: Deal[]; - tagIds: number[]; - productQuantity: number; -} - -interface Deal { - quantity: string; - price: string; - validTill: Date | null; -} - -export interface ProductFormRef { - clearImages: () => void; -} - -interface ProductFormProps { - mode: 'create' | 'edit'; - initialValues: ProductFormData; - onSubmit: (values: ProductFormData, images: ImageUploaderNeoPayload[], imagesToDelete: string[]) => void; - isLoading: boolean; - existingImages?: ImageUploaderNeoItem[]; - existingImageKeys?: string[]; -} - -const unitOptions = [ - { label: 'Kg', value: 1 }, - { label: 'Litre', value: 2 }, - { label: 'Dozen', value: 3 }, - { label: 'Unit Piece', value: 4 }, -]; - -const ProductForm = forwardRef(({ - mode, - initialValues, - onSubmit, - isLoading, - existingImages:existingImagesRaw, - existingImageKeys = [], -}, ref) => { - const { theme } = useTheme(); - const [images, setImages] = useState([]); - - const existingImages = existingImagesRaw || [] - // Sync images state when existingImages prop changes (e.g., when async query data arrives) - useEffect(() => { - setImages(existingImages); - }, [existingImagesRaw]); - - const { data: storesData } = trpc.common.getStoresSummary.useQuery(); - const storeOptions = storesData?.stores.map(store => ({ - label: store.name, - value: store.id, - })) || []; - - const { data: tagsData } = trpc.admin.product.getProductTags.useQuery(); - const tagOptions = tagsData?.tags.map(tag => ({ - label: tag.tagName, - value: tag.id.toString(), - })) || []; - - // Build signed URL -> S3 key mapping for existing images - const signedUrlToKey = useMemo(() => { - const map: Record = {}; - existingImages.forEach((img, i) => { - if (existingImageKeys[i]) { - map[img.imgUrl] = existingImageKeys[i]; - } - }); - return map; - }, [existingImages, existingImageKeys]); - - return ( - { - // New images have mimeType set, existing images have mimeType === null - const newImages = images.filter(img => img.mimeType !== null); - const deletedImageKeys = existingImages - .filter(existing => !images.some(current => current.imgUrl === existing.imgUrl)) - .map(deleted => signedUrlToKey[deleted.imgUrl]) - .filter(Boolean); - - onSubmit( - values, - newImages.map(img => ({ url: img.imgUrl, mimeType: img.mimeType })), - deletedImageKeys, - ); - }} - enableReinitialize - > - {({ handleChange, handleSubmit, values, setFieldValue, resetForm }) => { - const clearForm = useCallback(() => { - setImages([]); - resetForm(); - }, [resetForm]); - - useFocusCallback(clearForm); - - useImperativeHandle(ref, () => ({ - clearImages: clearForm, - }), [clearForm]); - - const submit = () => handleSubmit(); - - return ( - - - - - - setImages(prev => [...prev, ...payloads.map(p => ({ imgUrl: p.url, mimeType: p.mimeType }))])} - onImageRemove={(payload) => setImages(prev => prev.filter(img => img.imgUrl !== payload.url))} - allowMultiple={true} - /> - - setFieldValue('unitId', value)} - placeholder="Select unit" - style={{ marginBottom: 16 }} - /> - setFieldValue('productQuantity', text)} - style={{ marginBottom: 16 }} - /> - setFieldValue('storeId', value)} - placeholder="Select store" - style={{ marginBottom: 16 }} - /> - id.toString())} - options={tagOptions} - onValueChange={(value) => setFieldValue('tagIds', (value as string[]).map(id => parseInt(id)))} - multiple={true} - placeholder="Select tags" - style={{ marginBottom: 16 }} - /> - - - - - setFieldValue('isSuspended', !values.isSuspended)} - style={tw`mr-3`} - /> - Suspend Product - - - - { - setFieldValue('isFlashAvailable', !values.isFlashAvailable); - if (values.isFlashAvailable) setFieldValue('flashPrice', ''); - }} - style={tw`mr-3`} - /> - Flash Available - - - {values.isFlashAvailable && ( - - )} - - - - {isLoading ? (mode === 'create' ? 'Creating...' : 'Updating...') : (mode === 'create' ? 'Create Product' : 'Update Product')} - - - - ); - }} - - ); -}); - -ProductForm.displayName = 'ProductForm'; - -export default ProductForm;