228 lines
No EOL
9.3 KiB
TypeScript
228 lines
No EOL
9.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, Alert, KeyboardAvoidingView, Platform, TextInput, ActivityIndicator } from 'react-native';
|
|
import { MaterialIcons, Ionicons } from '@expo/vector-icons';
|
|
import { tw, MyText, MyTouchableOpacity, BottomDialog } from 'common-ui';
|
|
import { trpc } from '@/src/trpc-client';
|
|
import ComplaintForm from '@/components/ComplaintForm';
|
|
|
|
interface OrderMenuProps {
|
|
orderId: string;
|
|
postActionHandler?: () => void;
|
|
}
|
|
|
|
const OrderMenu: React.FC<OrderMenuProps> = ({ orderId, postActionHandler }) => {
|
|
const [open, setOpen] = useState(false);
|
|
const [editNotesDialogOpen, setEditNotesDialogOpen] = useState(false);
|
|
const [editNotes, setEditNotes] = useState('');
|
|
const [complaintDialogOpen, setComplaintDialogOpen] = useState(false);
|
|
const [cancelDialogOpen, setCancelDialogOpen] = useState(false);
|
|
const [cancelReason, setCancelReason] = useState('');
|
|
|
|
const cancelOrderMutation = trpc.user.order.cancelOrder.useMutation();
|
|
const updateNotesMutation = trpc.user.order.updateUserNotes.useMutation({
|
|
onSuccess: () => {
|
|
Alert.alert('Success', 'Notes updated successfully');
|
|
setEditNotesDialogOpen(false);
|
|
setEditNotes('');
|
|
postActionHandler?.();
|
|
},
|
|
onError: (error: any) => {
|
|
Alert.alert('Error', error.message || 'Failed to update notes');
|
|
},
|
|
});
|
|
|
|
const handleEditNotes = async () => {
|
|
try {
|
|
await updateNotesMutation.mutateAsync({
|
|
id: orderId,
|
|
userNotes: editNotes.trim()
|
|
});
|
|
} catch (error) {
|
|
// Error handled in mutation
|
|
}
|
|
};
|
|
|
|
const handleCancelOrder = async () => {
|
|
if (!cancelReason.trim()) {
|
|
Alert.alert('Error', 'Please enter a reason for cancellation');
|
|
return;
|
|
}
|
|
try {
|
|
await cancelOrderMutation.mutateAsync({ id: orderId, reason: cancelReason });
|
|
Alert.alert('Success', 'Order cancelled successfully');
|
|
setCancelDialogOpen(false);
|
|
setCancelReason('');
|
|
postActionHandler?.();
|
|
} catch (error: any) {
|
|
Alert.alert('Error', error.message || 'Failed to cancel order');
|
|
}
|
|
};
|
|
|
|
const handleComplaintClose = () => {
|
|
setComplaintDialogOpen(false);
|
|
postActionHandler?.();
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* Menu Trigger */}
|
|
<MyTouchableOpacity
|
|
style={tw`w-10 h-10 rounded-full bg-white border border-slate-200 items-center justify-center shadow-sm`}
|
|
onPress={() => setOpen(true)}
|
|
>
|
|
<Ionicons name="ellipsis-vertical" size={18} color="#475569" />
|
|
</MyTouchableOpacity>
|
|
|
|
{/* Menu Dialog */}
|
|
<BottomDialog open={open} onClose={() => setOpen(false)}>
|
|
<View style={tw`pb-8 pt-2 px-4`}>
|
|
{/* Handle */}
|
|
<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 Options</MyText>
|
|
<MyText style={tw`text-sm text-gray-500`}>Select an action for Order #{orderId}</MyText>
|
|
</View>
|
|
|
|
<View style={tw`space-y-3`}>
|
|
<MyTouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl shadow-sm`}
|
|
onPress={() => {
|
|
setEditNotes('');
|
|
setEditNotesDialogOpen(true);
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-blue-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="edit" size={20} color="#2563EB" />
|
|
</View>
|
|
<View style={tw`flex-1`}>
|
|
<MyText style={tw`text-gray-900 font-semibold text-base`}>Edit Notes</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>Add special instructions</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
|
|
<MyTouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl shadow-sm`}
|
|
onPress={() => setComplaintDialogOpen(true)}
|
|
>
|
|
<View style={tw`w-10 h-10 rounded-full bg-yellow-50 items-center justify-center mr-4`}>
|
|
<MaterialIcons name="report-problem" size={20} color="#D97706" />
|
|
</View>
|
|
<View style={tw`flex-1`}>
|
|
<MyText style={tw`text-gray-900 font-semibold text-base`}>Raise Complaint</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>Report an issue with this order</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
|
|
<MyTouchableOpacity
|
|
style={tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl shadow-sm`}
|
|
onPress={() => setCancelDialogOpen(true)}
|
|
>
|
|
<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 style={tw`flex-1`}>
|
|
<MyText style={tw`text-gray-900 font-semibold text-base`}>Cancel Order</MyText>
|
|
<MyText style={tw`text-gray-500 text-xs`}>Request order cancellation</MyText>
|
|
</View>
|
|
<MaterialIcons name="chevron-right" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</BottomDialog>
|
|
|
|
{/* Edit Notes Dialog */}
|
|
<BottomDialog open={editNotesDialogOpen} onClose={() => setEditNotesDialogOpen(false)}>
|
|
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
|
|
<View style={tw`p-6`}>
|
|
<View style={tw`flex-row justify-between items-center mb-4`}>
|
|
<MyText style={tw`text-xl font-bold text-gray-900`}>Edit Instructions</MyText>
|
|
<MyTouchableOpacity onPress={() => setEditNotesDialogOpen(false)}>
|
|
<MaterialIcons name="close" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
|
|
<TextInput
|
|
style={tw`bg-gray-50 border border-gray-200 rounded-xl p-4 min-h-32 text-base text-gray-800 mb-6`}
|
|
value={editNotes}
|
|
onChangeText={setEditNotes}
|
|
placeholder="Add special delivery instructions here..."
|
|
placeholderTextColor="#9CA3AF"
|
|
multiline
|
|
numberOfLines={4}
|
|
textAlignVertical="top"
|
|
/>
|
|
|
|
<MyTouchableOpacity
|
|
style={tw`bg-blue-600 py-4 rounded-xl shadow-sm items-center ${updateNotesMutation.isPending ? 'opacity-70' : ''}`}
|
|
onPress={handleEditNotes}
|
|
disabled={updateNotesMutation.isPending}
|
|
>
|
|
{updateNotesMutation.isPending ? (
|
|
<ActivityIndicator color="white" />
|
|
) : (
|
|
<MyText style={tw`text-white font-bold text-lg`}>Save Instructions</MyText>
|
|
)}
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
</KeyboardAvoidingView>
|
|
</BottomDialog>
|
|
|
|
{/* Cancel Order Dialog */}
|
|
<BottomDialog open={cancelDialogOpen} onClose={() => setCancelDialogOpen(false)}>
|
|
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
|
|
<View style={tw`p-6`}>
|
|
<View style={tw`flex-row justify-between items-center mb-4`}>
|
|
<MyText style={tw`text-xl font-bold text-gray-900`}>Cancel Order</MyText>
|
|
<MyTouchableOpacity onPress={() => setCancelDialogOpen(false)}>
|
|
<MaterialIcons name="close" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
|
|
<View style={tw`bg-red-50 p-4 rounded-xl mb-4 border border-red-100`}>
|
|
<MyText style={tw`text-red-800 text-sm`}>
|
|
Are you sure you want to cancel this order? This action cannot be undone.
|
|
</MyText>
|
|
</View>
|
|
|
|
<MyText style={tw`text-gray-700 font-medium mb-2`}>Reason for cancellation</MyText>
|
|
<TextInput
|
|
style={tw`bg-gray-50 border border-gray-200 rounded-xl p-4 min-h-24 text-base text-gray-800 mb-6`}
|
|
value={cancelReason}
|
|
onChangeText={setCancelReason}
|
|
placeholder="Please tell us why you are cancelling..."
|
|
placeholderTextColor="#9CA3AF"
|
|
multiline
|
|
numberOfLines={3}
|
|
textAlignVertical="top"
|
|
/>
|
|
|
|
<MyTouchableOpacity
|
|
style={tw`bg-red-600 py-4 rounded-xl shadow-sm items-center ${cancelOrderMutation.isPending ? 'opacity-70' : ''}`}
|
|
onPress={handleCancelOrder}
|
|
disabled={cancelOrderMutation.isPending}
|
|
>
|
|
{cancelOrderMutation.isPending ? (
|
|
<ActivityIndicator color="white" />
|
|
) : (
|
|
<MyText style={tw`text-white font-bold text-lg`}>Confirm Cancellation</MyText>
|
|
)}
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
</KeyboardAvoidingView>
|
|
</BottomDialog>
|
|
|
|
{/* Raise Complaint Dialog */}
|
|
<BottomDialog open={complaintDialogOpen} onClose={handleComplaintClose}>
|
|
<ComplaintForm
|
|
open={complaintDialogOpen}
|
|
onClose={handleComplaintClose}
|
|
orderId={orderId}
|
|
/>
|
|
</BottomDialog>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default OrderMenu; |