import React, { useState } from 'react'; import { View, FlatList, StyleSheet, TouchableOpacity, ActivityIndicator, } from 'react-native'; import Animated, { FadeInDown, FadeIn } from 'react-native-reanimated'; import { CreditCard, Calendar, Hash, IndianRupee, Percent, Server, Wifi, WifiOff, Receipt, CheckCircle2, } from 'lucide-react-native'; import { InsideHeader, Loader } from '../../Component/Index'; import { useDispatch, useSelector } from 'react-redux'; import { useOfflineTenderPurchase } from '../../Services/ApiCall/Hooks'; import { StackActions, useNavigation } from '@react-navigation/native'; import { showErrorAlert, showToast } from '../../Constant/ShowDailog'; import { clearPurchaseTender } from '../../Redux/Slices/SelectedPurchaseTender'; import { useTheme } from '../../Hooks/useTheme'; import AppText from '../../components/AppText'; const ProceedToPurTender = () => { const navigation: any = useNavigation(); const Dispatch = useDispatch(); const { colors, spacing, shadows } = useTheme(); const [loading, setLoading] = useState(false); const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseTender); const { mutate, isPending } = useOfflineTenderPurchase(); const calculateTotalAmount = (item: any) => { const gstAmount = (Number(item.documentFees) + Number(item.portalCharge)) * (Number(item.gst) / 100); return Number(item.documentFees) + Number(item.portalCharge) + gstAmount; }; const grandTotal = SelectedPurchaseList.reduce( (sum: number, item: any) => sum + calculateTotalAmount(item), 0 ); const handleOfflinePurchase = async () => { const orderNo = `ORD${Date.now()}`; const body = { tenderDetails: SelectedPurchaseList.map((item: any, index: number) => ({ gst: item.gst, regId: item.regId || 0, deptId: item.deptId || 1, gstAmount: item.gst / 100, payableAmount: calculateTotalAmount(item), portalCharge: item.portalCharge, tenderFees: item.documentFees, tenderId: item.tenderId, tenderNumber: item.tenderNumber, tenderStatus: item.tenderStatus ?? '', tenderType: item.tenderType ?? '', isPurchased: item.purchaseStatus ?? false, totalPayableAmount: calculateTotalAmount(item), percentageAmount: calculateTotalAmount(item) / 100, newTenderDocumentFees: item.documentFees * index + 1, })), orderNo, }; try { mutate(body, { onSuccess: (res: any) => { if (res.statusCode === 200) { showToast(res.message); navigation.dispatch(StackActions.pop(2)); Dispatch(clearPurchaseTender()); } }, onError: (error: any) => { showErrorAlert('Something went wrong'); console.log(error, '================purchse Error'); }, }); } catch (error) { console.log('purchase offline error', error); } }; const handlePurchase = (type: 'online' | 'offline') => { setLoading(true); setTimeout(() => { setLoading(false); type === 'online' ? showErrorAlert('Online Purchase is disabled') : handleOfflinePurchase(); }, 1200); }; const styles = makeStyles(colors, spacing, shadows); const renderItem = ({ item, index }: { item: any; index: number }) => { const total = calculateTotalAmount(item); const gstAmount = (Number(item.documentFees) + Number(item.portalCharge)) * (Number(item.gst) / 100); return ( {/* Card Top Accent */} {/* Header */} {String(index + 1).padStart(2, '0')} {item.auctionOfWork || item.auctionNumber} {item.auctionPattern ? ( {item.auctionPattern} ) : null} {/* Divider */} {/* Info Rows */} } label="Tender No" value={item.tenderNumber} colors={colors} /> } label="Purchase End" value={item.purchaseEnd || '—'} colors={colors} /> {/* Divider */} {/* Fee breakdown */} FEE BREAKDOWN {/* Total Banner */} Total Payable ₹ {total.toFixed(2)} ); }; return ( {/* Grand Total Strip */} {SelectedPurchaseList.length} tender{SelectedPurchaseList.length !== 1 ? 's' : ''} ₹ {grandTotal.toFixed(2)} Ready to pay item?.tenderId?.toString()} contentContainerStyle={styles.container} showsVerticalScrollIndicator={false} /> {/* Bottom Action Buttons */} handlePurchase('online')} > Online handlePurchase('offline')} > Offline {/* Loading Overlay */} {(loading || isPending) && ( Processing purchase… )} ); }; export default ProceedToPurTender; /* ─── Sub-components ─── */ const InfoRow = ({ icon, label, value, colors, }: { icon: React.ReactNode; label: string; value: string; colors: any; }) => ( {icon} {label} {value} ); const infoRowStyles = StyleSheet.create({ row: { flexDirection: 'row', alignItems: 'center', paddingVertical: 5, gap: 6, }, iconWrap: { width: 22, alignItems: 'center', }, label: { flex: 1, fontWeight: '500', } as any, value: { fontWeight: '600', } as any, }); const FeeRow = ({ label, value, colors, }: { label: string; value: string; colors: any; }) => ( {label} {value} ); const feeRowStyles = StyleSheet.create({ row: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 3, }, }); /* ─── Styles factory ─── */ const makeStyles = (colors: any, spacing: any, shadows: any) => StyleSheet.create({ screen: { flex: 1, backgroundColor: colors.background, }, grandTotalStrip: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', backgroundColor: colors.surface, marginHorizontal: spacing.m, marginTop: spacing.m, marginBottom: spacing.s, paddingHorizontal: spacing.m, paddingVertical: spacing.m, borderRadius: 18, ...shadows.medium, }, grandTotalRight: { flexDirection: 'row', alignItems: 'center', gap: 5, backgroundColor: `${colors.success}15`, paddingHorizontal: spacing.s + 2, paddingVertical: spacing.xs + 2, borderRadius: 20, }, container: { paddingHorizontal: spacing.m, paddingTop: spacing.s, paddingBottom: 120, }, card: { backgroundColor: colors.surface, borderRadius: 20, marginBottom: spacing.m, overflow: 'hidden', ...shadows.medium, }, cardAccent: { height: 4, backgroundColor: colors.primary, }, cardBody: { padding: spacing.m, }, cardHeader: { flexDirection: 'row', alignItems: 'flex-start', marginBottom: spacing.s, }, indexBadge: { width: 32, height: 32, borderRadius: 10, backgroundColor: colors.primary, alignItems: 'center', justifyContent: 'center', marginTop: 2, }, patternBadge: { alignSelf: 'flex-start', backgroundColor: `${colors.primary}15`, paddingHorizontal: spacing.s, paddingVertical: 2, borderRadius: 8, marginTop: 4, }, divider: { height: StyleSheet.hairlineWidth, backgroundColor: colors.border, marginVertical: spacing.s, }, feeSection: { backgroundColor: colors.overlay, borderRadius: 12, padding: spacing.s + 2, marginBottom: spacing.s, }, feeHeader: { letterSpacing: 1.2, marginBottom: spacing.xs + 2, fontWeight: '700', } as any, totalBanner: { backgroundColor: colors.primary, borderRadius: 14, paddingVertical: 12, paddingHorizontal: spacing.m, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, totalLeft: { flexDirection: 'row', alignItems: 'center', gap: spacing.s, }, footer: { position: 'absolute', bottom: 0, left: 0, right: 0, flexDirection: 'row', paddingHorizontal: spacing.m, paddingTop: spacing.s + 4, paddingBottom: spacing.m + 4, backgroundColor: colors.surface, gap: spacing.s, ...shadows.strong, }, button: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 14, borderRadius: 16, gap: spacing.s, }, onlineButton: { backgroundColor: colors.surface, borderWidth: 1.5, borderColor: colors.primary, }, offlineButton: { backgroundColor: colors.buttonPrimary, ...shadows.medium, }, onlineBtnText: { letterSpacing: 1.2, } as any, offlineBtnText: { letterSpacing: 1.2, } as any, loadingOverlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.3)', justifyContent: 'center', alignItems: 'center', zIndex: 10, }, loadingCard: { backgroundColor: colors.surface, borderRadius: 20, padding: spacing.l, alignItems: 'center', ...shadows.strong, }, });