This commit is contained in:
Abin Toppo
2026-01-28 16:08:19 +05:30
parent 78a74472dd
commit 080f1b57cd
25 changed files with 354 additions and 314 deletions
View File
View File
+2 -2
View File
@@ -11,7 +11,7 @@ export const apiCall = async <R, D = {}>(
): Promise<R> => {
try {
const token: any = store.getState().token.token;
console.log("api payload", data)
const response = await axios({
method,
url,
@@ -22,7 +22,7 @@ export const apiCall = async <R, D = {}>(
'Content-Type': contentType || 'application/json',
},
});
console.log("api response",response)
return response.data;
} catch (error: any) {
const errorMessage = error?.response?.data?.error;
+2 -1
View File
@@ -23,6 +23,7 @@ const NavigationString = {
Profile:'Profile',
ViewTenderDetail:'ViewTenderDetail',
ResetPassword:'ResetPassword',
KycWebViewScreen:'KycWebViewScreen'
KycWebViewScreen:'KycWebViewScreen',
StageThreeScreen:'StageThree'
}
export default NavigationString
+2
View File
@@ -48,6 +48,8 @@ export default function MainStack() {
<Stack.Screen name={NavigationString.ResetPassword} component={Screens.ResetPassword} options={option} />
<Stack.Screen name={NavigationString.ViewTenderDetail} component={Screens.ViewTenderDetail} options={option} />
<Stack.Screen name={NavigationString.KycWebViewScreen} component={Screens.KycWebViewScreen} options={option} />
<Stack.Screen name={NavigationString.StageThreeScreen} component={Screens.StageThreeScreen} options={option} />
</Stack.Navigator>
);
}
+6 -24
View File
@@ -15,37 +15,24 @@ import Skeleton from '../../Component/Skelton/Skelton';
const LiveAuction = () => {
const Dispatch = useDispatch()
const user = useSelector((state: any) => state.token?.token);
const onEndReachedCalledDuringMomentum = useRef(true);
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseAuction);
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
const [allBoolean, setAllBoolean] = useState({ liveAuctionData: [], isLoading: false })
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch, isPending }: any = useFetchLiveAuction();
console.log("object----",data,)
// My Methods
const getMyAuction = async () => {
try {
setAllBoolean(prev => ({ ...prev, isLoading: true }))
const res = await apiCall<any>('get', `${GET_MY_AUCTION}`,);
if (res?.statusCode === 200) {
const purchasedIds = new Set(res.data.map((item: any) => item.auctionId));
const filteredLive = data?.result.map((item: any) => ({ ...item, active: !purchasedIds.has(item.auctionId) }));
setAllBoolean(prev => ({ ...prev, liveAuctionData: filteredLive }));
}
} catch (error) {
console.error('getMyAuction error', error);
} finally {
setAllBoolean(prev => ({ ...prev, isLoading: false }));
}
};
const renderItem = useCallback(
({ item, index }: any) => {
console.log("item core ",item)
const isPurchase = SelectedPurchaseList.findIndex((prev: any) => prev.auctionNumber === item.auctionNumber)
return <LiveAuctionTile
data={item}
index={index}
isPurchasedByContractor={item.contractorId?.includes(String(user.contractorId))}
auctionId={item.auctionId}
auctionDispatchDate={item.auctionDispatchDate}
isPurchased={isPurchase !== -1 ? true : false}
@@ -90,11 +77,6 @@ const LiveAuction = () => {
}
}, [isRefetching]);
useEffect(() => {
if (data?.result?.length > 0) {
getMyAuction()
}
}, [data])
if (isLoading) {
return <Skelton />;
@@ -141,9 +123,9 @@ const LiveAuction = () => {
</Animated.View>
)}
{
isPending || allBoolean.isLoading ? <Skeleton /> :
isPending ? <Skeleton /> :
<FlatList
data={allBoolean.liveAuctionData ?? []}
data={data?.result ?? []}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 50, paddingTop: 10 }}
+6 -4
View File
@@ -15,7 +15,9 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
purchaseEnd,
auctionFees,
auctionNumber,
isPurchasedByContractor
}) => {
console.log("1",data)
const [showDetail, setShowDetail] = React.useState(false);
const purchaseEnded = moment().isAfter(moment(purchaseEnd, 'DD-MM-YYYY HH:mm:ss'));
@@ -80,12 +82,12 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
styles.mainButton,
purchaseEnded
? styles.btnDisabled
: !data.active ? { backgroundColor: 'lightgray' } : isPurchased
: isPurchasedByContractor ? { backgroundColor: 'lightgray' } : isPurchased
? styles.btnPurchased
: styles.btnActive,
]}
onPress={onPurchasePress}
disabled={purchaseEnded ? true : data.active ? false : true}
disabled={purchaseEnded ? true : !isPurchasedByContractor ? false : true}
>
<Text
style={[
@@ -93,9 +95,9 @@ const LiveAuctionTile: React.FC<LiveAuctionTileProps> = ({
isPurchased && !purchaseEnded ? { color: colors.white } : { color: '#fff' },
]}
>
{purchaseEnded ? 'Expired' : !data.active ? 'Purchased' : isPurchased ? 'Remove' : 'Add to Cart'}
{purchaseEnded ? (isPurchasedByContractor ? 'Purchased' : 'Expired') : isPurchasedByContractor ? 'Purchased' : isPurchased ? 'Remove' : 'Add to Cart'}
</Text>
{!purchaseEnded && (
{!purchaseEnded && !isPurchasedByContractor && (
<ArrowRight size={16} color={isPurchased ? colors.white : '#fff'} />
)}
</TouchableOpacity>
+28 -3
View File
@@ -20,6 +20,7 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
const [allBoolean, setAllBoolean] = useState({ showItemDetail: false, selectedItem: {}, fileLoading: false });
const { data: auctionDocuments } = useGetAucitonDocument({ auctionId: data?.auctionId })
const { mutate } = useAuctionItem()
console.log("jkjkjk",auctionData)
const formatDate = (date?: string) => {
if (!date) return '-';
@@ -156,18 +157,42 @@ const AuctionFullDetail: React.FC<Props> = ({ visible, onClose, data }) => {
<View style={styles.iconCircle}><Clock size={16} color="#64748b" /></View>
<View>
<Text style={styles.label}>Auction Purchase (Start)</Text>
<Text style={styles.value}>{formatDate(data?.auctionDispatchDate)}</Text>
<Text style={styles.value}>{formatDate(
auctionData?.auctionStatus === "Amended" ? auctionData?.amendedkeyDates.auctionPurchase.startDateTime : auctionData?.keyDates.auctionPurchase.startDateTime)}</Text>
</View>
</View>
<View style={styles.timelineConnector} />
<View style={styles.timelineRow}>
<View style={[styles.iconCircle, { backgroundColor: '#fee2e2' }]}><Clock size={16} color="#ef4444" /></View>
<View>
<Text style={styles.label}>Purchase Deadline (End)</Text>
<Text style={styles.value}>{formatDate(data?.keyDates?.auctionPurchase?.startDateTime)}</Text>
<Text style={styles.label}>Purchase Purchase (End)</Text>
<Text style={styles.value}>{formatDate(
auctionData?.auctionStatus === "Amended" ? auctionData?.amendedkeyDates.auctionPurchase.endDateTime : auctionData?.keyDates.auctionPurchase.endDateTime)}</Text>
</View>
</View>
<View style={styles.timelineConnector} />
<View style={styles.timelineRow}>
<View style={styles.iconCircle}><Clock size={16} color="#64748b" /></View>
<View>
<Text style={styles.label}>Bidding Start (Start)</Text>
<Text style={styles.value}>{formatDate(
auctionData?.auctionStatus === "Amended" ? auctionData?.amendedkeyDates.auctionBidding.startDateTime : auctionData?.keyDates.auctionBidding.startDateTime)}</Text>
</View>
</View>
<View style={styles.timelineConnector} />
<View style={styles.timelineRow}>
<View style={[styles.iconCircle, { backgroundColor: '#fee2e2' }]}><Clock size={16} color="#ef4444" /></View>
<View>
<Text style={styles.label}>Bidding Deadline (End)</Text>
<Text style={styles.value}>{formatDate(
auctionData?.auctionStatus === "Amended" ? auctionData?.amendedkeyDates.auctionBidding.endDateTime : auctionData?.keyDates.auctionBidding.endDateTime)}</Text>
</View>
</View>
</View>
</Section>
{/* 4. Item Table Section */}
+2 -1
View File
@@ -35,8 +35,9 @@ const PurchaseAuction = () => {
}
function isAuctionEnd(item: any): boolean {
console.log("item wih power ",item)
const now = moment();
const end = moment(item?.keyDates?.auctionBidding?.endDateTime, format);
const end = moment(item.auctionStatus === "Amended" ? item?.amendedkeyDates?.auctionBidding?.endDateTime : item?.keyDates?.auctionBidding?.endDateTime, format);
if (!end.isValid()) return false;
+2 -2
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { use, 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';
@@ -79,7 +79,7 @@ const PurchaseAuctionList = () => {
}
},
onError: (error) => {
console.log(error, "================purchse Error");
// console.log(error, "================purchse Error");
}
})
+4 -4
View File
@@ -10,7 +10,7 @@ const PurchaseAuctionTile = ({ item, onPressDetails, onStartBidding, buttonEnabl
const [showDetail, setShowDetail] = React.useState(false);
const scale = useSharedValue(1);
const elevation = useSharedValue(8);
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", item);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
@@ -73,14 +73,14 @@ const PurchaseAuctionTile = ({ item, onPressDetails, onStartBidding, buttonEnabl
<Text style={styles.dateText}>
<Text style={styles.dateLabel}>Bidding Start: </Text>
{moment(
item?.keyDates?.auctionBidding?.startDateTime?.replace(' kk', ''),
item?.auctionStatus === "Amended" ? item?.amendedkeyDates?.auctionBidding?.startDateTime?.replace(' kk', '') : item?.keyDates?.auctionBidding?.startDateTime?.replace(' kk', ''),
'DD-MM-YYYY HH:mm:ss'
).format('DD MMM YYYY, hh:mm A')}
</Text>
<Text style={styles.dateText}>
<Text style={styles.dateLabel}>Bidding Ends: </Text>
{moment(
item?.keyDates?.auctionBidding?.endDateTime?.replace(' kk', ''),
item?.auctionStatus === "Amended" ? item?.amendedkeyDates?.auctionBidding?.endDateTime?.replace(' kk', '') : item?.keyDates?.auctionBidding?.endDateTime?.replace(' kk', ''),
'DD-MM-YYYY HH:mm:ss'
).format('DD MMM YYYY, hh:mm A')}
</Text>
@@ -92,7 +92,7 @@ const PurchaseAuctionTile = ({ item, onPressDetails, onStartBidding, buttonEnabl
<Text style={styles.footerLabel}>Remaining Time</Text>
{buttonEnable && !isAuctionEnd ? (
<CountdownTimer
endDate={item.keyDates.auctionBidding.endDateTime}
endDate={item?.auctionStatus === "Amended" ? item?.amendedkeyDates?.auctionBidding?.endDateTime : item?.keyDates?.auctionBidding?.endDateTime}
/>
) : (
<Text style={styles.endedText}>--:--:--</Text>
+1
View File
@@ -38,6 +38,7 @@ useEffect(() => {
{/* Cards */}
{SelectedPurchaseList.map((item: any, index: any) => {
console.log("item nn", item);
const expanded = expandedIndex === index;
return (
<Animated.View
+1
View File
@@ -10,6 +10,7 @@ export interface LiveAuctionTileProps {
isPurchased?: boolean;
auctionId?: any;
auctionNumber?: any;
isPurchasedByContractor?: boolean
}
export interface allBooleanProps {
+2 -1
View File
@@ -465,7 +465,8 @@ const EditProfileModal: React.FC<EditProfileModalProps> = ({
}
try {
await updateProfileMutation.mutateAsync(formData);
const result = await updateProfileMutation.mutateAsync(formData);
console.log("UserProfile ",result)
Alert.alert('Success', 'Profile updated successfully');
onSuccess();
onClose();
+6 -5
View File
@@ -19,6 +19,7 @@ import MyInput from '../../Component/MyInput';
import { showToast } from '../../Constant/ShowDailog';
import { STAGETHREE } from '../../Services/BBPS/ApiUrls';
import { useContractorStageThreeSubmit } from '../../Services/BBPS/Hooks';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
type Company = {
@@ -37,7 +38,7 @@ type StageThreeRouteParams = {
const StageThreeScreen = () => {
const route = useRoute<RouteProp<{ params: StageThreeRouteParams }, 'params'>>();
const navigation = useNavigation<any>();
const insets = useSafeAreaInsets()
const [company, setCompany] = useState<Company[]>([
{
director: '',
@@ -71,7 +72,7 @@ const StageThreeScreen = () => {
]);
};
console.log("first company route : ", route);
const handleSubmit = async () => {
setLoading(true);
try {
@@ -119,8 +120,8 @@ const StageThreeScreen = () => {
};
return (
<View style={{ flex: 1 }}>
<Text style={styles.heading}>Stage Three For {route.params?.orgType == '4' ? 'Public' : route.params?.orgType == '5' ? 'Private' : route.params?.orgType == '6' ? 'Limited Liability Partnership (LLP)' : route.params?.orgType} Organization</Text>
<View style={{ flex: 1 ,paddingHorizontal:10 }}>
<Text style={[styles.heading,{marginTop:insets.top}]}>Stage Three For {route.params?.orgType == '4' ? 'Public' : route.params?.orgType == '5' ? 'Private' : route.params?.orgType == '6' ? 'Limited Liability Partnership (LLP)' : route.params?.orgType} Organization</Text>
<SafeAreaView style={{ flex: 1 }}>
<KeyboardAvoidingView
style={{ flex: 1 }}
@@ -225,7 +226,7 @@ const styles = StyleSheet.create({
marginBottom: 10,
},
scrollContainer: {
// backgroundColor: color.background,
flexGrow: 1,
},
addButton: {
@@ -42,6 +42,7 @@ const StageOne: React.FC<Props> = ({
setSelectedOrg,
selectedOrg
}) => {
console.log("masterdata",allOrganizations,allMsmeOrgs,allSocialCategories,contractorClassItems,selectedOrg !== 8)
const [selectedAllMSME, setSelectedAllMSME] = useState()
const [open, setOpen] = useState(false)
+9 -2
View File
@@ -49,9 +49,16 @@ const Splash: React.FC = () => {
const routeByOrgType = (params: { otherId: any; orgType: any }) => {
const orgType = String(params.orgType);
// const orgType = params.orgType;
const orgType = "7" as string; // For testing purpose
console.log("orgType value:", orgType);
console.log("orgType type:", typeof orgType);
if (orgType === '4' || orgType === '5' || orgType === '6') {
navigation.replace('StageThree', params);
navigation.replace(NavigationString.StageThreeScreen, params);
return;
}
@@ -1,285 +1,285 @@
import React, { useEffect, useState } from 'react';
import { View, Text, TextInput, ScrollView, TouchableOpacity, StyleSheet, ActivityIndicator, Alert, } from 'react-native';
import {
View,
Text,
TextInput,
ScrollView,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
Alert,
} from 'react-native';
import RNFS from 'react-native-fs';
import * as XLSX from 'xlsx';
import axios from 'axios';
import { useSelector } from 'react-redux';
import { InsideHeader } from '../../../Component/Index';
import colors from '../../../Constant/Color';
import { GET_ENVELOPE_C, SUBMIT_ENVELOPE_C_UPLOAD } from '../../../Services/BBPS/ApiUrls';
import { useNavigation } from '@react-navigation/native';
/* -------------------- UTILS -------------------- */
// Excel column keys
const QTY_KEY = '__EMPTY_1';
const RATE_KEY = '__EMPTY_2';
const VALUE_KEY = '__EMPTY_3';
const TOTAL_LABEL = 'TOTAL';
// Convert ArrayBuffer → Base64
const arrayBufferToBase64 = (buffer: ArrayBuffer) => {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return global.btoa(binary);
};
const EnvelopeCExcelPreview = (tenderData: any) => {
const token = useSelector((state: any) => state.token.token);
const navigation = useNavigation() as any;
const [data, setData] = useState<any[]>([]);
const [columns, setColumns] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
console.log("kllkl",tenderData)
useEffect(() => {
loadExcelFromApi();
}, []);
// Find column dynamically by keywords
const findColumnKey = (columns: string[], keywords: string[]) =>
columns.find(col =>
keywords.some(k => col.toLowerCase().includes(k.toLowerCase()))
);
// ArrayBuffer → Base64
const arrayBufferToBase64 = (buffer: ArrayBuffer) => {
let binary = '';
const bytes = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
// Detect TOTAL row (any column contains TOTAL)
const isTotalRow = (row: any) =>
Object.values(row).some(v => String(v).toUpperCase() === 'TOTAL');
/* -------------------- COMPONENT -------------------- */
const EnvelopeCExcelPreview = (props: any) => {
const tenderData = props;
const token = useSelector((state: any) => state.token.token);
const navigation = useNavigation() as any;
const [data, setData] = useState<any[]>([]);
const [columns, setColumns] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadExcelFromApi();
}, []);
/* -------------------- LOAD EXCEL -------------------- */
const loadExcelFromApi = async () => {
try {
setLoading(true);
const response = await axios.get(
`${GET_ENVELOPE_C}${tenderData?.tenderId?.tenderId}`,
{
responseType: 'arraybuffer',
headers: {
Authentication: `Bearer ${token.token}`,
},
}
return global.btoa(binary);
};
);
// Calculate TOTAL VALUE
const calculateTotal = (rows: any[]) =>
rows.reduce((sum, row) => {
if (typeof row['DEMO DEPARTEMENT'] !== 'number') return sum;
const val = Number(row[VALUE_KEY]);
return sum + (isNaN(val) ? 0 : val);
}, 0);
const base64 = arrayBufferToBase64(response.data);
const workbook = XLSX.read(base64, { type: 'base64' });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows: any[] = XLSX.utils.sheet_to_json(sheet, { defval: '' });
// LOAD EXCEL
const loadExcelFromApi = async () => {
try {
setLoading(true);
setColumns(Object.keys(rows[0] || {}));
setData(rows);
const response = await axios.get(`${GET_ENVELOPE_C}${tenderData?.tenderId?.tenderId}`, {
responseType: 'arraybuffer',
headers: {
Authentication: `Bearer ${token.token}`,
},
});
console.log("excel response",response)
} catch (e) {
Alert.alert('Error', 'Failed to load Excel');
} finally {
setLoading(false);
}
};
const base64 = arrayBufferToBase64(response.data);
const workbook = XLSX.read(base64, { type: 'base64' });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows: any[] = XLSX.utils.sheet_to_json(sheet, { defval: '' });
/* -------------------- UPDATE CELL -------------------- */
setColumns(Object.keys(rows[0] || {}));
setData(rows);
const updateCell = (rowIndex: number, key: string, value: string) => {
const updated = [...data];
const row = updated[rowIndex];
await RNFS.writeFile(
`${RNFS.DocumentDirectoryPath}/envelopeC.xlsx`,
base64,
'base64'
);
} catch (e) {
Alert.alert('Error', 'Failed to load Excel');
} finally {
setLoading(false);
}
};
if (isTotalRow(row)) return;
// UPDATE CELL (QTY / RATE) + AUTO VALUE + AUTO TOTAL
const updateCell = (rowIndex: number, key: string, value: string) => {
const updated = [...data];
const row = updated[rowIndex];
const qtyKey:any = findColumnKey(columns, ['qty', 'quantity']);
const rateKey:any = findColumnKey(columns, ['rate', 'price']);
const valueKey = findColumnKey(columns, ['value', 'amount', 'total']);
// TOTAL row locked
if (row['DEMO DEPARTEMENT'] === TOTAL_LABEL) return;
if (key === qtyKey || key === rateKey) {
row[key] = value;
// Allow only QTY & RATE edit
if (key === QTY_KEY || key === RATE_KEY) {
row[key] = value;
const qty = Number(row[qtyKey]);
const rate = Number(row[rateKey]);
const qty = Number(row[QTY_KEY]);
const rate = Number(row[RATE_KEY]);
// 🔥 Auto VALUE = QTY × RATE
row[VALUE_KEY] =
!isNaN(qty) && !isNaN(rate) ? qty * rate : 0;
}
// 🔥 Update TOTAL
const totalRowIndex = updated.findIndex(
r => r['DEMO DEPARTEMENT'] === TOTAL_LABEL
);
if (totalRowIndex !== -1) {
updated[totalRowIndex][VALUE_KEY] = calculateTotal(updated);
}
setData(updated);
};
// SAVE UPDATED EXCEL
const saveUpdatedExcel = async () => {
try {
setLoading(true);
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// Generate binary string
const binary = XLSX.write(workbook, {
bookType: 'xlsx',
type: 'binary',
});
// Convert binary string to buffer
const buffer = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
buffer[i] = binary.charCodeAt(i) & 0xff;
}
const filePath = `${RNFS.DocumentDirectoryPath}/envelopeC_updated.xlsx`;
// Write as binary
await RNFS.writeFile(filePath, buffer.toString(), 'ascii');
// const fileBinary = await RNFS.readFile(filePath, 'ascii');
// console.log('Excel binary content:', fileBinary);
// Alert.alert('Success', 'Excel saved successfully');
const formData = new FormData();
// requestDto payload
formData.append(
'requestDto',
JSON.stringify({
tenderId: tenderData?.tenderId?.tenderId,
deptId: tenderData?.tenderId?.deptId,
typesOfTender: tenderData?.tenderId?.typesOfTender,
fieldValue: '',
fieldValueInWord: 'zero',
})
);
// binary file
formData.append('file', {
uri: `file://${filePath}`,
name: 'envelopeC_updated.xlsx',
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const res = await axios.post(SUBMIT_ENVELOPE_C_UPLOAD, formData, {
headers: {
'Content-Type': 'multipart/form-data',
Authentication: `Bearer ${token.token}`,
},
});
navigation.goBack();
console.log("res of updated excel file : ", res)
} catch (e) {
console.error(e);
Alert.alert('Error', 'Save failed');
} finally {
setLoading(false);
}
};
if (loading) {
return (
<View style={styles.loader}>
<ActivityIndicator size="large" />
</View>
);
if (valueKey) {
row[valueKey] =
!isNaN(qty) && !isNaN(rate) ? qty * rate : 0;
}
}
// Recalculate TOTAL
const totalRowIndex = updated.findIndex(isTotalRow);
if (totalRowIndex !== -1 && valueKey) {
updated[totalRowIndex][valueKey] = updated.reduce((sum, r) => {
if (isTotalRow(r)) return sum;
const val = Number(r[valueKey]);
return sum + (isNaN(val) ? 0 : val);
}, 0);
}
setData(updated);
};
/* -------------------- SAVE & UPLOAD EXCEL -------------------- */
const saveUpdatedExcel = async () => {
try {
setLoading(true);
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
const binary = XLSX.write(workbook, {
bookType: 'xlsx',
type: 'binary',
});
const buffer = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
buffer[i] = binary.charCodeAt(i) & 0xff;
}
const filePath = `${RNFS.DocumentDirectoryPath}/envelopeC_updated.xlsx`;
await RNFS.writeFile(filePath, buffer.toString(), 'ascii');
const formData = new FormData();
formData.append(
'requestDto',
JSON.stringify({
tenderId: tenderData?.tenderId?.tenderId,
deptId: tenderData?.tenderId?.deptId,
typesOfTender: tenderData?.tenderId?.typesOfTender,
fieldValue: '',
fieldValueInWord: 'zero',
})
);
formData.append('file', {
uri: `file://${filePath}`,
name: 'envelopeC_updated.xlsx',
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
await axios.post(SUBMIT_ENVELOPE_C_UPLOAD, formData, {
headers: {
'Content-Type': 'multipart/form-data',
Authentication: `Bearer ${token.token}`,
},
});
navigation.goBack();
} catch (e) {
Alert.alert('Error', 'Save failed');
} finally {
setLoading(false);
}
};
/* -------------------- UI -------------------- */
if (loading) {
return (
<View style={styles.container}>
<ScrollView horizontal contentContainerStyle={{ paddingHorizontal: 10, paddingTop: 20, backgroundColor: colors.white }}>
<View>
{/* HEADER */}
<View style={styles.row}>
{columns.map(col => (
<Text key={col} style={styles.headerCell}>
{col}
</Text>
))}
</View>
{/* DATA */}
<ScrollView style={{ maxHeight: 420 }}>
{data.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{columns.map(key => {
const isTotal = row['DEMO DEPARTEMENT'] === TOTAL_LABEL;
const isEditable =
!isTotal && (key === QTY_KEY || key === RATE_KEY);
return (
<TextInput
key={key}
value={String(row[key])}
editable={isEditable}
keyboardType={
key === QTY_KEY || key === RATE_KEY
? 'numeric'
: 'default'
}
style={[
styles.cell,
isTotal && styles.totalCell,
key === VALUE_KEY && styles.valueCell,
]}
onChangeText={text =>
updateCell(rowIndex, key, text)
}
/>
);
})}
</View>
))}
</ScrollView>
</View>
</ScrollView>
{tenderData?.buttonEnable && <TouchableOpacity style={styles.button} onPress={saveUpdatedExcel}>
<Text style={styles.buttonText}>Save Updated Excel</Text>
</TouchableOpacity>}
</View>
<View style={styles.loader}>
<ActivityIndicator size="large" />
</View>
);
}
const qtyKey = findColumnKey(columns, ['qty', 'quantity']);
const rateKey = findColumnKey(columns, ['rate', 'price']);
const valueKey = findColumnKey(columns, ['value', 'amount', 'total']);
return (
<View style={styles.container}>
<ScrollView horizontal contentContainerStyle={{ padding: 10 }}>
<View>
{/* HEADER */}
<View style={styles.row}>
{columns.map(col => (
<Text key={col} style={styles.headerCell}>{col}</Text>
))}
</View>
{/* DATA */}
<ScrollView style={{ maxHeight: 420 }}>
{data.map((row, rowIndex) => (
<View key={rowIndex} style={styles.row}>
{columns.map(key => {
const editable =
!isTotalRow(row) && (key === qtyKey || key === rateKey);
return (
<TextInput
key={key}
value={String(row[key])}
editable={editable}
keyboardType={editable ? 'numeric' : 'default'}
style={[
styles.cell,
isTotalRow(row) && styles.totalCell,
key === valueKey && styles.valueCell,
]}
onChangeText={text =>
updateCell(rowIndex, key, text)
}
/>
);
})}
</View>
))}
</ScrollView>
</View>
</ScrollView>
{tenderData?.buttonEnable && (
<TouchableOpacity style={styles.button} onPress={saveUpdatedExcel}>
<Text style={styles.buttonText}>Save Updated Excel</Text>
</TouchableOpacity>
)}
</View>
);
};
export default EnvelopeCExcelPreview;
/* -------------------- STYLES -------------------- */
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff' },
loader: { flex: 1, justifyContent: 'center', alignItems: 'center' },
title: { fontSize: 18, fontWeight: '700', marginBottom: 10 },
row: { flexDirection: 'row' },
headerCell: {
minWidth: 140,
padding: 10,
backgroundColor: '#f1f5f9',
borderWidth: 1,
fontWeight: '700',
},
cell: {
minWidth: 140,
padding: 10,
borderWidth: 1,
borderColor: '#cbd5e1',
},
valueCell: {
backgroundColor: '#f8fafc',
},
totalCell: {
backgroundColor: '#e5e7eb',
fontWeight: '700',
},
button: {
marginTop: 15,
backgroundColor: colors.primary,
padding: 14,
borderRadius: 8,
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontWeight: '600',
},
container: { flex: 1, backgroundColor: '#fff' },
loader: { flex: 1, justifyContent: 'center', alignItems: 'center' },
row: { flexDirection: 'row' },
headerCell: {
minWidth: 140,
padding: 10,
backgroundColor: '#f1f5f9',
borderWidth: 1,
fontWeight: '700',
},
cell: {
minWidth: 140,
padding: 10,
borderWidth: 1,
borderColor: '#cbd5e1',
},
valueCell: {
backgroundColor: '#f8fafc',
},
totalCell: {
backgroundColor: '#e5e7eb',
fontWeight: '700',
},
button: {
margin: 15,
backgroundColor: colors.primary,
padding: 14,
borderRadius: 8,
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontWeight: '600',
},
});
+3 -1
View File
@@ -17,7 +17,7 @@ const LiveTender = () => {
console.log("userdata",user)
const SelectedPurchaseList = useSelector((state: any) => state.selectPurchaseTender);
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isRefetching, refetch }: any = useFetchLiveTender();
console.log("to show ",data)
const [showRefreshBanner, setShowRefreshBanner] = useState(false);
useEffect(() => {
@@ -49,6 +49,8 @@ const LiveTender = () => {
const renderItem = useCallback(
({ item, index }: any) => {
console.log("opopopopoopopopop",item.tenderNumber,item)
if(item.tenderStatus==="Cancelled") return null;
const isPurchase = SelectedPurchaseList.findIndex((prev: any) => prev.tenderId === item.tenderId)
return <LiveTenderTile
contractorId={user?.id}
+10 -7
View File
@@ -52,6 +52,7 @@ const LiveTenderDetail = () => {
const tender = route?.params;
console.log("object---",tender)
const { data } = useFetchLiveTenderById(tender?.tenderId);
console.log("huh",data)
const [downloadingId, setDownloadingId] = useState<string | number | null>(null);
const insets = useSafeAreaInsets()
if (!data?.data?.[0]) return null;
@@ -198,38 +199,40 @@ const LiveTenderDetail = () => {
<InfoRow
label="Purchase Start"
value={formatDateTime(
tenderData?.keydates?.tenderPurchaseDate?.startDateTime,
tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.tenderPurchaseDate?.startDateTime : tenderData?.keydates?.tenderPurchaseDate?.startDateTime
)}
/>
<InfoRow
label="Purchase End"
value={formatDateTime(
tenderData?.keydates?.tenderPurchaseDate?.endDateTime,
tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.tenderPurchaseDate?.endDateTime : tenderData?.keydates?.tenderPurchaseDate?.endDateTime
)}
/>
<InfoRow
label="Bid Submission Start"
value={formatDateTime(
tenderData?.keydates?.bidSubmissionDate?.startDateTime,
tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.bidSubmissionDate?.startDateTime : tenderData?.keydates?.bidSubmissionDate?.startDateTime
)}
/>
<InfoRow
label="Bid Submission End"
value={formatDateTime(
tenderData?.keydates?.bidSubmissionDate?.endDateTime,
tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.bidSubmissionDate?.endDateTime : tenderData?.keydates?.bidSubmissionDate?.endDateTime,
)}
/>
<InfoRow
label="Opening Envelope A"
value={formatDateTime(tenderData?.keydates?.openingEA)}
value={formatDateTime(
tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.openingEA : tenderData?.keydates?.openingEA
)}
/>
<InfoRow
label="Opening Envelope B"
value={formatDateTime(tenderData?.keydates?.openingEB)}
value={formatDateTime(tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.openingEB : tenderData?.keydates?.openingEB)}
/>
<InfoRow
label="Opening Envelope C"
value={formatDateTime(tenderData?.keydates?.openingEC)}
value={formatDateTime(tender.tenderStatus === "Amended" ? tenderData?.tenderKeyDatesAmendment?.openingEC : tenderData?.keydates?.openingEC)}
/>
</View>
</Section>
+7 -4
View File
@@ -21,7 +21,7 @@ const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
tenderNumber,
}) => {
const navigation: any = useNavigation();
const purchaseEnded = !moment().isAfter(moment(purchaseEnd, 'DD-MM-YYYY HH:mm:ss'));
const purchaseEnded = moment().isAfter(moment(purchaseEnd, 'YYYY-MM-DD HH:mm:ss'));
const contractorIds = typeof data?.contractorId === 'string'
? data.contractorId.split(',').map((id: any) => id.trim())
@@ -30,7 +30,10 @@ const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
: [];
const purchased = contractorIds.includes(String(contractorId));
console.log("item is ",data)
if(data.tenderStatus==="Amended"){
}
return (
<View style={styles.cardWrapper}>
@@ -77,7 +80,7 @@ const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
<View style={styles.infoTextGroup}>
<Text style={styles.infoLabel}>Deadline</Text>
<Text style={[styles.infoValue, purchaseEnded && { color: '#ef4444' }]}>
{moment(purchaseEnd, 'DD-MM-YYYY HH:mm:ss').format('DD MMM, YY')}
{moment(purchaseEnd, 'YYYY-MM-DD HH:mm:ss').format('DD MMM, YY')}
</Text>
</View>
</View>
@@ -108,7 +111,7 @@ const LiveTenderTile: React.FC<LiveTenderTileProps> = ({
isPurchased && !purchaseEnded ? { color: colors.white } : { color: '#fff' },
]}
>
{purchaseEnded ? 'Expired' : (purchased ? 'Purchased' : isPurchased ? 'Remove' : 'Add to Cart')}
{purchaseEnded ? (purchased ? 'Purchased' : 'Expired') : (purchased ? 'Purchased' : isPurchased ? 'Remove' : 'Add to Cart')}
</Text>
{(!purchaseEnded && !purchased) && (
<ArrowRight size={16} color={isPurchased ? colors.white : '#fff'} />
+4 -1
View File
@@ -12,6 +12,7 @@ import Onboarding from "./Onboarding/Onboarding";
import ProfileTab from "./Profile/ProfileTab";
import Partnership from "./Ragistration/PartnerShip";
import Registration from "./Ragistration/Ragistration";
import StageThreeScreen from "./Ragistration/StageThree";
import Signup from "./SignUp/SignUp";
import Splash from "./Splash/Splash";
import LiveTenderDetail from "./Tender/LiveTenderDetail";
@@ -46,6 +47,8 @@ const Screens = {
ProfileTab,
ViewTenderDetail,
ResetPassword,
KycWebViewScreen
KycWebViewScreen,
StageThreeScreen
}
export default Screens
+4
View File
@@ -26,6 +26,7 @@ type City = { id: number; name: string };
export const userLogin = async (payload: { emailAdd: string, password: string }): Promise<any> => {
try {
console.log("RES",payload)
// const response = await axios.post(LOG_IN_URL, { ...payload, divice: "mobileApp" });
const response = await axios.post(TENDER_LOGIN, { ...payload, device: "mobileApp" });
return response.data;
@@ -141,6 +142,7 @@ export const fetchLiveTender = async ({page, size}:{page:number, size:number}):
}
export const fetchContractorProfile = async (): Promise<any> => {
const data = await apiCall<any>('get', `${GET_CONTRACTOR_PROFILE}`);
console.log("ContractorProfile data : ", data)
return data.data
}
export const fetchTenderById = async (tenderId: string): Promise<any> => {
@@ -191,6 +193,7 @@ export const updateUserProfile = (
fullname: string
}
): Promise<any> => {
console.log("UserProfile",payload)
return apiCall<any>(
'put',
CONTRACTOR_PROFILE_UPDATE,
@@ -231,6 +234,7 @@ export const contractorStageThreeSubmit = (
export const contractorStageTwoSubmit = (
fileData: any
): Promise<any> => {
console.log("contractorStageTwoSubmit",fileData)
return apiCall<any>(
'post',
REJ_STAGE_TWO,
View File