187 lines
No EOL
7.1 KiB
TypeScript
187 lines
No EOL
7.1 KiB
TypeScript
import React from 'react';
|
|
import { View, Linking, TouchableOpacity, ActivityIndicator } from 'react-native';
|
|
import { Image } from 'expo-image';
|
|
import { MyText, tw, useManualRefresh, MyFlatList, useMarkDataFetchers, theme, MyTouchableOpacity } from 'common-ui';
|
|
import { MaterialIcons, Ionicons } from '@expo/vector-icons';
|
|
import { trpc } from '@/src/trpc-client';
|
|
import { useGetEssentialConsts } from '@/src/api-hooks/essential-consts.api';
|
|
import dayjs from 'dayjs';
|
|
import { useRouter } from 'expo-router';
|
|
|
|
interface ComplaintItemProps {
|
|
item: any;
|
|
}
|
|
|
|
const ComplaintItem: React.FC<ComplaintItemProps> = ({ item }) => (
|
|
<View style={tw`bg-white rounded-2xl p-5 mb-4 shadow-sm border border-gray-100`}>
|
|
{/* Header: ID, Date, Status */}
|
|
<View style={tw`flex-row justify-between items-start mb-3`}>
|
|
<View>
|
|
<View style={tw`flex-row items-center`}>
|
|
<MyText style={tw`text-base font-bold text-gray-900`}>
|
|
Complaint #{item.id}
|
|
</MyText>
|
|
{item.orderId && (
|
|
<View style={tw`bg-gray-100 px-2 py-0.5 rounded ml-2`}>
|
|
<MyText style={tw`text-[10px] font-bold text-gray-500`}>
|
|
Order #{item.orderId}
|
|
</MyText>
|
|
</View>
|
|
)}
|
|
</View>
|
|
<MyText style={tw`text-xs text-gray-400 mt-1`}>
|
|
{dayjs(item.createdAt).format('MMM DD, YYYY • h:mm A')}
|
|
</MyText>
|
|
</View>
|
|
|
|
<View style={tw`px-3 py-1 rounded-full ${item.isResolved ? 'bg-green-100' : 'bg-amber-100'
|
|
}`}>
|
|
<MyText style={tw`text-xs font-bold ${item.isResolved ? 'text-green-700' : 'text-amber-700'
|
|
}`}>
|
|
{item.isResolved ? 'Resolved' : 'Pending'}
|
|
</MyText>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Complaint Body */}
|
|
<MyText style={tw`text-gray-700 text-sm leading-6 mb-4`}>
|
|
{item.complaintBody}
|
|
</MyText>
|
|
|
|
{/* Admin Response */}
|
|
{item.response && (
|
|
<View style={tw`bg-blue-50 p-4 rounded-xl border border-blue-100`}>
|
|
<View style={tw`flex-row items-center mb-2`}>
|
|
<View style={tw`w-6 h-6 bg-blue-100 rounded-full items-center justify-center mr-2`}>
|
|
<MaterialIcons name="support-agent" size={14} color="#2563EB" />
|
|
</View>
|
|
<MyText style={tw`text-xs font-bold text-blue-800 uppercase tracking-wide`}>
|
|
Support Response
|
|
</MyText>
|
|
</View>
|
|
<MyText style={tw`text-sm text-blue-900 leading-5`}>
|
|
{item.response}
|
|
</MyText>
|
|
</View>
|
|
)}
|
|
|
|
{!item.response && !item.isResolved && (
|
|
<View style={tw`flex-row items-center mt-2`}>
|
|
<MaterialIcons name="schedule" size={14} color="#9CA3AF" />
|
|
<MyText style={tw`text-xs text-gray-400 ml-1 italic`}>
|
|
We are reviewing your complaint...
|
|
</MyText>
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
|
|
export default function Complaints() {
|
|
const router = useRouter();
|
|
const { data, isLoading, error, refetch } = trpc.user.complaint.getAll.useQuery();
|
|
const complaints = data?.complaints || [];
|
|
|
|
const { data: constsData } = useGetEssentialConsts();
|
|
|
|
useManualRefresh(() => refetch());
|
|
|
|
useMarkDataFetchers(() => {
|
|
refetch();
|
|
});
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
|
<MyText style={tw`text-gray-500 font-medium`}>Loading complaints...</MyText>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
|
<MaterialIcons name="error-outline" size={48} color="#EF4444" />
|
|
<MyText style={tw`text-gray-900 text-lg font-bold mt-4`}>Oops!</MyText>
|
|
<MyText style={tw`text-gray-500 mt-2`}>Failed to load complaints</MyText>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
<View style={tw`flex-1 bg-gray-50`}>
|
|
<MyFlatList
|
|
data={complaints}
|
|
keyExtractor={(item) => item.id.toString()}
|
|
renderItem={({ item }) => <ComplaintItem item={item} />}
|
|
contentContainerStyle={tw`px-4 py-6`}
|
|
ListHeaderComponent={
|
|
<View style={tw`bg-brand500 px-4 py-5`}>
|
|
<View style={tw`flex-row items-center mb-4`}>
|
|
<View style={tw`w-10 h-10 bg-white/20 rounded-full items-center justify-center mr-3`}>
|
|
<MaterialIcons name="support-agent" size={22} color="white" />
|
|
</View>
|
|
<MyText style={tw`text-lg font-bold text-white`}>Need Help?</MyText>
|
|
</View>
|
|
|
|
<View style={tw`flex-col`}>
|
|
<TouchableOpacity
|
|
style={tw`w-full bg-white rounded-xl p-3 mb-3 flex-row items-center`}
|
|
onPress={() => {
|
|
const phone = constsData?.supportMobile || '8688182552';
|
|
Linking.openURL(`tel:${phone}`);
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 bg-green-100 rounded-full items-center justify-center mr-3`}>
|
|
<Ionicons name="call" size={20} color="#16A34A" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`text-[10px] text-gray-500 uppercase font-bold`}>Call Us</MyText>
|
|
<MyText style={tw`text-base font-bold text-gray-900`}>
|
|
{constsData?.supportMobile || '8688182552'}
|
|
</MyText>
|
|
</View>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={tw`w-full bg-white rounded-xl p-3 flex-row items-center`}
|
|
onPress={() => {
|
|
const email = constsData?.supportEmail || 'qushammohd@gmail.com';
|
|
Linking.openURL(`mailto:${email}`);
|
|
}}
|
|
>
|
|
<View style={tw`w-10 h-10 bg-blue-100 rounded-full items-center justify-center mr-3`}>
|
|
<MaterialIcons name="email" size={20} color="#2563EB" />
|
|
</View>
|
|
<View>
|
|
<MyText style={tw`text-[10px] text-gray-500 uppercase font-bold`}>Email</MyText>
|
|
<MyText style={tw`text-sm font-bold text-gray-900`} numberOfLines={1}>
|
|
{constsData?.supportEmail || 'qushammohd@gmail.com'}
|
|
</MyText>
|
|
</View>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
}
|
|
ListEmptyComponent={
|
|
<View style={tw`flex-1 justify-center items-center py-20`}>
|
|
<View style={tw`w-20 h-20 bg-gray-100 rounded-full items-center justify-center mb-6`}>
|
|
<MaterialIcons name="thumb-up-off-alt" size={40} color="#9CA3AF" />
|
|
</View>
|
|
<MyText style={tw`text-xl font-bold text-gray-900`}>No Complaints</MyText>
|
|
<MyText style={tw`text-gray-500 text-center mt-2 px-10 leading-5`}>
|
|
You haven't raised any complaints yet. That's great!
|
|
</MyText>
|
|
<MyTouchableOpacity
|
|
onPress={() => router.push('/(drawer)/(tabs)/home')}
|
|
style={tw`mt-8 bg-brand500 px-6 py-3 rounded-xl shadow-sm`}
|
|
>
|
|
<MyText style={tw`text-white font-bold`}>Continue Shopping</MyText>
|
|
</MyTouchableOpacity>
|
|
</View>
|
|
}
|
|
/>
|
|
</View>
|
|
);
|
|
} |