Auciton process complete
This commit is contained in:
@@ -1,52 +1,40 @@
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import React, { useCallback, useState, useEffect, useRef } from 'react';
|
||||
import { View, FlatList, ActivityIndicator, RefreshControl, Text } from 'react-native';
|
||||
import Animated, { FadeInDown, FadeOutUp } from 'react-native-reanimated';
|
||||
import LiveAuctionTile from './LiveAuctionTile';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useFetchLiveAuction } from '../../Services/BBPS/Hooks';
|
||||
import { SearchInput } from '../../Component/Serach/SeacrhInput';
|
||||
import { Skelton } from '../../Component/Index';
|
||||
import colors from '../../Constant/Color';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { selectPurchaseAuctionSlice, togglePurchaseAuction } from '../../Redux/Slices/selectPurchaseAuction';
|
||||
import { togglePurchaseAuction } from '../../Redux/Slices/selectPurchaseAuction';
|
||||
import { apiCall } from '../../Axios/Axios';
|
||||
import { GET_MY_AUCTION, LIVE_AUCTION } from '../../Services/BBPS/ApiUrls';
|
||||
import moment from 'moment';
|
||||
import { GET_MY_AUCTION } from '../../Services/BBPS/ApiUrls';
|
||||
|
||||
const LiveAuction = () => {
|
||||
const navigation: any = useNavigation();
|
||||
const Dispatch = useDispatch()
|
||||
const onEndReachedCalledDuringMomentum = useRef(true);
|
||||
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
|
||||
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch }: any = useFetchLiveAuction();
|
||||
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
|
||||
const [allBoolean, setAllBoolean] = useState({ liveAuctionData: [] })
|
||||
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch, isPending }: any = useFetchLiveAuction();
|
||||
|
||||
useEffect(() => {
|
||||
if (isRefetching) {
|
||||
setShowRefreshBanner(true);
|
||||
} else {
|
||||
const timer = setTimeout(() => {
|
||||
setShowRefreshBanner(false);
|
||||
}, 1000);
|
||||
// My Methods
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
const getMyAuction = async () => {
|
||||
try {
|
||||
const res = await apiCall<any>('get', `${GET_MY_AUCTION}`,);
|
||||
if (res?.statusCode === 200) {
|
||||
const purchasedIds = new Set(res.data.map((item: any) => item.auctionId));
|
||||
const filteredLive = data?.result.map((item: any) => ({ ...item, active: !purchasedIds.has(item.auctionId) }));
|
||||
setAllBoolean(prev => ({ ...prev, liveAuctionData: filteredLive }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('getMyAuction error', error);
|
||||
} finally {
|
||||
setAllBoolean(prev => ({ ...prev, isLoading: false }));
|
||||
}
|
||||
}, [isRefetching]);
|
||||
|
||||
const loadMore = useCallback(() => {
|
||||
if (hasNextPage && !isFetchingNextPage) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}, [hasNextPage, isFetchingNextPage]);
|
||||
|
||||
const renderFooter = useCallback(() => {
|
||||
if (!isFetchingNextPage) return null;
|
||||
return (
|
||||
<View style={{ paddingVertical: 12 }}>
|
||||
<ActivityIndicator size="small" color={colors.primary} />
|
||||
</View>
|
||||
);
|
||||
}, [isFetchingNextPage]);
|
||||
};
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ item, index }: any) => {
|
||||
@@ -68,32 +56,35 @@ const LiveAuction = () => {
|
||||
[SelectedPurchaseList]
|
||||
);
|
||||
|
||||
const getMyAuction = async () => {
|
||||
try {
|
||||
const loadMore = useCallback(() => {
|
||||
if (onEndReachedCalledDuringMomentum.current) return;
|
||||
|
||||
const res = await apiCall<any>('get', `${GET_MY_AUCTION}`,);
|
||||
if (!hasNextPage || isFetchingNextPage) return;
|
||||
|
||||
if (res?.statusCode === 200) {
|
||||
const purchasedIds = new Set(
|
||||
res.data.map((item: any) => item.auctionId),
|
||||
);
|
||||
fetchNextPage();
|
||||
onEndReachedCalledDuringMomentum.current = true;
|
||||
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
||||
|
||||
const filteredLive = data?.result.map((item: any) => ({
|
||||
...item,
|
||||
active: !purchasedIds.has(item.auctionId), // false if match, true otherwise
|
||||
}));
|
||||
const renderFooter = useCallback(() => {
|
||||
if (!isFetchingNextPage) return null;
|
||||
return (
|
||||
<View style={{ paddingVertical: 12 }}>
|
||||
<ActivityIndicator size="small" color={colors.primary} />
|
||||
</View>
|
||||
);
|
||||
}, [isFetchingNextPage]);
|
||||
|
||||
setAllBoolean(prev => ({
|
||||
...prev,
|
||||
liveAuctionData: filteredLive
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('getMyAuction error', error);
|
||||
} finally {
|
||||
setAllBoolean(prev => ({ ...prev, isLoading: false }));
|
||||
useEffect(() => {
|
||||
if (isRefetching) {
|
||||
setShowRefreshBanner(true);
|
||||
} else {
|
||||
const timer = setTimeout(() => {
|
||||
setShowRefreshBanner(false);
|
||||
}, 1000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
}, [isRefetching]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.result?.length > 0) {
|
||||
@@ -148,27 +139,34 @@ const LiveAuction = () => {
|
||||
|
||||
<FlatList
|
||||
data={allBoolean.liveAuctionData ?? []}
|
||||
keyExtractor={(item: any) => String(item.auctionNumber)}
|
||||
renderItem={renderItem}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={{ paddingBottom: 50, paddingTop: 10 }}
|
||||
|
||||
onEndReached={loadMore}
|
||||
onEndReachedThreshold={0.2}
|
||||
onEndReachedThreshold={0.1}
|
||||
|
||||
onMomentumScrollBegin={() => {
|
||||
onEndReachedCalledDuringMomentum.current = false;
|
||||
}}
|
||||
|
||||
ListFooterComponent={renderFooter}
|
||||
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isRefetching}
|
||||
onRefresh={refetch}
|
||||
tintColor="transparent" // Set to transparent if you only want your custom banner to show
|
||||
tintColor="transparent"
|
||||
colors={[colors.primary]}
|
||||
/>
|
||||
}
|
||||
|
||||
initialNumToRender={6}
|
||||
maxToRenderPerBatch={6}
|
||||
windowSize={7}
|
||||
removeClippedSubviews
|
||||
updateCellsBatchingPeriod={50}
|
||||
/>
|
||||
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -21,8 +21,6 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
|
||||
|
||||
return (
|
||||
<View style={styles.cardWrapper}>
|
||||
{/* Status Tag */}
|
||||
|
||||
{
|
||||
!showDetail ?
|
||||
<>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { memo, useState } from 'react';
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, SafeAreaView, Platform, StatusBar } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
import moment from 'moment';
|
||||
@@ -6,26 +6,29 @@ import { Briefcase, Calendar, FileText, Download, Eye, Layers, ArrowLeft, Clock
|
||||
import colors from '../../../Constant/Color';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import AuctionItemDetail from './AuctionItemDetail';
|
||||
import { useAucitonDocDownload, useAuctionItem, useGetAuciton, useGetAucitonDocument } from '../../../Services/BBPS/Hooks';
|
||||
import ReactNativeBlobUtil from 'react-native-blob-util';
|
||||
import { AUCTION_DOCUMENT_DOWNLOAD, ITEM_DOCUMENT_DOWNLOAD } from '../../../Services/BBPS/ApiUrls';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Loader } from '../../../Component/Index';
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
data?: any;
|
||||
}
|
||||
interface Props { visible: boolean; onClose: () => void; data?: any }
|
||||
|
||||
const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
|
||||
const inset = useSafeAreaInsets()
|
||||
const [allBoolean, setAllBoolean] = useState({ showItemDetail: false })
|
||||
const { data: auctionData, isLoading } = useGetAuciton({ auctionId: data?.auctionId })
|
||||
const [aucitonDetail, setAuciotnDetail] = useState<any>(auctionData)
|
||||
const [allBoolean, setAllBoolean] = useState({ showItemDetail: false, selectedItem: {}, fileLoading: false });
|
||||
const { data: auctionDocuments } = useGetAucitonDocument({ auctionId: data?.auctionId })
|
||||
const { mutate: downloadDocument, isPending } = useAucitonDocDownload()
|
||||
const { mutate } = useAuctionItem()
|
||||
const formatDate = (date?: string) => {
|
||||
if (!date) return '-';
|
||||
return moment(date, 'DD-MM-YYYY HH:mm:ss').format('DD MMM YYYY, hh:mm A');
|
||||
};
|
||||
|
||||
const isLive = data?.purchaseEnd
|
||||
? moment().isBefore(moment(data.purchaseEnd, 'DD-MM-YYYY HH:mm:ss'))
|
||||
: false;
|
||||
const isLive = data?.purchaseEnd ? moment().isBefore(moment(data.purchaseEnd, 'DD-MM-YYYY HH:mm:ss')) : false;
|
||||
|
||||
// Internal Components
|
||||
const Section = ({ title, icon: Icon, children }: any) => (
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={styles.sectionHeader}>
|
||||
@@ -43,6 +46,64 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
const handleDownload = async (id: number, fileName: string) => {
|
||||
try {
|
||||
setAllBoolean((prev: any) => ({ ...prev, fileLoading: true }));
|
||||
const { dirs } = ReactNativeBlobUtil.fs;
|
||||
|
||||
// ✅ PUBLIC DOWNLOADS DIRECTORY
|
||||
const path = `${dirs.DownloadDir}/${fileName}.pdf`;
|
||||
|
||||
console.log('📂 Saving to:', path);
|
||||
|
||||
const downloadUrl = `${AUCTION_DOCUMENT_DOWNLOAD}?documentId=${id}&isAmendment=false`;
|
||||
console.log('🌐 Download URL:', downloadUrl);
|
||||
|
||||
const response = await ReactNativeBlobUtil.config({
|
||||
fileCache: false, // important for public folder
|
||||
addAndroidDownloads: {
|
||||
useDownloadManager: true,
|
||||
notification: true,
|
||||
path,
|
||||
mime: 'application/pdf',
|
||||
title: `${fileName}.pdf`,
|
||||
description: 'Downloading document',
|
||||
mediaScannable: true, // 👈 makes it visible instantly
|
||||
},
|
||||
}).fetch('GET', downloadUrl, {
|
||||
Accept: 'application/pdf',
|
||||
});
|
||||
|
||||
console.log('✅ Download completed');
|
||||
console.log('📦 Status:', response.info().status);
|
||||
console.log('📦 Headers:', response.info().headers);
|
||||
console.log('📍 Saved at:', path);
|
||||
|
||||
const stat = await ReactNativeBlobUtil.fs.stat(path);
|
||||
console.log('📦 File size:', stat.size);
|
||||
|
||||
} catch (error: any) {
|
||||
console.log('❌ Download failed');
|
||||
console.log('❌ Error:', error?.message || error);
|
||||
} finally {
|
||||
setAllBoolean((prev: any) => ({ ...prev, fileLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
mutate({ auctionNumber: data?.auctionNumber, status: data?.auctionPattern }, {
|
||||
onSuccess: (res) => {
|
||||
setAuciotnDetail((prev: any) => ({ ...prev, auctionItems: res.data, auctionDocuments }))
|
||||
}, onError: (err) => {
|
||||
console.log(err, '-----auction item error');
|
||||
}
|
||||
});
|
||||
}, [data.auctionNumber, auctionDocuments]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={visible}
|
||||
@@ -94,12 +155,11 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
|
||||
{/* 2. Work Description */}
|
||||
<Section title="Auction Details" icon={Briefcase}>
|
||||
<View style={styles.grid}>
|
||||
<InfoBox label="Auction Name" value={'Auction of cars'} />
|
||||
<InfoBox label="Category Of Auction " value={'Live'} />
|
||||
<InfoBox label="Auto Time Increment " value={'yes'} />
|
||||
<InfoBox label="Auction Fees (In Figure) " value={'500'} />
|
||||
<InfoBox label="Auction Fees (In Words)" value={'Five Hundred'} />
|
||||
<InfoBox label="Auction Keyword" value={'Dev Furniture, Furnture'} />
|
||||
<InfoBox label="Auction Name" value={auctionData?.auctionOfWork} />
|
||||
<InfoBox label="Category Of Auction " value={auctionData?.auctionCategories} />
|
||||
<InfoBox label="Auction Fees (In Figure) " value={auctionData?.auctionFees} />
|
||||
<InfoBox label="Auction Fees (In Words)" value={auctionData?.auctionFeesInWord} />
|
||||
<InfoBox label="Auction Keyword" value={auctionData?.auctionKeywordName} />
|
||||
</View>
|
||||
</Section>
|
||||
|
||||
@@ -129,68 +189,55 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
|
||||
<View style={styles.tableWrapper}>
|
||||
<View style={styles.tableHead}>
|
||||
<Text style={[styles.tableLabel, { flex: 2 }]}>Item</Text>
|
||||
<Text style={styles.tableLabel}>Qty</Text>
|
||||
<Text style={styles.tableLabel}>Time</Text>
|
||||
<Text style={[styles.tableLabel, { textAlign: 'right' }]}>View</Text>
|
||||
</View>
|
||||
{/* Dummy Item Row */}
|
||||
<View style={styles.tableRow}>
|
||||
<View style={{ flex: 2 }}>
|
||||
<Text style={styles.itemMain}>Sick Sari / Laundry</Text>
|
||||
<Text style={styles.itemSub}>Category: Sari</Text>
|
||||
{aucitonDetail?.auctionItems?.map((item: any, index: number) => (
|
||||
<View style={styles.tableRow}>
|
||||
<View style={{ flex: 2 }}>
|
||||
<Text style={styles.itemMain}>{item.productName}</Text>
|
||||
<Text style={styles.itemSub}>Category: {item?.categoryName}</Text>
|
||||
</View>
|
||||
<Text style={styles.itemQty}>{item.timeDurationType}</Text>
|
||||
<TouchableOpacity style={styles.actionIcon} onPress={() => { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: true, selectedItem: item })) }}>
|
||||
<Eye size={18} color={colors.primary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Text style={styles.itemQty}>120,000</Text>
|
||||
<TouchableOpacity style={styles.actionIcon} onPress={() => { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: true })) }}>
|
||||
<Eye size={18} color={colors.primary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</Section>
|
||||
|
||||
{/* 5. Downloads */}
|
||||
<Section title="Downloads" icon={Download}>
|
||||
<TouchableOpacity style={styles.fileCard}>
|
||||
<View style={styles.fileIcon}><FileText size={20} color="#ef4444" /></View>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.fileName}>Auction_Notice_Main.pdf</Text>
|
||||
<Text style={styles.fileSize}>1.2 MB • PDF</Text>
|
||||
</View>
|
||||
<Download size={20} color="#94a3b8" />
|
||||
</TouchableOpacity>
|
||||
{aucitonDetail?.auctionDocuments?.map((doc: any, index: number) => (
|
||||
<TouchableOpacity style={styles.fileCard} onPress={() => {
|
||||
handleDownload(
|
||||
doc.auctionDocumentId,
|
||||
doc.fileName.replace('.pdf', '')
|
||||
)
|
||||
}}>
|
||||
<View style={styles.fileIcon}><FileText size={20} color="#ef4444" /></View>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.fileName}>{doc.fileName}</Text>
|
||||
</View>
|
||||
{allBoolean.fileLoading ? (
|
||||
<View >
|
||||
<Loader size='small' color='#94a3b8' />
|
||||
</View>
|
||||
) : (
|
||||
<Download size={20} color="#94a3b8" />
|
||||
)}
|
||||
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</Section>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
{/* Sticky Footer */}
|
||||
<View style={styles.footer}>
|
||||
<TouchableOpacity
|
||||
style={[styles.mainBtn, !isLive && styles.btnDisabled]}
|
||||
disabled={!isLive}
|
||||
>
|
||||
<Text style={styles.mainBtnText}>
|
||||
{isLive ? 'Add to Cart / Purchase' : 'Auction Closed'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<AuctionItemDetail
|
||||
data={{
|
||||
productName: "sick sari",
|
||||
timeDuration: "112 YEAR",
|
||||
category: "laundry",
|
||||
subCategory: "sari",
|
||||
reservePriceFig: "120000",
|
||||
reservePriceWords: "One Lakh Twenty Thousand",
|
||||
auctionStartFig: "120000",
|
||||
auctionStartWords: "One Lakh Twenty Thousand",
|
||||
bidVariationFig: "200",
|
||||
bidVariationWords: "Two Hundred",
|
||||
emdFig: "2000",
|
||||
emdWords: "Two Thousand",
|
||||
description: "Auction of cars",
|
||||
documentName: "BBPS screens.pdf"
|
||||
}} onClose={() => { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: false })) }} visible={allBoolean.showItemDetail} />
|
||||
{allBoolean.showItemDetail && <AuctionItemDetail data={allBoolean.selectedItem} onClose={() => { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: false })) }} visible={allBoolean.showItemDetail} />}
|
||||
</View>
|
||||
</Modal>
|
||||
</Modal >
|
||||
);
|
||||
};
|
||||
|
||||
@@ -242,7 +289,7 @@ const styles = StyleSheet.create({
|
||||
liveText: { fontSize: 11, fontWeight: '800', color: '#475569' },
|
||||
|
||||
scrollView: { flex: 1, backgroundColor: '#f8fafc' },
|
||||
scrollContent: { padding: 16, paddingBottom: 100 },
|
||||
scrollContent: { padding: 16, paddingBottom: 30 },
|
||||
|
||||
sectionContainer: {
|
||||
backgroundColor: '#fff',
|
||||
|
||||
@@ -1,60 +1,21 @@
|
||||
import React, { memo } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
SafeAreaView,
|
||||
Platform,
|
||||
StatusBar,
|
||||
Dimensions
|
||||
} from 'react-native';
|
||||
import React, { memo, useState } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Platform, Dimensions } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
import {
|
||||
X,
|
||||
Package,
|
||||
Clock,
|
||||
Tag,
|
||||
IndianRupee,
|
||||
FileText,
|
||||
Download,
|
||||
ArrowLeft,
|
||||
Info,
|
||||
Layers,
|
||||
ChevronRight
|
||||
} from 'lucide-react-native';
|
||||
import { Package, IndianRupee, FileText, Download, ArrowLeft, Info, } from 'lucide-react-native';
|
||||
import colors from '../../../Constant/Color';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { useAucitonItemDetail } from '../../../Services/BBPS/Hooks';
|
||||
import ReactNativeBlobUtil from 'react-native-blob-util';
|
||||
import { AUCTION_ITEM_DOCUMENT_DOWNLOAD } from '../../../Services/BBPS/ApiUrls';
|
||||
import { Loader } from '../../../Component/Index';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
interface Props { visible: boolean; onClose: () => void; data?: any; }
|
||||
|
||||
// --- Exact Dummy Data Mapping ---
|
||||
const ITEM_DUMMY_DATA = {
|
||||
productName: "sick sari",
|
||||
timeDuration: "112 YEAR",
|
||||
category: "laundry",
|
||||
subCategory: "sari",
|
||||
reservePriceFig: "120000",
|
||||
reservePriceWords: "One Lakh Twenty Thousand",
|
||||
auctionStartFig: "120000",
|
||||
auctionStartWords: "One Lakh Twenty Thousand",
|
||||
bidVariationFig: "200",
|
||||
bidVariationWords: "Two Hundred",
|
||||
emdFig: "2000",
|
||||
emdWords: "Two Thousand",
|
||||
description: "Auction of cars",
|
||||
documentName: "BBPS screens.pdf"
|
||||
};
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
data?: typeof ITEM_DUMMY_DATA;
|
||||
}
|
||||
|
||||
const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data = ITEM_DUMMY_DATA }) => {
|
||||
const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
|
||||
const inset = useSafeAreaInsets()
|
||||
const [allBoolean, setAllBoolean] = useState({ fileLoading: false });
|
||||
const { data: itemData } = useAucitonItemDetail({ auctionItemId: data.id });
|
||||
|
||||
const Section = ({ title, icon: Icon, children }: any) => (
|
||||
<View style={styles.sectionCard}>
|
||||
<View style={styles.sectionHeader}>
|
||||
@@ -75,6 +36,50 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data = ITEM_DUMM
|
||||
</View>
|
||||
);
|
||||
|
||||
const handleDownload = async (id: number, fileName: string) => {
|
||||
try {
|
||||
setAllBoolean((prev: any) => ({ ...prev, fileLoading: true }));
|
||||
const { dirs } = ReactNativeBlobUtil.fs;
|
||||
|
||||
// ✅ PUBLIC DOWNLOADS DIRECTORY
|
||||
const path = `${dirs.DownloadDir}/${fileName}.pdf`;
|
||||
|
||||
console.log('📂 Saving to:', path);
|
||||
|
||||
const downloadUrl = `${AUCTION_ITEM_DOCUMENT_DOWNLOAD}?auctionItemId=${id}`;
|
||||
console.log('🌐 Download URL:', downloadUrl);
|
||||
|
||||
const response = await ReactNativeBlobUtil.config({
|
||||
fileCache: false, // important for public folder
|
||||
addAndroidDownloads: {
|
||||
useDownloadManager: true,
|
||||
notification: true,
|
||||
path,
|
||||
mime: 'application/pdf',
|
||||
title: `${fileName}.pdf`,
|
||||
description: 'Downloading document',
|
||||
mediaScannable: true, // 👈 makes it visible instantly
|
||||
},
|
||||
}).fetch('GET', downloadUrl, {
|
||||
Accept: 'application/pdf',
|
||||
});
|
||||
|
||||
console.log('✅ Download completed');
|
||||
console.log('📦 Status:', response.info().status);
|
||||
console.log('📦 Headers:', response.info().headers);
|
||||
console.log('📍 Saved at:', path);
|
||||
|
||||
const stat = await ReactNativeBlobUtil.fs.stat(path);
|
||||
console.log('📦 File size:', stat.size);
|
||||
|
||||
} catch (error: any) {
|
||||
console.log('❌ Download failed');
|
||||
console.log('❌ Error:', error?.message || error);
|
||||
} finally {
|
||||
setAllBoolean((prev: any) => ({ ...prev, fileLoading: false }));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={visible}
|
||||
@@ -106,72 +111,76 @@ const AuctionItemDetail: React.FC<Props> = ({ visible, onClose, data = ITEM_DUMM
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* Product Identity Card */}
|
||||
<Section title="Product Specification" icon={Package}>
|
||||
<View style={styles.identityHeader}>
|
||||
<Text style={styles.productNameText}>{data.productName.toUpperCase()}</Text>
|
||||
<View style={styles.categoryBadge}>
|
||||
<Text style={styles.categoryText}>{data.category}</Text>
|
||||
<Text style={styles.categoryText}>{data.categoryName}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.specGrid}>
|
||||
<View style={styles.specItem}>
|
||||
<Text style={styles.label}>Sub Category</Text>
|
||||
<Text style={styles.specValue}>{data.subCategory}</Text>
|
||||
<Text style={styles.specValue}>{data.subCategoryName}</Text>
|
||||
</View>
|
||||
<View style={styles.specItem}>
|
||||
<Text style={styles.label}>Duration</Text>
|
||||
<Text style={styles.specValue}>{data.timeDuration}</Text>
|
||||
<Text style={styles.specValue}>{data.timeDurationType}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Section>
|
||||
|
||||
{/* Pricing & Financials */}
|
||||
<Section title="Reserve & Bid Values" icon={IndianRupee}>
|
||||
<PriceTile
|
||||
label="Reserve Price"
|
||||
fig={data.reservePriceFig}
|
||||
words={data.reservePriceWords}
|
||||
fig={data.reservePrice}
|
||||
words={data.reservePriceInWords}
|
||||
full
|
||||
/>
|
||||
<View style={styles.hDivider} />
|
||||
<PriceTile
|
||||
label="Auction Start Value"
|
||||
fig={data.auctionStartFig}
|
||||
words={data.auctionStartWords}
|
||||
fig={data.reservePrice}
|
||||
words={data.reservePriceInWords}
|
||||
full
|
||||
/>
|
||||
<View style={styles.hDivider} />
|
||||
<View style={styles.row}>
|
||||
{/* <View style={styles.row}>
|
||||
<PriceTile label="Bid Variation" fig={data.bidVariationFig} words={data.bidVariationWords} />
|
||||
<PriceTile label="EMD Amount" fig={data.emdFig} words={data.emdWords} />
|
||||
</View>
|
||||
<PriceTile label="Auction Start Value" fig={data.auctionStartValue} words={data.auctionStartValueInWords
|
||||
} />
|
||||
</View> */}
|
||||
</Section>
|
||||
|
||||
{/* Description Card */}
|
||||
<Section title="Brief Description" icon={Info}>
|
||||
<Text style={styles.descContent}>{data.description}</Text>
|
||||
<Text style={styles.descContent}>{data.briefDescription}</Text>
|
||||
</Section>
|
||||
|
||||
{/* Documents Card */}
|
||||
<Section title="View Documents" icon={FileText}>
|
||||
{itemData?.length && <Section title="View Documents" icon={FileText}>
|
||||
<View style={styles.docTableHead}>
|
||||
<Text style={styles.tableLabel}>Sr No.</Text>
|
||||
<Text style={[styles.tableLabel, { flex: 2 }]}>Document Name</Text>
|
||||
<Text style={styles.tableLabel}>Action</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.docRow} activeOpacity={0.7}>
|
||||
<Text style={styles.docIndex}>1</Text>
|
||||
<View style={{ flex: 2 }}>
|
||||
<Text style={styles.docTitle} numberOfLines={1}>{data.documentName}</Text>
|
||||
</View>
|
||||
<View style={styles.downloadIconBox}>
|
||||
<Download size={18} color={colors.primary} />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</Section>
|
||||
{itemData?.map((doc: any, index: any) => (
|
||||
<TouchableOpacity style={styles.docRow} activeOpacity={0.7} onPress={() => { handleDownload(doc.assetId, doc.fileName) }} key={index}>
|
||||
<Text style={styles.docIndex}>{index + 1}</Text>
|
||||
<View style={{ flex: 2 }}>
|
||||
<Text style={styles.docTitle} numberOfLines={1}>{doc.fileName}</Text>
|
||||
</View>
|
||||
<View style={styles.downloadIconBox}>
|
||||
{allBoolean.fileLoading ? (
|
||||
<View >
|
||||
<Loader size='small' color='#94a3b8' />
|
||||
</View>
|
||||
) : (
|
||||
<Download size={20} color={colors.primary} />
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>))}
|
||||
</Section>}
|
||||
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { View, Text, FlatList, StyleSheet, TouchableOpacity, Alert } from 'react-native';
|
||||
import { InsideHeader, Loader } from '../../Component/Index';
|
||||
import colors from '../../Constant/Color';
|
||||
import { CreditCard, Calendar, User, DollarSign, ArrowRight } from 'lucide-react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useOfflineAuctionPurchase } from '../../Services/BBPS/Hooks';
|
||||
import { useOfflineAuctionPurchase, usePurchaseAuctionList } from '../../Services/BBPS/Hooks';
|
||||
import { showSuccessAlert } from '../../Constant/ShowDailog';
|
||||
import { clearPurchaseAuction } from '../../Redux/Slices/selectPurchaseAuction';
|
||||
import { CommonActions, useNavigation } from '@react-navigation/native';
|
||||
import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
|
||||
import NavigationString from '../../Constant/NavigationString';
|
||||
import Skeleton from '../../Component/Skelton/Skelton';
|
||||
|
||||
const dummyAuctionList = [
|
||||
{
|
||||
@@ -23,39 +24,18 @@ const dummyAuctionList = [
|
||||
portalCharge: 100,
|
||||
payableAmount: 3050,
|
||||
},
|
||||
{
|
||||
auctionId: 2,
|
||||
auctionNumber: 'AUC-2025-002',
|
||||
auctionPattern: 'Two Stage',
|
||||
auctionDispatchDate: '28 Feb 2025',
|
||||
auctionDispatcherNumber: 'DISP-002',
|
||||
auctionFees: 1800,
|
||||
gst: 18,
|
||||
gstAmount: 324,
|
||||
portalCharge: 80,
|
||||
payableAmount: 2204,
|
||||
},
|
||||
{
|
||||
auctionId: 3,
|
||||
auctionNumber: 'AUC-2025-003',
|
||||
auctionPattern: 'Single Stage',
|
||||
auctionDispatchDate: '01 Mar 2025',
|
||||
auctionDispatcherNumber: 'DISP-003',
|
||||
auctionFees: 3200,
|
||||
gst: 18,
|
||||
gstAmount: 576,
|
||||
portalCharge: 120,
|
||||
payableAmount: 3896,
|
||||
},
|
||||
];
|
||||
|
||||
const PurchaseAuctionList = () => {
|
||||
const Navigation = useNavigation()
|
||||
const Dispatch = useDispatch()
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [list, setList] = useState(dummyAuctionList);
|
||||
const [list, setList] = useState([]);
|
||||
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
|
||||
const LoginUser = useSelector((state: any) => state.token.token);
|
||||
const { mutate, isPending } = useOfflineAuctionPurchase()
|
||||
const { mutate: purchaseListMutation, isPending: purchaseListPending } = usePurchaseAuctionList();
|
||||
|
||||
const calculateTotalAmount = (item: any) => {
|
||||
const gstAmount =
|
||||
(Number(item.auctionFees) + Number(item.portalCharge)) *
|
||||
@@ -68,7 +48,7 @@ const PurchaseAuctionList = () => {
|
||||
|
||||
const handleOfflinePurchase = async () => {
|
||||
const body = {
|
||||
auctionDetails: SelectedPurchaseList.map((b: any) => ({
|
||||
auctionDetails: list.map((b: any) => ({
|
||||
auctionDispatchDate: b?.auctionDispatchDate,
|
||||
auctionDispatcherNumber: b?.auctionDispatcherNumber,
|
||||
auctionFees: b?.auctionFees,
|
||||
@@ -155,16 +135,37 @@ const PurchaseAuctionList = () => {
|
||||
</View>
|
||||
);
|
||||
|
||||
const getPurchaseList = () => {
|
||||
const auctionNumbers: string[] = SelectedPurchaseList.map(
|
||||
(item: { auctionNumber: string }) => item.auctionNumber
|
||||
);
|
||||
purchaseListMutation({ auctionNumbers, contractorId: LoginUser.contractorId }, {
|
||||
onSuccess: (res) => {
|
||||
if (res.statusCode == 200) {
|
||||
setList(res.data)
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error, "=================purchase list error");
|
||||
}
|
||||
})
|
||||
}
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
getPurchaseList()
|
||||
}, [SelectedPurchaseList])
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: colors.white }}>
|
||||
<InsideHeader title="Purchase List" showArrow />
|
||||
<View style={styles.screen}>
|
||||
<FlatList
|
||||
data={SelectedPurchaseList}
|
||||
{purchaseListPending ? <Skeleton /> : <FlatList
|
||||
data={list}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={(item) => item.auctionId.toString()}
|
||||
contentContainerStyle={styles.container}
|
||||
/>
|
||||
/>}
|
||||
</View>
|
||||
|
||||
<View style={styles.bottomButtonContainer}>
|
||||
|
||||
@@ -31,7 +31,6 @@ const PurchaseAuctionTile = ({ item, onPressDetails, onStartBidding, buttonEnabl
|
||||
const statusColor = isAuctionEnd ? '#EF4444' : buttonEnable ? colors.primary : '#94A3B8';
|
||||
|
||||
const lightStatusBg = isAuctionEnd ? '#FEF2F2' : buttonEnable ? '#EFF6FF' : '#F8FAFC';
|
||||
console.log(item?.keyDates?.auctionBidding?.endDateTime, 'kk');
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
|
||||
@@ -26,7 +26,7 @@ const PurchaseList = () => {
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.heading}>Purchase List</Text>
|
||||
<Info size={20} color="#0F172A" />
|
||||
{/* <Info size={20} color="#0F172A" /> */}
|
||||
</View>
|
||||
|
||||
{/* Cards */}
|
||||
|
||||
Reference in New Issue
Block a user