349 lines
13 KiB
TypeScript
349 lines
13 KiB
TypeScript
import React, { useCallback, useEffect, useState } from 'react';
|
|
import { View, FlatList, StyleSheet, Platform, Alert, BackHandler, Text, ToastAndroid } from 'react-native';
|
|
import LottieView from 'lottie-react-native';
|
|
import { InsideHeader } from '../../Component/Index';
|
|
import colors from '../../Constant/Color';
|
|
import { useWebSocketService } from '../../socket/Socket';
|
|
import Variables from '../../Constant/Variable';
|
|
import { useSelector } from 'react-redux';
|
|
import { apiCall } from '../../Axios/Axios';
|
|
import { AUCTION_ONE_TIME_BID, GET_AUCTION_DETAILS, REVERSE_AUCTION_ITEM, SELECTED_AUCTION_ITEM } from '../../Services/ApiCall/ApiUrls';
|
|
import { CommonActions, useFocusEffect, useNavigation } from '@react-navigation/native';
|
|
import NavigationString from '../../Constant/NavigationString';
|
|
import CountdownTimer from '../../Component/Counter/CountdownTimer';
|
|
import { useTheme } from '../../Hooks/useTheme';
|
|
import AppText from '../../components/AppText';
|
|
import ReverseBiddingCard from './Component/ReverseBiddingCard';
|
|
import ConfirmBidModal from './Component/ConfirmBidModal';
|
|
import GoBackModal from './Component/GoBackModal';
|
|
|
|
const StartReverseBidding = () => {
|
|
const { colors } = useTheme();
|
|
const styles = React.useMemo(() => makeStyles(colors), [colors]);
|
|
const SelectedAuction = useSelector((state: any) => state.auction.auction);
|
|
const loginUser = useSelector((state: any) => state.token.token)
|
|
const Navigation: any = useNavigation()
|
|
const [items, setItems] = useState<any>([]);
|
|
const [bidValues, setBidValues] = useState<Record<number, number>>({});
|
|
const [allBoolean, setAllBoolean] = useState({ showSuccess: false, showDialog: false, showBackDialog: false, bidPayload: {} as any, oneTimeBid: false, rebid: false, reload: false })
|
|
const { subscribe, createRoom, placeBid } = useWebSocketService(
|
|
Variables.webSocketUrl,
|
|
() => console.log('Connected!'),
|
|
(error) => console.log('WebSocket Error:', error),
|
|
loginUser.token,
|
|
);
|
|
const getAuction = async () => {
|
|
const selectedRes = await apiCall<any>('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<any>('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 };
|
|
let auctionItem: any[] = [];
|
|
|
|
if (SelectedAuction.auctionPattern === 'Reverse') {
|
|
const res = await apiCall<any>('get', REVERSE_AUCTION_ITEM, {}, payload);
|
|
if (res?.statusCode === 200) auctionItem = res.data || [];
|
|
}
|
|
|
|
const selectedRes = await apiCall<any>('get', SELECTED_AUCTION_ITEM, {}, payload);
|
|
|
|
const uniqueArray: number[] = Array.from(
|
|
new Set(selectedRes?.data || [])
|
|
);
|
|
|
|
const filteredItems = auctionItem.filter(item =>
|
|
uniqueArray.includes(item.id)
|
|
);
|
|
|
|
if (SelectedAuction.auctionCategories == 'Live') {
|
|
const result = await createRoom(SelectedAuction.auctionNumber);
|
|
|
|
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, data => {
|
|
console.log('🔥 BID UPDATE:', data);
|
|
});
|
|
const bidAmountMap2 = new Map<number, { bidAmount: number; contractorId: number }>();
|
|
|
|
(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<number, number>();
|
|
|
|
(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.auctionStartValue,
|
|
bidAvilable: bidData?.bidAmount ?? 0,
|
|
me: bidData?.contractorId == loginUser.contractorId ? true : false
|
|
};
|
|
});
|
|
|
|
const initialBids: Record<number, number> = {};
|
|
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<number, any>();
|
|
|
|
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.auctionStartValue,
|
|
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<number, number> = {};
|
|
mergedData.forEach(item => {
|
|
initialBids[item.id] = item.bidAmount;
|
|
});
|
|
setBidValues(initialBids);
|
|
setItems(mergedData)
|
|
setBidValues(initialBids);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching auction items:', error);
|
|
}
|
|
};
|
|
|
|
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, async (message) => {
|
|
|
|
const result = message[message.length - 1]
|
|
|
|
const updatedBidItem = (prev: any[]) =>
|
|
prev.map(item =>
|
|
item.id === result.auctionItemId
|
|
? { ...item, bidAmount: result.bidAmount, me: result.contractorId == loginUser.contractorId ? true : false }
|
|
: item
|
|
);
|
|
|
|
setItems(updatedBidItem);
|
|
|
|
setBidValues(prev => ({
|
|
...prev,
|
|
[result.auctionItemId]: result.bidAmount,
|
|
}));
|
|
try {
|
|
|
|
} catch (err) {
|
|
console.log('JSON parse error:', err);
|
|
}
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (SelectedAuction.auctionCategories == 'One-time') {
|
|
getAuction()
|
|
}
|
|
getAllAcutionItems();
|
|
subscribe(`/topic/room/${SelectedAuction.auctionNumber}`, (data) => { });
|
|
}, [allBoolean.reload]);
|
|
|
|
useEffect(() => {
|
|
const initial: Record<number, number> = {};
|
|
items.forEach((item: any) => {
|
|
initial[item.id] = item.bidAmount + item.bidVariationValue;
|
|
});
|
|
setBidValues(initial);
|
|
}, []);
|
|
|
|
const handleUpdate = (id: number, val: number) => {
|
|
setBidValues(prev => ({ ...prev, [id]: prev[id] + val }));
|
|
};
|
|
|
|
const submitBid = async (item: any) => {
|
|
const payload = {
|
|
itemId: item.id,
|
|
bidAmount: bidValues[item.id],
|
|
auctionId: SelectedAuction.auctionId,
|
|
contractorId: loginUser.contractorId,
|
|
fullName: loginUser.fullName,
|
|
roomId: SelectedAuction.auctionNumber,
|
|
};
|
|
setAllBoolean((prev: any) => ({ ...prev, bidPayload: payload, showDialog: true }));
|
|
};
|
|
|
|
const placeBidSubmit = async (data: any) => {
|
|
setAllBoolean((prev: any) => ({ ...prev, showDialog: false }));
|
|
try {
|
|
const result: any = await placeBid(data);
|
|
|
|
if (result?.status && result.data) {
|
|
const updatedBidItem = (prev: any[]) =>
|
|
prev.map(item =>
|
|
item.id === result.data.auctionItemId
|
|
? { ...item, bidAmount: result.data.bidAmount, me: result.data?.contractorId == loginUser.contractorId ? true : false }
|
|
: item
|
|
);
|
|
|
|
getAllAcutionItems()
|
|
}
|
|
} catch (error) {
|
|
console.error('Error placing bid:', error);
|
|
}
|
|
};
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
const onBackPress = () => {
|
|
setAllBoolean((prev: any) => ({ ...prev, showBackDialog: true }));
|
|
return true; // block default back action
|
|
};
|
|
|
|
const subscription = BackHandler.addEventListener(
|
|
'hardwareBackPress',
|
|
onBackPress
|
|
);
|
|
|
|
return () => subscription.remove();
|
|
}, [Navigation])
|
|
);
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<InsideHeader title="Bidding Panel" showArrow />
|
|
<View style={styles.container2}>
|
|
<AppText variant="h3" color={colors.text} bold style={styles.title as any}>
|
|
{SelectedAuction.deptName}
|
|
</AppText>
|
|
|
|
<View style={styles.timerWrapper}>
|
|
<CountdownTimer
|
|
endDate={SelectedAuction.keyDates.auctionBidding.endDateTime}
|
|
myStyle={{ fontSize: 30 }}
|
|
size={30}
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
<FlatList
|
|
data={items}
|
|
keyExtractor={item => item.id.toString()}
|
|
renderItem={({ item, index }) => (
|
|
<ReverseBiddingCard
|
|
item={{ ...item, index }}
|
|
bidValue={bidValues[item.id] || 0}
|
|
onIncrease={() => handleUpdate(item.id, item.emdAmount)}
|
|
onDecrease={() => handleUpdate(item.id, -item.emdAmount)}
|
|
onPlaceBid={() => { submitBid(item) }}
|
|
SelectedAuction={SelectedAuction}
|
|
allBoolean={allBoolean}
|
|
setAllBoolean={setAllBoolean}
|
|
/>
|
|
)}
|
|
contentContainerStyle={{ padding: 16 }}
|
|
/>
|
|
|
|
{allBoolean.showSuccess && (
|
|
<View style={styles.overlay}>
|
|
<LottieView
|
|
source={require('../../lottie/Success.json')}
|
|
autoPlay
|
|
loop={false}
|
|
style={{ width: 200, height: 200 }}
|
|
/>
|
|
</View>
|
|
)}
|
|
|
|
<ConfirmBidModal
|
|
visible={allBoolean.showDialog}
|
|
onClose={() => setAllBoolean(prev => ({ ...prev, showDialog: false }))}
|
|
onConfirm={() => placeBidSubmit(allBoolean.bidPayload)}
|
|
bidAmount={allBoolean.bidPayload?.bidAmount}
|
|
/>
|
|
|
|
<GoBackModal
|
|
visible={allBoolean.showBackDialog}
|
|
onClose={() => setAllBoolean(prev => ({ ...prev, showBackDialog: false }))}
|
|
onConfirm={() => {
|
|
setAllBoolean(prev => ({ ...prev, showBackDialog: false }));
|
|
Navigation.dispatch(
|
|
CommonActions.reset({
|
|
index: 0,
|
|
routes: [{ name: NavigationString.Home }],
|
|
})
|
|
);
|
|
}}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default StartReverseBidding;
|
|
|
|
const makeStyles = (colors: any) => StyleSheet.create({
|
|
container: { flex: 1, backgroundColor: colors.background },
|
|
container2: {
|
|
paddingHorizontal: 16,
|
|
paddingTop: 12,
|
|
paddingBottom: 8,
|
|
},
|
|
title: {
|
|
marginBottom: 6,
|
|
} as any,
|
|
timerWrapper: {
|
|
alignItems: 'center',
|
|
},
|
|
overlay: { ...StyleSheet.absoluteFillObject, backgroundColor: colors.overlay, justifyContent: 'center', alignItems: 'center', zIndex: 99 },
|
|
}); |