This commit is contained in:
shafi54 2026-01-28 09:14:02 +05:30
parent 4e54a8c6ee
commit d8271dd502
7 changed files with 82 additions and 17 deletions

View file

@ -66,6 +66,7 @@ interface OrderType {
unit: string; unit: string;
isPackaged?: boolean; isPackaged?: boolean;
isPackageVerified?: boolean; isPackageVerified?: boolean;
productSize: number;
}[]; }[];
createdAt: string; createdAt: string;
deliveryTime: string | null; deliveryTime: string | null;
@ -437,7 +438,7 @@ const OrderItem = ({ order, refetch }: { order: OrderType; refetch: () => void }
<View key={idx} style={tw`py-2 border-b border-gray-50 last:border-0`}> <View key={idx} style={tw`py-2 border-b border-gray-50 last:border-0`}>
<View style={tw`flex-row items-center`}> <View style={tw`flex-row items-center`}>
<View style={tw`bg-gray-100 px-2 py-1 rounded items-center justify-center mr-2`}> <View style={tw`bg-gray-100 px-2 py-1 rounded items-center justify-center mr-2`}>
<MyText style={tw`text-xs font-bold text-gray-600`}>{item.quantity} {item.unit}</MyText> <MyText style={tw`text-xs font-bold text-gray-600`}>{item.quantity * item.productSize } {item.unit}</MyText>
</View> </View>
<MyText style={tw`text-sm text-gray-800 flex-1`} numberOfLines={1} ellipsizeMode="tail"> <MyText style={tw`text-sm text-gray-800 flex-1`} numberOfLines={1} ellipsizeMode="tail">
{item.name.length > 30 ? `${item.name.substring(0, 30)}...` : item.name} {item.name.length > 30 ? `${item.name.substring(0, 30)}...` : item.name}

View file

@ -41,6 +41,7 @@ const ProductItemComponent: React.FC<ProductItemProps> = ({
const displayPrice = change.price !== undefined ? change.price : product.price; const displayPrice = change.price !== undefined ? change.price : product.price;
const displayMarketPrice = change.marketPrice !== undefined ? change.marketPrice : product.marketPrice; const displayMarketPrice = change.marketPrice !== undefined ? change.marketPrice : product.marketPrice;
const displayFlashPrice = change.flashPrice !== undefined ? change.flashPrice : product.flashPrice; const displayFlashPrice = change.flashPrice !== undefined ? change.flashPrice : product.flashPrice;
const displayProductQuantity = change.productQuantity !== undefined ? change.productQuantity : product.productQuantity;
return ( return (
<View style={tw`bg-white p-4 mb-3 rounded-xl border border-gray-200 shadow-sm`}> <View style={tw`bg-white p-4 mb-3 rounded-xl border border-gray-200 shadow-sm`}>
@ -67,7 +68,7 @@ const ProductItemComponent: React.FC<ProductItemProps> = ({
resizeMode="cover" resizeMode="cover"
/> />
{/* Product name and Flash Checkbox */} {/* Product name and Flash Checkbox */}
<View style={tw`flex-1 flex-row items-center`}> <View style={tw`flex-1 flex-row items-center`}>
<MyText style={tw`text-base font-medium text-gray-800`} numberOfLines={1}> <MyText style={tw`text-base font-medium text-gray-800`} numberOfLines={1}>
{product.name.length > 25 ? product.name.substring(0, 25) + '...' : product.name} {product.name.length > 25 ? product.name.substring(0, 25) + '...' : product.name}
@ -92,12 +93,12 @@ const ProductItemComponent: React.FC<ProductItemProps> = ({
</View> </View>
</View> </View>
{/* Second row: Prices */} {/* Prices and Product Size Row */}
<View style={tw`flex-row items-center justify-between`}> <View style={tw`flex-row items-center justify-between`}>
{/* Our Price */} {/* Our Price */}
<View style={tw`items-center flex-1`}> <View style={tw`items-center`}>
<MyText style={tw`text-xs text-gray-500 mb-1`}>Our Price</MyText> <MyText style={tw`text-xs text-gray-500 mb-1`}>Our Price</MyText>
<View style={tw`flex-row items-center justify-center`}> <View style={tw`flex-row items-center`}>
<MyText style={tw`text-sm font-bold text-green-600`}>{displayPrice}</MyText> <MyText style={tw`text-sm font-bold text-green-600`}>{displayPrice}</MyText>
<TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}> <TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}>
<MaterialIcons name="edit" size={14} color="#6b7280" /> <MaterialIcons name="edit" size={14} color="#6b7280" />
@ -106,9 +107,9 @@ const ProductItemComponent: React.FC<ProductItemProps> = ({
</View> </View>
{/* Market Price */} {/* Market Price */}
<View style={tw`items-center flex-1`}> <View style={tw`items-center`}>
<MyText style={tw`text-xs text-gray-500 mb-1`}>Market Price</MyText> <MyText style={tw`text-xs text-gray-500 mb-1`}>Market Price</MyText>
<View style={tw`flex-row items-center justify-center`}> <View style={tw`flex-row items-center`}>
<MyText style={tw`text-sm text-gray-600`}>{displayMarketPrice ? `${displayMarketPrice}` : "N/A"}</MyText> <MyText style={tw`text-sm text-gray-600`}>{displayMarketPrice ? `${displayMarketPrice}` : "N/A"}</MyText>
<TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}> <TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}>
<MaterialIcons name="edit" size={14} color="#6b7280" /> <MaterialIcons name="edit" size={14} color="#6b7280" />
@ -117,15 +118,26 @@ const ProductItemComponent: React.FC<ProductItemProps> = ({
</View> </View>
{/* Flash Price */} {/* Flash Price */}
<View style={tw`items-center flex-1`}> <View style={tw`items-center`}>
<MyText style={tw`text-xs text-gray-500 mb-1`}>Flash Price</MyText> <MyText style={tw`text-xs text-gray-500 mb-1`}>Flash Price</MyText>
<View style={tw`flex-row items-center justify-center`}> <View style={tw`flex-row items-center`}>
<MyText style={tw`text-sm text-orange-600`}>{displayFlashPrice ? `${displayFlashPrice}` : "N/A"}</MyText> <MyText style={tw`text-sm text-orange-600`}>{displayFlashPrice ? `${displayFlashPrice}` : "N/A"}</MyText>
<TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}> <TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}>
<MaterialIcons name="edit" size={14} color="#6b7280" /> <MaterialIcons name="edit" size={14} color="#6b7280" />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
{/* Product Size */}
<View style={tw`items-center`}>
<MyText style={tw`text-xs text-gray-500 mb-1`}>Size</MyText>
<View style={tw`flex-row items-center`}>
<MyText style={tw`text-sm text-blue-600`}>{displayProductQuantity ? `${displayProductQuantity}${product.unit.shortNotation || ''}` : "N/A"}</MyText>
<TouchableOpacity onPress={() => openEditDialog(product)} style={tw`ml-1`}>
<MaterialIcons name="edit" size={14} color="#6b7280" />
</TouchableOpacity>
</View>
</View>
</View> </View>
</View> </View>
); );
@ -135,6 +147,7 @@ interface PendingChange {
price?: number; price?: number;
marketPrice?: number | null; marketPrice?: number | null;
flashPrice?: number | null; flashPrice?: number | null;
productQuantity?: number | null;
isFlashAvailable?: boolean; isFlashAvailable?: boolean;
} }
@ -144,6 +157,7 @@ interface EditDialogState {
tempPrice: string; tempPrice: string;
tempMarketPrice: string; tempMarketPrice: string;
tempFlashPrice: string; tempFlashPrice: string;
tempProductQuantity: string;
} }
export default function PricesOverview() { export default function PricesOverview() {
@ -156,6 +170,7 @@ export default function PricesOverview() {
tempPrice: "", tempPrice: "",
tempMarketPrice: "", tempMarketPrice: "",
tempFlashPrice: "", tempFlashPrice: "",
tempProductQuantity: "",
}); });
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
@ -211,6 +226,7 @@ export default function PricesOverview() {
tempPrice: (change.price ?? product.price)?.toString() || "", tempPrice: (change.price ?? product.price)?.toString() || "",
tempMarketPrice: (change.marketPrice ?? product.marketPrice)?.toString() || "", tempMarketPrice: (change.marketPrice ?? product.marketPrice)?.toString() || "",
tempFlashPrice: (change.flashPrice ?? product.flashPrice)?.toString() || "", tempFlashPrice: (change.flashPrice ?? product.flashPrice)?.toString() || "",
tempProductQuantity: (change.productQuantity ?? product.productQuantity)?.toString() || "",
}); });
}; };
@ -219,6 +235,7 @@ export default function PricesOverview() {
const price = parseFloat(editDialog.tempPrice); const price = parseFloat(editDialog.tempPrice);
const marketPrice = editDialog.tempMarketPrice ? parseFloat(editDialog.tempMarketPrice) : null; const marketPrice = editDialog.tempMarketPrice ? parseFloat(editDialog.tempMarketPrice) : null;
const flashPrice = editDialog.tempFlashPrice ? parseFloat(editDialog.tempFlashPrice) : null; const flashPrice = editDialog.tempFlashPrice ? parseFloat(editDialog.tempFlashPrice) : null;
const productQuantity = editDialog.tempProductQuantity ? parseFloat(editDialog.tempProductQuantity) : null;
if (isNaN(price) || price <= 0) { if (isNaN(price) || price <= 0) {
Alert.alert("Error", "Please enter a valid price"); Alert.alert("Error", "Please enter a valid price");
@ -235,16 +252,22 @@ export default function PricesOverview() {
return; return;
} }
if (editDialog.tempProductQuantity && (isNaN(productQuantity!) || productQuantity! <= 0)) {
Alert.alert("Error", "Please enter a valid product size");
return;
}
setPendingChanges(prev => ({ setPendingChanges(prev => ({
...prev, ...prev,
[editDialog.product.id]: { [editDialog.product.id]: {
price: price !== editDialog.product.price ? price : undefined, price: price !== editDialog.product.price ? price : undefined,
marketPrice: marketPrice !== editDialog.product.marketPrice ? marketPrice : undefined, marketPrice: marketPrice !== editDialog.product.marketPrice ? marketPrice : undefined,
flashPrice: flashPrice !== editDialog.product.flashPrice ? flashPrice : undefined, flashPrice: flashPrice !== editDialog.product.flashPrice ? flashPrice : undefined,
productQuantity: productQuantity !== editDialog.product.productQuantity ? productQuantity : undefined,
}, },
})); }));
setEditDialog({ open: false, product: null, tempPrice: "", tempMarketPrice: "", tempFlashPrice: "" }); setEditDialog({ open: false, product: null, tempPrice: "", tempMarketPrice: "", tempFlashPrice: "", tempProductQuantity: "" });
}; };
// Handle save all changes // Handle save all changes
@ -254,6 +277,7 @@ export default function PricesOverview() {
if (change.price !== undefined) update.price = change.price; if (change.price !== undefined) update.price = change.price;
if (change.marketPrice !== undefined) update.marketPrice = change.marketPrice; if (change.marketPrice !== undefined) update.marketPrice = change.marketPrice;
if (change.flashPrice !== undefined) update.flashPrice = change.flashPrice; if (change.flashPrice !== undefined) update.flashPrice = change.flashPrice;
if (change.productQuantity !== undefined) update.productQuantity = change.productQuantity;
if (change.isFlashAvailable !== undefined) update.isFlashAvailable = change.isFlashAvailable; if (change.isFlashAvailable !== undefined) update.isFlashAvailable = change.isFlashAvailable;
return update; return update;
}); });
@ -351,7 +375,7 @@ export default function PricesOverview() {
)} )}
{/* Edit Dialog */} {/* Edit Dialog */}
<BottomDialog open={editDialog.open} onClose={() => setEditDialog({ ...editDialog, open: false, tempFlashPrice: "" })}> <BottomDialog open={editDialog.open} onClose={() => setEditDialog({ ...editDialog, open: false, tempFlashPrice: "", tempMarketPrice: "", tempPrice: "", tempProductQuantity: "" })}>
<View style={tw`p-4`}> <View style={tw`p-4`}>
<MyText style={tw`text-lg font-bold mb-4`}>{editDialog.product?.name}</MyText> <MyText style={tw`text-lg font-bold mb-4`}>{editDialog.product?.name}</MyText>
@ -388,6 +412,17 @@ export default function PricesOverview() {
/> />
</View> </View>
<View style={tw`mb-4`}>
<MyText style={tw`text-sm font-medium mb-1`}>Product Size</MyText>
<TextInput
style={tw`border border-gray-300 rounded-md px-3 py-2`}
value={editDialog.tempProductQuantity}
onChangeText={(text) => setEditDialog({ ...editDialog, tempProductQuantity: text })}
keyboardType="decimal-pad"
placeholder="Enter product size"
/>
</View>
<TouchableOpacity <TouchableOpacity
style={tw`bg-blue-600 py-3 rounded-md items-center`} style={tw`bg-blue-600 py-3 rounded-md items-center`}
onPress={saveEditDialog} onPress={saveEditDialog}

View file

@ -775,6 +775,7 @@ export const orderRouter = router({
amount: amount:
parseFloat(item.quantity) * parseFloat(item.price.toString()), parseFloat(item.quantity) * parseFloat(item.price.toString()),
unit: item.product.unit?.shortNotation || "", unit: item.product.unit?.shortNotation || "",
productSize: item.product.productQuantity,
isPackaged: item.is_packaged, isPackaged: item.is_packaged,
isPackageVerified: item.is_package_verified, isPackageVerified: item.is_package_verified,
})) }))

