freshyo/apps/admin-ui/app/(drawer)/offers/index.tsx
2026-07-28 01:47:38 +05:30

146 lines
5.7 KiB
TypeScript

import React from 'react'
import { View, TouchableOpacity, Alert, Image, FlatList } from 'react-native'
import { MaterialCommunityIcons } from '@expo/vector-icons'
import { MyText, tw, MyTouchableOpacity, useManualRefresh, useMarkDataFetchers } from 'common-ui'
import { trpc } from '@/src/trpc-client'
import { useRouter } from 'expo-router'
import dayjs from 'dayjs'
import { LinearGradient } from 'expo-linear-gradient'
export default function OffersList() {
const router = useRouter()
const { data, isLoading, refetch } = trpc.admin.offers.getAll.useQuery()
const toggleSuspend = trpc.admin.offers.toggleSuspend.useMutation({
onSuccess: () => refetch(),
})
const deleteOffer = trpc.admin.offers.delete.useMutation({
onSuccess: () => refetch(),
})
const offers = data?.offers || []
useManualRefresh(() => refetch())
useMarkDataFetchers(() => refetch())
if (isLoading) {
return (
<View style={tw`flex-1 justify-center items-center bg-white`}>
<MyText>Loading offers...</MyText>
</View>
)
}
const handleToggleSuspend = (id: number) => {
toggleSuspend.mutate({ id })
}
const handleDelete = (id: number) => {
Alert.alert('Delete Offer', 'Are you sure you want to delete this offer?', [
{ text: 'Cancel', style: 'cancel' },
{ text: 'Delete', style: 'destructive', onPress: () => deleteOffer.mutate({ id }) },
])
}
return (
<View style={tw`flex-1 bg-white relative`}>
<FlatList
data={offers}
keyExtractor={(item: any) => item.id.toString()}
contentContainerStyle={tw`p-4`}
ListEmptyComponent={
<View style={tw`flex-1 justify-center items-center py-20`}>
<MaterialCommunityIcons name="sale" size={64} color="#E5E7EB" />
<MyText style={tw`text-gray-500 mt-4 text-lg`}>No offers yet</MyText>
<MyText style={tw`text-gray-400 text-sm mt-1`}>Create your first offer</MyText>
</View>
}
renderItem={({ item: offer }: { item: any }) => (
<TouchableOpacity
onPress={() => router.push(`/offers/edit/${offer.id}` as any)}
style={tw`bg-white border border-gray-200 rounded-2xl mb-4 overflow-hidden shadow-sm`}
>
<View style={tw`h-40 bg-gray-100`}>
{offer.images?.[0] ? (
<Image source={{ uri: offer.images[0] }} style={tw`w-full h-full`} resizeMode="cover" />
) : (
<View style={tw`flex-1 justify-center items-center`}>
<MaterialCommunityIcons name="image-off" size={48} color="#D1D5DB" />
</View>
)}
{offer.isSuspended && (
<View style={tw`absolute top-3 left-3 bg-red-500 px-3 py-1 rounded-full`}>
<MyText style={tw`text-white text-xs font-bold`}>Suspended</MyText>
</View>
)}
</View>
<View style={tw`p-4`}>
<MyText style={tw`text-lg font-bold text-gray-900`} numberOfLines={1}>
{offer.name}
</MyText>
{offer.shortDescription && (
<MyText style={tw`text-gray-500 text-sm mt-1`} numberOfLines={2}>
{offer.shortDescription}
</MyText>
)}
<View style={tw`flex-row items-center mt-3`}>
<MyText style={tw`text-xl font-bold text-gray-900`}>{offer.price}</MyText>
{offer.marketPrice && Number(offer.marketPrice) > Number(offer.price) && (
<MyText style={tw`text-sm text-gray-400 line-through ml-2`}>
{offer.marketPrice}
</MyText>
)}
</View>
<View style={tw`flex-row items-center mt-2`}>
<MaterialCommunityIcons name="package-variant" size={16} color="#9CA3AF" />
<MyText style={tw`text-gray-500 text-sm ml-1`}>
{offer.items?.length || 0} product{(offer.items?.length || 0) !== 1 ? 's' : ''}
</MyText>
</View>
<MyText style={tw`text-gray-400 text-xs mt-2`}>
Added {dayjs(offer.addedOn).format('DD MMM, YYYY')}
</MyText>
</View>
<View style={tw`flex-row border-t border-gray-100`}>
<TouchableOpacity
onPress={() => handleToggleSuspend(offer.id)}
style={tw`flex-1 py-3 items-center ${offer.isSuspended ? 'bg-green-50' : 'bg-red-50'}`}
>
<MyText style={tw`text-sm font-bold ${offer.isSuspended ? 'text-green-600' : 'text-red-600'}`}>
{offer.isSuspended ? 'Activate' : 'Suspend'}
</MyText>
</TouchableOpacity>
<TouchableOpacity
onPress={() => handleDelete(offer.id)}
style={tw`flex-1 py-3 items-center bg-red-50 border-l border-gray-100`}
>
<MyText style={tw`text-sm font-bold text-red-600`}>Delete</MyText>
</TouchableOpacity>
</View>
</TouchableOpacity>
)}
/>
<MyTouchableOpacity
testID="add-offer-fab"
accessibilityLabel="add-offer-fab"
onPress={() => router.push('/offers/add' as any)}
style={{ position: 'absolute', bottom: 32, right: 24, zIndex: 100 }}
>
<LinearGradient
colors={['#F83758', '#E91E63']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={tw`w-16 h-16 rounded-[24px] items-center justify-center shadow-lg`}
>
<MaterialCommunityIcons name="plus" size={32} color="white" />
</LinearGradient>
</MyTouchableOpacity>
</View>
)
}