integrated etender biding detail

This commit is contained in:
Jaanu423
2026-01-07 17:59:56 +05:30
parent ce40aa388f
commit 860d70d86e
23 changed files with 1758 additions and 525 deletions
+121
View File
@@ -0,0 +1,121 @@
import { StyleSheet, TextInput, View, TextInputProps, StyleProp, TextStyle, ViewStyle, TouchableOpacity } from 'react-native';
import React, { ReactNode } from 'react';
import Icon from 'lucide-react-native';
type MyInputProps = {
icon?: string;
placeholder?: string;
value?: string;
onChangeText?: (text: string) => void;
isVarify?: boolean;
maxlength?: number;
onFocus?: () => void;
onBlur?: () => void;
focused?: boolean;
keyboardType?: TextInputProps['keyboardType'];
editable?: boolean;
autoCapitalize?: TextInputProps['autoCapitalize'];
rightIcon?: string,
rightIconPress?:()=>void
} & TextInputProps;
const MyInput: React.FC<MyInputProps> = ({
icon,
placeholder,
value,
onChangeText,
isVarify,
maxlength,
onFocus,
onBlur,
focused,
keyboardType,
editable = true,
autoCapitalize,
rightIcon,
rightIconPress,
...textInputProps
}) => {
return (
<View
style={[
styles.inputWrapper,
focused && styles.inputFocused,
!editable && styles.inputDisabled,
]}
>
{/* <Icon
name={icon}
size={18}
color={focused ? "#0000" : '#aaa'}
style={styles.icon}
/> */}
<TextInput
{...textInputProps}
placeholder={placeholder}
style={[styles.input, !editable && { color: '#999' }]}
placeholderTextColor="#aaa"
value={value}
onChangeText={onChangeText}
maxLength={maxlength}
editable={editable}
onFocus={onFocus}
onBlur={onBlur}
keyboardType={keyboardType}
autoCapitalize={autoCapitalize}
/>
{
rightIcon ?
<TouchableOpacity onPress={rightIconPress}>
{/* <Icon
name={rightIcon}
size={18}
color={focused ? color.primary : '#aaa'}
style={styles.icon}
/> */}
</TouchableOpacity>
: null}
{/* {isVarify ? (
<Icon
name="check-circle"
size={18}
color={color.success}
style={styles.icon}
/>
) : null} */}
</View>
);
};
export default MyInput;
const styles = StyleSheet.create({
inputWrapper: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#fff',
borderRadius: 12,
borderWidth: 1,
borderColor: '#e0e0e0',
paddingHorizontal: 10,
marginVertical: 10,
height: 55,
},
icon: {
marginRight: 10,
},
input: {
flex: 1,
fontSize: 15,
color: '#000',
paddingVertical: 0,
},
inputFocused: {
borderColor: '#007BFF',
},
inputDisabled: {
backgroundColor: '#f2f2f2',
},
});
+4
View File
@@ -34,6 +34,10 @@ const colors = {
Orange: '#F97316',
OrangeLight: '#FDBA74',
OrangeSoft: '#FFF3E8',
darkGray: '#5f6368',
lightestGray: '#f1f3f4',
successLight: '#e6f4ea',
};
export default colors;
+5
View File
@@ -1,3 +1,6 @@
import ProceedToBidDetail from "../Screens/Tender/ProceedToBidDetail"
import TenderBidding from "../Screens/Tender/tenderBidding/TenderBidding"
const NavigationString = {
Login: 'Login',
Splash: 'Splash',
@@ -12,5 +15,7 @@ const NavigationString = {
// tender
PurchaseTenderList:'PurchaseTenderList',
ProceedToPurTender:'ProceedToPurTender',
TenderBidding:'TenderBidding',
ProceedToBidDetail:'ProceedToBidDetail',
}
export default NavigationString
+2
View File
@@ -38,6 +38,8 @@ export default function MainStack() {
<Stack.Screen name={NavigationString.PurchaseAuctionList} component={Screens.PurchaseAuctionList} options={option} />
<Stack.Screen name={NavigationString.PurchaseTenderList} component={Screens.PurchaseTenderList} options={option} />
<Stack.Screen name={NavigationString.ProceedToPurTender} component={Screens.ProceedToPurTender} options={option} />
<Stack.Screen name={NavigationString.TenderBidding} component={Screens.TenderBidding} options={option} />
<Stack.Screen name={NavigationString.ProceedToBidDetail} component={Screens.ProceedToBidDetail} options={option} />
</Stack.Navigator>
);
+1 -1
View File
@@ -17,7 +17,7 @@ export const selectPurchaseTenderSlice = createSlice({
action: PayloadAction<TenderItem>
) => {
const index = state.findIndex(
item => item.TenderNumber === action.payload.TenderNumber
item => item.tenderId === action.payload.tenderId
);
if (index !== -1) {
+5 -2
View File
@@ -13,8 +13,11 @@ export const tenderSlice = createSlice({
},
removeTender: (state) => {
state.tender = '';
}
},
setTenderDetails: (state, { payload }) => {
state.tender = payload;
},
},
});
export const { setTender , removeTender} = tenderSlice.actions;
export const { setTender , removeTender, setTenderDetails } = tenderSlice.actions;
export default tenderSlice.reducer;
-1
View File
@@ -38,7 +38,6 @@ const PurchaseAuction = () => {
return now.isAfter(end);
}
console.log(allBoolean);
return (
<View style={{ flex: 1 }}>
+1 -3
View File
@@ -49,8 +49,7 @@ const PurchaseAuctionList = () => {
const [loading, setLoading] = useState(false);
const [list, setList] = useState(dummyAuctionList);
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
console.log(SelectedPurchaseList,'iiiiiiiiiiiiiiiiiiiiiiii');
const { mutate, isPending } = useOfflineAuctionPurchase()
const calculateTotalAmount = (item: any) => {
const gstAmount =
@@ -80,7 +79,6 @@ const PurchaseAuctionList = () => {
};
try {
// console.log(body);
mutate(body, {
onSuccess: (res) => {
console.log(res, '---------------------purchsase response');
-1
View File
@@ -17,7 +17,6 @@ const LiveTender = () => {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch }: any = useFetchLiveTender();
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
console.log("live tender SelectedPurchaseList : ", SelectedPurchaseList)
useEffect(() => {
if (isRefetching) {
setShowRefreshBanner(true);
+3 -2
View File
@@ -4,7 +4,8 @@ import moment from 'moment';
import colors from '../../Constant/Color';
import { LiveTenderTileProps } from './types/types';
import { Calendar, Tag, Info, ArrowRight } from 'lucide-react-native';
import TenderDetail from './Modal/TenderDetail';
import TenderDetail from './Modal/TenderFullDetail';
import TenderFullDetail from './Modal/TenderFullDetail';
const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
data,
@@ -103,7 +104,7 @@ const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
</View>
{/* Tender Detail Modal */}
<TenderDetail visible={showDetail} data={data} onClose={() => setShowDetail(false)} />
<TenderFullDetail visible={showDetail} data={data} onClose={() => setShowDetail(false)} />
</TouchableOpacity>
</View>
);
@@ -32,6 +32,8 @@ interface Props {
}
const TenderFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
const inset = useSafeAreaInsets();
const { data: tenderResponse }: any = useFetchTenderById(data?.tenderId);
const tender = tenderResponse?.data?.[0];
@@ -1,257 +0,0 @@
import React, { memo } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ScrollView,
SafeAreaView,
Platform,
} from 'react-native';
import Modal from 'react-native-modal';
import {
Package,
IndianRupee,
FileText,
Download,
ArrowLeft,
Info,
} from 'lucide-react-native';
import colors from '../../../Constant/Color';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
interface Props {
visible: boolean;
onClose: () => void;
data?: any;
}
const TenderItemDetail: React.FC<Props> = ({ visible, onClose, data }) => {
const inset = useSafeAreaInsets();
if (!data) {
return null;
}
const Section = ({ title, icon: Icon, children }: any) => (
<View style={styles.sectionCard}>
<View style={styles.sectionHeader}>
<View style={styles.iconCircle}>
<Icon size={18} color={colors.primary} />
</View>
<Text style={styles.sectionTitle}>{title}</Text>
</View>
{children}
</View>
);
const PriceTile = ({ label, fig, words, full = false }: any) => (
<View style={[styles.priceTile, full && { width: '100%' }]}>
<Text style={styles.label}>{label}</Text>
<Text style={styles.priceFig}>
₹{Number(fig || 0).toLocaleString('en-IN')}
</Text>
<Text style={styles.priceWords}>{words || '-'}</Text>
</View>
);
return (
<Modal
isVisible={visible}
style={styles.fullModal}
animationIn="slideInUp"
animationOut="slideOutDown"
useNativeDriver
statusBarTranslucent
>
<SafeAreaView style={styles.safeArea}>
{/* Header */}
<View style={[styles.header, { paddingTop: inset.top }]}>
<TouchableOpacity onPress={onClose} style={styles.backBtn}>
<ArrowLeft size={24} color="#1e293b" />
</TouchableOpacity>
<View>
<Text style={styles.headerTitle}>Item Information</Text>
<Text style={styles.headerSub}>Detail View</Text>
</View>
</View>
<ScrollView contentContainerStyle={styles.scrollContent}>
{/* Product Specification */}
<Section title="Product Specification" icon={Package}>
<View style={styles.identityHeader}>
<Text style={styles.productNameText}>
{data.productName || '-'}
</Text>
<View style={styles.categoryBadge}>
<Text style={styles.categoryText}>
{data.category || '-'}
</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>
</View>
<View style={styles.specItem}>
<Text style={styles.label}>Duration</Text>
<Text style={styles.specValue}>{data.timeDuration || '-'}</Text>
</View>
</View>
</Section>
{/* Pricing */}
<Section title="Reserve & Bid Values" icon={IndianRupee}>
<PriceTile
label="Reserve Price"
fig={data.reservePriceFig}
words={data.reservePriceWords}
full
/>
<View style={styles.hDivider} />
<PriceTile
label="Tender Start Value"
fig={data.TenderStartFig}
words={data.TenderStartWords}
full
/>
<View style={styles.hDivider} />
<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>
</Section>
{/* Description */}
<Section title="Brief Description" icon={Info}>
<Text style={styles.descContent}>
{data.description || '-'}
</Text>
</Section>
{/* Documents */}
<Section title="Documents" icon={FileText}>
<TouchableOpacity style={styles.docRow}>
<Text style={styles.docIndex}>1</Text>
<View style={{ flex: 2 }}>
<Text style={styles.docTitle} numberOfLines={1}>
{data.documentName || 'Document'}
</Text>
</View>
<View style={styles.downloadIconBox}>
<Download size={18} color={colors.primary} />
</View>
</TouchableOpacity>
</Section>
</ScrollView>
</SafeAreaView>
</Modal>
);
};
const styles = StyleSheet.create({
fullModal: { margin: 0, backgroundColor: '#f8fafc' },
safeArea: { flex: 1 },
header: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#f1f5f9',
},
backBtn: { padding: 8, marginRight: 8 },
headerTitle: { fontSize: 18, fontWeight: '800', color: '#0f172a' },
headerSub: { fontSize: 12, color: '#94a3b8', fontWeight: '600', textTransform: 'uppercase' },
scrollView: { flex: 1 },
scrollContent: { padding: 16, paddingBottom: 50 },
sectionCard: {
backgroundColor: '#fff',
borderRadius: 24,
padding: 20,
marginBottom: 16,
...Platform.select({
ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.05, shadowRadius: 10 },
android: { elevation: 3 }
})
},
sectionHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
marginBottom: 20,
},
iconCircle: {
width: 36,
height: 36,
borderRadius: 12,
backgroundColor: colors.primary + '10',
alignItems: 'center',
justifyContent: 'center',
},
sectionTitle: {
fontSize: 14,
fontWeight: '800',
color: '#334155',
textTransform: 'uppercase',
letterSpacing: 0.5,
},
// Product Identity
identityHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 15 },
productNameText: { fontSize: 20, fontWeight: '900', color: '#1e293b', flex: 1 },
categoryBadge: { backgroundColor: '#f1f5f9', paddingHorizontal: 12, paddingVertical: 6, borderRadius: 20 },
categoryText: { fontSize: 11, fontWeight: '800', color: '#64748b', textTransform: 'uppercase' },
specGrid: { flexDirection: 'row', gap: 24, marginTop: 5 },
specItem: { flex: 1 },
specValue: { fontSize: 15, fontWeight: '700', color: '#334155', marginTop: 2 },
// Pricing
priceTile: { marginBottom: 16 },
label: { fontSize: 11, color: '#94a3b8', fontWeight: '700', textTransform: 'uppercase', marginBottom: 4 },
priceFig: { fontSize: 22, fontWeight: '900', color: colors.black },
priceWords: { fontSize: 13, color: '#64748b', fontStyle: 'italic', marginTop: 2 },
hDivider: { height: 1, backgroundColor: '#f1f5f9', marginBottom: 16 },
row: { flexDirection: 'row', justifyContent: 'space-between' },
// Description
descContent: { fontSize: 15, color: '#475569', lineHeight: 22, fontWeight: '500' },
// Table
docTableHead: { flexDirection: 'row', paddingBottom: 10, borderBottomWidth: 1, borderBottomColor: '#f1f5f9', marginBottom: 10 },
tableLabel: { fontSize: 11, fontWeight: '800', color: '#94a3b8', flex: 1 },
docRow: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#f8fafc', padding: 12, borderRadius: 12 },
docIndex: { flex: 1, fontSize: 14, fontWeight: '700', color: '#64748b' },
docTitle: { fontSize: 14, fontWeight: '700', color: '#1e293b' },
downloadIconBox: { backgroundColor: '#fff', padding: 8, borderRadius: 10, borderWidth: 1, borderColor: '#e2e8f0' },
// Footer
footer: {
position: 'absolute',
bottom: 0, width: '100%',
backgroundColor: '#fff',
padding: 20,
paddingBottom: Platform.OS === 'ios' ? 34 : 20,
borderTopWidth: 1, borderTopColor: '#f1f5f9'
},
primaryBtn: {
backgroundColor: colors.primary,
height: 56, borderRadius: 18,
flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10
},
primaryBtnText: { color: '#fff', fontSize: 16, fontWeight: '800' }
});
export default memo(TenderItemDetail);
+618
View File
@@ -0,0 +1,618 @@
import { StyleSheet, Text, View, ScrollView, StatusBar, TouchableOpacity } from 'react-native'
import React from 'react'
import { InsideHeader } from '../../Component/Index'
import colors from '../../Constant/Color'
import { useNavigation } from '@react-navigation/native'
const ProceedToBidDetail = () => {
// Sample data based on your JSON
const navigation = useNavigation<any>()
const tenderData = {
tenderId: 1372,
envelopeASubmittStatus: true,
envelopeBSubmittStatus: true,
envelopeCSubmittStatus: true,
envelopeA_Logs: {
logId: 314,
contractorId: 1,
activity: "Bid on Envelope A",
tenderId: 1372,
dateTime: "Fri Dec 12 13:07:44 IST 2025",
osName: "Linux",
browserName: "Chrome-142.0.0.0",
ipAddress: "192.168.5.10",
macAddress: "00:00:00:00:00:00",
logMessage: "Envelope A bidding is Submitted",
headingMsg: null,
status: null,
envelope: "EA"
},
envelopeB_Logs: {
logId: 315,
contractorId: 1,
activity: "Bid on Envelope B",
tenderId: 1372,
dateTime: "Fri Dec 12 13:08:00 IST 2025",
osName: "Linux",
browserName: "Chrome-142.0.0.0",
ipAddress: "192.168.5.10",
macAddress: "00:00:00:00:00:00",
logMessage: "Envelope B bidding is Submitted",
headingMsg: null,
status: null,
envelope: "EB"
},
envelopeC_Logs: {
logId: 316,
contractorId: 1,
activity: "Bid on Envelope C",
tenderId: 1372,
dateTime: "Fri Dec 12 13:08:31 IST 2025",
osName: "Linux",
browserName: "Chrome-142.0.0.0",
ipAddress: "192.168.5.10",
macAddress: "00:00:00:00:00:00",
logMessage: "Envelope C bidding is Submitted",
headingMsg: "Percentage Rate Tender",
status: null,
envelope: "EC"
},
showEB: true,
showEC: true,
showQCBS: false,
showLCS: false,
viewBid: true,
proceedtoBid: false,
tenderNumber: "TN/152",
emdInFig: "100",
tenderBidWithdraw: "Allowed",
tenderRebid: "Allowed",
nitNo: "NIT-410",
nameofWork: "Tender is created for Testing Process only",
reBid: "Allowed",
bidWithDraw: "Allowed",
envelopeType: "3",
biddingStatus: true,
tenderStages: "1",
dscStatus: false,
submittedStartDate: [2025, 3, 4, 10, 0],
submittedEndDate: [2026, 3, 4, 23, 50],
bidWithdrawStatus: true
};
// Format date from array
const formatDate = (dateArray: any[]) => {
if (!dateArray || dateArray.length < 3) return "N/A";
const [year, month, day, hour = 0, minute = 0] = dateArray;
return `${day.toString().padStart(2, '0')}/${month.toString().padStart(2, '0')}/${year} ${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
};
// Status indicator component
const StatusIndicator = ({ status, label }) => (
<View style={styles.statusContainer}>
<View style={[styles.statusDot, { backgroundColor: status ? colors.success : colors.error }]} />
<Text style={[styles.statusText, { color: status ? colors.success : colors.error }]}>
{label}: {status ? "Submitted" : "Not Submitted"}
</Text>
</View>
);
// Envelope log card component
const EnvelopeLogCard = ({ log, title }) => (
<View style={styles.envelopeCard}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>{title}</Text>
<View style={[styles.envelopeBadge, { backgroundColor: colors.primary }]}>
<Text style={styles.envelopeBadgeText}>{log.envelope}</Text>
</View>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Activity:</Text>
<Text style={styles.value}>{log.activity}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Date & Time:</Text>
<Text style={styles.value}>{log.dateTime}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>System Info:</Text>
<Text style={styles.value}>{log.osName} / {log.browserName}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>IP Address:</Text>
<Text style={styles.value}>{log.ipAddress}</Text>
</View>
<View style={styles.logDetailRow}>
<Text style={styles.label}>Status Message:</Text>
<Text style={[styles.value, styles.successText]}>{log.logMessage}</Text>
</View>
{log.headingMsg && (
<View style={styles.logDetailRow}>
<Text style={styles.label}>Heading:</Text>
<Text style={styles.value}>{log.headingMsg}</Text>
</View>
)}
</View>
);
// Information row component
const InfoRow = ({ label, value, isHighlighted = false }) => (
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>{label}:</Text>
<Text style={[styles.infoValue, isHighlighted && styles.highlightedValue]}>{value}</Text>
</View>
);
// Feature chip component
const FeatureChip = ({ label, enabled }) => (
<View style={[styles.chip, { backgroundColor: enabled ? colors.successLight : colors.lightGray }]}>
<Text style={[styles.chipText, { color: enabled ? colors.success : colors.darkGray }]}>
{label} {enabled ? '✓' : '✗'}
</Text>
</View>
);
return (
<View style={{ flex: 1, backgroundColor: colors.white }}>
<StatusBar backgroundColor={colors.primary} barStyle="light-content" />
<InsideHeader title="Tender Detail" showArrow />
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
{/* Tender Header Section */}
<View style={styles.headerCard}>
<View style={styles.tenderHeader}>
<View>
<Text style={styles.tenderNumber}>{tenderData.tenderNumber}</Text>
<Text style={styles.tenderId}>ID: {tenderData.tenderId}</Text>
</View>
<View style={[styles.statusBadge, { backgroundColor: tenderData.biddingStatus ? colors.success : colors.warning }]}>
<Text style={styles.statusBadgeText}>
{tenderData.biddingStatus ? "Active" : "Inactive"}
</Text>
</View>
</View>
<Text style={styles.workDescription}>{tenderData.nameofWork}</Text>
<View style={styles.headerInfoRow}>
<View style={styles.headerInfoItem}>
<Text style={styles.headerInfoLabel}>NIT No.</Text>
<Text style={styles.headerInfoValue}>{tenderData.nitNo}</Text>
</View>
<View style={styles.separator} />
<View style={styles.headerInfoItem}>
<Text style={styles.headerInfoLabel}>EMD Amount</Text>
<Text style={styles.headerInfoValue}>₹{tenderData.emdInFig}</Text>
</View>
</View>
</View>
{/* Envelope Submission Status */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Envelope Submission Status</Text>
<View style={styles.statusGrid}>
<StatusIndicator status={tenderData.envelopeASubmittStatus} label="Envelope A" />
<StatusIndicator status={tenderData.envelopeBSubmittStatus} label="Envelope B" />
<StatusIndicator status={tenderData.envelopeCSubmittStatus} label="Envelope C" />
</View>
</View>
{/* Envelope Logs */}
{tenderData.envelopeA_Logs && (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Submission Logs</Text>
<EnvelopeLogCard log={tenderData.envelopeA_Logs} title="Envelope A Submission" />
<EnvelopeLogCard log={tenderData.envelopeB_Logs} title="Envelope B Submission" />
<EnvelopeLogCard log={tenderData.envelopeC_Logs} title="Envelope C Submission" />
</View>
)}
{/* Tender Details */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Tender Details</Text>
<View style={styles.detailsCard}>
<InfoRow label="Envelope Type" value={tenderData.envelopeType} />
<InfoRow label="Tender Stages" value={tenderData.tenderStages} />
<InfoRow label="Bid Withdrawal" value={tenderData.bidWithDraw} isHighlighted={tenderData.bidWithdrawStatus} />
<InfoRow label="Re-bid" value={tenderData.reBid} />
<InfoRow label="DSC Status" value={tenderData.dscStatus ? "Required" : "Not Required"} />
</View>
</View>
{/* Time Period */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Submission Time Period</Text>
<View style={styles.timeCard}>
<View style={styles.timeRow}>
<Text style={styles.timeLabel}>Starts On:</Text>
<Text style={styles.timeValue}>{formatDate(tenderData.submittedStartDate)}</Text>
</View>
<View style={styles.timeRow}>
<Text style={styles.timeLabel}>Ends On:</Text>
<Text style={styles.timeValue}>{formatDate(tenderData.submittedEndDate)}</Text>
</View>
</View>
</View>
{/* Feature Flags */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Available Features</Text>
<View style={styles.chipsContainer}>
<FeatureChip label="View Bid" enabled={tenderData.viewBid} />
<FeatureChip label="Proceed to Bid" enabled={tenderData.proceedtoBid} />
<FeatureChip label="Show Envelope B" enabled={tenderData.showEB} />
<FeatureChip label="Show Envelope C" enabled={tenderData.showEC} />
<FeatureChip label="QCBS" enabled={tenderData.showQCBS} />
<FeatureChip label="LCS" enabled={tenderData.showLCS} />
</View>
</View>
{/* Final Status */}
<View style={styles.finalStatusCard}>
<Text style={styles.finalStatusTitle}>Overall Status</Text>
<View style={styles.finalStatusRow}>
<Text style={styles.finalStatusLabel}>All Envelopes Submitted:</Text>
<Text style={[styles.finalStatusValue,
{
color: tenderData.envelopeASubmittStatus && tenderData.envelopeBSubmittStatus && tenderData.envelopeCSubmittStatus
? colors.success : colors.error
}]}>
{tenderData.envelopeASubmittStatus && tenderData.envelopeBSubmittStatus && tenderData.envelopeCSubmittStatus
? "COMPLETED" : "PENDING"}
</Text>
</View>
<View style={styles.finalStatusRow}>
<Text style={styles.finalStatusLabel}>Bidding Status:</Text>
<Text style={[styles.finalStatusValue,
{ color: tenderData.biddingStatus ? colors.success : colors.error }]}>
{tenderData.biddingStatus ? "ACTIVE" : "CLOSED"}
</Text>
</View>
</View>
<View style={styles.footerSpace} />
</ScrollView>
<View style={styles.footer}>
<TouchableOpacity style={styles.proceedButton} onPress={() => {
navigation.navigate('TenderBidding', { tenderData: tenderData });
}}>
<Text style={styles.proceedButtonText}>Proceed to Bid</Text>
</TouchableOpacity>
{
// tenderData?.proceedtoBid && !tenderData?.viewBid && tenderData?.biddingStatus && tenderData?.bidWithdrawStatus === false ? (
// <TouchableOpacity style={styles.proceedButton} onPress={() => {
// navigation.navigate('TenderBidding', { tenderData: tenderData });
// }}>
// <Text style={styles.proceedButtonText}>Proceed to Bid</Text>
// </TouchableOpacity>
// ) : <Text style={styles.footerText}>One time bidding is completed</Text>
} </View>
</View>
)
}
export default ProceedToBidDetail
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
marginBottom: 60,
},
headerCard: {
backgroundColor: colors.primaryLight,
borderRadius: 12,
padding: 20,
marginBottom: 20,
borderLeftWidth: 4,
borderLeftColor: colors.primary,
},
tenderHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
tenderNumber: {
fontSize: 22,
fontWeight: 'bold',
color: colors.primary,
},
tenderId: {
fontSize: 14,
color: colors.darkGray,
marginTop: 4,
},
statusBadge: {
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 20,
},
statusBadgeText: {
color: colors.white,
fontWeight: '600',
fontSize: 12,
},
workDescription: {
fontSize: 16,
color: colors.darkText,
lineHeight: 22,
marginBottom: 16,
},
headerInfoRow: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.white,
borderRadius: 8,
padding: 12,
},
headerInfoItem: {
flex: 1,
alignItems: 'center',
},
headerInfoLabel: {
fontSize: 12,
color: colors.darkGray,
marginBottom: 4,
},
headerInfoValue: {
fontSize: 16,
fontWeight: '600',
color: colors.primary,
},
separator: {
width: 1,
height: 30,
backgroundColor: colors.lightGray,
},
section: {
marginBottom: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
color: colors.primary,
marginBottom: 12,
paddingLeft: 4,
},
statusGrid: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
statusContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
statusDot: {
width: 12,
height: 12,
borderRadius: 6,
marginRight: 10,
},
statusText: {
fontSize: 15,
fontWeight: '500',
},
envelopeCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
marginBottom: 12,
borderWidth: 1,
borderColor: colors.lightGray,
},
cardHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
cardTitle: {
fontSize: 16,
fontWeight: '600',
color: colors.primary,
},
envelopeBadge: {
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 12,
},
envelopeBadgeText: {
color: colors.white,
fontWeight: 'bold',
fontSize: 12,
},
logDetailRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 8,
},
label: {
fontSize: 14,
color: colors.darkGray,
flex: 1,
},
value: {
fontSize: 14,
color: colors.darkText,
fontWeight: '500',
flex: 2,
textAlign: 'right',
},
successText: {
color: colors.success,
fontWeight: '600',
},
detailsCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
infoRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: colors.lightestGray,
},
infoLabel: {
fontSize: 14,
color: colors.darkGray,
},
infoValue: {
fontSize: 15,
fontWeight: '500',
color: colors.darkText,
},
highlightedValue: {
color: colors.success,
fontWeight: '600',
},
timeCard: {
backgroundColor: colors.white,
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
timeRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: colors.lightestGray,
},
timeLabel: {
fontSize: 15,
color: colors.darkGray,
fontWeight: '500',
},
timeValue: {
fontSize: 15,
color: colors.primary,
fontWeight: '600',
},
chipsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 10,
},
chip: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
marginBottom: 8,
},
chipText: {
fontSize: 14,
fontWeight: '500',
},
finalStatusCard: {
backgroundColor: colors.primaryLight,
borderRadius: 12,
padding: 20,
marginTop: 10,
borderWidth: 2,
borderColor: colors.primary,
},
finalStatusTitle: {
fontSize: 18,
fontWeight: 'bold',
color: colors.primary,
marginBottom: 16,
textAlign: 'center',
},
finalStatusRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: 'rgba(0, 0, 0, 0.1)',
},
finalStatusLabel: {
fontSize: 16,
color: colors.darkText,
fontWeight: '500',
},
finalStatusValue: {
fontSize: 16,
fontWeight: 'bold',
},
footerSpace: {
height: 30,
},
success: {
color: colors.success,
},
error: {
color: colors.error,
},
primary: {
color: colors.primary,
},
warning: {
color: colors.warning,
},
successLight: {
backgroundColor: colors.successLight,
},
lightGray: {
backgroundColor: colors.lightGray,
},
footer: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: colors.white,
padding: 16,
borderTopWidth: 1,
borderTopColor: colors.lightGray,
elevation: 10,
},
proceedButton: {
backgroundColor: colors.primary,
paddingVertical: 14,
borderRadius: 30,
alignItems: 'center',
},
proceedButtonText: {
color: colors.white,
fontSize: 16,
fontWeight: '600',
},
footerText: {
textAlign: 'center',
color: colors.darkGray,
fontSize: 14,
},
});
+1 -3
View File
@@ -12,8 +12,7 @@ const ProceedToPurTender = () => {
const navigation: any = useNavigation();
const [loading, setLoading] = useState(false);
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseTender);
console.log(SelectedPurchaseList, 'iiiiiiiiiiiiiiiiiiiiiiii tender purchase list : ', SelectedPurchaseList);
const { mutate, isPending } = useOfflineTenderPurchase()
const calculateTotalAmount = (item: any) => {
const gstAmount =
@@ -50,7 +49,6 @@ const ProceedToPurTender = () => {
console.log("tender offline body : ", body)
try {
// console.log(body);
mutate(body, {
onSuccess: (res) => {
console.log(res, '---------------------purchsase response');
+92 -60
View File
@@ -1,6 +1,5 @@
import React, { useState, useCallback, memo } from 'react';
import React, { useState, useCallback, memo, useEffect } from 'react';
import { View, Text, StyleSheet, FlatList, RefreshControl, ActivityIndicator } from 'react-native';
import LiveTenderTile from './LiveTenderTile';
import { useNavigation } from '@react-navigation/native';
import moment from 'moment';
import { useFetchPurchaseTender } from '../../Services/BBPS/Hooks';
@@ -12,6 +11,8 @@ import { Skelton } from '../../Component/Index';
import { allBooleanProps } from './types/types';
import FilterModal from './Modal/FilterModal';
import colors from '../../Constant/Color';
import Animated, { FadeInDown, FadeOutUp } from 'react-native-reanimated';
import NavigationString from '../../Constant/NavigationString';
const PurchaseTenderAllList = () => {
@@ -19,28 +20,22 @@ const PurchaseTenderAllList = () => {
const Dispatch = useDispatch()
const [allBoolean, setAllBoolean] = useState<allBooleanProps>({ isShowFilter: false })
const [page, setPage] = useState(1);
const { data: data, isPending, isFetching } = useFetchPurchaseTender(page);
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch }: any = useFetchPurchaseTender();
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
console.log("data my data : ", data);
const [allData, setAllData] = useState<any[]>([]);
useEffect(() => {
if (isRefetching) {
setShowRefreshBanner(true);
} else {
const timer = setTimeout(() => {
setShowRefreshBanner(false);
}, 1000);
return () => clearTimeout(timer);
}
}, [isRefetching]);
const format = 'DD-MM-YYYY HH:mm:ss';
const tenderList = data?.data || [];
const totalCount = data?.totalCount || 0;
// Append new page data
React.useEffect(() => {
if (tenderList.length) {
setAllData(prev => {
const merged = [...prev, ...tenderList];
const unique = merged.filter(
(v, i, a) => a.findIndex(t => t.tenderId === v.tenderId) === i
);
return unique;
});
}
}, [tenderList]);
function isTenderActive(item: any): boolean {
const now = moment();
const start = moment(item?.keyDates?.TenderBidding?.startDateTime, format);
@@ -59,51 +54,88 @@ const PurchaseTenderAllList = () => {
return now.isAfter(end);
}
console.log(allBoolean);
const loadMore = () => {
if (allData.length < totalCount && !isFetching) {
setPage(prev => prev + 1);
const loadMore = useCallback(() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
};
const renderFooter = () => {
if (!isFetching) return null;
return (
<ActivityIndicator
size="small"
color={colors.primary}
style={{ marginVertical: 16 }}
/>
);
};
}, [hasNextPage, isFetchingNextPage]);
console.log("all data : ", allData)
const renderFooter = useCallback(() => {
if (!isFetchingNextPage) return null;
return (
<View style={{ paddingVertical: 12 }}>
<ActivityIndicator size="small" color={colors.primary} />
</View>
);
}, [isFetchingNextPage]);
return (
<View style={{ flex: 1 }}>
<SearchInput onChange={() => { }} placeholder='Search....' filterPress={() => { setAllBoolean((prev: any) => ({ ...prev, isShowFilter: !prev.isShowFilter })) }} />
{isPending ? <Skelton /> : <FlatList
data={allData || []}
keyExtractor={(_, index) => index.toString()}
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 200, paddingHorizontal: 10 }}
renderItem={({ item, index }) => (
<PurchaseTenderTile
item={item}
onPressDetails={() => {
navigation.navigate('TenderDetail', { item, onAddToPurchase: () => { }, routeFrom: 'PurchasedTender' });
{showRefreshBanner && (
<Animated.View
entering={FadeInDown.duration(200)}
exiting={FadeOutUp.duration(500)}
style={{
alignSelf: 'center',
flexDirection: 'row',
alignItems: 'center',
gap: 8,
paddingVertical: 8,
paddingHorizontal: 14,
marginTop: 6,
borderRadius: 20,
backgroundColor: '#FFFFFF',
shadowColor: '#000',
shadowOpacity: 0.06,
shadowRadius: 8,
shadowOffset: { width: 0, height: 3 },
elevation: 4,
zIndex: 10, // Ensure it stays on top
position: 'absolute',
top: 60, // Adjust based on your SearchInput height
}}
>
<ActivityIndicator size="small" color={colors.primary} />
<Text
style={{
fontSize: 13,
color: '#374151',
fontWeight: '500',
}}
onStartBidding={() => {
Dispatch(setTender(item))
// navigation.navigate(NavigationString, { data: item })
}}
buttonEnable={isTenderActive(item)}
isTenderEnd={isTenderEnd(item)}
/>
)}
onEndReached={loadMore}
onEndReachedThreshold={0.6}
ListFooterComponent={renderFooter}
/>}
>
Refreshing tenders
</Text>
</Animated.View>
)}
{isLoading ? <Skelton />
: <FlatList
data={data?.result ?? []}
keyExtractor={(item) => String(item.tenderId || item.id)}
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 200, paddingHorizontal: 10 }}
renderItem={({ item, index }) => (
<PurchaseTenderTile
item={item}
onPressDetails={() => {
navigation.navigate('TenderDetail', { item, onAddToPurchase: () => { }, routeFrom: 'PurchasedTender' });
}}
onStartBidding={() => {
Dispatch(setTender(item))
navigation.navigate(NavigationString.TenderBidding, { data: item })
}}
buttonEnable={isTenderActive(item)}
isTenderEnd={isTenderEnd(item)}
/>
)}
onEndReached={loadMore}
onEndReachedThreshold={0.6}
ListFooterComponent={renderFooter}
refreshing={isRefetching}
onRefresh={refetch}
/>}
{allBoolean.isShowFilter && <View style={{ flex: 1 }}>
@@ -19,7 +19,6 @@ const PurchaseTenderList = () => {
};
console.log("SelectedPurchaseList : ", SelectedPurchaseList)
return (
<View style={styles.screen}>
<InsideHeader title="Purchase" showArrow />
+166 -135
View File
@@ -5,6 +5,7 @@ import {
StyleSheet,
TouchableOpacity,
Platform,
Alert,
} from 'react-native';
import Animated, {
FadeInUp,
@@ -15,20 +16,39 @@ import Animated, {
import moment from 'moment';
import CountdownTimer from '../../Component/Counter/CountdownTimer';
import colors from '../../Constant/Color';
import { useFetchTenderById, useProceedToBid } from '../../Services/BBPS/Hooks';
import { useNavigation } from '@react-navigation/native';
import TenderFullDetail from './Modal/TenderFullDetail';
const PurchaseTenderTile = ({
item,
onPressDetails,
onStartPurchase,
}: any) => {
const scale = useSharedValue(1);
const elevation = useSharedValue(8);
const navigation = useNavigation<any>();
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
elevation: elevation.value,
}));
const { data: tenderResponse, }: any = useFetchTenderById(item?.tenderId);
const tender = tenderResponse?.data;
// const {
// refetch,
// isFetching,
// isError,
// } = useProceedToBid(item?.tenderId);
// const handleProceed = async (item: any) => {
// const res = await refetch();
// if (res.data && !isError) {
// navigation.navigate('TenderBidding', { tenderData: res.data?.data });
// }
// };
const handlePressIn = () => {
scale.value = withTiming(0.97, { duration: 120 });
elevation.value = withTiming(3, { duration: 120 });
@@ -43,6 +63,7 @@ const PurchaseTenderTile = ({
const statusColor = isLive ? colors.primary : '#94A3B8';
const lightStatusBg = isLive ? '#EFF6FF' : '#F8FAFC';
const [showDetail, setShowDetail] = React.useState(false);
return (
<Animated.View
@@ -80,7 +101,9 @@ const PurchaseTenderTile = ({
</View>
{/* Date */}
<View style={styles.dateRow}>
<TouchableOpacity style={styles.dateRow} onPress={() => {
setShowDetail(true)
}}>
<Text style={styles.dateText}>
<Text style={styles.dateLabel}>Purchase Ends: </Text>
{moment(
@@ -88,7 +111,7 @@ const PurchaseTenderTile = ({
'DD-MM-YYYY HH:mm:ss'
).format('DD MMM, hh:mm A')}
</Text>
</View>
</TouchableOpacity>
{/* Footer */}
<View style={styles.footer}>
@@ -108,7 +131,11 @@ const PurchaseTenderTile = ({
<TouchableOpacity
disabled={!isLive}
onPress={onStartPurchase}
onPress={() => {
if (isLive) {
navigation.navigate('ProceedToBidDetail', { tender });
}
}}
activeOpacity={0.85}
style={[
styles.actionButton,
@@ -117,11 +144,15 @@ const PurchaseTenderTile = ({
]}
>
<Text style={styles.addText}>
{isLive ? 'Proceed to Purchase' : 'Tender Closed'}
{isLive ? 'Proceed to Bid' : 'Tender Closed'}
</Text>
</TouchableOpacity>
</View>
</View>
{/* Tender Detail Modal */}
<TenderFullDetail visible={showDetail} data={item} onClose={() => setShowDetail(false)} />
</TouchableOpacity>
</Animated.View>
);
@@ -131,134 +162,134 @@ export default PurchaseTenderTile;
const styles = StyleSheet.create({
shadowContainer: {
marginHorizontal: 5,
marginTop: 14,
marginBottom: 6,
borderRadius: 16,
backgroundColor: '#fff',
elevation: 8,
},
cardInternal: {
borderRadius: 16,
overflow: 'hidden',
flexDirection: 'row',
backgroundColor: '#fff',
},
statusAccent: {
width: 5,
height: '100%',
},
mainInfo: {
flex: 1,
padding: 16,
},
headerRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 12,
},
statusBadge: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: 6,
marginBottom: 6,
alignSelf: 'flex-start',
},
statusDot: {
width: 6,
height: 6,
borderRadius: 3,
marginRight: 5,
},
statusText: {
fontSize: 10,
fontWeight: '800',
letterSpacing: 0.5,
},
title: {
fontWeight: '800',
fontSize: 16,
color: '#1E293B',
},
amountContainer: {
alignItems: 'flex-end',
},
amount: {
fontWeight: '900',
fontSize: 18,
color: '#0F172A',
},
feeLabel: {
fontSize: 10,
color: '#64748B',
fontWeight: '500',
},
dateRow: {
backgroundColor: '#F8FAFC',
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 10,
marginBottom: 16,
borderWidth: 1,
borderColor: '#F1F5F9',
},
dateText: {
fontSize: 12,
color: '#334155',
fontWeight: '600',
},
dateLabel: {
fontWeight: '400',
color: '#64748B',
},
footer: {
borderTopWidth: 1,
borderTopColor: '#F1F5F9',
paddingTop: 12,
},
footerTop: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
footerLabel: {
fontSize: 11,
fontWeight: '600',
color: '#94A3B8',
textTransform: 'uppercase',
},
endedText: {
fontSize: 13,
fontWeight: '700',
color: '#CBD5E1',
},
actionButton: {
width: '100%',
height: 48,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
}),
},
disabledButton: {
backgroundColor: '#E2E8F0',
},
addText: {
color: '#fff',
fontSize: 14,
fontWeight: '800',
letterSpacing: 0.2,
},
shadowContainer: {
marginHorizontal: 5,
marginTop: 14,
marginBottom: 6,
borderRadius: 16,
backgroundColor: '#fff',
elevation: 8,
},
cardInternal: {
borderRadius: 16,
overflow: 'hidden',
flexDirection: 'row',
backgroundColor: '#fff',
},
statusAccent: {
width: 5,
height: '100%',
},
mainInfo: {
flex: 1,
padding: 16,
},
headerRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 12,
},
statusBadge: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 8,
paddingVertical: 3,
borderRadius: 6,
marginBottom: 6,
alignSelf: 'flex-start',
},
statusDot: {
width: 6,
height: 6,
borderRadius: 3,
marginRight: 5,
},
statusText: {
fontSize: 10,
fontWeight: '800',
letterSpacing: 0.5,
},
title: {
fontWeight: '800',
fontSize: 16,
color: '#1E293B',
},
amountContainer: {
alignItems: 'flex-end',
},
amount: {
fontWeight: '900',
fontSize: 18,
color: '#0F172A',
},
feeLabel: {
fontSize: 10,
color: '#64748B',
fontWeight: '500',
},
dateRow: {
backgroundColor: '#F8FAFC',
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 10,
marginBottom: 16,
borderWidth: 1,
borderColor: '#F1F5F9',
},
dateText: {
fontSize: 12,
color: '#334155',
fontWeight: '600',
},
dateLabel: {
fontWeight: '400',
color: '#64748B',
},
footer: {
borderTopWidth: 1,
borderTopColor: '#F1F5F9',
paddingTop: 12,
},
footerTop: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
footerLabel: {
fontSize: 11,
fontWeight: '600',
color: '#94A3B8',
textTransform: 'uppercase',
},
endedText: {
fontSize: 13,
fontWeight: '700',
color: '#CBD5E1',
},
actionButton: {
width: '100%',
height: 48,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
}),
},
disabledButton: {
backgroundColor: '#E2E8F0',
},
addText: {
color: '#fff',
fontSize: 14,
fontWeight: '800',
letterSpacing: 0.2,
},
});
+1 -4
View File
@@ -30,12 +30,9 @@ const Tender = () => {
const { data: purchaseTenderData = {} } : any = useFetchPurchaseTender();
const SelectedPurchaseList = useSelector((state: any) => state?.selectPurchaseTender);
console.log("liveTenderData : ", liveTenderData)
console.log("purchaseTenderData : ", purchaseTenderData)
const liveCount = liveTenderData?.totalCount || 0;
const purchaseCount = purchaseTenderData?.totalCount || 0;
const purchaseCount = purchaseTenderData?.pages?.[0]?.totalCount || 0;
const [selectedTab, setSelectedTab] = useState<'live' | 'purchase'>('live');
const translateX = useRef(new Animated.Value(0)).current;
@@ -0,0 +1,663 @@
import {
ActivityIndicator,
Alert,
FlatList,
ScrollView,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View,
} from 'react-native';
import React, { use, useEffect, useState } from 'react';
import { useNavigation, useRoute } from '@react-navigation/native';
import MyInput from '../../../../src/Component/MyInput';
import { pick, types } from '@react-native-documents/picker';
import { InsideHeader } from '../../../Component/Index';
import colors from '../../../Constant/Color';
type EnvelopeType = 'A' | 'B' | 'C';
type EnvelopeFormState = {
A: Record<number, string>;
B: Record<number, string>;
C: Record<number, string>;
};
interface EnvelopeButtonProps {
title: string;
onPress: () => void;
}
interface InfoRowProps {
title: string;
value: string;
}
interface TenderBiddingData {
data?: {
tenderNumber?: string;
nitNo?: string;
emdInFig?: string;
tenderRebid?: boolean;
showEA?: boolean;
showEB?: boolean;
showEC?: boolean;
tenderEnvelopeAList?: any[];
tenderEnvelopeBList?: any[];
tenderEnvelopeCList?: any[];
};
}
const TenderBidding = () => {
const route = useRoute();
const navigation = useNavigation();
const [bidData] = useState<any>(route.params?.tenderData || null);
const [activeEnvelope, setActiveEnvelope] = useState<EnvelopeType | null>('A');
const [isLoading, setIsLoading] = useState(false);
const [envelopForm, setEnvelopForm] = useState<EnvelopeFormState>({
A: {},
B: {},
C: {},
});
const [loading, setLoading] = useState(false)
const [loadingUpload, setLoadingUpload] = useState(false)
const [check, setCheck] = useState(false)
const InfoRow = ({ title, value }: InfoRowProps) => (
<View style={styles.infoRow}>
<Text style={styles.label}>{title}</Text>
<Text style={styles.value}>{value || '-'}</Text>
</View>
);
const EnvelopeButton = ({ title, envelopeType, onPress }: EnvelopeButtonProps & { envelopeType: EnvelopeType }) => (
<TouchableOpacity
onPress={onPress}
style={[
styles.envelopeButton,
{
borderWidth: activeEnvelope === envelopeType ? 1 : 0,
borderColor: activeEnvelope === envelopeType ? colors.primary : 'transparent'
}
]}
>
<Text style={styles.envelopeButtonText}>{title}</Text>
</TouchableOpacity>
);
const handleEnvelopeChange = (
envelopeType: EnvelopeType,
sequenceId: number,
value: any
) => {
setEnvelopForm(prev => ({
...prev,
[envelopeType]: {
...prev[envelopeType],
[sequenceId]: value,
},
}));
};
const pickPdf = async (
envelopeType: EnvelopeType,
sequenceId: number
) => {
try {
const res = await pick({
type: types.pdf,
allowMultiSelection: false,
});
const file = res[0];
handleEnvelopeChange(envelopeType, sequenceId, file);
} catch (err: any) {
if (err?.code === 'DOCUMENT_PICKER_CANCELED') {
return;
}
console.error(err);
}
};
const renderEnvelopeItem = ({
item,
envelopeType,
}: {
item: any;
envelopeType: EnvelopeType;
}) => {
const sequenceId = item?.[`tenderEnvelope${envelopeType}SequnceId`];
if (!sequenceId) {
return null;
}
const labelName = item?.[`labelName${envelopeType}`] || '';
const labelType = item?.[`labelType${envelopeType}`] || '';
const showInput =
activeEnvelope === envelopeType !== 'C' &&
!bidData?.[`envelope${envelopeType}SubmittStatus`];
return (
<View key={sequenceId}>
<View style={styles.envelopeItem}>
<View style={{ flexDirection: 'row', gap: 20 }}>
{/* <Text style={styles.label}>Label Name</Text> */}
<Text style={styles.value}>{labelName || '-'}</Text>
{item?.[`labelMandatory${activeEnvelope}`] && <Text style={{ color: validateEnvelope() ? 'gray' : 'red', }}>*</Text>}
</View>
{/* <View>
<Text style={styles.label}>Label Type</Text>
<Text style={styles.value}>{labelType || '-'}</Text>
</View> */}
</View>
{showInput ? (
<>
{labelType === '1' && (
<MyInput
placeholder={`Enter ${labelName} numeric value`}
value={envelopForm?.[envelopeType]?.[sequenceId] ?? ''}
onChangeText={(text: string) =>
handleEnvelopeChange(envelopeType, sequenceId, text)
}
keyboardType="numeric"
/>
)}
{labelType === '2' && (
<MyInput
placeholder={`Enter ${labelName} Alph-numeric value`}
value={envelopForm?.[envelopeType]?.[sequenceId] ?? ''}
onChangeText={(text: string) =>
handleEnvelopeChange(envelopeType, sequenceId, text)
}
keyboardType="default"
/>
)}
{labelType === '3' && (
<>
<TouchableOpacity
style={[
styles.envelopeButton,
{ borderColor: colors.primary, borderWidth: 1, marginBottom: 8 }
]}
onPress={() => pickPdf(activeEnvelope, sequenceId)}
>
<Text style={styles.envelopeButtonText}>
{envelopForm?.[activeEnvelope]?.[sequenceId]
? 'Change Document'
: 'Upload Document'}
</Text>
</TouchableOpacity>
{envelopForm?.[activeEnvelope]?.[sequenceId] && (
<Text style={{ fontSize: 12, color: '#555' }}>
{(envelopForm[activeEnvelope][sequenceId] as any)?.name}
</Text>
)}
</>
)}
{labelType === '4' && (
<MyInput
placeholder={`Enter ${labelName} currency value`}
value={envelopForm?.[envelopeType]?.[sequenceId] ?? ''}
onChangeText={(text: string) =>
handleEnvelopeChange(envelopeType, sequenceId, text)
}
keyboardType="numeric"
/>
)}
</>
) : <Text>Envelop {activeEnvelope} unavailable</Text>}
</View>
);
};
const hasEnvelopes = () => {
const hasA = bidData?.tenderEnvelopeAList?.length > 0;
const hasB = bidData?.tenderEnvelopeBList?.length > 0;
// const hasC = bidData?.tenderEnvelopeCList?.length > 0;
return hasA || hasB;
};
const digitToWordMap: Record<string, string> = {
'0': 'Zero',
'1': 'One',
'2': 'Two',
'3': 'Three',
'4': 'Four',
'5': 'Five',
'6': 'Six',
'7': 'Seven',
'8': 'Eight',
'9': 'Nine',
};
const convertDigitsToWords = (value: string): string => {
return value
.split('')
.map(digit => digitToWordMap[digit] || '')
.join(' ') || value;
};
const buildEnvelopePayload = () => {
const list =
bidData?.[`tenderEnvelope${activeEnvelope}List`] || [];
const formValues = envelopForm?.[activeEnvelope] || {};
// 🔹 NON-FILE FIELDS (labelType !== '3')
const saveData = list
.filter(
(item: any) =>
item[`labelType${activeEnvelope}`] !== '3'
)
.map((item: any) => {
const seqId =
item[`tenderEnvelope${activeEnvelope}SequnceId`];
const value = formValues[seqId];
return {
[`tenderEnvelope${activeEnvelope}SequnceId`]: seqId,
[`labelName${activeEnvelope}`]:
item[`labelName${activeEnvelope}`],
[`labelType${activeEnvelope}`]:
item[`labelType${activeEnvelope}`],
[`labelMandatory${activeEnvelope}`]:
item[`labelMandatory${activeEnvelope}`],
fieldValue: value ?? '',
fieldValueInWord: value
? convertDigitsToWords(value)
: '',
};
});
// 🔹 FILE FIELDS (labelType === '3') → upload separately
const fileData = list
.filter(
(item: any) =>
item[`labelType${activeEnvelope}`] === '3'
)
.map((item: any) => {
const seqId =
item[`tenderEnvelope${activeEnvelope}SequnceId`];
return {
[`tenderEnvelope${activeEnvelope}SequnceId`]: seqId,
[`labelName${activeEnvelope}`]:
item[`labelName${activeEnvelope}`],
[`labelType${activeEnvelope}`]:
item[`labelType${activeEnvelope}`],
[`labelMandatory${activeEnvelope}`]:
item[`labelMandatory${activeEnvelope}`],
};
});
return payload = {
deptId: bidData?.deptId,
tenderId: bidData?.tenderId,
[`tenderEnvelope${activeEnvelope}NameId`]:
bidData?.[`tenderEnvelope${activeEnvelope}List`]?.[0]?.[
`tenderEnvelope${activeEnvelope}NameId`
],
[`envelope${activeEnvelope}TemplateName`]:
bidData?.[`tenderEnvelope${activeEnvelope}List`]?.[0]?.[
`envelope${activeEnvelope}TemplateName`
],
[`save${activeEnvelope}Data`]: envelopForm?.[activeEnvelope]?.[3]
? fileData
: saveData,
};
};
const validateEnvelope = () => {
const list = bidData?.[`tenderEnvelope${activeEnvelope}List`] || [];
const formValues = envelopForm[activeEnvelope];
const missing = list.some((item: any) => {
const seqId = item[`tenderEnvelope${activeEnvelope}SequnceId`];
const isMandatory = item[`labelMandatory${activeEnvelope}`];
const value = formValues?.[seqId];
if (!isMandatory) return false;
// File upload
if (item[`labelType${activeEnvelope}`] === '3') {
return !value;
}
// Text / numeric
return !value || value.toString().trim() === '';
});
return !missing;
};
const handleSubmitEnvelopeA = async () => {
if (!validateEnvelope()) {
Alert.alert('Validation Error', 'Please fill all mandatory fields');
return;
}
const payload = buildEnvelopePayload();
console.log('Envelope A Payload:', payload);
setLoading(true)
if (envelopForm?.[activeEnvelope]?.[3]) {
handleSubmitEnvelopeFile()
}
try {
const res = await apiCallForPostWithToken(SUBMIT_ENVELOPE_A, payload)
console.log("res A envelop : ", res)
ToastAndroid.show(res.message, ToastAndroid.SHORT)
navigation.goBack()
} catch (error) {
console.log("error A envelop submit : ", error)
} finally {
setLoading(false)
}
};
const handleSubmitEnvelopeB = async () => {
if (!validateEnvelope()) {
Alert.alert('Validation Error', 'Please fill all mandatory fields');
return;
}
setLoading(true)
const payload = buildEnvelopePayload();
console.log('Envelope B Payload:', payload);
if (envelopForm?.[activeEnvelope]?.[3]) {
handleSubmitEnvelopeFile()
}
try {
const res = await apiCallForPostWithToken(SUBMIT_ENVELOPE_B, payload)
console.log("res B envelop : ", res)
ToastAndroid.show(res.message, ToastAndroid.SHORT)
navigation.goBack()
} catch (error) {
console.log("error B envelop submit : ", error)
} finally {
setLoading(false)
}
}
const handleSubmitEnvelopeFile = async () => {
setLoadingUpload(true)
const payload = buildEnvelopePayload();
console.log(`Envelope file ${activeEnvelope} Payload:`, payload);
try {
const formData = new FormData();
formData.append('files', {
uri: envelopForm?.[activeEnvelope]?.[3].uri,
name: envelopForm?.[activeEnvelope]?.[3].name,
type: envelopForm?.[activeEnvelope]?.[3].type,
});
formData.append('requestDto', payload)
console.log("reuestDto for fil doc : ", formData)
// return
const res = await apiCallForPostWithToken(activeEnvelope === 'B' ? SUBMIT_ENVELOPE_B : SUBMIT_ENVELOPE_A, payload)
console.log(`res file ${activeEnvelope} Payload:`, res)
ToastAndroid.show(res.message, ToastAndroid.SHORT)
// navigation.goBack()
} catch (error) {
console.log(`Envelope file ${activeEnvelope} error:`, error)
} finally {
setLoadingUpload(false)
}
}
if (isLoading) {
return (
<>
<View style={styles.loadingContainer}>
<Text>Loading...</Text>
</View>
</>
);
}
console.log("route for date : ", route.params)
return (
<View style={styles.container}>
<InsideHeader title="Tender Bidding Start" showArrow />
<ScrollView contentContainerStyle={styles.scrollContainer}>
{/* Tender Info */}
<View style={styles.card}>
<View style={styles.row}>
<InfoRow title="Tender Number" value={bidData?.tenderNumber || '-'} />
<InfoRow title="NIT Number" value={bidData?.nitNo || '-'} />
</View>
<View style={styles.row}>
<InfoRow title="EMD (in Fig.)" value={bidData?.emdInFig || '-'} />
<InfoRow
title="Re-Bid Allowed"
value={bidData?.tenderRebid ? 'Yes' : 'No'}
/>
</View>
<InfoRow title="Bid Withdraw" value={bidData?.bidWithdraw || '-'} />
</View>
{/* Envelope Buttons */}
<View style={styles.card}>
<Text style={styles.sectionTitle}>Bid Envelopes</Text>
<View style={styles.envelopeRow}>
{bidData?.showEA && (
<EnvelopeButton
title="Envelope A"
envelopeType="A"
onPress={() => setActiveEnvelope('A')}
/>
)}
{bidData?.showEB && (
<EnvelopeButton
title="Envelope B"
envelopeType="B"
onPress={() => {
if
(bidData?.envelopeASubmittStatus) {
setActiveEnvelope('B')
} else {
Alert.alert('Info', 'First Fill Envelop A First')
}
}}
/>
)}
{bidData?.showEC && (
<EnvelopeButton
title="Envelope C"
envelopeType="C"
onPress={() => setActiveEnvelope('C')}
/>
)}
</View>
</View>
{/* Envelope A List */}
{bidData?.[`tenderEnvelope${activeEnvelope}List`]?.length > 0 && activeEnvelope !== 'C' && (
<View style={styles.card}>
<Text style={styles.sectionTitle}>Envelope {activeEnvelope} Details</Text>
<FlatList
data={bidData?.[`tenderEnvelope${activeEnvelope}List`]}
keyExtractor={(item) => item?.[`tenderEnvelope${activeEnvelope}SequnceId`]?.toString()}
renderItem={({ item }) => renderEnvelopeItem({ item, envelopeType: activeEnvelope })}
scrollEnabled={false}
/>
{/* <View style={[styles.infoRow, { flexDirection: 'row', gap: 10 }]}>
<TouchableOpacity onPress={() => setCheck(!check)}>
{check ? <Fontisto name="checkbox-active" size={24} color={colors.primary} /> :
<Fontisto name="checkbox-passive" size={24} color={colors.primary} />
}</TouchableOpacity>
<Text>Check First Terms&Condition</Text>
</View> */}
</View>
)}
<View style={styles.footer}>
{hasEnvelopes() ? (
<TouchableOpacity
style={styles.primaryButton}
onPress={() => {
if (!check) {
Alert.alert('Info', 'check first terms & condition')
}
if (activeEnvelope === 'A') {
handleSubmitEnvelopeA()
} else {
handleSubmitEnvelopeB()
}
}}
>
<Text style={styles.primaryButtonText}>{loading ? 'Submitting...' : `Submit Bid (${activeEnvelope})`}</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={styles.secondaryButton}
onPress={() => navigation.goBack()}
>
<Text style={styles.secondaryButtonText}>Go Back</Text>
</TouchableOpacity>
)}
</View>
</ScrollView>
</View>
);
};
export default TenderBidding;
const styles = StyleSheet.create({
container: {
flex: 1, backgroundColor: colors.white
},
scrollContainer: {
padding: 16,
paddingBottom: '100%',
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
marginBottom: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
},
sectionTitle: {
fontSize: 16,
fontWeight: '600',
marginBottom: 12,
color: '#333',
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 8,
},
infoRow: {
flex: 1,
marginBottom: 10,
},
label: {
fontSize: 13,
color: '#777',
marginBottom: 2,
},
value: {
fontSize: 15,
color: '#222',
fontWeight: '500',
},
envelopeRow: {
flexDirection: 'row',
gap: 10,
flexWrap: 'wrap',
},
envelopeButton: {
backgroundColor: '#EEF2FF',
paddingVertical: 10,
paddingHorizontal: 14,
borderRadius: 8,
minWidth: 100,
alignItems: 'center',
},
envelopeButtonText: {
color: '#3F51B5',
fontWeight: '600',
fontSize: 14,
},
envelopeItem: {
borderWidth: 1,
borderColor: '#eee',
borderRadius: 10,
padding: 12,
marginBottom: 12,
backgroundColor: '#f9f9f9',
flexDirection: 'row',
justifyContent: 'space-between'
},
footer: {
flexDirection: 'row',
justifyContent: 'flex-end',
marginVertical: 20,
},
primaryButton: {
backgroundColor: '#3F51B5',
paddingVertical: 14,
paddingHorizontal: 28,
borderRadius: 10,
minWidth: 120,
alignItems: 'center',
},
primaryButtonText: {
color: '#fff',
fontWeight: '600',
fontSize: 15,
},
secondaryButton: {
borderWidth: 1,
borderColor: '#EEF2FF',
paddingVertical: 14,
paddingHorizontal: 28,
borderRadius: 10,
minWidth: 120,
alignItems: 'center',
},
secondaryButtonText: {
color: '#3F51B5',
fontWeight: '600',
fontSize: 15,
},
});
+5 -1
View File
@@ -7,9 +7,11 @@ import Home from "./Home/Home";
import Login from "./Login/Login";
import Onboarding from "./Onboarding/Onboarding";
import Splash from "./Splash/Splash";
import ProceedToBidDetail from "./Tender/ProceedToBidDetail";
import ProceedToPurTender from "./Tender/ProceedToPurTender";
import PurchaseTenderList from "./Tender/PurchaseTenderList";
import Tender from "./Tender/Tender";
import TenderBidding from "./Tender/tenderBidding/TenderBidding";
const Screens = {
@@ -24,6 +26,8 @@ const Screens = {
StartBidding,
PurchaseAuctionList,
PurchaseTenderList,
ProceedToPurTender
ProceedToPurTender,
TenderBidding,
ProceedToBidDetail
}
export default Screens
+12 -1
View File
@@ -34,7 +34,7 @@ const PURCHASE_OFFLINE_AUCTION = `${BASE_URL_Auction}api/auction/purchaseAuction
const PURCHASE_TENDER = `https://procurelinc.in/EProcurementSB/tenderPayment/purchaseTender`
const PURCHASE_TENDER_OFFLINE = `https://procurelinc.in/EProcurementSB/tenderPayment/purchaseTenderOffline`
const AUCTION_PURCHASE_STATUS = `https://api.godemo.in/Auction/api/auction/transactionStatus?orderNo=`
const GET_TENDER_DETAILS = `${BASE_URL}eTendering/getTenderById?tenderId=`
const GET_TENDER_DETAILS = `https://procurelinc.in/EProcurementSB/tenderBidding/getTenderDetail?tenderId=`
const GET_DOCID = `${BASE_URL}eTendering/download/docId?docId=`
// https://procurelinc.in/EProcurementSB/eTendering/download/docId?docId=158
// const DOWNLOAD_DOC = `${BASE_URL}eTende ring/download/docId?docId=`
@@ -66,6 +66,12 @@ const DASHBOARD_COUNT = `${BASE_URL_Auction}api/auction/home/dashboard/counts`
//tender
const TENDER_LOGIN = `${BASE_URL}eproc/loginWithoutDecryption`
const PROCEED_TO_BID = `${BASE_URL}tenderBidding/proceedToBid?tenderId=`
const SUBMIT_ENVELOPE_A = `${BASE_URL}tenderBidding/getSaveEnvelopeAData`
const SUBMIT_ENVELOPE_B = `${BASE_URL}tenderBidding/getSaveEnvelopeBData`
const SUBMIT_ENVELOPE_FILE_A = `${BASE_URL}tenderBidding/addDocumentsEnvelopeA?requestDto=`
const SUBMIT_ENVELOPE_FILE_B = `${BASE_URL}tenderBidding/addDocumentsEnvelopeB?requestDto=`
export {
@@ -127,5 +133,10 @@ export {
PURCHASE_OFFLINE_AUCTION,
TENDER_LOGIN,
PURCHASE_TENDER_OFFLINE,
PROCEED_TO_BID,
SUBMIT_ENVELOPE_A,
SUBMIT_ENVELOPE_B,
SUBMIT_ENVELOPE_FILE_A,
SUBMIT_ENVELOPE_FILE_B
};
+36 -27
View File
@@ -1,5 +1,5 @@
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
import { fetchDashboard, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseTender, offlineAuctionPurchase, userLogin, offlineTenderPurchase, fetchTenderById } from './apis';
import { fetchDashboard, fetchLiveAuction, fetchLiveTender, fetchPurchaseAuction, fetchPurchaseTender, offlineAuctionPurchase, userLogin, offlineTenderPurchase, fetchTenderById, proceedToBid } from './apis';
// User
@@ -19,11 +19,31 @@ export const useDashboard = () => {
// Auction & Tender
export const useFetchPurchaseTender = (size: number) => {
return useQuery({
queryKey: ['purchaseTender', size],
queryFn: () => fetchPurchaseTender({ page: 0, size }),
});
export const useFetchPurchaseTender = () => {
return useInfiniteQuery({
queryKey: ['fetchPurchaseTender'],
initialPageParam: 1,
queryFn: ({ pageParam }) =>
fetchPurchaseTender({
page: pageParam,
size: 10,
}),
getNextPageParam: (lastPage) => {
const { page, size, totalCount } = lastPage;
const totalPages = Math.ceil(totalCount / size);
return page < totalPages ? page + 1 : undefined;
},
select: (data) => ({
...data,
result: data.pages.flatMap(
(page: any) => page?.data ?? []
),
}),
});
};
@@ -37,27 +57,7 @@ export const useFetchLiveTender = () => {
export const useFetchPurchaseAuction = () => {
return useQuery({
queryKey: ['fetchPurchaseAuction',],
queryFn: ({ pageParam = 1 }) =>
fetchPurchaseAuction({
page: pageParam,
size: 10,
}),
getNextPageParam: (lastPage: any) => {
const { page, size, totalCount } = lastPage;
const totalPages = Math.ceil(totalCount / size);
const nextPage = page + 1;
return nextPage < totalPages ? nextPage : undefined;
},
select: (data) => {
const mergedResults = data.pages.flatMap((page: any) => page.data ?? []);
console.log("mergedResults for tender : ", mergedResults)
return {
...data,
result: mergedResults,
};
},
queryFn: () => fetchPurchaseAuction()
});
};
@@ -107,7 +107,16 @@ export const useFetchTenderById = (tenderId: string) => {
return useQuery({
queryKey: ['fetchTenderById', tenderId],
queryFn: () => fetchTenderById(tenderId)
});
}
export const useProceedToBid = (tenderId?: string) => {
return useQuery({
queryKey: ['proceedToBid', tenderId],
queryFn: () => proceedToBid(tenderId as string),
enabled: false, // 👈 manual trigger
});
};
+20 -26
View File
@@ -1,5 +1,5 @@
import axios from "axios";
import { DASHBOARD_COUNT, GET_MY_AUCTION, GET_MY_TENDER, GET_TENDER_DETAILS, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PURCHASE_TENDER_OFFLINE, TENDER_LOGIN } from "./ApiUrls";
import { DASHBOARD_COUNT, GET_MY_AUCTION, GET_MY_TENDER, GET_TENDER_DETAILS, LIVE_AUCTION, LIVE_TENDER, LOG_IN_URL, PROCEED_PURCHASE_AUCTION, PROCEED_TO_BID, PURCHASE_TENDER_OFFLINE, TENDER_LOGIN } from "./ApiUrls";
import { apiCall } from "../../Axios/Axios";
// User
@@ -19,8 +19,8 @@ export const fetchDashboard = async (): Promise<any> => {
return data
}
export const fetchPurchaseAuction = async (payload: any): Promise<any> => {
const data = await apiCall<any>('get', `${GET_MY_AUCTION}`, {}, { payload });
export const fetchPurchaseAuction = async (): Promise<any> => {
const data = await apiCall<any>('get', `${GET_MY_AUCTION}`);
return data
}
export const fetchLiveAuction = async (payload: any): Promise<any> => {
@@ -49,43 +49,37 @@ export const offlineTenderPurchase = async (payload: any): Promise<any> => {
};
// tender
export const fetchPurchaseTender = async (payload: any): Promise<any> => {
const data = await apiCall<any>(
export const fetchPurchaseTender = async ({
page,
size,
}: {
page: number;
size: number;
}) => {
return apiCall<any>(
'get',
`${GET_MY_TENDER}`, {},
{ payload }
`${GET_MY_TENDER}?page=${page}&size=${size}`
);
return data;
};
// export const fetchPurchaseTender = async (
// page: number,
// size: number
// ): Promise<any> => {
// const data = await apiCall<any>(
// 'get',
// `${GET_MY_TENDER}?page=0&size=${size}`
// );
// console.log('Purchased Tenders Response:', data);
// return data;
// };
export const fetchLiveTender = async (): Promise<any> => {
const data = await apiCall<any>('get', `${LIVE_TENDER}`);
return data
}
export const fetchTenderById = async (tenderId: string): Promise<any> => {
console.log('Fetching tender with ID:', tenderId);
const data = await apiCall<any>(
'get',
`https://procurelinc.in/EProcurementSB/eTendering/getTenderById?tenderId=${tenderId}`
`${GET_TENDER_DETAILS}${tenderId}`
);
console.log('API response:', data);
return data;
};
export const proceedToBid = async (tenderId: string): Promise<any> => {
const data = await apiCall<any>(
'get',
`${PROCEED_TO_BID}${tenderId}`
);
return data;
}