121 lines
4 KiB
TypeScript
121 lines
4 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, TextInput, ActivityIndicator, KeyboardAvoidingView, Platform, Alert } from 'react-native';
|
|
import { MaterialIcons } from '@expo/vector-icons'
|
|
import { MyText, ImageUploaderNeo, tw, MyTouchableOpacity, type ImageUploaderNeoItem, type ImageUploaderNeoPayload } from 'common-ui'
|
|
import { trpc } from '@/src/trpc-client'
|
|
import { useUploadToObjectStorage } from '../hooks/useUploadToObjectStore'
|
|
|
|
interface ComplaintFormProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
orderId: number;
|
|
}
|
|
|
|
export default function ComplaintForm({ open, onClose, orderId }: ComplaintFormProps) {
|
|
const [complaintBody, setComplaintBody] = useState('');
|
|
const [complaintImages, setComplaintImages] = useState<ImageUploaderNeoItem[]>([])
|
|
|
|
const raiseComplaintMutation = trpc.user.complaint.raise.useMutation()
|
|
|
|
const { upload, isUploading } = useUploadToObjectStorage()
|
|
|
|
const handleAddImages = (images: ImageUploaderNeoPayload[]) => {
|
|
setComplaintImages((prev) => [
|
|
...prev,
|
|
...images.map((image) => ({
|
|
imgUrl: image.url,
|
|
mimeType: image.mimeType,
|
|
})),
|
|
])
|
|
}
|
|
|
|
const handleRemoveImage = (image: ImageUploaderNeoPayload) => {
|
|
setComplaintImages((prev) => prev.filter((item) => item.imgUrl !== image.url))
|
|
}
|
|
|
|
const handleSubmit = async () => {
|
|
if (!complaintBody.trim()) {
|
|
Alert.alert('Error', 'Please enter complaint details');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
let imageUrls: string[] = []
|
|
|
|
if (complaintImages.length > 0) {
|
|
const uploadImages = await Promise.all(
|
|
complaintImages.map(async (image) => {
|
|
const response = await fetch(image.imgUrl)
|
|
const blob = await response.blob()
|
|
return { blob, mimeType: image.mimeType || 'image/jpeg' }
|
|
})
|
|
)
|
|
|
|
const { keys } = await upload({
|
|
images: uploadImages,
|
|
contextString: 'complaint',
|
|
})
|
|
|
|
imageUrls = keys
|
|
}
|
|
|
|
await raiseComplaintMutation.mutateAsync({
|
|
orderId: orderId.toString(),
|
|
complaintBody: complaintBody.trim(),
|
|
imageUrls,
|
|
})
|
|
|
|
Alert.alert('Success', 'Complaint raised successfully')
|
|
setComplaintBody('')
|
|
setComplaintImages([])
|
|
onClose()
|
|
} catch (error: any) {
|
|
Alert.alert('Error', error.message || 'Failed to raise complaint')
|
|
}
|
|
}
|
|
|
|
if (!open) return null;
|
|
|
|
return (
|
|
<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`}>Raise Complaint</MyText>
|
|
<MyTouchableOpacity onPress={onClose}>
|
|
<MaterialIcons name="close" size={24} color="#9CA3AF" />
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
|
|
<MyText style={tw`text-gray-700 font-medium mb-2`}>Describe the issue</MyText>
|
|
<TextInput
|
|
style={tw`bg-gray-50 border border-gray-200 rounded-xl p-4 min-h-32 text-base text-gray-800 mb-4`}
|
|
value={complaintBody}
|
|
onChangeText={setComplaintBody}
|
|
placeholder="Tell us what went wrong..."
|
|
placeholderTextColor="#9CA3AF"
|
|
multiline
|
|
numberOfLines={4}
|
|
textAlignVertical="top"
|
|
/>
|
|
|
|
<ImageUploaderNeo
|
|
images={complaintImages}
|
|
onImageAdd={handleAddImages}
|
|
onImageRemove={handleRemoveImage}
|
|
/>
|
|
|
|
<MyTouchableOpacity
|
|
style={tw`bg-yellow-500 py-4 rounded-xl shadow-sm items-center mt-4 ${raiseComplaintMutation.isPending || isUploading ? 'opacity-70' : ''}`}
|
|
onPress={handleSubmit}
|
|
disabled={raiseComplaintMutation.isPending || isUploading}
|
|
>
|
|
{raiseComplaintMutation.isPending || isUploading ? (
|
|
<ActivityIndicator color="white" />
|
|
) : (
|
|
<MyText style={tw`text-white font-bold text-lg`}>Submit Complaint</MyText>
|
|
)}
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
</KeyboardAvoidingView>
|
|
);
|
|
}
|