View file

@ -143,10 +143,22 @@ export default function Dashboard() {
const initialBatchRaw = products; const initialBatchRaw = products;
// Filter to include only products with available slots // Filter to include only products with available slots
const initialBatch = initialBatchRaw.filter(product => { // const initialBatch = initialBatchRaw.filter(product => {
const slot = getQuickestSlot(product.id); // const slot = getQuickestSlot(product.id);
return slot !== null && slot !== undefined && !product.isOutOfStock; // return !product.isOutOfStock;
}); // });
const initialBatch = initialBatchRaw.sort((a, b) => {
const slotA = getQuickestSlot(a.id);
const slotB = getQuickestSlot(b.id);
if (slotA && !slotB) return -1;
if (!slotA && slotB) return 1;
if(a.isOutOfStock && !b.isOutOfStock) return 1;
if(!a.isOutOfStock && b.isOutOfStock) return -1;
return 0;
})
setDisplayedProducts(initialBatch); setDisplayedProducts(initialBatch);
setHasMore(products.length > 10); setHasMore(products.length > 10);
@ -593,6 +605,9 @@ export default function Dashboard() {
/> />
</View> </View>
)} )}
initialNumToRender={4}
maxToRenderPerBatch={4}
windowSize={4}
// onEndReached={() => { // onEndReached={() => {
// if (!isLoadingMore && hasMore) { // if (!isLoadingMore && hasMore) {
// loadMoreProducts(); // loadMoreProducts();

