306 lines
No EOL
10 KiB
TypeScript
306 lines
No EOL
10 KiB
TypeScript
import React from 'react';
|
|
import { View, TouchableOpacity, Linking, Alert, TextInput, ScrollView, Dimensions } from 'react-native';
|
|
import * as Location from 'expo-location';
|
|
|
|
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
|
|
import {
|
|
MyText,
|
|
tw,
|
|
BottomDialog,
|
|
} from 'common-ui';
|
|
import { trpc } from '@/src/trpc-client';
|
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
|
import Ionicons from '@expo/vector-icons/Ionicons';
|
|
|
|
interface OrderOptionsMenuProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
order: {
|
|
id: number;
|
|
readableId: number;
|
|
isPackaged: boolean;
|
|
isDelivered: boolean;
|
|
isFlashDelivery?: boolean;
|
|
address: string;
|
|
addressId: number;
|
|
adminNotes?: string | null;
|
|
userNotes?: string | null;
|
|
latitude?: number | null;
|
|
longitude?: number | null;
|
|
status?: string;
|
|
};
|
|
onViewDetails: () => void;
|
|
onTogglePackaged: () => void;
|
|
onToggleDelivered: () => void;
|
|
onOpenAdminNotes: () => void;
|
|
onCancelOrder: () => void;
|
|
onAttachLocation: () => void;
|
|
onWhatsApp: () => void;
|
|
onDial: () => void;
|
|
}
|
|
|
|
export function OrderOptionsMenu({
|
|
open,
|
|
onClose,
|
|
order,
|
|
onViewDetails,
|
|
onTogglePackaged,
|
|
onToggleDelivered,
|
|
onOpenAdminNotes,
|
|
onCancelOrder,
|
|
onAttachLocation,
|
|
onWhatsApp,
|
|
onDial,
|
|
}: OrderOptionsMenuProps) {
|
|
const updateAddressCoordsMutation = trpc.admin.order.updateAddressCoords.useMutation();
|
|
|
|
const handleAttachLocation = async () => {
|
|
try {
|
|
const { status } = await Location.requestForegroundPermissionsAsync();
|
|
if (status !== 'granted') {
|
|
Alert.alert(
|
|
'Permission Denied',
|
|
'Location permission is required to attach coordinates.'
|
|
);
|
|
return;
|
|
}
|
|
const location = await Location.getCurrentPositionAsync({
|
|
accuracy: Location.Accuracy.High,
|
|
});
|
|
const { latitude, longitude } = location.coords;
|
|
await updateAddressCoordsMutation.mutateAsync({
|
|
addressId: order.addressId,
|
|
latitude,
|
|
longitude,
|
|
});
|
|
Alert.alert('Success', 'Location attached to address successfully.');
|
|
onAttachLocation();
|
|
} catch (error) {
|
|
Alert.alert('Error', 'Failed to attach location. Please try again.');
|
|
}
|
|
};
|
|
|
|
const extractPhone = (address: string) => {
|
|
const phoneMatch = address.match(/Phone: (\d+)/);
|
|
return phoneMatch ? phoneMatch[1] : null;
|
|
};
|
|
|
|
const handleWhatsApp = () => {
|
|
const phone = extractPhone(order.address);
|
|
if (phone) {
|
|
Linking.openURL(`whatsapp://send?phone=+91${phone}`);
|
|
} else {
|
|
Alert.alert('No phone number found');
|
|
}
|
|
};
|
|
|
|
const handleDial = () => {
|
|
const phone = extractPhone(order.address);
|
|
if (phone) {
|
|
Linking.openURL(`tel:${phone}`);
|
|
} else {
|
|
Alert.alert('No phone number found');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<BottomDialog open={open} onClose={onClose}>
|
|
<View style={{ maxHeight: SCREEN_HEIGHT * 0.7 }}>
|
|
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{ flexGrow: 1 }}>
|
|
<View style={tw`pb-8 pt-2 px-4`}>
|
|
<View style={tw`items-center mb-6`}>
|
|
<View style={tw`w-12 h-1.5 bg-gray-200 rounded-full mb-4`} />
|
|
<MyText style={tw`text-lg font-bold text-gray-900`}>
|
|
Order #{order.readableId}
|
|
</MyText>
|
|
<MyText style={tw`text-sm text-gray-500`}>
|
|
Select an action to perform
|
|
</MyText>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
onViewDetails();
|
|
onClose();
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-purple-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="visibility" size={20} color="#9333ea" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
View Details
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
See full order information
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
|
|
<View style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}>
|
|
<View
|
|
style={tw`p-1`}
|
|
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
|
|
onStartShouldSetResponder={() => true}
|
|
onResponderEnd={(e) => {
|
|
e.stopPropagation();
|
|
onTogglePackaged();
|
|
}}
|
|
>
|
|
<Ionicons
|
|
name={order.isPackaged ? 'checkbox' : 'square-outline'}
|
|
size={24}
|
|
color={order.isPackaged ? '#10B981' : '#1570EF'}
|
|
/>
|
|
</View>
|
|
<View style={tw`ml-3 flex-1`}>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Packaged
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
{order.isPackaged ? 'Mark as not packaged' : 'Mark as packaged'}
|
|
</MyText>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}>
|
|
<View
|
|
style={tw`p-1`}
|
|
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
|
|
onStartShouldSetResponder={() => true}
|
|
onResponderEnd={(e) => {
|
|
e.stopPropagation();
|
|
onToggleDelivered();
|
|
}}
|
|
>
|
|
<Ionicons
|
|
name={order.isDelivered ? 'checkbox' : 'square-outline'}
|
|
size={24}
|
|
color={order.isDelivered ? '#10B981' : '#1570EF'}
|
|
/>
|
|
</View>
|
|
<View style={tw`ml-3 flex-1`}>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Delivered
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
{order.isDelivered ? 'Mark as not delivered' : 'Mark as delivered'}
|
|
</MyText>
|
|
</View>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
onOpenAdminNotes();
|
|
onClose();
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-yellow-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="edit" size={20} color="#ca8a04" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Admin Notes
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
{order.adminNotes ? 'Edit existing notes' : 'Add admin notes'}
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
|
|
{order.status !== 'cancelled' && (
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
onCancelOrder();
|
|
onClose();
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-red-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="cancel" size={20} color="#dc2626" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-red-700 text-base`}>
|
|
Cancel Order
|
|
</MyText>
|
|
<MyText style={tw`text-red-500 text-xs`}>
|
|
Cancel and provide reason
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
)}
|
|
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
handleAttachLocation();
|
|
onClose();
|
|
}}
|
|
disabled={updateAddressCoordsMutation.isPending}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-orange-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="add-location-alt" size={20} color="#ea580c" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Attach Location
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
Save GPS coordinates to address
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
handleWhatsApp();
|
|
onClose();
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-green-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="message" size={20} color="#16a34a" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Message On WhatsApp
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
Send message via WhatsApp
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`}
|
|
onPress={() => {
|
|
handleDial();
|
|
onClose();
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-green-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="phone" size={20} color="#16a34a" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`font-semibold text-gray-800 text-base`}>
|
|
Dial Mobile Number
|
|
</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>
|
|
Call customer directly
|
|
</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9ca3af" style={tw`ml-auto`} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
</View>
|
|
</BottomDialog>
|
|
);
|
|
} |