This commit is contained in:
shafi54 2026-02-20 12:42:59 +05:30
parent d4afa75eaf
commit 10d13408d3
3 changed files with 148 additions and 108 deletions

View file

@ -36,21 +36,32 @@ interface FloatingCartBarProps {
} }
// Smart time window formatting function // Smart time window formatting function
const formatTimeRange = (deliveryTime: string) => { const formatTimeRange = (deliveryTime: string) => {
const time = dayjs(deliveryTime); const time = dayjs(deliveryTime);
const endTime = time.add(1, 'hour'); const endTime = time.add(1, 'hour');
const startPeriod = time.format('A'); const startPeriod = time.format('A');
const endPeriod = endTime.format('A'); const endPeriod = endTime.format('A');
let timeRange; let timeRange;
if (startPeriod === endPeriod) { if (startPeriod === endPeriod) {
timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`; timeRange = `${time.format('h')}-${endTime.format('h')} ${startPeriod}`;
} else { } else {
timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`; timeRange = `${time.format('h:mm')} ${startPeriod} - ${endTime.format('h:mm')} ${endPeriod}`;
} }
return `${time.format('ddd, DD MMM ')}${timeRange}`; return `${time.format('ddd, DD MMM ')}${timeRange}`;
}; };
// Product name component with quantity
const ProductNameWithQuantity = ({ name, productQuantity, unitNotation }: { name: string; productQuantity: number; unitNotation: string }) => {
const truncatedName = name.length > 25 ? name.substring(0, 25) + '...' : name;
const unit = unitNotation ? ` ${unitNotation}` : '';
return (
<MyText style={tw`text-slate-900 font-extrabold text-sm flex-1`} numberOfLines={1}>
{truncatedName} <MyText style={tw`text-slate-500 font-medium text-xs`}>({productQuantity}{unit})</MyText>
</MyText>
);
};
const FloatingCartBar: React.FC<FloatingCartBarProps> = ({ const FloatingCartBar: React.FC<FloatingCartBarProps> = ({
isFlashDelivery = false, isFlashDelivery = false,
@ -252,9 +263,11 @@ useEffect(() => {
<View style={tw`flex-1 ml-4`}> <View style={tw`flex-1 ml-4`}>
<View style={tw`flex-row items-center justify-between mb-1`}> <View style={tw`flex-row items-center justify-between mb-1`}>
<MyText style={tw`text-slate-900 font-extrabold text-sm flex-1`} numberOfLines={1}> <ProductNameWithQuantity
{item.product.name.length > 30 ? item.product.name.substring(0, 30) + '...' : item.product.name} name={item.product.name}
</MyText> productQuantity={item.product.productQuantity}
unitNotation={item.product.unitNotation}
/>
<MiniQuantifier <MiniQuantifier
value={quantities[item.id] || item.quantity} value={quantities[item.id] || item.quantity}
onChange={(value) => { onChange={(value) => {

View file

@ -6,7 +6,7 @@ import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useCartStore } from '@/src/store/cartStore'; import { useCartStore } from '@/src/store/cartStore';
import { useFlashCartStore } from '@/src/store/flashCartStore'; import { useFlashCartStore } from '@/src/store/flashCartStore';
import { trpc } from '@/src/trpc-client'; import { trpc } from '@/src/trpc-client';
import { useAddToCart, useGetCart, useUpdateCartItem } from '@/hooks/cart-query-hooks'; import { useAddToCart, useGetCart, useUpdateCartItem, useRemoveFromCart } from '@/hooks/cart-query-hooks';
import { useGetEssentialConsts } from '@/src/api-hooks/essential-consts.api'; import { useGetEssentialConsts } from '@/src/api-hooks/essential-consts.api';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
@ -38,6 +38,12 @@ export default function AddToCartDialog() {
refetchCart: true, refetchCart: true,
}); });
const removeFromCart = useRemoveFromCart({
showSuccessAlert: false,
showErrorAlert: false,
refetchCart: true,
});
const isOpen = !!addedToCartProduct; const isOpen = !!addedToCartProduct;
@ -91,7 +97,7 @@ export default function AddToCartDialog() {
const cartItem = cartData?.items?.find((item: any) => item.productId === product?.id); const cartItem = cartData?.items?.find((item: any) => item.productId === product?.id);
// Determine if updating existing item (quantity > 1 means it's an update) // Determine if updating existing item (quantity > 1 means it's an update)
const isUpdate = (cartItem?.quantity || 0) > 1; const isUpdate = (cartItem?.quantity || 0) >= 1;
// Check if flash delivery option should be shown // Check if flash delivery option should be shown
const showFlashOption = product?.isFlashAvailable === true && isFlashDeliveryEnabled; const showFlashOption = product?.isFlashAvailable === true && isFlashDeliveryEnabled;
@ -122,99 +128,120 @@ export default function AddToCartDialog() {
return ( return (
<BottomDialog open={isOpen} onClose={clearAddedToCartProduct}> <BottomDialog open={isOpen} onClose={clearAddedToCartProduct}>
<SafeAreaView> <SafeAreaView>
<View style={tw`p-6 max-h-[650px]`}> <View style={tw`p-6 max-h-[650px]`}>
<View style={tw`flex-row items-center mb-2`}> <View style={tw`flex-row items-center mb-2`}>
<View style={tw`w-10 h-10 bg-blue-50 rounded-full items-center justify-center mr-3`}> <View style={tw`w-10 h-10 bg-blue-50 rounded-full items-center justify-center mr-3`}>
<MaterialIcons name="schedule" size={20} color="#3B82F6" /> <MaterialIcons name="schedule" size={20} color="#3B82F6" />
</View>
<View>
<MyText style={tw`text-xl font-bold text-gray-900`}>Select Delivery Slot</MyText>
{product?.name && (
<MyText style={tw`text-sm text-gray-500`}>
{product.name} ({product.productQuantity}{product.unitNotation ? ` ${product.unitNotation}` : ''})
</MyText>
)}
</View>
</View> </View>
<View>
<MyText style={tw`text-xl font-bold text-gray-900`}>Select Delivery Slot</MyText>
{product?.name && (
<MyText style={tw`text-sm text-gray-500`}>{product.name}</MyText>
)}
</View>
</View>
<ScrollView showsVerticalScrollIndicator={false}> <ScrollView showsVerticalScrollIndicator={false}>
{availableSlots.map((slot: any) => ( {availableSlots.map((slot: any) => (
<MyTouchableOpacity
key={slot.id}
style={tw`flex-row items-start mb-4 bg-gray-50 p-4 rounded-xl border border-gray-100 ${selectedSlotId === slot.id ? 'border-brand500' : 'border-gray-100'
}`}
onPress={() => {
setSelectedSlotId(slot.id);
setSelectedFlashDelivery(false);
}}
activeOpacity={0.7}
>
<MaterialIcons name="local-shipping" size={20} color="#3B82F6" style={tw`mt-0.5`} />
<View style={tw`ml-3 flex-1`}>
<MyText style={tw`text-gray-900 font-bold text-base`}>
{dayjs(slot.deliveryTime).format('ddd, DD MMM • h:mm A')}
</MyText>
</View>
{selectedSlotId === slot.id ? (
<MaterialIcons name="check-circle" size={24} color="#3B82F6" style={tw`mt-0.5`} />
) : (
<MaterialIcons name="check-box-outline-blank" size={24} color="#9CA3AF" style={tw`mt-0.5`} />
)}
</MyTouchableOpacity>
))}
</ScrollView>
{showFlashOption && (
<MyTouchableOpacity <MyTouchableOpacity
key={slot.id} key="flash-delivery"
style={tw`flex-row items-start mb-4 bg-gray-50 p-4 rounded-xl border border-gray-100 ${ style={tw`flex-row items-center mb-4 bg-pink-50 p-4 rounded-xl border ${selectedFlashDelivery ? 'border-pink-500' : 'border-pink-200'
selectedSlotId === slot.id ? 'border-brand500' : 'border-gray-100' }`}
}`}
onPress={() => { onPress={() => {
setSelectedSlotId(slot.id); setSelectedFlashDelivery(true);
setSelectedFlashDelivery(false); setSelectedSlotId(null);
}} }}
activeOpacity={0.7} activeOpacity={0.7}
> >
<MaterialIcons name="local-shipping" size={20} color="#3B82F6" style={tw`mt-0.5`} /> <MaterialIcons name="bolt" size={20} color="#f81260" />
<View style={tw`ml-3 flex-1`}> <View style={tw`ml-3 flex-1`}>
<MyText style={tw`text-gray-900 font-bold text-base`}> <MyText style={tw`text-gray-900 font-bold text-base`}>1 hr Delivery</MyText>
{dayjs(slot.deliveryTime).format('ddd, DD MMM • h:mm A')}
</MyText>
</View> </View>
{selectedSlotId === slot.id ? ( {selectedFlashDelivery ? (
<MaterialIcons name="check-circle" size={24} color="#3B82F6" style={tw`mt-0.5`} /> <MaterialIcons name="check-circle" size={24} color="#f81260" />
) : ( ) : (
<MaterialIcons name="check-box-outline-blank" size={24} color="#9CA3AF" style={tw`mt-0.5`} /> <MaterialIcons name="check-box-outline-blank" size={24} color="#f81260" />
)} )}
</MyTouchableOpacity> </MyTouchableOpacity>
))} )}
</ScrollView>
{showFlashOption && ( <View style={tw`mt-4`}>
<MyTouchableOpacity <MyText style={tw`text-sm font-bold text-gray-900 mb-2`}>Quantity</MyText>
key="flash-delivery" <View style={tw`flex-row items-center`}>
style={tw`flex-row items-center mb-4 bg-pink-50 p-4 rounded-xl border ${ <View style={tw`flex-1`}>
selectedFlashDelivery ? 'border-pink-500' : 'border-pink-200' <Quantifier
}`} value={quantity}
onPress={() => { setValue={setQuantity}
setSelectedFlashDelivery(true); step={1}
setSelectedSlotId(null); unit={product.unitNotation}
}} />
activeOpacity={0.7} </View>
> {isUpdate && (
<MaterialIcons name="bolt" size={20} color="#f81260" /> <MyTouchableOpacity
<View style={tw`ml-3 flex-1`}> onPress={() => {
<MyText style={tw`text-gray-900 font-bold text-base`}>1 hr Delivery</MyText> if (cartItem?.id) {
removeFromCart.mutate(
{ itemId: cartItem.id },
{ onSuccess: () => clearAddedToCartProduct() }
);
} else {
clearAddedToCartProduct();
}
}}
style={tw`p-2 ml-3 bg-red-50 rounded-lg border border-red-200`}
>
<MaterialIcons name="delete-outline" size={24} color="#EF4444" />
</MyTouchableOpacity>
)}
</View> </View>
{selectedFlashDelivery ? ( </View>
<MaterialIcons name="check-circle" size={24} color="#f81260" />
) : (
<MaterialIcons name="check-box-outline-blank" size={24} color="#f81260" />
)}
</MyTouchableOpacity>
)}
<View style={tw`mt-4`}> <View style={tw`flex-row gap-3 mt-4 pb-12`}>
<MyText style={tw`text-sm font-bold text-gray-900 mb-2`}>Quantity</MyText> <MyTouchableOpacity
<Quantifier style={tw`flex-1 bg-brand500 py-3.5 rounded-xl items-center ${(!selectedSlotId && !selectedFlashDelivery) ? 'opacity-50' : ''}`}
value={quantity} onPress={handleAddToCart}
setValue={setQuantity} disabled={(addToCart.isLoading || updateCartItem.isLoading) || (!selectedSlotId && !selectedFlashDelivery)}
step={product.incrementStep} >
unit={product.unitNotation} <MyText style={tw`text-white font-bold`}>
/> {addToCart.isLoading || updateCartItem.isLoading ? (isUpdate ? 'Updating...' : 'Adding...') : (isUpdate ? 'Update Item' : 'Add to Cart')}
</MyText>
</MyTouchableOpacity>
<MyTouchableOpacity
style={tw`flex-1 bg-gray-100 py-3.5 rounded-xl items-center`}
onPress={clearAddedToCartProduct}
>
<MyText style={tw`text-gray-700 font-bold`}>Cancel</MyText>
</MyTouchableOpacity>
</View>
</View> </View>
<View style={tw`flex-row gap-3 mt-4 pb-12`}>
<MyTouchableOpacity
style={tw`flex-1 bg-brand500 py-3.5 rounded-xl items-center ${(!selectedSlotId && !selectedFlashDelivery) ? 'opacity-50' : ''}`}
onPress={handleAddToCart}
disabled={(addToCart.isLoading || updateCartItem.isLoading) || (!selectedSlotId && !selectedFlashDelivery)}
>
<MyText style={tw`text-white font-bold`}>
{addToCart.isLoading || updateCartItem.isLoading ? (isUpdate ? 'Updating...' : 'Adding...') : (isUpdate ? 'Update Item' : 'Add to Cart')}
</MyText>
</MyTouchableOpacity>
<MyTouchableOpacity
style={tw`flex-1 bg-gray-100 py-3.5 rounded-xl items-center`}
onPress={clearAddedToCartProduct}
>
<MyText style={tw`text-gray-700 font-bold`}>Cancel</MyText>
</MyTouchableOpacity>
</View>
</View>
</SafeAreaView> </SafeAreaView>
</BottomDialog> </BottomDialog>
); );

View file

@ -63,8 +63,8 @@ const isDevMode = Constants.executionEnvironment !== "standalone";
// const BASE_API_URL = API_URL; // const BASE_API_URL = API_URL;
// const BASE_API_URL = 'http://10.0.2.2:4000'; // const BASE_API_URL = 'http://10.0.2.2:4000';
// const BASE_API_URL = 'http://192.168.100.101:4000'; // const BASE_API_URL = 'http://192.168.100.101:4000';
const BASE_API_URL = 'http://192.168.1.3:4000'; // const BASE_API_URL = 'http://192.168.1.3:4000';
// let BASE_API_URL = "https://mf.freshyo.in"; let BASE_API_URL = "https://mf.freshyo.in";
// let BASE_API_URL = 'http://192.168.100.104:4000'; // let BASE_API_URL = 'http://192.168.100.104:4000';
// let BASE_API_URL = 'http://192.168.29.176:4000'; // let BASE_API_URL = 'http://192.168.29.176:4000';