diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e189252..aa069ff 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,14 @@ + + + + + + + =22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/ttlcache": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", @@ -4968,6 +4991,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -10589,6 +10617,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -11084,6 +11121,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -11597,6 +11659,56 @@ "integrity": "sha512-Zkjaol6X3BbZkHUpVDj2LjdidpS6rCgKi0fx80xgGKa0pHxBRd4swWTv2bHnnvu5k1/HXwYk0mY2TbK+2jHl5w==", "license": "MIT" }, + "node_modules/react-native-blob-util": { + "version": "0.24.6", + "resolved": "https://registry.npmjs.org/react-native-blob-util/-/react-native-blob-util-0.24.6.tgz", + "integrity": "sha512-e4231VTT0bO1Yh9KGtY6jXq7pkLXgDTz+ziClEEbiGwWBuG92Z+wFRLptlzdVbibW8XtrO1XrdtiE8AOlplEXQ==", + "license": "MIT", + "dependencies": { + "base-64": "0.1.0", + "glob": "13.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ronradtke" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-blob-util/node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-native-blob-util/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/react-native-bouncy-checkbox": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/react-native-bouncy-checkbox/-/react-native-bouncy-checkbox-4.1.2.tgz", @@ -11616,6 +11728,25 @@ "react-native": ">= 0.64.3" } }, + "node_modules/react-native-fs": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", + "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==", + "license": "MIT", + "dependencies": { + "base-64": "^0.1.0", + "utf8": "^3.0.0" + }, + "peerDependencies": { + "react-native": "*", + "react-native-windows": "*" + }, + "peerDependenciesMeta": { + "react-native-windows": { + "optional": true + } + } + }, "node_modules/react-native-gesture-handler": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.30.0.tgz", @@ -13602,6 +13733,12 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 057d06d..9f384ec 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,10 @@ "react-native": "0.79.0", "react-native-alert-notification": "^0.4.2", "react-native-app-intro-slider": "^4.0.4", + "react-native-blob-util": "^0.24.6", "react-native-bouncy-checkbox": "^4.1.2", "react-native-date-picker": "^5.0.13", + "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.30.0", "react-native-gifted-charts": "^1.4.70", "react-native-haptic-feedback": "^2.3.3", diff --git a/src/Redux/Slices/selectPurchaseAuction.tsx b/src/Redux/Slices/selectPurchaseAuction.tsx index 078c069..1c0f230 100644 --- a/src/Redux/Slices/selectPurchaseAuction.tsx +++ b/src/Redux/Slices/selectPurchaseAuction.tsx @@ -5,7 +5,6 @@ export interface AuctionItem { [key: string]: any; } -// ✅ DEFAULT = EMPTY ARRAY const initialState: AuctionItem[] = []; export const selectPurchaseAuctionSlice = createSlice({ diff --git a/src/Screens/Auction/LiveAuction.tsx b/src/Screens/Auction/LiveAuction.tsx index 532a1e8..40519f9 100644 --- a/src/Screens/Auction/LiveAuction.tsx +++ b/src/Screens/Auction/LiveAuction.tsx @@ -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('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 ( - - - - ); - }, [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('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 ( + + + + ); + }, [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 = () => { 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={ } + initialNumToRender={6} maxToRenderPerBatch={6} windowSize={7} removeClippedSubviews - updateCellsBatchingPeriod={50} /> + ); }; diff --git a/src/Screens/Auction/LiveAuctionTile.tsx b/src/Screens/Auction/LiveAuctionTile.tsx index e243a91..a5f0002 100644 --- a/src/Screens/Auction/LiveAuctionTile.tsx +++ b/src/Screens/Auction/LiveAuctionTile.tsx @@ -21,8 +21,6 @@ const LiveAuctionTile: React.FC = ({ return ( - {/* Status Tag */} - { !showDetail ? <> diff --git a/src/Screens/Auction/Modal/AuctionDetail.tsx b/src/Screens/Auction/Modal/AuctionDetail.tsx index 4802cb4..fb85e9a 100644 --- a/src/Screens/Auction/Modal/AuctionDetail.tsx +++ b/src/Screens/Auction/Modal/AuctionDetail.tsx @@ -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 = ({ visible, onClose, data }) => { const inset = useSafeAreaInsets() - const [allBoolean, setAllBoolean] = useState({ showItemDetail: false }) + const { data: auctionData, isLoading } = useGetAuciton({ auctionId: data?.auctionId }) + const [aucitonDetail, setAuciotnDetail] = useState(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) => ( @@ -43,6 +46,64 @@ const AuctionFullDetail: React.FC = ({ visible, onClose, data }) => { ); + + + + 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 ( = ({ visible, onClose, data }) => { {/* 2. Work Description */}
- - - - - - + + + + +
@@ -129,68 +189,55 @@ const AuctionFullDetail: React.FC = ({ visible, onClose, data }) => { Item - Qty + Time View {/* Dummy Item Row */} - - - Sick Sari / Laundry - Category: Sari + {aucitonDetail?.auctionItems?.map((item: any, index: number) => ( + + + {item.productName} + Category: {item?.categoryName} + + {item.timeDurationType} + { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: true, selectedItem: item })) }}> + + - 120,000 - { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: true })) }}> - - - + ))} {/* 5. Downloads */}
- - - - Auction_Notice_Main.pdf - 1.2 MB • PDF - - - + {aucitonDetail?.auctionDocuments?.map((doc: any, index: number) => ( + { + handleDownload( + doc.auctionDocumentId, + doc.fileName.replace('.pdf', '') + ) + }}> + + + {doc.fileName} + + {allBoolean.fileLoading ? ( + + + + ) : ( + + )} + + + ))}
- {/* Sticky Footer */} - - - - {isLive ? 'Add to Cart / Purchase' : 'Auction Closed'} - - - - - { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: false })) }} visible={allBoolean.showItemDetail} /> + {allBoolean.showItemDetail && { setAllBoolean((prev: any) => ({ ...prev, showItemDetail: false })) }} visible={allBoolean.showItemDetail} />}
-
+ ); }; @@ -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', diff --git a/src/Screens/Auction/Modal/AuctionItemDetail.tsx b/src/Screens/Auction/Modal/AuctionItemDetail.tsx index befda66..af69b23 100644 --- a/src/Screens/Auction/Modal/AuctionItemDetail.tsx +++ b/src/Screens/Auction/Modal/AuctionItemDetail.tsx @@ -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 = ({ visible, onClose, data = ITEM_DUMMY_DATA }) => { +const AuctionItemDetail: React.FC = ({ 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) => ( @@ -75,6 +36,50 @@ const AuctionItemDetail: React.FC = ({ visible, onClose, data = ITEM_DUMM ); + 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 ( = ({ visible, onClose, data = ITEM_DUMM contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} > - {/* Product Identity Card */}
{data.productName.toUpperCase()} - {data.category} + {data.categoryName} Sub Category - {data.subCategory} + {data.subCategoryName} Duration - {data.timeDuration} + {data.timeDurationType}
- {/* Pricing & Financials */}
- + {/* - - + + */}
- {/* Description Card */}
- {data.description} + {data.briefDescription}
- {/* Documents Card */} -
+ {itemData?.length &&
Sr No. Document Name Action - - 1 - - {data.documentName} - - - - - -
+ {itemData?.map((doc: any, index: any) => ( + { handleDownload(doc.assetId, doc.fileName) }} key={index}> + {index + 1} + + {doc.fileName} + + + {allBoolean.fileLoading ? ( + + + + ) : ( + + )} + + ))} +
}
diff --git a/src/Screens/Auction/PurchaseAuctionList.tsx b/src/Screens/Auction/PurchaseAuctionList.tsx index 6afc792..898d3bf 100644 --- a/src/Screens/Auction/PurchaseAuctionList.tsx +++ b/src/Screens/Auction/PurchaseAuctionList.tsx @@ -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 = () => {
); + 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 ( - : item.auctionId.toString()} contentContainerStyle={styles.container} - /> + />} diff --git a/src/Screens/Auction/PurchaseAuctionTile.tsx b/src/Screens/Auction/PurchaseAuctionTile.tsx index 9b183e4..578cb5b 100644 --- a/src/Screens/Auction/PurchaseAuctionTile.tsx +++ b/src/Screens/Auction/PurchaseAuctionTile.tsx @@ -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 ( diff --git a/src/Screens/Auction/PurchaseList.tsx b/src/Screens/Auction/PurchaseList.tsx index fe36fb6..a33700f 100644 --- a/src/Screens/Auction/PurchaseList.tsx +++ b/src/Screens/Auction/PurchaseList.tsx @@ -26,7 +26,7 @@ const PurchaseList = () => { {/* Header */} Purchase List - + {/* */} {/* Cards */} diff --git a/src/Screens/Bidding/Component/BiddingCard.tsx b/src/Screens/Bidding/Component/BiddingCard.tsx index 853e785..485b7d3 100644 --- a/src/Screens/Bidding/Component/BiddingCard.tsx +++ b/src/Screens/Bidding/Component/BiddingCard.tsx @@ -1,12 +1,20 @@ -import React, { memo, useCallback, useRef } from 'react'; -import { View, Text, TouchableOpacity, StyleSheet, Platform } from 'react-native'; +import React, { memo, useCallback, useRef, useState } from 'react'; +import { View, Text, TouchableOpacity, StyleSheet, Platform, TextInput, Alert } from 'react-native'; import Animated, { FadeInUp, Layout, interpolate, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'; import colors from '../../../Constant/Color'; import AuctionItemDetail from '../../Auction/Modal/AuctionItemDetail'; import MainStyle from '../../../Styles/MainStyle'; +import { Loader } from '../../../Component/Index'; +import { useSelector } from 'react-redux'; +import axios from 'axios'; +import Variables from '../../../Constant/Variable'; +import { showErrorAlert, showSuccessAlert } from '../../../Constant/ShowDailog'; -const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, SelectedAuction }: any) => { - const [showDetail, setShowDetail] = React.useState(false); +const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, SelectedAuction, allBoolean, setAllBoolean }: any) => { + const Token = useSelector((state: any) => state.token.token) + const [showDetail, setShowDetail] = useState(false); + const [value, setValue] = useState(`${item.bidAmount}`); + const [allState, setAllState] = useState({ isLoading: false }) const isMin = bidValue <= item.bidAmount; // 🔒 Persist expand state safely @@ -26,6 +34,11 @@ const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, Selec opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]), marginTop: interpolate(animation.value, [0, 1], [0, 15]), })); + const bodyStyle2 = useAnimatedStyle(() => ({ + height: interpolate(animation.value, [0, 1], [0, 100]), + opacity: interpolate(animation.value, [0, 0.5, 1], [0, 0, 1]), + marginTop: interpolate(animation.value, [0, 1], [0, 15]), + })); const arrowStyle = useAnimatedStyle(() => ({ transform: [ @@ -34,6 +47,53 @@ const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, Selec }, ], })); + const MAX_VALUE = Number(item.bidAmount); + + const handleChange = (text: string) => { + let cleaned = text.replace(/[^0-9.]/g, ''); + if ((cleaned.match(/\./g) || []).length > 1) return; + setValue(cleaned); + }; + + + const oneTimePlaceBid = async () => { + try { + if (Number(value) < MAX_VALUE) { + showErrorAlert("Enter the greather vlaue to current bid value") + return false + } + setAllState((prev: any) => ({ ...prev, isLoading: true })) + const payload = { + itemId: item.id, + bidAmount: Number(value), + auctionId: SelectedAuction.auctionId, + contractorId: Token.contractorId, + fullName: Token.fullName, + }; + + + const res = await axios.post( + `${Variables.socketUrl}bidding/placeBidForAuction`, + [payload], + { headers: { Authentication: `Bearer ${Token.token}` } } + ); + + if (res.data.statusCode === 200) { + showSuccessAlert(res.data.message); + } + setAllBoolean((prev: any) => ({ ...prev, reload: !prev.reload })) + } catch (error) { + if (axios.isAxiosError(error)) { + showErrorAlert(error.response?.data.message) + } else { + console.log('UNKNOWN ERROR:', error); + } + + } finally { + setAllState((prev: any) => ({ ...prev, isLoading: false })) + } + } + // console.log(item, 'jkjjj'); return ( @@ -80,7 +140,7 @@ const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, Selec Current Bid - ₹{item?.bidAmount} + ₹{item?.bidAmount || item.auctionStartValueFigure} @@ -92,12 +152,12 @@ const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, Selec {/* COLLAPSIBLE BODY */} - + Set Your Bid - + {!allBoolean.oneTimeBid && + - + } + { + (allBoolean.oneTimeBid || allBoolean.rebid) && + ₹ - + + } + {(!allBoolean.rebid && item.contractorId == undefined) ? - Confirm Bid - + { + allState.isLoading ? : Confirm Bid + } + : null} : @@ -135,7 +209,31 @@ const BiddingCard = ({ item, bidValue, onIncrease, onDecrease, onPlaceBid, Selec }; export default memo(BiddingCard); + const styles = StyleSheet.create({ + inputBox2: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#F1F5F9', + borderRadius: 12, + height: 45, + paddingHorizontal: 12, + width: '100%', + marginBottom: 20 + }, + currency2: { + fontSize: 16, + fontWeight: 'bold', + color: '#64748B', + marginRight: 4, + }, + input: { + flex: 1, + fontSize: 18, + fontWeight: '700', + color: '#0F172A', + width: '100%' + }, card: { backgroundColor: '#FFF', borderRadius: 24, diff --git a/src/Screens/Bidding/Emd.tsx b/src/Screens/Bidding/Emd.tsx index 548a4a1..613b940 100644 --- a/src/Screens/Bidding/Emd.tsx +++ b/src/Screens/Bidding/Emd.tsx @@ -11,9 +11,12 @@ import { useNavigation } from '@react-navigation/native'; import { useSelector } from 'react-redux'; import { useAuctionItem, useEmdCheck } from '../../Services/BBPS/Hooks'; import { apiCall } from '../../Axios/Axios'; -import { AUCTION_ITEM_SUBMIT, CHECK_TECHNICAL_DOCUMENTAION, GET_TECHNICAL_DOCUMENTAION } from '../../Services/BBPS/ApiUrls'; +import { AUCITON_SINGLE_EMD, AUCTION_ITEM_SUBMIT, CHECK_TECHNICAL_DOCUMENTAION, GET_AUCTION_DETAILS, GET_TECHNICAL_DOCUMENTAION } from '../../Services/BBPS/ApiUrls'; import TemplateFormModal from './Component/TemplateFormModal'; import { SelectedItem } from './Type/BidType'; +import FontsFamily from '../../Constant/FontsFamily'; +import { all } from 'axios'; +import { showSuccessAlert } from '../../Constant/ShowDailog'; const Emd = () => { @@ -21,7 +24,7 @@ const Emd = () => { const SelectedAuction = useSelector((state: any) => state.auction.auction) const [selectedItems, setSelectedItems] = useState([]); const [acceptedPolicy, setAcceptedPolicy] = useState(false); - const [allBoolean, setAllBoolean] = useState({ isSubmitEmdLoading: false, isEmdComplete: false, auctionItems: [], technicalDocumentStatus: false, selectTemplate: {}, technicalDocModalVisible: false }) + const [allBoolean, setAllBoolean]: any = useState({ isSubmitEmdLoading: false, isEmdComplete: false, auctionItems: [], technicalDocumentStatus: false, selectTemplate: {}, technicalDocModalVisible: false, emdType: false, fileName: '', file: {} }) const { mutate } = useEmdCheck() const { mutate: AuctionItemMutate, isPending } = useAuctionItem() @@ -62,8 +65,15 @@ const Emd = () => { } }; - - + const pickFileSingle = async () => { + try { + const res = await pick({ type: ['application/pdf'] }); + const file = res[0]; + setAllBoolean((prev: any) => ({ ...prev, file: { name: file.name ?? 'document.pdf', uri: file.uri, type: 'application/pdf' } })) + } catch { + console.log('Pick cancelled'); + } + }; /* ---------------- Render Item ---------------- */ const renderItem = ({ item }: any) => { const selected = isSelected(item.id); @@ -201,15 +211,33 @@ const Emd = () => { setAllBoolean((prev: any) => ({ ...prev, isLoading: false })) } } + const getAuction = async () => { + const selectedRes = await apiCall('get', GET_AUCTION_DETAILS, {}, { id: SelectedAuction.auctionId }); + const emdType = String(selectedRes.data.emd) + .trim() + .replace(/\s+/g, ' ') + .toLowerCase(); + + + if (selectedRes.statusCode == 200 && emdType === 'auction wise') { + return true + } else { + return false + } + } const AlreadyEmdCheck = async () => { try { mutate({ auctionNumber: SelectedAuction.auctionNumber }, { - onSuccess: (res => { - console.log(SelectedAuction.auctionNumber, res , SelectedAuction,'iiiiiiiiiiiiiiiiiiiiiiiii'); - + onSuccess: (async (res) => { if (res.statusCode == 200) { + if (res.message == 'No EMD Documents') { + const result = await getAuction() + if (result) { + setAllBoolean((prev: any) => ({ ...prev, emdType: true })) + return + } setAllBoolean((prev: any) => ({ ...prev, isEmdComplete: false })) getAuctionItem() } else { @@ -307,7 +335,53 @@ const Emd = () => { getTemplateDocumentation() } } + + + const singleEmdSubmit = async () => { + try { + setAllBoolean((prev: any) => ({ ...prev, isSubmitEmdLoading: true })) + + if (!acceptedPolicy) { + Alert.alert('Policy Required', 'Please accept terms'); + return; + } + const formData = new FormData(); + + formData.append('auctionId', SelectedAuction.auctionId); + formData.append('productImageName', allBoolean.fileName); + formData.append('files', allBoolean.file); + + const response = await apiCall( + 'post', + AUCITON_SINGLE_EMD, + formData, + {}, + 'multipart/form-data' + ); + + if (response?.statusCode === 200) { + showSuccessAlert(response.message || 'EMD submitted successfully'); + if (SelectedAuction.auctionPattern === 'Forward') { + Navigation.navigate(NavigationString.StartBidding) + } else { + Navigation.navigate(NavigationString.StartReverseBidding) + } + } + } catch (error: any) { + if (error?.response) { + console.log('Server error:', error.response.data); + } else if (error?.request) { + console.log('Network error:', error.request); + } else { + console.log('Error message:', error.message); + } + } finally { + setAllBoolean((prev: any) => ({ ...prev, isSubmitEmdLoading: false })) + } + }; + useEffect(() => { + // getAuction() AlreadyEmdCheck() }, []) @@ -323,7 +397,49 @@ const Emd = () => { ) : allBoolean.isEmdComplete ? ( - ) : <> + ) : allBoolean.emdType ? + + Document Name + { setAllBoolean((prev: any) => ({ ...prev, fileName: text })) }} + /> + + { pickFileSingle() }}> + {allBoolean?.file?.name ? allBoolean?.file?.name : 'Choose File'} + + + + setAcceptedPolicy(p => !p)} + text="I agree to Terms & Privacy Policy" + textStyle={styles.policyText} + /> + + + { + allBoolean.isSubmitEmdLoading ? : Submit EMD + } + + + + : <> item.auctionId} @@ -369,9 +485,29 @@ export default Emd; const styles = StyleSheet.create({ container: { flex: 1, - paddingHorizontal: 10 + // paddingHorizontal: 10, + backgroundColor: colors.white }, + container2: { + paddingHorizontal: 10, + paddingVertical: 10, + backgroundColor: colors.white, + elevation: 2, + borderRadius: 10, + marginTop: 20, + marginHorizontal: 10 + }, + button: { + backgroundColor: colors.primary, + padding: 12, + borderRadius: 6, + alignItems: 'center', + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, card: { backgroundColor: '#FFFFFF', marginHorizontal: 5, @@ -433,6 +569,16 @@ const styles = StyleSheet.create({ fontSize: 14, color: colors.black }, + input2: { + borderWidth: 1, + borderColor: '#CBD5E1', + borderRadius: 14, + padding: 12, + backgroundColor: '#FFFFFF', + fontSize: 14, + color: colors.black, + marginBottom: 20 + }, uploadBtn: { marginTop: 12, diff --git a/src/Screens/Bidding/StartBidding.tsx b/src/Screens/Bidding/StartBidding.tsx index eb74a14..930ac27 100644 --- a/src/Screens/Bidding/StartBidding.tsx +++ b/src/Screens/Bidding/StartBidding.tsx @@ -7,7 +7,7 @@ import { useWebSocketService } from '../../socket/Socket'; import Variables from '../../Constant/Variable'; import { useSelector } from 'react-redux'; import { apiCall } from '../../Axios/Axios'; -import { FORWARD_AUCTION_ITEM, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/BBPS/ApiUrls'; +import { AUCTION_ONE_TIME_BID, FORWARD_AUCTION_ITEM, GET_AUCTION_DETAILS, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/BBPS/ApiUrls'; import BiddingCard from './Component/BiddingCard'; import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native'; import NavigationString from '../../Constant/NavigationString'; @@ -20,7 +20,7 @@ const StartBidding = () => { const Navigation: any = useNavigation() const [items, setItems] = useState([]); const [bidValues, setBidValues] = useState>({}); - const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, bidPayload: {} }) + const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, bidPayload: {}, oneTimeBid: false, rebid: false, reload: false }) const { subscribe, createRoom, placeBid } = useWebSocketService( Variables.webSocketUrl, () => console.log('Connected!'), @@ -28,6 +28,25 @@ const StartBidding = () => { loginUser.token, ); + const getAuction = async () => { + const selectedRes = await apiCall('get', GET_AUCTION_DETAILS, {}, { id: SelectedAuction.auctionId }); + if (selectedRes.statusCode == 200 && selectedRes.data.contractorId.length) { + setAllBoolean((prev: any) => ({ ...prev, oneTimeBid: true })) + } + } + const getOneTimeBidValue = async () => { + try { + const selectedRes = await apiCall('get', AUCTION_ONE_TIME_BID, {}, { auctionId: SelectedAuction.auctionId }); + if (selectedRes.statusCode == 200) { + return selectedRes.data + } else { + return [] + } + } catch (error) { + + } + + } const getAllAcutionItems = async () => { try { const payload = { auctionNumber: SelectedAuction.auctionNumber }; @@ -36,13 +55,9 @@ const StartBidding = () => { if (SelectedAuction.auctionPattern === 'Forward') { const res = await apiCall('get', FORWARD_AUCTION_ITEM, {}, payload); if (res?.statusCode === 200) auctionItem = res.data || []; - } else { - const res = await apiCall('get', REVERSE_AUCTION_ITEM, {}, payload); - if (res?.statusCode === 200) auctionItem = res.data || []; } const selectedRes = await apiCall('get', SELECTED_AUCTION_ITEM, {}, payload); -console.log(selectedRes,'jhhhhhhhhhh'); const uniqueArray: number[] = Array.from( new Set(selectedRes?.data || []) @@ -52,47 +67,96 @@ console.log(selectedRes,'jhhhhhhhhhh'); uniqueArray.includes(item.id) ); + if (SelectedAuction.auctionCategories == 'Live') { + const result = await createRoom(SelectedAuction.auctionNumber); - const result = await createRoom(SelectedAuction.auctionNumber); - - subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => { - console.log('🔥 BID UPDATE:', data); - }); - - const bidAmountMap2 = new Map(); - - (result || []).forEach((r: any) => { - bidAmountMap2.set(r.auctionItemId, { - bidAmount: r.bidAmount, - contractorId: r.contractorId, + subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => { + console.log('🔥 BID UPDATE:', data); }); - }); + const bidAmountMap2 = new Map(); + (result || []).forEach((r: any) => { + bidAmountMap2.set(r.auctionItemId, { + bidAmount: r.bidAmount, + contractorId: r.contractorId, + }); + }); + // Check One Time bid enable butoon + if (SelectedAuction.auctionCategories != 'Live') { + const myBid = result.find( + (bid: any) => bid.contractorId === loginUser.contractorId + ); + if (myBid) { + setAllBoolean((prev: any) => ({ ...prev, oneTimeBid: true })) + } + } - const bidAmountMap = new Map(); + const bidAmountMap = new Map(); - (result || []).forEach((r: any) => { - bidAmountMap.set(r.auctionItemId, r.bidAmount); - }); + (result || []).forEach((r: any) => { + bidAmountMap.set(r.auctionItemId, r.bidAmount); + }); - const updatedFilteredItems = filteredItems.map(item => { - const bidData = bidAmountMap2.get(item.id); - return { - ...item, - bidAmount: bidData?.bidAmount ?? item.auctionStartValueFigure, - bidAvilable: bidData?.bidAmount ?? 0, - me: bidData?.contractorId == loginUser.contractorId ? true : false - }; - }); + const updatedFilteredItems = filteredItems.map(item => { + const bidData = bidAmountMap2.get(item.id); + return { + ...item, + bidAmount: bidData?.bidAmount ?? item.auctionStartValueFigure, + bidAvilable: bidData?.bidAmount ?? 0, + me: bidData?.contractorId == loginUser.contractorId ? true : false + }; + }); - const initialBids: Record = {}; - updatedFilteredItems.forEach(item => { - initialBids[item.id] = item.bidAmount; - }); - setBidValues(initialBids); - setItems(updatedFilteredItems); + const initialBids: Record = {}; + updatedFilteredItems.forEach(item => { + initialBids[item.id] = item.bidAmount; + }); + setBidValues(initialBids); + setItems(updatedFilteredItems); + } else { + let result = [] + if (SelectedAuction.rebidAllowed) { + setAllBoolean((prev: any) => ({ ...prev, rebid: true })) + } + if (SelectedAuction.auctionCategories != 'Live') { + result = await getOneTimeBidValue() + } + const bidMap = new Map(); + + result.forEach((bid: any) => { + bidMap.set(bid.auctionItemId, bid); + }); + const mergedData = auctionItem.map((item: any) => { + const bid = bidMap.get(item.id); + + if (!bid) { + return { + ...item, + bidAmount: item.auctionStartValueFigure, + contractorId: item.contractorId, + }; + } + + return { + ...item, + bidAmount: bid.bidAmount, + bidId: bid.bidId, + contractorId: bid.contractorId, + contractorName: bid.contractorName, + me: bid.contractorId === loginUser.contractorId, + bidTime: bid.bidTime, + }; + }); + const initialBids: Record = {}; + mergedData.forEach(item => { + initialBids[item.id] = item.bidAmount; + }); + setBidValues(initialBids); + setItems(mergedData) + setBidValues(initialBids); + } } catch (error) { console.error('Error fetching auction items:', error); } @@ -122,11 +186,14 @@ console.log(selectedRes,'jhhhhhhhhhh'); } }); + useEffect(() => { + if (SelectedAuction.auctionCategories == 'One-time') { + getAuction() + } getAllAcutionItems(); subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, (data) => { }); - }, []); - + }, [allBoolean.reload]); useEffect(() => { const initial: Record = {}; @@ -233,6 +300,8 @@ console.log(selectedRes,'jhhhhhhhhhh'); return () => subscription.remove(); }, [Navigation]) ); + // console.log(bidValues, 'jjfdlsjfldsjfl'); + return ( @@ -261,9 +330,11 @@ console.log(selectedRes,'jhhhhhhhhhh'); onDecrease={() => handleUpdate(item.id, -item.bidVariationValue)} onPlaceBid={() => { submitBid(item) }} SelectedAuction={SelectedAuction} + allBoolean={allBoolean} + setAllBoolean={setAllBoolean} /> )} - contentContainerStyle={{ padding: 16 }} + contentContainerStyle={{ padding: 16, paddingBottom: 300 }} /> {allBoolean.showSuccess && ( diff --git a/src/Screens/Home/Home.tsx b/src/Screens/Home/Home.tsx index 2f10bc0..8b1cfe7 100644 --- a/src/Screens/Home/Home.tsx +++ b/src/Screens/Home/Home.tsx @@ -142,17 +142,6 @@ const Home = () => { }, ]; - /* ---------------- WebSocket ---------------- */ - const { connect } = useWebSocketService( - Variables.webSocketUrl, - () => console.log('WebSocket Connected'), - error => console.log('WebSocket Error:', error), - ); - - useFocusEffect(() => { - connect(); - }); - return (
diff --git a/src/Services/BBPS/ApiUrls.tsx b/src/Services/BBPS/ApiUrls.tsx index 8181600..270a659 100644 --- a/src/Services/BBPS/ApiUrls.tsx +++ b/src/Services/BBPS/ApiUrls.tsx @@ -61,13 +61,25 @@ const ITEM_DOCUMENT_DOWNLOAD = `${BASE_URL_Auction}api/auction/home/downloadDocu // Rohit const DASHBOARD_COUNT = `${BASE_URL_Auction}api/auction/home/dashboard/counts` -const AUCTION_ONE_TIME_BID =`${BASE_URL_Auction}api/bidding/getBidForAuction` +const AUCTION_ONE_TIME_BID = `${BASE_URL_Auction}api/bidding/getBidForAuction` +const AUCITON_SINGLE_EMD = `${BASE_URL_Auction}api/auction/addEMDDocumentsAuctionWise` +const PURCHASE_AUCTION_LIST = `${BASE_URL_Auction}api/auction/proceedToPurchase` +const VIEW_AUCTION_ITEM_DETAIL = `${BASE_URL_Auction}api/auction/home/viewDocumentsForAuctionItemDetails` +const VIEW_AUCTION_DOCUMENTS = `${BASE_URL_Auction}api/auction/viewDocumentsForAuction` +const AUCTION_DOCUMENT_DOWNLOAD = `${BASE_URL_Auction}api/auction/home/downloadDocumentForAuction` +const AUCTION_ITEM_DOCUMENT_DOWNLOAD = `${BASE_URL_Auction}api/auction/home/downloadDocument/auctionItemId` export { // Rohit + VIEW_AUCTION_ITEM_DETAIL, + AUCTION_ITEM_DOCUMENT_DOWNLOAD, + AUCTION_DOCUMENT_DOWNLOAD, + VIEW_AUCTION_DOCUMENTS, + AUCITON_SINGLE_EMD, DASHBOARD_COUNT, AUCTION_ONE_TIME_BID, ITEM_DOCUMENT_DOWNLOAD, + PURCHASE_AUCTION_LIST, ITEM_DETAIL, TECHNICAL_DOCUMENT_SUBMIT, TECHNICAL_VALUE_SUBMIT, diff --git a/src/Services/BBPS/Hooks.ts b/src/Services/BBPS/Hooks.ts index fdfbf32..a362d0a 100644 --- a/src/Services/BBPS/Hooks.ts +++ b/src/Services/BBPS/Hooks.ts @@ -1,5 +1,5 @@ import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query'; -import { fetchAuctionItem, fetchDashboard, fetchEmdCheck, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseTender, offlineAuctionPurchase, userLogin } from './apis'; +import { fetchAuctionItem, fetchDashboard, fetchEmdCheck, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseAuctionList, fetchPurchaseTender, getAuction, offlineAuctionPurchase, userLogin, viewAuctionDocumentDownload, viewAuctionDocuments, viewAuctionItemDocuments } from './apis'; // User @@ -32,6 +32,7 @@ export const useFetchLiveTender = () => { queryFn: () => fetchLiveTender() }); }; + export const useFetchPurchaseAuction = () => { return useQuery({ queryKey: ['fetchPurchaseAuction',], @@ -39,25 +40,28 @@ export const useFetchPurchaseAuction = () => { }); }; - export const useFetchLiveAuction = () => { return useInfiniteQuery({ - queryKey: ['fetchLiveAuction',], - queryFn: ({ pageParam = 1 }) => + queryKey: ['fetchLiveAuction'], + queryFn: ({ pageParam = 0 }) => fetchLiveAuction({ page: pageParam, size: 10, }), - initialPageParam: 1, - getNextPageParam: (lastPage) => { - const { page, size, totalCount } = lastPage; + initialPageParam: 0, + + getNextPageParam: (lastPage, allPages) => { + const { size, totalCount } = lastPage; const totalPages = Math.ceil(totalCount / size); - const nextPage = page + 1; + const nextPage = allPages.length; return nextPage < totalPages ? nextPage : undefined; }, - select: (data) => { - const mergedResults = data.pages.flatMap((page: any) => page.data ?? []); + select: (data) => { + const mergedResults = data.pages.flatMap( + (page: any) => page?.data ?? [] + ); + return { ...data, result: mergedResults, @@ -67,7 +71,6 @@ export const useFetchLiveAuction = () => { }; - // Auction Purchase offline export const useOfflineAuctionPurchase = () => { @@ -85,6 +88,41 @@ export const useEmdCheck = () => { export const useAuctionItem = () => { return useMutation({ - mutationFn: (payload: any) => fetchAuctionItem(payload), + mutationFn: (payload: { auctionNumber: string, status: string }) => fetchAuctionItem(payload), }); -}; \ No newline at end of file +}; + + +// Purchase Auction List +export const usePurchaseAuctionList = () => { + return useMutation({ + mutationFn: (payload: any) => fetchPurchaseAuctionList(payload), + }); +}; + +export const useGetAuciton = (payload: { auctionId: string }) => { + return useQuery({ + queryKey: ['getAuction'], + queryFn: () => getAuction(payload) + }); +}; + +export const useGetAucitonDocument = (payload: { auctionId: number }) => { + return useQuery({ + queryKey: ['viewAuctionDocuments'], + queryFn: () => viewAuctionDocuments(payload) + }); +}; + +export const useAucitonItemDetail = (payload: { auctionItemId: number }) => { + return useQuery({ + queryKey: ['viewAuctionItemDocuments'], + queryFn: () => viewAuctionItemDocuments(payload) + }); +}; + +export const useAucitonDocDownload = () => { + return useMutation({ + mutationFn: (payload: { documentId: number, isAmendment: boolean }) => viewAuctionDocumentDownload(payload), + }); +}; diff --git a/src/Services/BBPS/apis.ts b/src/Services/BBPS/apis.ts index dbbc97d..ea7f34b 100644 --- a/src/Services/BBPS/apis.ts +++ b/src/Services/BBPS/apis.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { DASHBOARD_COUNT, EMD_CHECK, FORARD_AUCTION_ITEM, GET_MY_AUCTION, GET_MY_TENDER, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PURCHASE_OFFLINE_AUCTION, REVERSE_AUCTION_ITEM } from "./ApiUrls"; +import { AUCTION_DOCUMENT_DOWNLOAD, DASHBOARD_COUNT, EMD_CHECK, FORARD_AUCTION_ITEM, GET_AUCTION_DETAILS, GET_MY_AUCTION, GET_MY_TENDER, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PURCHASE_AUCTION_LIST, PURCHASE_OFFLINE_AUCTION, REVERSE_AUCTION_ITEM, VIEW_AUCTION_DOCUMENTS, VIEW_AUCTION_ITEM_DETAIL } from "./ApiUrls"; import { apiCall } from "../../Axios/Axios"; // User @@ -32,7 +32,7 @@ export const fetchPurchaseAuction = async (): Promise => { return data } export const fetchLiveAuction = async (payload: any): Promise => { - const data = await apiCall('get', `${LIVE_AUCTION}`, {}, { payload }); + const data = await apiCall('get', `${LIVE_AUCTION}`, {}, payload); return data } @@ -71,4 +71,27 @@ export const fetchAuctionItem = async (payload: any): Promise => { } catch (error: any) { throw error.response?.data || error.message; } -}; \ No newline at end of file +}; + + +export const fetchPurchaseAuctionList = async (payload: any): Promise => { + const data = await apiCall('post', `${PURCHASE_AUCTION_LIST}`, payload); + return data +} + +export const getAuction = async (payload: any) => { + const selectedRes = await apiCall('get', GET_AUCTION_DETAILS, {}, { id: payload.auctionId }); + return selectedRes.data; +} +export const viewAuctionItemDocuments = async (payload: { auctionItemId: number }) => { + const selectedRes = await apiCall('get', VIEW_AUCTION_ITEM_DETAIL, {}, payload); + return selectedRes.data; +} +export const viewAuctionDocuments = async (payload: { auctionId: number }) => { + const selectedRes = await apiCall('get', VIEW_AUCTION_DOCUMENTS, {}, payload); + return selectedRes.data; +} +export const viewAuctionDocumentDownload = async (payload: { documentId: number, isAmendment: boolean }) => { + const selectedRes = await apiCall('get', AUCTION_DOCUMENT_DOWNLOAD, {}, payload); + return selectedRes.data; +} \ No newline at end of file diff --git a/waste.ts b/waste.ts index 0c84711..5a2c2cd 100644 --- a/waste.ts +++ b/waste.ts @@ -1,5 +1,5 @@ // import React, { useCallback, useEffect, useState } from 'react'; -// import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text, ToastAndroid } from 'react-native'; +// import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text } from 'react-native'; // import LottieView from 'lottie-react-native'; // import { InsideHeader } from '../../Component/Index'; // import colors from '../../Constant/Color'; @@ -36,12 +36,13 @@ // if (SelectedAuction.auctionPattern === 'Forward') { // const res = await apiCall('get', FORWARD_AUCTION_ITEM, {}, payload); // if (res?.statusCode === 200) auctionItem = res.data || []; -// } else if(SelectedAuction.auctionPattern === 'Reverse') { +// } else { // const res = await apiCall('get', REVERSE_AUCTION_ITEM, {}, payload); // if (res?.statusCode === 200) auctionItem = res.data || []; // } // const selectedRes = await apiCall('get', SELECTED_AUCTION_ITEM, {}, payload); +// console.log(selectedRes, 'jhhhhhhhhhh'); // const uniqueArray: number[] = Array.from( // new Set(selectedRes?.data || []) @@ -98,7 +99,7 @@ // }; // subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, async (message) => { - +// // console.log('RAW MESSAGE:', message[message.length - 1]); // const result = message[message.length - 1] // const updatedBidItem = (prev: any[]) => @@ -160,6 +161,7 @@ // { // text: 'Submit', // onPress: () => { + // placeBidSubmit(payload); // }, // }, @@ -180,7 +182,6 @@ // : item // ); -// // ToastAndroid.show(result.message, ToastAndroid.SHORT) // // setItems(updatedBidItem);