View file

@ -350,10 +350,12 @@ export function SlotProducts({ slotId:slotIdParent, storeId:storeIdParent, baseU
const productsQuery = trpc.user.product.getAllProductsSummary.useQuery(); const productsQuery = trpc.user.product.getAllProductsSummary.useQuery();
const { addToCart = () => { } } = useAddToCart({ showSuccessAlert: false, showErrorAlert: false, refetchCart: true }, "flash") || {}; const { addToCart = () => { } } = useAddToCart({ showSuccessAlert: false, showErrorAlert: false, refetchCart: true }, "regular") || {};
const handleAddToCart = (productId: number) => { const handleAddToCart = (productId: number) => {
setIsLoadingDialogOpen(true); setIsLoadingDialogOpen(true);
// console.log({productId})
addToCart(productId, 1, slotId || 0, () => setIsLoadingDialogOpen(false)); addToCart(productId, 1, slotId || 0, () => setIsLoadingDialogOpen(false));
}; };

View file

@ -305,11 +305,16 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) {
// Auto-select delivery slots for each cart item // Auto-select delivery slots for each cart item
useEffect(() => { useEffect(() => {
const cartSlotIds = cartData?.items.reduce((acc,item) => {
acc[item.id] = item.slotId;
return acc;
}, {} as Record<number, number>);
if (cartItems.length > 0) { if (cartItems.length > 0) {
const newSelectedSlots = { ...selectedSlots }; const newSelectedSlots = { ...selectedSlots };
cartItems.forEach(item => { cartItems.forEach(item => {
const existingSlotId = selectedSlots[item.id]; // const existingSlotId = selectedSlots[item.id];
const existingSlotId = cartSlotIds ? cartSlotIds[item.id] : undefined;
if (isFlashDelivery) { if (isFlashDelivery) {
newSelectedSlots[item.id] = 0; newSelectedSlots[item.id] = 0;
@ -325,6 +330,8 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) {
); );
if (upcomingSlots.length > 0) { if (upcomingSlots.length > 0) {
console.log({upcomingSlots, existingSlotId, cartSlotIds})
if (existingSlotId) { if (existingSlotId) {
const slotStillValid = upcomingSlots.some(slot => slot.id === existingSlotId); const slotStillValid = upcomingSlots.some(slot => slot.id === existingSlotId);
if (slotStillValid) { if (slotStillValid) {

View file

@ -91,6 +91,8 @@ const addToLocalCart = async (productId: number, quantity: number, slotId?: numb
items.push(cartItem); items.push(cartItem);
} }
console.log({items})
await saveLocalCart(items, cartType); await saveLocalCart(items, cartType);
return items; return items;
}; };
@ -301,6 +303,8 @@ export function useAddToCart(options?: {
const addToCart = (productId: number, quantity = 1, slotId?: number, onSettled?: (data: any, error: any) => void) => { const addToCart = (productId: number, quantity = 1, slotId?: number, onSettled?: (data: any, error: any) => void) => {
// console.log({productId, quantity, slotId})
if (slotId == null) { if (slotId == null) {
throw new Error('slotId is required for adding to cart'); throw new Error('slotId is required for adding to cart');
} }