277 lines
No EOL
11 KiB
TypeScript
277 lines
No EOL
11 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, ScrollView, Dimensions } from 'react-native';
|
|
import { useRouter } from 'expo-router';
|
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
|
import { BottomDialog, MyTouchableOpacity, MyText, tw, theme } from 'common-ui';
|
|
import { useAuth } from '@/src/contexts/AuthContext';
|
|
import { trpc } from '@/src/trpc-client';
|
|
import { useAddressStore } from '@/src/store/addressStore';
|
|
import dayjs from 'dayjs';
|
|
|
|
interface QuickDeliveryAddressSelectorProps {
|
|
deliveryTime?: string;
|
|
slotId?: number;
|
|
onSlotChange?: (slotId: number) => void;
|
|
isForFlashDelivery?: boolean;
|
|
}
|
|
|
|
const QuickDeliveryAddressSelector: React.FC<QuickDeliveryAddressSelectorProps> = ({
|
|
deliveryTime,
|
|
slotId,
|
|
onSlotChange,
|
|
isForFlashDelivery = false
|
|
}) => {
|
|
const router = useRouter();
|
|
const [dialogOpen, setDialogOpen] = useState(false);
|
|
|
|
const { isAuthenticated } = useAuth();
|
|
const { selectedAddressId, setSelectedAddressId } = useAddressStore();
|
|
|
|
const { data: defaultAddressData } = trpc.user.address.getDefaultAddress.useQuery();
|
|
const { data: addressesData } = trpc.user.address.getUserAddresses.useQuery(undefined, {
|
|
enabled: isAuthenticated,
|
|
});
|
|
const { data: slotsData } = trpc.user.slots.getSlotsWithProducts.useQuery();
|
|
|
|
const defaultAddress = defaultAddressData?.data;
|
|
const addresses = addressesData?.data || [];
|
|
|
|
// Find earliest slot for pre-selection
|
|
const earliestSlot = slotsData?.slots?.sort((a, b) =>
|
|
dayjs(a.deliveryTime).diff(dayjs(b.deliveryTime))
|
|
)[0];
|
|
|
|
// Transform addresses for display
|
|
const addressOptions = addresses.map(address => ({
|
|
id: address.id,
|
|
name: address.name,
|
|
address: `${address.addressLine1}${address.addressLine2 ? `, ${address.addressLine2}` : ''}, ${address.city}, ${address.state} - ${address.pincode}`,
|
|
phone: address.phone,
|
|
}));
|
|
|
|
// Transform slots for display
|
|
const slotOptions = slotsData?.slots?.map(slot => ({
|
|
id: slot.id,
|
|
deliveryTime: dayjs(slot.deliveryTime).format('MMM DD, h:mm A'),
|
|
closeTime: dayjs(slot.freezeTime).format('h:mm A'),
|
|
})) || [];
|
|
|
|
// Get current selected slot display
|
|
const getCurrentSlotDisplay = () => {
|
|
if (isForFlashDelivery) return '30 minutes';
|
|
if (slotId) {
|
|
const slot = slotsData?.slots?.find(s => s.id === slotId);
|
|
return slot ? dayjs(slot.deliveryTime).format('MMM DD, h:mm A') : 'Select time';
|
|
}
|
|
if (earliestSlot) {
|
|
return dayjs(earliestSlot.deliveryTime).format('MMM DD, h:mm A');
|
|
}
|
|
return 'Select time';
|
|
};
|
|
|
|
// Get current selected address display
|
|
const getCurrentAddressDisplay = () => {
|
|
if (selectedAddressId) {
|
|
const address = addresses.find(a => a.id === selectedAddressId);
|
|
if (address) return `${address.name} - ${address.addressLine1}`;
|
|
}
|
|
if (defaultAddress) {
|
|
return `${defaultAddress.name} - ${defaultAddress.addressLine1}`;
|
|
}
|
|
return 'Select address';
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
<>
|
|
|
|
{isForFlashDelivery && (
|
|
<View style={tw`flex-row items-center mb-1`}>
|
|
<MyTouchableOpacity
|
|
onPress={() => router.back()}
|
|
style={tw`p-2 -ml-2`}
|
|
activeOpacity={0.7}
|
|
>
|
|
<MaterialIcons name="chevron-left" size={24} color="#f81260" />
|
|
</MyTouchableOpacity>
|
|
<MyText style={[tw`text-lg font-bold ml-2`, { color: '#f81260' }]}>
|
|
Delivery in 30 minutes
|
|
</MyText>
|
|
</View>
|
|
)}
|
|
|
|
{!isForFlashDelivery && (
|
|
<View style={tw`flex-1 mr-2`}>
|
|
<View style={tw`flex-row items-center mb-1`}>
|
|
<MyTouchableOpacity
|
|
onPress={() => router.back()}
|
|
style={tw`p-2 -ml-2`}
|
|
activeOpacity={0.7}
|
|
>
|
|
<MaterialIcons name="chevron-left" size={24} />
|
|
</MyTouchableOpacity>
|
|
<MyText style={[tw`text-lg font-bold ml-2`]}>
|
|
Delivery At {getCurrentSlotDisplay()}
|
|
</MyText>
|
|
</View>
|
|
{/* Trigger Component with Separate Chevrons */}
|
|
<View style={tw`bg-brand50 border border-brand100 rounded-lg p-3`}>
|
|
|
|
/* Regular Delivery Time Section */
|
|
<MyTouchableOpacity
|
|
onPress={() => setDialogOpen(true)}
|
|
style={tw`flex-row items-center justify-between mb-2`}
|
|
activeOpacity={0.7}
|
|
>
|
|
<View style={tw`flex-1`}>
|
|
{/* <MyText style={tw`text-xs text-brand500 font-bold uppercase tracking-wider leading-3`}>
|
|
Delivery Time
|
|
</MyText> */}
|
|
<MyText style={tw`text-sm font-bold text-brand900 leading-4`}>
|
|
Delivery at: {getCurrentSlotDisplay()}
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="keyboard-arrow-down" size={20} color={theme.colors.brand500} />
|
|
</MyTouchableOpacity>
|
|
|
|
|
|
{/* Address Section */}
|
|
<MyTouchableOpacity
|
|
onPress={() => setDialogOpen(true)}
|
|
style={tw`flex-row items-center justify-between`}
|
|
activeOpacity={0.7}
|
|
>
|
|
<View style={tw`flex-1`}>
|
|
{/* <MyText style={tw`text-xs text-brand500 font-bold uppercase tracking-wider leading-3`}>
|
|
Delivery Address
|
|
</MyText> */}
|
|
<MyText style={tw`text-sm font-bold text-brand900 leading-4`} numberOfLines={1}>
|
|
TO: {getCurrentAddressDisplay()}
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="keyboard-arrow-down" size={20} color={theme.colors.brand500} />
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
|
|
{/* Consolidated Dialog - 80% height */}
|
|
<BottomDialog
|
|
open={dialogOpen}
|
|
onClose={() => setDialogOpen(false)}
|
|
>
|
|
<View style={[tw`py-6`, { height: Dimensions.get('window').height * 0.8 }]}>
|
|
<MyText style={tw`text-xl font-bold text-gray-900 mb-6 text-center`}>
|
|
Select Delivery Options
|
|
</MyText>
|
|
|
|
<View style={tw`flex-1`}>
|
|
{/* Section 1: Delivery Time Selection */}
|
|
<View style={tw`mb-6`}>
|
|
<MyText style={tw`text-lg font-bold text-gray-900 mb-3`}>
|
|
Select Delivery Time
|
|
</MyText>
|
|
|
|
<ScrollView style={tw`max-h-40`} showsVerticalScrollIndicator={false}>
|
|
{isForFlashDelivery ? (
|
|
<View style={tw`p-3 bg-green-50 border border-green-200 rounded-lg mb-2`}>
|
|
<View style={tw`flex-row items-center`}>
|
|
<MaterialIcons name="bolt" size={20} color="#16a34a" />
|
|
<MyText style={tw`text-green-800 font-medium ml-2`}>
|
|
Flash Delivery - 30 minutes
|
|
</MyText>
|
|
</View>
|
|
<MyText style={tw`text-green-700 text-xs mt-1`}>
|
|
Selected automatically for flash delivery
|
|
</MyText>
|
|
</View>
|
|
) : (
|
|
slotOptions.map(slot => (
|
|
<MyTouchableOpacity
|
|
key={slot.id}
|
|
style={tw`p-3 border border-gray-200 rounded-lg mb-2 ${
|
|
slot.id === (slotId || earliestSlot?.id) ? 'bg-brand50 border-brand500' : 'bg-white'
|
|
}`}
|
|
onPress={() => {
|
|
onSlotChange?.(slot.id);
|
|
setDialogOpen(false);
|
|
}}
|
|
activeOpacity={0.7}
|
|
>
|
|
<MyText style={tw`font-medium text-gray-900`}>
|
|
Delivery: {slot.deliveryTime}
|
|
</MyText>
|
|
<MyText style={tw`text-xs text-gray-500 mt-1`}>
|
|
Orders Close at: {slot.closeTime}
|
|
</MyText>
|
|
</MyTouchableOpacity>
|
|
))
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
|
|
{/* Divider */}
|
|
<View style={tw`h-px bg-gray-200 mb-6`} />
|
|
|
|
{/* Section 2: Address Selection */}
|
|
<View style={tw`flex-1`}>
|
|
<MyText style={tw`text-lg font-bold text-gray-900 mb-3`}>
|
|
Select Delivery Address
|
|
</MyText>
|
|
|
|
<ScrollView style={tw`flex-1`} showsVerticalScrollIndicator={false}>
|
|
{!isAuthenticated ? (
|
|
<View style={tw`p-4 bg-red-50 border border-red-200 rounded-lg`}>
|
|
<View style={tw`flex-row items-center`}>
|
|
<MaterialIcons name="error" size={20} color="#DC2626" />
|
|
<MyText style={tw`text-red-800 font-medium ml-2`}>
|
|
Authentication Required
|
|
</MyText>
|
|
</View>
|
|
<MyText style={tw`text-red-700 text-sm mt-2`}>
|
|
Please log in to select and manage delivery addresses.
|
|
</MyText>
|
|
</View>
|
|
) : addressOptions.length === 0 ? (
|
|
<View style={tw`p-4 bg-gray-50 border border-gray-200 rounded-lg`}>
|
|
<MyText style={tw`text-gray-600 text-center`}>
|
|
No delivery addresses available. Please add an address first.
|
|
</MyText>
|
|
</View>
|
|
) : (
|
|
addressOptions.map(address => (
|
|
<MyTouchableOpacity
|
|
key={address.id}
|
|
style={tw`p-3 border border-gray-200 rounded-lg mb-2 ${
|
|
address.id === (selectedAddressId || defaultAddress?.id) ? 'bg-brand50 border-brand500' : 'bg-white'
|
|
}`}
|
|
onPress={() => {
|
|
setSelectedAddressId(address.id);
|
|
setDialogOpen(false);
|
|
}}
|
|
activeOpacity={0.7}
|
|
>
|
|
<MyText style={tw`font-medium text-gray-900`}>
|
|
{address.name}
|
|
</MyText>
|
|
<MyText style={tw`text-sm text-gray-600 mt-1`} numberOfLines={2}>
|
|
{address.address}
|
|
</MyText>
|
|
<MyText style={tw`text-xs text-gray-500 mt-1`}>
|
|
Phone: {address.phone}
|
|
</MyText>
|
|
</MyTouchableOpacity>
|
|
))
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</BottomDialog>
|
|
</View>
|
|
)}
|
|
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default QuickDeliveryAddressSelector; |