import React, { useState, useCallback, useMemo } from 'react';
import { View, TouchableOpacity, Alert, RefreshControl, Dimensions } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import { tw, MyButton, MyText, SearchBar, MyFlatList, useMarkDataFetchers, MyTouchableOpacity, BottomDropdown } from 'common-ui';
import useManualRefresh from 'common-ui/hooks/useManualRefresh';
import { trpc } from '@/src/trpc-client';
import { useRouter } from 'expo-router';
import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
const CouponItem = ({ item, onDelete }: { item: any; onDelete: (id: number) => void }) => {
const router = useRouter();
const getCouponStatus = (coupon: any) => {
if (coupon.isInvalidated) return 'inactive';
if (coupon.validTill && new Date(coupon.validTill) <= new Date()) return 'expired';
return 'active';
};
const status = getCouponStatus(item);
const getBorderColor = () => {
if (status === 'active') return 'border-green-500';
if (status === 'expired') return 'border-yellow-500';
return 'border-red-500';
};
const getBgColor = () => {
if (status === 'active') return 'bg-green-100';
if (status === 'expired') return 'bg-yellow-100';
return 'bg-red-100';
};
const getTextColor = () => {
if (status === 'active') return 'text-green-600';
if (status === 'expired') return 'text-yellow-600';
return 'text-red-600';
};
const getIconColor = () => {
if (status === 'active') return '#10b981';
if (status === 'expired') return '#f59e0b';
return '#ef4444';
};
return (
{item.couponCode}
ID: {item.id}
{status === 'active' ? 'Active' : status === 'expired' ? 'Expired' : 'Inactive'}
Discount: {item.discountPercent ? `${item.discountPercent}% off` : item.flatDiscount ? `₹${item.flatDiscount} off` : 'N/A'}
Min Order: {item.minOrder ? `₹${item.minOrder}` : 'None'}
Max: {item.maxValue ? `₹${item.maxValue}` : 'None'}
Valid Till: {item.validTill ? new Date(item.validTill).toLocaleDateString() : 'No expiry'}
Target: {item.isApplyForAll ? 'All Users' : item.applicableUsers?.length > 0 ? `${item.applicableUsers.length} Users` : 'All Users'}
{item.applicableProducts && item.applicableProducts.length > 0 && (
Products: {item.applicableProducts.length} selected
)}
router.push(`/(drawer)/edit-coupon/${item.id}`)}
style={tw`bg-blue-500 p-3 rounded-lg shadow-md flex-1 flex-row items-center justify-center`}
>
Edit
onDelete(item.id)}
style={tw`bg-red-500 p-3 rounded-lg shadow-md flex-1 flex-row items-center justify-center`}
>
Delete
);
};
const ReservedCouponItem = ({ item }: { item: any }) => {
const getStatus = () => {
if (item.isRedeemed) return 'redeemed';
if (item.validTill && new Date(item.validTill) <= new Date()) return 'expired';
return 'active';
};
const status = getStatus();
const getBorderColor = () => {
if (status === 'active') return 'border-green-500';
if (status === 'expired') return 'border-yellow-500';
return 'border-blue-500';
};
const getBgColor = () => {
if (status === 'active') return 'bg-green-100';
if (status === 'expired') return 'bg-yellow-100';
return 'bg-blue-100';
};
const getTextColor = () => {
if (status === 'active') return 'text-green-600';
if (status === 'expired') return 'text-yellow-600';
return 'text-blue-600';
};
const getIconColor = () => {
if (status === 'active') return '#10b981';
if (status === 'expired') return '#f59e0b';
return '#3b82f6';
};
return (
{item.secretCode}
Coupon: {item.couponCode}
{status === 'active' ? 'Active' : status === 'expired' ? 'Expired' : 'Redeemed'}
Discount: {item.discountPercent ? `${item.discountPercent}% off` : item.flatDiscount ? `₹${item.flatDiscount} off` : 'N/A'}
Min Order: {item.minOrder ? `₹${item.minOrder}` : 'None'}
Max: {item.maxValue ? `₹${item.maxValue}` : 'None'}
Valid Till: {item.validTill ? new Date(item.validTill).toLocaleDateString() : 'No expiry'}
{item.isRedeemed && item.redeemedUser && (
Redeemed by: {item.redeemedUser.name || 'Unknown'} ({item.redeemedUser.mobile})
Redeemed on: {item.redeemedAt ? new Date(item.redeemedAt).toLocaleDateString() : 'N/A'}
)}
Created by: {item.creator?.name || 'Unknown'}
);
};
const GeneralTab = () => {
const router = useRouter();
const [refreshing, setRefreshing] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [statusFilters, setStatusFilters] = useState([]);
const {
data,
fetchNextPage,
hasNextPage,
isLoading,
isFetchingNextPage,
error,
refetch,
} = trpc.admin.coupon.getAll.useInfiniteQuery(
{ limit: 20, search: searchQuery },
{ getNextPageParam: (lastPage) => lastPage.nextCursor }
);
const coupons = useMemo(() => data?.pages.flatMap(page => page.coupons) || [], [data]);
const getCouponStatus = (coupon: any) => {
if (coupon.isInvalidated) return 'inactive';
if (coupon.validTill && new Date(coupon.validTill) <= new Date()) return 'expired';
return 'active';
};
const filteredCoupons = useMemo(() => {
let filtered = coupons;
if (statusFilters.length > 0) {
filtered = filtered.filter(coupon => statusFilters.includes(getCouponStatus(coupon)));
}
return filtered;
}, [coupons, statusFilters]);
const handleRefresh = useCallback(async () => {
setRefreshing(true);
await refetch();
setRefreshing(false);
}, [refetch]);
useManualRefresh(() => refetch());
useMarkDataFetchers(() => {
refetch();
});
const deleteCoupon = trpc.admin.coupon.delete.useMutation();
const handleDeleteCoupon = (id: number) => {
Alert.alert('Delete Coupon', 'Are you sure you want to delete this coupon?', [
{ text: 'Cancel', style: 'cancel' },
{
text: 'Delete',
style: 'destructive',
onPress: () => {
deleteCoupon.mutate({ id }, {
onSuccess: () => {
Alert.alert('Success', 'Coupon deleted successfully');
refetch();
},
onError: (error: any) => {
Alert.alert('Error', error.message || 'Failed to delete coupon');
},
});
},
},
]);
};
if (isLoading) {
return (
Loading Coupons...
);
}
if (error) {
return (
Failed to load coupons
refetch()} style={tw`bg-red-500`}>
Retry
);
}
return (
setStatusFilters(value as string[])}
multiple={true}
triggerComponent={({ onPress }) => (
)}
/>
item.id.toString()}
renderItem={({ item }) => }
refreshControl={
}
contentContainerStyle={tw`px-4 pb-4`}
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}}
onEndReachedThreshold={0.5}
ListEmptyComponent={
No Coupons Found
{searchQuery ? (
setSearchQuery('')} style={tw`bg-gray-500 mt-4`}>
Clear Search
) : null}
}
/>
);
};
const ReservedTab = () => {
const router = useRouter();
const [refreshing, setRefreshing] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [statusFilters, setStatusFilters] = useState([]);
const {
data,
isLoading,
isFetchingNextPage,
hasNextPage,
fetchNextPage,
error,
refetch
} = trpc.admin.coupon.getReservedCoupons.useInfiniteQuery(
{ limit: 20, search: searchQuery },
{ getNextPageParam: (lastPage) => lastPage.nextCursor }
);
const coupons = useMemo(() => data?.pages.flatMap((page) => page.coupons) || [], [data]);
const getStatus = (coupon: any) => {
if (coupon.isRedeemed) return 'redeemed';
if (coupon.validTill && new Date(coupon.validTill) <= new Date()) return 'expired';
return 'active';
};
const filteredCoupons = useMemo(() => {
let filtered = coupons;
if (statusFilters.length > 0) {
filtered = filtered.filter(coupon => statusFilters.includes(getStatus(coupon)));
}
return filtered;
}, [coupons, statusFilters]);
const handleRefresh = useCallback(async () => {
setRefreshing(true);
await refetch();
setRefreshing(false);
}, [refetch]);
useManualRefresh(() => refetch());
useMarkDataFetchers(() => {
refetch();
});
if (isLoading) {
return (
Loading Reserved Coupons...
);
}
if (error) {
return (
Failed to load reserved coupons
refetch()} style={tw`bg-red-500`}>
Retry
);
}
return (
setStatusFilters(value as string[])}
multiple={true}
triggerComponent={({ onPress }) => (
)}
/>
item.id.toString()}
renderItem={({ item }) => }
refreshControl={
}
contentContainerStyle={tw`px-4 pb-4`}
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}}
onEndReachedThreshold={0.5}
ListEmptyComponent={
No Reserved Coupons Found
{searchQuery ? (
setSearchQuery('')} style={tw`bg-gray-500 mt-4`}>
Clear Search
) : null}
}
/>
);
};
export default function Coupons() {
const router = useRouter();
const [index, setIndex] = useState(0);
const routes = [
{ key: 'general', title: 'General' },
{ key: 'reserved', title: 'Reserved' },
];
return (
(
)}
/>
router.push('/(drawer)/create-coupon')}
activeOpacity={0.95}
style={{ position: 'absolute', bottom: 32, right: 24, zIndex: 100 }}
>
);
}